txs: async finalization at modal
This commit is contained in:
parent
7319c1b4eb
commit
06bb00d0dc
1 changed files with 91 additions and 43 deletions
|
@ -12,13 +12,16 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea};
|
||||||
use egui::scroll_area::ScrollBarVisibility;
|
use egui::scroll_area::ScrollBarVisibility;
|
||||||
use egui_pull_to_refresh::PullToRefresh;
|
use egui_pull_to_refresh::PullToRefresh;
|
||||||
use grin_core::core::amount_to_hr_string;
|
use grin_core::core::amount_to_hr_string;
|
||||||
use grin_util::ToHex;
|
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::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};
|
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.
|
/// Wallet transactions tab content.
|
||||||
pub struct WalletTransactions {
|
pub struct WalletTransactions {
|
||||||
/// Transaction identifier to use at info [`Modal`].
|
/// Transaction identifier to use at [`Modal`].
|
||||||
tx_info_id: Option<u32>,
|
tx_info_id: Option<u32>,
|
||||||
/// Transaction [`Slate`] to use at info [`Modal`].
|
/// Transaction [`Slate`] to use at [`Modal`].
|
||||||
tx_info_slate: Option<Slate>,
|
tx_info_slate: Option<Slate>,
|
||||||
/// Response Slatepack message input value at info [`Modal`].
|
/// Response Slatepack message input value at [`Modal`].
|
||||||
tx_info_response_edit: String,
|
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,
|
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,
|
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,
|
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<RwLock<Option<Result<Slate, Error>>>>,
|
||||||
|
|
||||||
/// Transaction identifier to use at confirmation[`Modal`].
|
/// Transaction identifier to use at confirmation [`Modal`].
|
||||||
confirm_cancel_tx_id: Option<u32>,
|
confirm_cancel_tx_id: Option<u32>,
|
||||||
|
|
||||||
/// Flag to check if sync of wallet was initiated manually at time.
|
/// 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_edit: "".to_string(),
|
||||||
tx_info_finalize_error: false,
|
tx_info_finalize_error: false,
|
||||||
tx_info_finalize: false,
|
tx_info_finalize: false,
|
||||||
|
tx_info_finalizing: false,
|
||||||
|
tx_info_final_result: Arc::new(RwLock::new(None)),
|
||||||
confirm_cancel_tx_id: None,
|
confirm_cancel_tx_id: None,
|
||||||
manual_sync: None,
|
manual_sync: None,
|
||||||
}
|
}
|
||||||
|
@ -300,7 +309,8 @@ impl WalletTransactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw cancel button for tx that can be reposted and canceled.
|
// 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 {
|
let cancel_rounding = if can_show_info {
|
||||||
Rounding::default()
|
Rounding::default()
|
||||||
} else {
|
} else {
|
||||||
|
@ -309,17 +319,19 @@ impl WalletTransactions {
|
||||||
rounding
|
rounding
|
||||||
};
|
};
|
||||||
View::item_button(ui, cancel_rounding, PROHIBIT, Some(Colors::RED), || {
|
View::item_button(ui, cancel_rounding, PROHIBIT, Some(Colors::RED), || {
|
||||||
self.confirm_cancel_tx_id = Some(tx.data.id);
|
if can_show_info {
|
||||||
// Show transaction cancellation confirmation modal.
|
self.confirm_cancel_tx_id = Some(tx.data.id);
|
||||||
Modal::new(CANCEL_TX_CONFIRMATION_MODAL)
|
// Show transaction cancellation confirmation modal.
|
||||||
.position(ModalPosition::Center)
|
Modal::new(CANCEL_TX_CONFIRMATION_MODAL)
|
||||||
.title(t!("modal.confirmation"))
|
.position(ModalPosition::Center)
|
||||||
.show();
|
.title(t!("modal.confirmation"))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw finalization button for tx that can be finalized.
|
// 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 {
|
let (icon, color) = if !can_show_info && self.tx_info_finalize {
|
||||||
(FILE_TEXT, None)
|
(FILE_TEXT, None)
|
||||||
} else {
|
} else {
|
||||||
|
@ -340,7 +352,8 @@ impl WalletTransactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw button to repost transaction.
|
// 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,
|
View::item_button(ui,
|
||||||
Rounding::default(),
|
Rounding::default(),
|
||||||
ARROW_CLOCKWISE,
|
ARROW_CLOCKWISE,
|
||||||
|
@ -536,16 +549,48 @@ impl WalletTransactions {
|
||||||
}
|
}
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
|
||||||
// Show button to close modal.
|
// Show button to close modal or finalizing loader.
|
||||||
ui.vertical_centered_justified(|ui| {
|
if !self.tx_info_finalizing {
|
||||||
View::button(ui, t!("close"), Colors::WHITE, || {
|
ui.vertical_centered_justified(|ui| {
|
||||||
self.tx_info_id = None;
|
View::button(ui, t!("close"), Colors::WHITE, || {
|
||||||
self.tx_info_finalize = false;
|
self.tx_info_id = None;
|
||||||
cb.hide_keyboard();
|
self.tx_info_finalize = false;
|
||||||
modal.close();
|
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.
|
/// Draw transaction information [`Modal`] item content.
|
||||||
|
@ -671,6 +716,10 @@ impl WalletTransactions {
|
||||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
// Do not show buttons on finalization.
|
||||||
|
if self.tx_info_finalizing {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if self.tx_info_finalize {
|
if self.tx_info_finalize {
|
||||||
// Draw paste button.
|
// Draw paste button.
|
||||||
let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste"));
|
let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste"));
|
||||||
|
@ -680,7 +729,7 @@ impl WalletTransactions {
|
||||||
|
|
||||||
// Callback on finalization message input change.
|
// Callback on finalization message input change.
|
||||||
if message_before != self.tx_info_finalize_edit {
|
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 {
|
} else {
|
||||||
// Draw copy button.
|
// Draw copy button.
|
||||||
|
@ -699,30 +748,29 @@ impl WalletTransactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse Slatepack message on transaction finalization input change.
|
/// Parse Slatepack message on transaction finalization input change.
|
||||||
fn on_finalization_input_change(&mut self,
|
fn on_finalization_input_change(&mut self, tx: &WalletTransaction, w: &Wallet, modal: &Modal) {
|
||||||
tx: &WalletTransaction,
|
|
||||||
wallet: &Wallet,
|
|
||||||
cb: &dyn PlatformCallbacks) {
|
|
||||||
let message = &self.tx_info_finalize_edit;
|
let message = &self.tx_info_finalize_edit;
|
||||||
if message.is_empty() {
|
if message.is_empty() {
|
||||||
self.tx_info_finalize_error = false;
|
self.tx_info_finalize_error = false;
|
||||||
} else {
|
} 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 &&
|
let send = slate.state == SlateState::Standard2 &&
|
||||||
tx.data.tx_type == TxLogEntryType::TxSent;
|
tx.data.tx_type == TxLogEntryType::TxSent;
|
||||||
let receive = slate.state == SlateState::Invoice2 &&
|
let receive = slate.state == SlateState::Invoice2 &&
|
||||||
tx.data.tx_type == TxLogEntryType::TxReceived;
|
tx.data.tx_type == TxLogEntryType::TxReceived;
|
||||||
if Some(slate.id) == tx.data.tx_slate_id && (send || receive) {
|
if Some(slate.id) == tx.data.tx_slate_id && (send || receive) {
|
||||||
match wallet.finalize(message, wallet.can_use_dandelion()) {
|
let message = message.clone();
|
||||||
Ok(_) => {
|
let wallet = w.clone();
|
||||||
self.tx_info_finalize = false;
|
let final_res = self.tx_info_final_result.clone();
|
||||||
self.tx_info_finalize_edit = "".to_string();
|
self.tx_info_finalizing = true;
|
||||||
cb.hide_keyboard();
|
modal.disable_closing();
|
||||||
}
|
// Finalize transaction at separate thread.
|
||||||
Err(_) => {
|
thread::spawn(move || {
|
||||||
self.tx_info_finalize_error = true;
|
let res = wallet.finalize(&message, wallet.can_use_dandelion());
|
||||||
}
|
let mut w_res = final_res.write();
|
||||||
}
|
*w_res = Some(res);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.tx_info_finalize_error = true;
|
self.tx_info_finalize_error = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue