From 06bb00d0dc3fc362272844b32058772e95461d1a Mon Sep 17 00:00:00 2001 From: ardocrat Date: Sun, 19 May 2024 10:50:40 +0300 Subject: [PATCH] txs: async finalization at modal --- src/gui/views/wallets/wallet/txs.rs | 134 +++++++++++++++++++--------- 1 file changed, 91 insertions(+), 43 deletions(-) diff --git a/src/gui/views/wallets/wallet/txs.rs b/src/gui/views/wallets/wallet/txs.rs index fd24550..63a22e6 100644 --- a/src/gui/views/wallets/wallet/txs.rs +++ b/src/gui/views/wallets/wallet/txs.rs @@ -12,13 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::time::{SystemTime, UNIX_EPOCH}; +use std::sync::Arc; +use std::thread; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea}; use egui::scroll_area::ScrollBarVisibility; use egui_pull_to_refresh::PullToRefresh; use grin_core::core::amount_to_hr_string; use grin_util::ToHex; -use grin_wallet_libwallet::{Slate, SlateState, TxLogEntryType}; +use grin_wallet_libwallet::{Error, Slate, SlateState, TxLogEntryType}; +use parking_lot::RwLock; use crate::gui::Colors; use crate::gui::icons::{ARROW_CIRCLE_DOWN, ARROW_CIRCLE_UP, ARROW_CLOCKWISE, BRIDGE, CALENDAR_CHECK, CHAT_CIRCLE_TEXT, CHECK, CHECK_CIRCLE, CLIPBOARD_TEXT, COPY, DOTS_THREE_CIRCLE, FILE_ARCHIVE, FILE_TEXT, GEAR_FINE, HASH_STRAIGHT, PROHIBIT, X_CIRCLE}; @@ -33,20 +36,24 @@ use crate::wallet::Wallet; /// Wallet transactions tab content. pub struct WalletTransactions { - /// Transaction identifier to use at info [`Modal`]. + /// Transaction identifier to use at [`Modal`]. tx_info_id: Option, - /// Transaction [`Slate`] to use at info [`Modal`]. + /// Transaction [`Slate`] to use at [`Modal`]. tx_info_slate: Option, - /// Response Slatepack message input value at info [`Modal`]. + /// Response Slatepack message input value at [`Modal`]. tx_info_response_edit: String, - /// Finalization Slatepack message input value at info [`Modal`]. + /// Finalization Slatepack message input value at [`Modal`]. tx_info_finalize_edit: String, - /// Flag to check if error happened during transaction finalization at info [`Modal`]. + /// Flag to check if error happened during transaction finalization at [`Modal`]. tx_info_finalize_error: bool, - /// Flag to check if tx finalization requested at info [`Modal`]. + /// Flag to check if tx finalization requested at [`Modal`]. tx_info_finalize: bool, + /// Flag to check if tx is finalizing at [`Modal`]. + tx_info_finalizing: bool, + /// Transaction finalization result for [`Modal`]. + tx_info_final_result: Arc>>>, - /// Transaction identifier to use at confirmation[`Modal`]. + /// Transaction identifier to use at confirmation [`Modal`]. confirm_cancel_tx_id: Option, /// Flag to check if sync of wallet was initiated manually at time. @@ -62,6 +69,8 @@ impl Default for WalletTransactions { tx_info_finalize_edit: "".to_string(), tx_info_finalize_error: false, tx_info_finalize: false, + tx_info_finalizing: false, + tx_info_final_result: Arc::new(RwLock::new(None)), confirm_cancel_tx_id: None, manual_sync: None, } @@ -300,7 +309,8 @@ impl WalletTransactions { } // Draw cancel button for tx that can be reposted and canceled. - if tx.can_repost(data) || tx.can_cancel() { + if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && + (tx.can_repost(data) || tx.can_cancel()) { let cancel_rounding = if can_show_info { Rounding::default() } else { @@ -309,17 +319,19 @@ impl WalletTransactions { rounding }; View::item_button(ui, cancel_rounding, PROHIBIT, Some(Colors::RED), || { - self.confirm_cancel_tx_id = Some(tx.data.id); - // Show transaction cancellation confirmation modal. - Modal::new(CANCEL_TX_CONFIRMATION_MODAL) - .position(ModalPosition::Center) - .title(t!("modal.confirmation")) - .show(); + if can_show_info { + self.confirm_cancel_tx_id = Some(tx.data.id); + // Show transaction cancellation confirmation modal. + Modal::new(CANCEL_TX_CONFIRMATION_MODAL) + .position(ModalPosition::Center) + .title(t!("modal.confirmation")) + .show(); + } }); } // Draw finalization button for tx that can be finalized. - if tx.can_finalize { + if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && tx.can_finalize { let (icon, color) = if !can_show_info && self.tx_info_finalize { (FILE_TEXT, None) } else { @@ -340,7 +352,8 @@ impl WalletTransactions { } // Draw button to repost transaction. - if tx.can_repost(data) { + if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && + tx.can_repost(data) { View::item_button(ui, Rounding::default(), ARROW_CLOCKWISE, @@ -536,16 +549,48 @@ impl WalletTransactions { } ui.add_space(8.0); - // Show button to close modal. - ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { - self.tx_info_id = None; - self.tx_info_finalize = false; - cb.hide_keyboard(); - modal.close(); + // Show button to close modal or finalizing loader. + if !self.tx_info_finalizing { + ui.vertical_centered_justified(|ui| { + View::button(ui, t!("close"), Colors::WHITE, || { + self.tx_info_id = None; + self.tx_info_finalize = false; + cb.hide_keyboard(); + modal.close(); + }); }); - }); - ui.add_space(6.0); + ui.add_space(6.0); + } else { + ui.vertical_centered(|ui| { + View::small_loading_spinner(ui); + ui.add_space(16.0); + }); + + // Check finalization result. + let has_res = { + let r_res = self.tx_info_final_result.read(); + r_res.is_some() + }; + if has_res { + let res = { + let r_res = self.tx_info_final_result.read(); + r_res.as_ref().unwrap().clone() + }; + if let Ok(_) = res { + self.tx_info_finalize = false; + self.tx_info_finalize_edit = "".to_string(); + } else { + self.tx_info_finalize_error = true; + } + // Clear status and result. + { + let mut w_res = self.tx_info_final_result.write(); + *w_res = None; + } + self.tx_info_finalizing = false; + modal.enable_closing(); + } + } } /// Draw transaction information [`Modal`] item content. @@ -671,6 +716,10 @@ impl WalletTransactions { View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(8.0); + // Do not show buttons on finalization. + if self.tx_info_finalizing { + return; + } if self.tx_info_finalize { // Draw paste button. let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); @@ -680,7 +729,7 @@ impl WalletTransactions { // Callback on finalization message input change. if message_before != self.tx_info_finalize_edit { - self.on_finalization_input_change(tx, wallet, cb); + self.on_finalization_input_change(tx, wallet, modal); } } else { // Draw copy button. @@ -699,30 +748,29 @@ impl WalletTransactions { } /// Parse Slatepack message on transaction finalization input change. - fn on_finalization_input_change(&mut self, - tx: &WalletTransaction, - wallet: &Wallet, - cb: &dyn PlatformCallbacks) { + fn on_finalization_input_change(&mut self, tx: &WalletTransaction, w: &Wallet, modal: &Modal) { let message = &self.tx_info_finalize_edit; if message.is_empty() { self.tx_info_finalize_error = false; } else { - if let Ok(slate) = wallet.parse_slatepack(message) { + // Parse input message to finalize. + if let Ok(slate) = w.parse_slatepack(message) { let send = slate.state == SlateState::Standard2 && tx.data.tx_type == TxLogEntryType::TxSent; let receive = slate.state == SlateState::Invoice2 && tx.data.tx_type == TxLogEntryType::TxReceived; if Some(slate.id) == tx.data.tx_slate_id && (send || receive) { - match wallet.finalize(message, wallet.can_use_dandelion()) { - Ok(_) => { - self.tx_info_finalize = false; - self.tx_info_finalize_edit = "".to_string(); - cb.hide_keyboard(); - } - Err(_) => { - self.tx_info_finalize_error = true; - } - } + let message = message.clone(); + let wallet = w.clone(); + let final_res = self.tx_info_final_result.clone(); + self.tx_info_finalizing = true; + modal.disable_closing(); + // Finalize transaction at separate thread. + thread::spawn(move || { + let res = wallet.finalize(&message, wallet.can_use_dandelion()); + let mut w_res = final_res.write(); + *w_res = Some(res); + }); } else { self.tx_info_finalize_error = true; }