From 7d53aa1944b4238c9b284d8684b8ab21fcf67b8f Mon Sep 17 00:00:00 2001 From: Misieq01 <38589417+Misieq01@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:06:20 +0200 Subject: [PATCH] chore(ui): implement listening to outside app activity (#30) Description --- Change autominer behavior so it would listen to user mouse movement outside app context Motivation and Context --- How Has This Been Tested? --- Manually What process can a PR reviewer use to test or verify this change? --- Turn on autominer and position mouse outside app window then be idle for 30 seconds, minining should by then start and if you move mouse it should stop Breaking Changes --- - [x] None - [ ] Requires data directory on base node to be deleted - [ ] Requires hard fork - [ ] Other - Please specify --- package-lock.json | 10 -- package.json | 1 - src-tauri/Cargo.lock | 38 ++++++ src-tauri/Cargo.toml | 1 + src-tauri/src/app_config.rs | 17 ++- src-tauri/src/main.rs | 66 +++++++++- src-tauri/src/user_listener.rs | 121 ++++++++++++++++++ src-tauri/tauri.conf.json | 1 + src/App.tsx | 12 ++ .../MiningView/components/MiningButton.tsx | 10 +- .../SideBar/Miner/components/AutoMiner.tsx | 49 +------ src/hooks/useGetStatus.ts | 9 +- src/hooks/useMining.ts | 11 +- src/store/appStateStore.ts | 2 - src/store/useAppStatusStore.ts | 13 +- src/store/useUIStore.ts | 8 +- src/types.ts | 2 +- src/types/app-status.ts | 3 +- src/types/invoke.ts | 12 ++ 19 files changed, 295 insertions(+), 91 deletions(-) create mode 100644 src-tauri/src/user_listener.rs create mode 100644 src/types/invoke.ts diff --git a/package-lock.json b/package-lock.json index ebf7dba49..23b31078a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^5.2.1", - "react-idle-timer": "^5.7.2", "zustand": "^4.5.4" }, "devDependencies": { @@ -4592,15 +4591,6 @@ "react": "*" } }, - "node_modules/react-idle-timer": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/react-idle-timer/-/react-idle-timer-5.7.2.tgz", - "integrity": "sha512-+BaPfc7XEUU5JFkwZCx6fO1bLVK+RBlFH+iY4X34urvIzZiZINP6v2orePx3E6pAztJGE7t4DzvL7if2SL/0GQ==", - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" - } - }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", diff --git a/package.json b/package.json index 0eeb96fd7..a908be9cf 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^5.2.1", - "react-idle-timer": "^5.7.2", "zustand": "^4.5.4" }, "devDependencies": { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 84c088e11..8667cfdb5 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1087,6 +1087,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" +[[package]] +name = "device_query" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafa241a89a5edccff5057d0b85fbc083a781bd03d766c11a688331604980985" +dependencies = [ + "lazy_static", + "macos-accessibility-client", + "pkg-config", + "readkey", + "readmouse", + "windows 0.48.0", + "x11", +] + [[package]] name = "diesel" version = "2.2.2" @@ -2659,6 +2674,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "macos-accessibility-client" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf7710fbff50c24124331760978fb9086d6de6288dcdb38b25a97f8b1bdebbb" +dependencies = [ + "core-foundation", + "core-foundation-sys", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -3954,6 +3979,18 @@ dependencies = [ "yasna", ] +[[package]] +name = "readkey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7677f98ca49bc9bb26e04c8abf80ba579e2cb98e8a384a0ff8128ad70670d249" + +[[package]] +name = "readmouse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be105c72a1e6a5a1198acee3d5b506a15676b74a02ecd78060042a447f408d94" + [[package]] name = "redox_syscall" version = "0.4.1" @@ -5054,6 +5091,7 @@ dependencies = [ "anyhow", "async-trait", "async_zip", + "device_query", "dirs-next 2.0.0", "flate2", "futures-lite", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5bf24251f..fc57a9347 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -64,6 +64,7 @@ libsqlite3-sys = { version = "0.25.1", features = ["bundled"] } log = "0.4.22" rand = "0.8.5" +device_query = "2.1.0" [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! diff --git a/src-tauri/src/app_config.rs b/src-tauri/src/app_config.rs index 36498ecd9..5bb9120d3 100644 --- a/src-tauri/src/app_config.rs +++ b/src-tauri/src/app_config.rs @@ -9,6 +9,7 @@ const LOG_TARGET: &str = "tari::universe::app_config"; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct AppConfigFromFile { pub mode: String, + pub auto_mining: bool, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -38,7 +39,7 @@ impl MiningMode { pub struct AppConfig { config_file: Option, pub mode: MiningMode, - // auto-mining in future etc. + pub auto_mining: bool, } impl AppConfig { @@ -46,6 +47,7 @@ impl AppConfig { Self { config_file: None, mode: MiningMode::Eco, + auto_mining: false, } } @@ -59,6 +61,7 @@ impl AppConfig { match serde_json::from_str::(&config) { Ok(config) => { self.mode = MiningMode::from_str(&config.mode).unwrap_or(MiningMode::Eco); + self.auto_mining = config.auto_mining; } Err(e) => { warn!(target: LOG_TARGET, "Failed to parse app config: {}", e.to_string()); @@ -68,6 +71,7 @@ impl AppConfig { info!(target: LOG_TARGET, "App config does not exist or is corrupt. Creating new one"); let config = &AppConfigFromFile { mode: MiningMode::to_str(self.mode.clone()), + auto_mining: self.auto_mining.clone(), }; let config = serde_json::to_string(&config)?; fs::write(file, config).await?; @@ -89,10 +93,21 @@ impl AppConfig { self.mode.clone() } + pub async fn set_auto_mining(&mut self, auto_mining: bool) -> Result<(), anyhow::Error> { + self.auto_mining = auto_mining; + self.update_config_file().await?; + Ok(()) + } + + pub fn get_auto_mining(&self) -> bool { + self.auto_mining.clone() + } + pub async fn update_config_file(&mut self) -> Result<(), anyhow::Error> { let file = self.config_file.clone().unwrap(); let config = &AppConfigFromFile { mode: MiningMode::to_str(self.mode.clone()), + auto_mining: self.auto_mining, }; let config = serde_json::to_string(config)?; info!(target: LOG_TARGET, "Updating config file: {:?} {:?}", file, self.clone()); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 64f1f376d..1492fb943 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -4,6 +4,7 @@ mod cpu_miner; mod mm_proxy_manager; mod process_watcher; +mod user_listener; mod xmrig; mod xmrig_adapter; @@ -25,6 +26,7 @@ use crate::cpu_miner::CpuMiner; use crate::internal_wallet::InternalWallet; use crate::mm_proxy_manager::MmProxyManager; use crate::node_manager::NodeManager; +use crate::user_listener::UserListener; use crate::wallet_adapter::WalletBalance; use crate::wallet_manager::WalletManager; use app_config::{AppConfig, MiningMode}; @@ -37,14 +39,12 @@ use std::{panic, process}; use tari_common_types::tari_address::TariAddress; use tari_core::transactions::tari_amount::MicroMinotari; use tari_shutdown::Shutdown; -use tauri::{RunEvent, UpdaterEvent}; +use tauri::{Manager, RunEvent, UpdaterEvent}; use tokio::sync::RwLock; use tokio::try_join; use crate::xmrig_adapter::XmrigAdapter; use dirs_next::cache_dir; -use std::thread; -use std::time::Duration; #[derive(Debug, Serialize, Deserialize, Clone)] struct SetupStatusEvent { @@ -122,6 +122,29 @@ async fn setup_application<'r>( Ok(()) } +#[tauri::command] +async fn set_auto_mining<'r>( + auto_mining: bool, + window: tauri::Window, + state: tauri::State<'r, UniverseAppState>, +) -> Result<(), String> { + let _ = state + .config + .write() + .await + .set_auto_mining(auto_mining) + .await; + let mut user_listener = state.user_listener.write().await; + + if auto_mining { + user_listener.start_listening_to_mouse_poisition_change(window); + } else { + user_listener.stop_listening_to_mouse_poisition_change(); + } + + Ok(()) +} + #[tauri::command] async fn start_mining<'r>( window: tauri::Window, @@ -233,6 +256,7 @@ async fn status(state: tauri::State<'_, UniverseAppState>) -> Result, cpu_miner_config: Arc>, + user_listener: Arc>, mm_proxy_manager: Arc>, node_manager: NodeManager, wallet_manager: WalletManager, @@ -312,11 +338,14 @@ fn main() { shutdown: shutdown.clone(), cpu_miner: CpuMiner::new().into(), cpu_miner_config: cpu_config.clone(), + user_listener: Arc::new(RwLock::new(UserListener::new())), mm_proxy_manager: mm_proxy_manager.clone(), node_manager, wallet_manager, }; + let user_listener = app_state.user_listener.clone(); + let app = tauri::Builder::default() .manage(app_state) .setup(|app| { @@ -330,10 +359,13 @@ fn main() { ) .expect("Could not set up logging"); + let app_config_clone = app_config.clone(); + let config_path = app.path_resolver().app_config_dir().unwrap(); let thread_config = tauri::async_runtime::spawn(async move { app_config.write().await.load_or_create(config_path).await }); + match tauri::async_runtime::block_on(thread_config).unwrap() { Ok(_) => {} Err(e) => { @@ -341,6 +373,27 @@ fn main() { } }; + // let auto_mining = app_config.read().auto_mining; + // let user_listener = app_state.user_listener.write(); + + // let user_listener = app_state.user_listener.clone(); + let app_window = app.get_window("main").unwrap().clone(); + let auto_miner_thread = tauri::async_runtime::spawn(async move { + let auto_mining = app_config_clone.read().await.auto_mining; + let mut user_listener = user_listener.write().await; + + if auto_mining { + user_listener.start_listening_to_mouse_poisition_change(app_window); + } + }); + + match tauri::async_runtime::block_on(auto_miner_thread) { + Ok(_) => {} + Err(e) => { + error!(target: LOG_TARGET, "Error setting up auto mining: {:?}", e); + } + } + let config_path = app.path_resolver().app_config_dir().unwrap(); let thread = tauri::async_runtime::spawn(async move { match InternalWallet::load_or_create(config_path).await { @@ -360,7 +413,7 @@ fn main() { return Err(e); } - }; + } Ok(()) }); match tauri::async_runtime::block_on(thread).unwrap() { @@ -376,7 +429,8 @@ fn main() { status, start_mining, stop_mining, - set_mode + set_auto_mining, + set_mode, ]) .build(tauri::generate_context!()) .expect("error while running tauri application"); @@ -406,7 +460,7 @@ fn main() { info!(target: LOG_TARGET, "App shutdown caught"); shutdown.trigger(); // TODO: Find a better way of knowing that all miners have stopped - sleep(std::time::Duration::from_secs(3)); + sleep(std::time::Duration::from_secs(5)); info!(target: LOG_TARGET, "App shutdown complete"); } RunEvent::MainEventsCleared => { diff --git a/src-tauri/src/user_listener.rs b/src-tauri/src/user_listener.rs new file mode 100644 index 000000000..6d0f4223a --- /dev/null +++ b/src-tauri/src/user_listener.rs @@ -0,0 +1,121 @@ +use device_query::{DeviceQuery, DeviceState}; +use log::info; +use tokio::time::{sleep, Duration}; +use tokio_util::sync::CancellationToken; + +#[derive(Debug, Clone)] +pub struct UserListener { + pub is_listening: bool, + pub is_mining_initialized: bool, + pub idle_timeout: u64, + pub cancelation_token: Option, +} + +#[derive(Clone, serde::Serialize)] +pub struct UserActivityEventPayload { + event_type: String, +} + +impl UserListener { + pub fn new() -> Self { + Self { + is_listening: false, + is_mining_initialized: false, + idle_timeout: 5000, + cancelation_token: None, + } + } + + pub fn read_user_mouse_coords() -> (i32, i32) { + let device_state = DeviceState::new(); + let mouse = device_state.get_mouse(); + + return mouse.coords; + } + + pub fn start_listening_to_mouse_poisition_change(&mut self, window: tauri::Window) { + let idle_timeout = self.idle_timeout; + + let cancellation_token = CancellationToken::new(); + self.cancelation_token = Some(cancellation_token.clone()); + self.is_listening = true; + + let mut user_listener = self.to_owned(); + let window = window.clone(); + + let mut timeout_counter: u64 = 0; + let mut last_mouse_coords = UserListener::read_user_mouse_coords(); + + tokio::spawn(async move { + tokio::select! { + _ = async { + info!("UserListener::listening for user inactivity has been started"); + loop { + let current_mouse_coords = UserListener::read_user_mouse_coords(); + + if current_mouse_coords != last_mouse_coords { + last_mouse_coords = current_mouse_coords; + timeout_counter = 0; + } else { + timeout_counter += 1000; + } + + + if timeout_counter >= idle_timeout && !user_listener.is_mining_initialized { + UserListener::on_user_idle(&window); + user_listener.is_mining_initialized = true; + } + + if timeout_counter < idle_timeout && user_listener.is_mining_initialized { + UserListener::on_user_active(&window); + user_listener.is_mining_initialized = false; + } + + sleep(Duration::from_millis(idle_timeout)).await; + } + } => {}, + _ = cancellation_token.cancelled() => { + info!("UserListener::listening for user inactivity has been cancelled"); + UserListener::on_user_active(&window); + user_listener.is_mining_initialized = false; + } + } + }); + } + + pub fn stop_listening_to_mouse_poisition_change(&mut self) { + match &self.cancelation_token { + Some(token) => { + token.cancel(); + self.is_listening = false; + } + None => { + info!( + "UserListener::triggered cancelation of listening for user inactivity but no cancelation token was found" + ); + } + } + } + + pub fn on_user_idle(window: &tauri::Window) { + window + .emit( + "message", + UserActivityEventPayload { + event_type: "user_idle".to_string(), + }, + ) + .unwrap(); + } + + pub fn on_user_active(window: &tauri::Window) { + window + .emit( + "message", + UserActivityEventPayload { + event_type: "user_active".to_string(), + }, + ) + .unwrap(); + } +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9316d4808..e0155af01 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -46,6 +46,7 @@ "windows": [ { "title": "tari-universe", + "label": "main", "width": 1200, "height": 800, "resizable": true, diff --git a/src/App.tsx b/src/App.tsx index dd6c104de..95fc24105 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,7 @@ import { useGetStatus } from './hooks/useGetStatus.ts'; import { listen } from '@tauri-apps/api/event'; import { TauriEvent } from './types.ts'; import useAppStateStore from './store/appStateStore.ts'; +import { useMining } from './hooks/useMining.ts'; import { preload } from './visuals.js'; @@ -26,6 +27,7 @@ function App() { const startupInitiated = useRef(false); const setSetupDetails = useAppStateStore((s) => s.setSetupDetails); const settingUpFinished = useAppStateStore((s) => s.settingUpFinished); + const { startMining, stopMining } = useMining(); const visualMode = useUIStore((s) => s.visualMode); useEffect(() => { @@ -45,6 +47,16 @@ function App() { settingUpFinished(); } break; + case 'user_idle': + startMining().then(() => { + console.log('Mining started'); + }); + break; + case 'user_active': + stopMining().then(() => { + console.log('Mining stopped'); + }); + break; default: console.debug('Unknown tauri event: ', { event, diff --git a/src/containers/Dashboard/MiningView/components/MiningButton.tsx b/src/containers/Dashboard/MiningView/components/MiningButton.tsx index 5328bb28d..e961e8ca9 100644 --- a/src/containers/Dashboard/MiningView/components/MiningButton.tsx +++ b/src/containers/Dashboard/MiningView/components/MiningButton.tsx @@ -1,7 +1,6 @@ import { Button } from '@mui/material'; import { IoChevronForwardCircle, IoPauseCircle } from 'react-icons/io5'; import { AiOutlineLoading } from 'react-icons/ai'; -import { useUIStore } from '../../../../store/useUIStore.ts'; import { useAppStatusStore } from '../../../../store/useAppStatusStore.ts'; import { useMining } from '../../../../hooks/useMining.ts'; import { styled } from '@mui/material/styles'; @@ -45,18 +44,13 @@ const StyledIcon = styled(AiOutlineLoading)(() => ({ function MiningButton() { const mining = useAppStatusStore((s) => s.cpu?.is_mining); - const setBackground = useUIStore((s) => s.setBackground); const { startMining, stopMining, isLoading } = useMining(); const handleMining = () => { if (mining) { - stopMining().then(() => { - setBackground('idle'); - }); + stopMining(); } else { - startMining().then(() => { - setBackground('mining'); - }); + startMining(); } }; diff --git a/src/containers/SideBar/Miner/components/AutoMiner.tsx b/src/containers/SideBar/Miner/components/AutoMiner.tsx index 41bcdc898..ddd68a26d 100644 --- a/src/containers/SideBar/Miner/components/AutoMiner.tsx +++ b/src/containers/SideBar/Miner/components/AutoMiner.tsx @@ -1,50 +1,15 @@ import { FormGroup, Switch, Stack, Typography } from '@mui/material'; import { AutoMinerContainer } from '../styles'; -import { useIdleTimer } from 'react-idle-timer'; -import React from 'react'; -import { useUIStore } from '../../../../store/useUIStore.ts'; -import { useMining } from '../../../../hooks/useMining.ts'; +import { invoke } from '@tauri-apps/api/tauri'; +import { useAppStatusStore } from '../../../../store/useAppStatusStore'; function AutoMiner() { - const isAutoMining = useUIStore((s) => s.isAutoMining); - const setBackground = useUIStore((s) => s.setBackground); - const setIsAutoMining = useUIStore((s) => s.setIsAutoMining); - const { startMining, stopMining } = useMining(); + const isAutoMining = useAppStatusStore((state) => state.auto_mining); - const enableAutoMining = () => { - startMining().then(() => { - setBackground('mining'); - }); - }; - const disableAutoMining = () => { - stopMining().then(() => { - setBackground('idle'); - }); - }; - - const { start, pause } = useIdleTimer({ - timeout: 1000 * 30, - startManually: true, - onIdle: enableAutoMining, - onActive: disableAutoMining, - events: ['mousemove'], - }); - - React.useEffect(() => { - if (isAutoMining) { - start(); - } else { - pause(); - } - }, [isAutoMining]); - - const handleAutoMining = () => { - if (isAutoMining) { - setIsAutoMining(false); - disableAutoMining(); - } else { - setIsAutoMining(true); - } + const handleAutoMining = (event: React.ChangeEvent) => { + const isChecked = event.target.checked; + console.log('Auto mining checked', isChecked); + invoke('set_auto_mining', { autoMining: isChecked }); }; return ( diff --git a/src/hooks/useGetStatus.ts b/src/hooks/useGetStatus.ts index 83e018282..4c7cd4b7e 100644 --- a/src/hooks/useGetStatus.ts +++ b/src/hooks/useGetStatus.ts @@ -1,7 +1,6 @@ import useAppStateStore from '../store/appStateStore.ts'; import { useEffect } from 'react'; import { invoke } from '@tauri-apps/api/tauri'; -import { AppStatus } from '../types/app-status.ts'; import useWalletStore from '../store/walletStore.ts'; import { useAppStatusStore } from '../store/useAppStatusStore.ts'; @@ -11,12 +10,12 @@ export function useGetStatus() { const setBalance = useWalletStore((state) => state.setBalance); const setAppStatus = useAppStatusStore((s) => s.setAppStatus); const setError = useAppStateStore((s) => s.setError); - const setMode = useAppStatusStore(s => s.setMode); + const setMode = useAppStatusStore((s) => s.setMode); useEffect(() => { const intervalId = setInterval(() => { - invoke('status', {}) - .then((status: AppStatus) => { + invoke('status') + .then((status) => { // console.debug('Status', status); // do we need to log this if (status) { setAppStatus(status); @@ -32,7 +31,7 @@ export function useGetStatus() { timelocked_balance + pending_incoming_balance ); - setMode(status.mode) + setMode(status.mode); } else { console.error('Could not get status'); } diff --git a/src/hooks/useMining.ts b/src/hooks/useMining.ts index 26bf491d4..097b35072 100644 --- a/src/hooks/useMining.ts +++ b/src/hooks/useMining.ts @@ -1,8 +1,13 @@ -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import { invoke } from '@tauri-apps/api/tauri'; +import { useUIStore } from '../store/useUIStore'; import { setStart, setPause } from '../visuals'; + export function useMining() { - const [isLoading, setIsLoading] = useState(false); + const isLoading = useUIStore((s) => s.isMiningLoading); + const setIsLoading = useUIStore((s) => s.setIsMiningLoading); + const setBackground = useUIStore((s) => s.setBackground); + const startMining = useCallback(async () => { setIsLoading(true); try { @@ -12,6 +17,7 @@ export function useMining() { console.error('Could not start mining', e); } finally { setIsLoading(false); + setBackground('mining'); } }, []); const stopMining = useCallback(async () => { @@ -23,6 +29,7 @@ export function useMining() { console.error('Could not stop mining', e); } finally { setIsLoading(false); + setBackground('idle'); } }, []); diff --git a/src/store/appStateStore.ts b/src/store/appStateStore.ts index 3873c43f8..0814feca3 100644 --- a/src/store/appStateStore.ts +++ b/src/store/appStateStore.ts @@ -12,7 +12,6 @@ interface AppState { setSetupDetails: (setupTitle: string, setupProgress: number) => void; // gui - isSettingUp: boolean; // functions @@ -26,7 +25,6 @@ const useAppStateStore = create((set) => ({ setTopStatus: (value) => set({ topStatus: value }), errorOpen: false, setErrorOpen: (value) => set({ errorOpen: value }), - isSettingUp: true, setupTitle: '', setupProgress: 0, diff --git a/src/store/useAppStatusStore.ts b/src/store/useAppStatusStore.ts index 71c07671d..f481126a7 100644 --- a/src/store/useAppStatusStore.ts +++ b/src/store/useAppStatusStore.ts @@ -3,22 +3,19 @@ import { AppStatus } from '../types/app-status.ts'; import { modeType } from './types.ts'; import { persist } from 'zustand/middleware'; import { invoke } from '@tauri-apps/api/tauri'; - -interface State extends AppStatus { - mode: modeType; -} interface Actions { setAppStatus: (appStatus: AppStatus) => void; setMode: (mode: modeType) => void; setConfigMode: (mode: modeType) => void; } -type AppStatusStoreState = State & Actions; +type AppStatusStoreState = AppStatus & Actions; -const initialState: State = { +const initialState: AppStatus = { cpu: undefined, base_node: undefined, wallet_balance: undefined, mode: 'Eco', + auto_mining: false, }; export const useAppStatusStore = create()( persist( @@ -29,10 +26,10 @@ export const useAppStatusStore = create()( setConfigMode: async (mode: modeType) => { try { await invoke('set_mode', { mode }); - set({ mode }) + set({ mode }); console.log(`Mode changed to ${mode}`); } catch (e) { - console.error('Could not change the mode', e); + console.error('Could not change the mode', e); } }, }), diff --git a/src/store/useUIStore.ts b/src/store/useUIStore.ts index 6748ab5f1..c2093b410 100644 --- a/src/store/useUIStore.ts +++ b/src/store/useUIStore.ts @@ -6,14 +6,14 @@ interface State { view: viewType; visualMode: boolean; sidebarOpen: boolean; - isAutoMining: boolean; + isMiningLoading: boolean; } interface Actions { setBackground: (background: State['background']) => void; setView: (view: State['view']) => void; setVisualMode: (visualMode: State['visualMode']) => void; setSidebarOpen: (sidebarOpen: State['sidebarOpen']) => void; - setIsAutoMining: (isAutoMining: State['isAutoMining']) => void; + setIsMiningLoading: (isMiningLoading: State['isMiningLoading']) => void; } type UIStoreState = State & Actions; @@ -23,7 +23,7 @@ const initialState: State = { view: 'setup', visualMode: true, sidebarOpen: false, - isAutoMining: false, + isMiningLoading: false, }; export const useUIStore = create()((set) => ({ @@ -32,5 +32,5 @@ export const useUIStore = create()((set) => ({ setView: (view) => set({ view }), setVisualMode: (visualMode) => set({ visualMode }), setSidebarOpen: (sidebarOpen) => set({ sidebarOpen }), - setIsAutoMining: (isAutoMining) => set({ isAutoMining }), + setIsMiningLoading: (isMiningLoading) => set({ isMiningLoading }), })); diff --git a/src/types.ts b/src/types.ts index 821d5b811..8d364c650 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,6 @@ // Use union type type TauriEventPayload = { - event_type: 'setup_status'; + event_type: 'setup_status' | 'user_idle' | 'user_active'; title: string; progress: number; }; diff --git a/src/types/app-status.ts b/src/types/app-status.ts index 57f08af2c..e79f10b53 100644 --- a/src/types/app-status.ts +++ b/src/types/app-status.ts @@ -1,10 +1,11 @@ -import { modeType } from "../store/types"; +import { modeType } from '../store/types'; export interface AppStatus { cpu?: CpuMinerStatus; base_node?: BaseNodeStatus; wallet_balance?: WalletBalance; mode: modeType; + auto_mining: boolean; } export interface CpuMinerStatus { diff --git a/src/types/invoke.ts b/src/types/invoke.ts new file mode 100644 index 000000000..5b09ac77d --- /dev/null +++ b/src/types/invoke.ts @@ -0,0 +1,12 @@ +import { AppStatus } from './app-status'; + +declare module '@tauri-apps/api/tauri' { + function invoke(param: 'setup_application'): Promise; + function invoke(param: 'status'): Promise; + function invoke(param: 'start_mining'): Promise; + function invoke(param: 'stop_mining'): Promise; + function invoke( + param: 'set_auto_mining', + payload: { autoMining: boolean } + ): Promise; +}