diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index 0f3443c3..7df2a417 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -35,14 +35,89 @@ use crate::{ daemon::{embedded::EmbeddedDaemon, Daemon}, }; +use self::state::SettingsState; + +struct Panels { + current: Menu, + home: Home, + coins: CoinsPanel, + transactions: TransactionsPanel, + psbts: PsbtsPanel, + recovery: RecoveryPanel, + receive: ReceivePanel, + create_spend: CreateSpendPanel, + settings: SettingsState, +} + +impl Panels { + fn new( + cache: &Cache, + wallet: Arc, + data_dir: PathBuf, + internal_bitcoind: Option<&Bitcoind>, + ) -> Panels { + Self { + current: Menu::Home, + home: Home::new(wallet.clone(), &cache.coins), + coins: CoinsPanel::new(&cache.coins, wallet.main_descriptor.first_timelock_value()), + transactions: TransactionsPanel::new(), + psbts: PsbtsPanel::new(wallet.clone(), &cache.spend_txs), + recovery: RecoveryPanel::new(wallet.clone(), &cache.coins, cache.blockheight), + receive: ReceivePanel::new(data_dir.clone(), wallet.clone()), + create_spend: CreateSpendPanel::new( + wallet.clone(), + &cache.coins, + cache.blockheight as u32, + cache.network, + ), + settings: state::SettingsState::new( + data_dir.clone(), + wallet.clone(), + internal_bitcoind.is_some(), + ), + } + } + + fn current(&self) -> &dyn State { + match self.current { + Menu::Home => &self.home, + Menu::Receive => &self.receive, + Menu::PSBTs => &self.psbts, + Menu::Transactions => &self.transactions, + Menu::Settings => &self.settings, + Menu::Coins => &self.coins, + Menu::CreateSpendTx => &self.create_spend, + Menu::Recovery => &self.recovery, + Menu::RefreshCoins(_) => &self.create_spend, + Menu::PsbtPreSelected(_) => &self.psbts, + } + } + + fn current_mut(&mut self) -> &mut dyn State { + match self.current { + Menu::Home => &mut self.home, + Menu::Receive => &mut self.receive, + Menu::PSBTs => &mut self.psbts, + Menu::Transactions => &mut self.transactions, + Menu::Settings => &mut self.settings, + Menu::Coins => &mut self.coins, + Menu::CreateSpendTx => &mut self.create_spend, + Menu::Recovery => &mut self.recovery, + Menu::RefreshCoins(_) => &mut self.create_spend, + Menu::PsbtPreSelected(_) => &mut self.psbts, + } + } +} + pub struct App { data_dir: PathBuf, - state: Box, cache: Cache, config: Config, wallet: Arc, daemon: Arc, internal_bitcoind: Option, + + panels: Panels, } impl App { @@ -54,12 +129,17 @@ impl App { data_dir: PathBuf, internal_bitcoind: Option, ) -> (App, Command) { - let state: Box = Home::new(wallet.clone(), &cache.coins).into(); - let cmd = state.load(daemon.clone()); + let panels = Panels::new( + &cache, + wallet.clone(), + data_dir.clone(), + internal_bitcoind.as_ref(), + ); + let cmd = panels.home.load(daemon.clone()); ( Self { + panels, data_dir, - state, cache, config, daemon, @@ -70,37 +150,14 @@ impl App { ) } - fn load_state(&mut self, menu: &Menu) -> Command { - self.state = match menu { - menu::Menu::Settings => state::SettingsState::new( - self.data_dir.clone(), - self.wallet.clone(), - self.internal_bitcoind.is_some(), - ) - .into(), - menu::Menu::Home => Home::new(self.wallet.clone(), &self.cache.coins).into(), - menu::Menu::Coins => CoinsPanel::new( - &self.cache.coins, - self.wallet.main_descriptor.first_timelock_value(), - ) - .into(), - menu::Menu::Recovery => RecoveryPanel::new( - self.wallet.clone(), - &self.cache.coins, - self.cache.blockheight, - ) - .into(), - menu::Menu::Receive => { - ReceivePanel::new(self.data_dir.clone(), self.wallet.clone()).into() - } - menu::Menu::Transactions => TransactionsPanel::new().into(), - menu::Menu::PSBTs => PsbtsPanel::new(self.wallet.clone(), &self.cache.spend_txs).into(), + fn set_current_panel(&mut self, menu: Menu) -> Command { + match &menu { menu::Menu::PsbtPreSelected(txid) => { // Get preselected spend from DB in case it's not yet in the cache. // We only need this single spend as we will go straight to its view and not show the PSBTs list. // In case of any error loading the spend or if it doesn't exist, fall back to using the cache // and load PSBTs list in usual way. - match self + self.panels.psbts = match self .daemon .list_spend_transactions(Some(&[*txid])) .map(|txs| txs.first().cloned()) @@ -109,31 +166,37 @@ impl App { PsbtsPanel::new_preselected(self.wallet.clone(), spend_tx).into() } _ => PsbtsPanel::new(self.wallet.clone(), &self.cache.spend_txs).into(), - } + }; } - menu::Menu::CreateSpendTx => CreateSpendPanel::new( - self.wallet.clone(), - &self.cache.coins, - self.cache.blockheight as u32, - self.cache.network, - ) - .into(), - menu::Menu::RefreshCoins(preselected) => CreateSpendPanel::new_self_send( - self.wallet.clone(), - &self.cache.coins, - self.cache.blockheight as u32, - preselected, - self.cache.network, - ) - .into(), + menu::Menu::CreateSpendTx => { + self.panels.create_spend = CreateSpendPanel::new( + self.wallet.clone(), + &self.cache.coins, + self.cache.blockheight as u32, + self.cache.network, + ) + .into(); + } + menu::Menu::RefreshCoins(preselected) => { + self.panels.create_spend = CreateSpendPanel::new_self_send( + self.wallet.clone(), + &self.cache.coins, + self.cache.blockheight as u32, + preselected, + self.cache.network, + ) + .into(); + } + _ => {} }; - self.state.load(self.daemon.clone()) + self.panels.current = menu; + self.panels.current().load(self.daemon.clone()) } pub fn subscription(&self) -> Subscription { Subscription::batch(vec![ time::every(Duration::from_secs(5)).map(|_| Message::Tick), - self.state.subscription(), + self.panels.current().subscription(), ]) } @@ -187,9 +250,12 @@ impl App { let res = self.load_wallet(); self.update(Message::WalletLoaded(res)) } - Message::View(view::Message::Menu(menu)) => self.load_state(&menu), + Message::View(view::Message::Menu(menu)) => self.set_current_panel(menu), Message::View(view::Message::Clipboard(text)) => clipboard::write(text), - _ => self.state.update(self.daemon.clone(), &self.cache, message), + _ => self + .panels + .current_mut() + .update(self.daemon.clone(), &self.cache, message), } } @@ -230,6 +296,6 @@ impl App { } pub fn view(&self) -> Element { - self.state.view(&self.cache).map(Message::View) + self.panels.current().view(&self.cache).map(Message::View) } }