diff --git a/gui/src/app/cache.rs b/gui/src/app/cache.rs index cc714a6f..05944514 100644 --- a/gui/src/app/cache.rs +++ b/gui/src/app/cache.rs @@ -1,4 +1,4 @@ -use crate::daemon::model::{Coin, SpendTx}; +use crate::daemon::model::Coin; use liana::miniscript::bitcoin::Network; use std::path::PathBuf; @@ -8,7 +8,6 @@ pub struct Cache { pub network: Network, pub blockheight: i32, pub coins: Vec, - pub spend_txs: Vec, pub rescan_progress: Option, } @@ -20,7 +19,6 @@ impl std::default::Default for Cache { network: Network::Bitcoin, blockheight: 0, coins: Vec::new(), - spend_txs: Vec::new(), rescan_progress: None, } } diff --git a/gui/src/app/message.rs b/gui/src/app/message.rs index 5f3488c0..abfd5b99 100644 --- a/gui/src/app/message.rs +++ b/gui/src/app/message.rs @@ -11,7 +11,7 @@ use liana::{ }; use crate::{ - app::{error::Error, view, wallet::Wallet}, + app::{cache::Cache, error::Error, view, wallet::Wallet}, daemon::model::*, hw::HardwareWalletMessage, }; @@ -19,6 +19,7 @@ use crate::{ #[derive(Debug)] pub enum Message { Tick, + UpdateCache(Result), View(view::Message), LoadDaemonConfig(Box), DaemonConfigLoaded(Result<(), Error>), diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index 0f3443c3..0586cec4 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()), + 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, + 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 mut panels = Panels::new( + &cache, + wallet.clone(), + data_dir.clone(), + internal_bitcoind.as_ref(), + ); + let cmd = panels.home.reload(daemon.clone()); ( Self { + panels, data_dir, - state, cache, config, daemon, @@ -70,70 +150,52 @@ 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 + // In case of any error loading the spend or if it doesn't exist, load PSBTs list in usual way. + if let Ok(Some(spend_tx)) = self .daemon .list_spend_transactions(Some(&[*txid])) .map(|txs| txs.first().cloned()) { - Ok(Some(spend_tx)) => { - PsbtsPanel::new_preselected(self.wallet.clone(), spend_tx).into() - } - _ => PsbtsPanel::new(self.wallet.clone(), &self.cache.spend_txs).into(), + self.panels.psbts.preselect(spend_tx); + self.panels.current = menu; + return Command::none(); + }; + } + 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, + ); + } + menu::Menu::CreateSpendTx => { + // redo the process of spending only if user want to start a new one. + if !self.panels.create_spend.is_first_step() { + self.panels.create_spend = CreateSpendPanel::new( + self.wallet.clone(), + &self.cache.coins, + self.cache.blockheight as u32, + self.cache.network, + ); } } - 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(), + _ => {} }; - self.state.load(self.daemon.clone()) + self.panels.current = menu; + self.panels.current_mut().reload(self.daemon.clone()) } pub fn subscription(&self) -> Subscription { Subscription::batch(vec![ - time::every(Duration::from_secs(5)).map(|_| Message::Tick), - self.state.subscription(), + time::every(Duration::from_secs(10)).map(|_| Message::Tick), + self.panels.current().subscription(), ]) } @@ -149,33 +211,33 @@ impl App { } pub fn update(&mut self, message: Message) -> Command { - // Update cache when values are passing by. - // State will handle the error case. - match &message { - Message::Coins(Ok(coins)) => { - self.cache.coins = coins.clone(); - } - Message::SpendTxs(Ok(txs)) => { - self.cache.spend_txs = txs.clone(); - } - Message::Info(Ok(info)) => { - self.cache.blockheight = info.block_height; - self.cache.rescan_progress = info.rescan_progress; - } - Message::StartRescan(Ok(())) => { - self.cache.rescan_progress = Some(0.0); - } - _ => {} - }; - match message { Message::Tick => { let daemon = self.daemon.clone(); + let datadir_path = self.cache.datadir_path.clone(); Command::perform( - async move { daemon.get_info().map_err(|e| e.into()) }, - Message::Info, + async move { + let info = daemon.get_info()?; + // todo: filter coins to only have current coins. + let coins = daemon.list_coins()?; + Ok(Cache { + datadir_path, + coins: coins.coins, + network: info.network, + blockheight: info.block_height, + rescan_progress: info.rescan_progress, + }) + }, + Message::UpdateCache, ) } + Message::UpdateCache(res) => { + match res { + Ok(cache) => self.cache = cache, + Err(e) => tracing::error!("Failed to update cache: {}", e), + } + Command::none() + } Message::LoadDaemonConfig(cfg) => { let path = self.config.daemon_config_path.clone().expect( "Application config must have a daemon configuration file path at this point.", @@ -187,9 +249,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 +295,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) } } diff --git a/gui/src/app/state/coins.rs b/gui/src/app/state/coins.rs index 12342fb1..fc9b49d7 100644 --- a/gui/src/app/state/coins.rs +++ b/gui/src/app/state/coins.rs @@ -150,7 +150,7 @@ impl State for CoinsPanel { Command::none() } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { let daemon1 = daemon.clone(); let daemon2 = daemon.clone(); Command::batch(vec![ diff --git a/gui/src/app/state/mod.rs b/gui/src/app/state/mod.rs index 1126f62f..0a0bc154 100644 --- a/gui/src/app/state/mod.rs +++ b/gui/src/app/state/mod.rs @@ -44,7 +44,7 @@ pub trait State { fn subscription(&self) -> Subscription { Subscription::none() } - fn load(&self, _daemon: Arc) -> Command { + fn reload(&mut self, _daemon: Arc) -> Command { Command::none() } } @@ -186,11 +186,7 @@ impl State for Home { Err(e) => self.warning = Some(e), Ok(events) => { self.warning = None; - for event in events { - if !self.pending_events.iter().any(|other| other.tx == event.tx) { - self.pending_events.push(event); - } - } + self.pending_events = events; } }, Message::View(view::Message::Label(_, _)) | Message::LabelsUpdated(_) => { @@ -210,6 +206,9 @@ impl State for Home { } }; } + Message::View(view::Message::Reload) => { + return self.reload(daemon); + } Message::View(view::Message::Close) => { self.selected_event = None; } @@ -259,7 +258,8 @@ impl State for Home { Command::none() } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { + self.selected_event = None; let daemon1 = daemon.clone(); let daemon2 = daemon.clone(); let daemon3 = daemon.clone(); diff --git a/gui/src/app/state/psbts.rs b/gui/src/app/state/psbts.rs index 943eb6b2..414e639e 100644 --- a/gui/src/app/state/psbts.rs +++ b/gui/src/app/state/psbts.rs @@ -24,26 +24,21 @@ pub struct PsbtsPanel { } impl PsbtsPanel { - pub fn new(wallet: Arc, spend_txs: &[SpendTx]) -> Self { + pub fn new(wallet: Arc) -> Self { Self { wallet, - spend_txs: spend_txs.to_vec(), + spend_txs: Vec::new(), warning: None, selected_tx: None, import_tx: None, } } - pub fn new_preselected(wallet: Arc, spend_tx: SpendTx) -> Self { - let psbt_state = psbt::PsbtState::new(wallet.clone(), spend_tx.clone(), true); - - Self { - wallet, - spend_txs: vec![spend_tx], - warning: None, - selected_tx: Some(psbt_state), - import_tx: None, - } + pub fn preselect(&mut self, spend_tx: SpendTx) { + let psbt_state = psbt::PsbtState::new(self.wallet.clone(), spend_tx, true); + self.selected_tx = Some(psbt_state); + self.warning = None; + self.import_tx = None; } } @@ -79,6 +74,9 @@ impl State for PsbtsPanel { message: Message, ) -> Command { match message { + Message::View(view::Message::Reload) | Message::View(view::Message::Close) => { + return self.reload(daemon); + } Message::SpendTxs(res) => match res { Err(e) => self.warning = Some(e), Ok(txs) => { @@ -91,16 +89,6 @@ impl State for PsbtsPanel { self.import_tx = Some(ImportPsbtModal::new()); } } - Message::View(view::Message::Close) => { - if self.selected_tx.is_some() { - self.selected_tx = None; - return self.load(daemon); - } - if self.import_tx.is_some() { - self.import_tx = None; - return self.load(daemon); - } - } Message::View(view::Message::Select(i)) => { if let Some(tx) = self.spend_txs.get(i) { let tx = psbt::PsbtState::new(self.wallet.clone(), tx.clone(), true); @@ -130,7 +118,9 @@ impl State for PsbtsPanel { } } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { + self.selected_tx = None; + self.import_tx = None; let daemon = daemon.clone(); Command::perform( async move { daemon.list_spend_transactions(None).map_err(|e| e.into()) }, diff --git a/gui/src/app/state/receive.rs b/gui/src/app/state/receive.rs index cd4bfca0..e5dac8ce 100644 --- a/gui/src/app/state/receive.rs +++ b/gui/src/app/state/receive.rs @@ -34,6 +34,12 @@ pub struct Addresses { labels: HashMap, } +impl Addresses { + fn is_empty(&self) -> bool { + self.list.is_empty() + } +} + impl Labelled for Addresses { fn labelled(&self) -> Vec { self.list @@ -154,7 +160,18 @@ impl State for ReceivePanel { )); Command::none() } - Message::View(view::Message::Next) => self.load(daemon), + Message::View(view::Message::Next) => { + let daemon = daemon.clone(); + Command::perform( + async move { + daemon + .get_new_address() + .map(|res| (res.address, res.derivation_index)) + .map_err(|e| e.into()) + }, + Message::ReceiveAddress, + ) + } _ => self .modal .as_mut() @@ -163,17 +180,22 @@ impl State for ReceivePanel { } } - fn load(&self, daemon: Arc) -> Command { - let daemon = daemon.clone(); - Command::perform( - async move { - daemon - .get_new_address() - .map(|res| (res.address, res.derivation_index)) - .map_err(|e| e.into()) - }, - Message::ReceiveAddress, - ) + fn reload(&mut self, daemon: Arc) -> Command { + // Fill at least with one address, user will then use the generate button. + if self.addresses.is_empty() { + let daemon = daemon.clone(); + Command::perform( + async move { + daemon + .get_new_address() + .map(|res| (res.address, res.derivation_index)) + .map_err(|e| e.into()) + }, + Message::ReceiveAddress, + ) + } else { + Command::none() + } } } diff --git a/gui/src/app/state/recovery.rs b/gui/src/app/state/recovery.rs index 2e7811e8..087d32e3 100644 --- a/gui/src/app/state/recovery.rs +++ b/gui/src/app/state/recovery.rs @@ -192,7 +192,7 @@ impl State for RecoveryPanel { Command::none() } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { let daemon = daemon.clone(); Command::perform( async move { diff --git a/gui/src/app/state/settings/bitcoind.rs b/gui/src/app/state/settings/bitcoind.rs index cf944660..83b13b9b 100644 --- a/gui/src/app/state/settings/bitcoind.rs +++ b/gui/src/app/state/settings/bitcoind.rs @@ -16,7 +16,7 @@ use liana::{ use liana_ui::{component::form, widget::Element}; use crate::{ - app::{cache::Cache, error::Error, message::Message, view, State}, + app::{cache::Cache, error::Error, message::Message, state::settings::State, view}, bitcoind::{RpcAuthType, RpcAuthValues}, daemon::Daemon, }; diff --git a/gui/src/app/state/settings/mod.rs b/gui/src/app/state/settings/mod.rs index 21cf2820..0788b459 100644 --- a/gui/src/app/state/settings/mod.rs +++ b/gui/src/app/state/settings/mod.rs @@ -55,14 +55,14 @@ impl State for SettingsState { ); self.setting .as_mut() - .map(|s| s.load(daemon)) + .map(|s| s.reload(daemon)) .unwrap_or_else(Command::none) } Message::View(view::Message::Settings(view::SettingsMessage::AboutSection)) => { self.setting = Some(AboutSettingsState::default().into()); self.setting .as_mut() - .map(|s| s.load(daemon)) + .map(|s| s.reload(daemon)) .unwrap_or_else(Command::none) } Message::View(view::Message::Settings(view::SettingsMessage::EditWalletSettings)) => { @@ -71,7 +71,7 @@ impl State for SettingsState { ); self.setting .as_mut() - .map(|s| s.load(daemon)) + .map(|s| s.reload(daemon)) .unwrap_or_else(Command::none) } _ => self @@ -97,6 +97,11 @@ impl State for SettingsState { view::settings::list(cache) } } + + fn reload(&mut self, _daemon: Arc) -> Command { + self.setting = None; + Command::none() + } } impl From for Box { @@ -145,7 +150,7 @@ impl State for AboutSettingsState { Command::none() } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { Command::perform( async move { daemon.get_info().map_err(|e| e.into()) }, Message::Info, diff --git a/gui/src/app/state/settings/wallet.rs b/gui/src/app/state/settings/wallet.rs index 85128297..7af6a837 100644 --- a/gui/src/app/state/settings/wallet.rs +++ b/gui/src/app/state/settings/wallet.rs @@ -180,7 +180,7 @@ impl State for WalletSettingsState { } } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { Command::perform( async move { daemon.get_info().map_err(|e| e.into()) }, Message::Info, diff --git a/gui/src/app/state/spend/mod.rs b/gui/src/app/state/spend/mod.rs index 4c39ef34..6bdf833b 100644 --- a/gui/src/app/state/spend/mod.rs +++ b/gui/src/app/state/spend/mod.rs @@ -63,6 +63,10 @@ impl CreateSpendPanel { ], } } + + pub fn is_first_step(&self) -> bool { + self.current == 0 + } } impl State for CreateSpendPanel { @@ -108,7 +112,7 @@ impl State for CreateSpendPanel { Command::none() } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { let daemon1 = daemon.clone(); let daemon2 = daemon.clone(); Command::batch(vec![ diff --git a/gui/src/app/state/spend/step.rs b/gui/src/app/state/spend/step.rs index f6ef9c9c..6efe4647 100644 --- a/gui/src/app/state/spend/step.rs +++ b/gui/src/app/state/spend/step.rs @@ -1,7 +1,14 @@ -use std::{cmp::Ordering, collections::HashMap, str::FromStr, sync::Arc}; +use std::{ + cmp::Ordering, + collections::{HashMap, HashSet}, + iter::FromIterator, + str::FromStr, + sync::Arc, +}; use iced::{Command, Subscription}; use liana::{ + commands::ListCoinsEntry, descriptors::LianaDescriptor, miniscript::bitcoin::{ address, psbt::Psbt, secp256k1, Address, Amount, Denomination, Network, OutPoint, @@ -142,6 +149,11 @@ impl DefineSpend { } pub fn with_coins_sorted(mut self, blockheight: u32) -> Self { + self.sort_coins(blockheight); + self + } + + fn sort_coins(&mut self, blockheight: u32) { let timelock = self.timelock; self.coins.sort_by(|(a, a_selected), (b, b_selected)| { if *a_selected && !b_selected || !a_selected && *b_selected { @@ -156,7 +168,6 @@ impl DefineSpend { a.block_height.cmp(&b.block_height) } }); - self } pub fn self_send(mut self) -> Self { @@ -399,6 +410,19 @@ impl Step for DefineSpend { self.batch_label.valid = label.len() <= 100; self.batch_label.value = label; } + view::CreateSpendMessage::Clear => { + *self = Self::new( + self.network, + self.descriptor.clone(), + self.coins + .iter() + .map(|(c, _)| c.clone()) + .collect::>() + .as_slice(), + self.timelock, + ); + return Command::none(); + } view::CreateSpendMessage::AddRecipient => { self.recipients.push(Recipient::default()); } @@ -528,6 +552,35 @@ impl Step for DefineSpend { } Err(e) => self.warning = Some(e), }, + Message::Coins(res) => match res { + Ok(coins) => { + let selected: HashSet = + HashSet::from_iter(self.coins.iter().filter_map(|(c, selected)| { + if *selected { + Some(c.outpoint) + } else { + None + } + })); + self.coins = coins + .into_iter() + .filter_map(|coin| { + if coin.spend_info.is_none() && !coin.is_immature { + let selected = selected.contains(&coin.outpoint); + Some((coin, selected)) + } else { + None + } + }) + .collect(); + self.sort_coins(cache.blockheight as u32); + // In case some selected coins are not spendable anymore and + // new coins make more sense to be selected. A redraft is triggered + // if all forms are valid (checked in the redraft method) + self.redraft(daemon); + } + Err(e) => self.warning = Some(e), + }, _ => {} }; Command::none() diff --git a/gui/src/app/state/transactions.rs b/gui/src/app/state/transactions.rs index c8349754..e0da0740 100644 --- a/gui/src/app/state/transactions.rs +++ b/gui/src/app/state/transactions.rs @@ -105,11 +105,7 @@ impl State for TransactionsPanel { Err(e) => self.warning = Some(e), Ok(txs) => { self.warning = None; - for tx in txs { - if !self.pending_txs.iter().any(|other| other.tx == tx.tx) { - self.pending_txs.push(tx); - } - } + self.pending_txs = txs; } }, Message::RbfModal(tx, is_cancel, res) => match res { @@ -121,8 +117,8 @@ impl State for TransactionsPanel { self.warning = e.into(); } }, - Message::View(view::Message::Close) => { - self.selected_tx = None; + Message::View(view::Message::Reload) | Message::View(view::Message::Close) => { + return self.reload(daemon); } Message::View(view::Message::Select(i)) => { self.selected_tx = Some(i); @@ -225,7 +221,8 @@ impl State for TransactionsPanel { Command::none() } - fn load(&self, daemon: Arc) -> Command { + fn reload(&mut self, daemon: Arc) -> Command { + self.selected_tx = None; let daemon1 = daemon.clone(); let daemon2 = daemon.clone(); let daemon3 = daemon.clone(); diff --git a/gui/src/app/view/message.rs b/gui/src/app/view/message.rs index bde8a7c0..36d9511a 100644 --- a/gui/src/app/view/message.rs +++ b/gui/src/app/view/message.rs @@ -38,6 +38,7 @@ pub enum CreateSpendMessage { SelectPath(usize), Generate, SendMaxToRecipient(usize), + Clear, } #[derive(Debug, Clone)] diff --git a/gui/src/app/view/mod.rs b/gui/src/app/view/mod.rs index 73887fa4..e760f58b 100644 --- a/gui/src/app/view/mod.rs +++ b/gui/src/app/view/mod.rs @@ -45,7 +45,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> { let home_button = if *menu == Menu::Home { row!( button::menu_active(Some(home_icon()), "Home") - .on_press(Message::Menu(Menu::Home)) + .on_press(Message::Reload) .width(iced::Length::Fill), menu_green_bar(), ) @@ -58,7 +58,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> { let transactions_button = if *menu == Menu::Transactions { row!( button::menu_active(Some(history_icon()), "Transactions") - .on_press(Message::Menu(Menu::Transactions)) + .on_press(Message::Reload) .width(iced::Length::Fill), menu_green_bar() ) @@ -85,7 +85,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> { let psbt_button = if *menu == Menu::PSBTs { row!( button::menu_active(Some(history_icon()), "PSBTs") - .on_press(Message::Menu(Menu::PSBTs)) + .on_press(Message::Reload) .width(iced::Length::Fill), menu_green_bar() ) @@ -98,7 +98,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> { let spend_button = if *menu == Menu::CreateSpendTx { row!( button::menu_active(Some(send_icon()), "Send") - .on_press(Message::Menu(Menu::CreateSpendTx)) + .on_press(Message::Reload) .width(iced::Length::Fill), menu_green_bar() ) diff --git a/gui/src/app/view/spend/mod.rs b/gui/src/app/view/spend/mod.rs index b41a2dad..2bcabbb8 100644 --- a/gui/src/app/view/spend/mod.rs +++ b/gui/src/app/view/spend/mod.rs @@ -294,7 +294,7 @@ pub fn create_spend_tx<'a>( .push(Space::with_width(Length::Fill)) .push( button::primary(None, "Clear") - .on_press(Message::Menu(Menu::CreateSpendTx)) + .on_press(Message::CreateSpend(CreateSpendMessage::Clear)) .width(Length::Fixed(100.0)), ) .push( diff --git a/gui/src/loader.rs b/gui/src/loader.rs index 19f43033..da9f8da8 100644 --- a/gui/src/loader.rs +++ b/gui/src/loader.rs @@ -368,14 +368,12 @@ pub async fn load_application( Wallet::new(info.descriptors.main).load_settings(&gui_config, &datadir_path, network)?; let coins = daemon.list_coins().map(|res| res.coins)?; - let spend_txs = daemon.list_spend_transactions(None)?; let cache = Cache { datadir_path, network: info.network, blockheight: info.block_height, coins, - spend_txs, ..Default::default() }; diff --git a/gui/src/utils/sandbox.rs b/gui/src/utils/sandbox.rs index 7a408e0d..7a9b45f4 100644 --- a/gui/src/utils/sandbox.rs +++ b/gui/src/utils/sandbox.rs @@ -38,7 +38,7 @@ impl Sandbox { } pub async fn load(mut self, daemon: Arc, cache: &Cache) -> Self { - let cmd = self.state.load(daemon.clone()); + let cmd = self.state.reload(daemon.clone()); for action in cmd.actions() { if let Action::Future(f) = action { let msg = f.await;