From 71fea20b904e1bc4cbac65f9a0a29a01c76b51d6 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Sun, 19 May 2024 12:50:08 +0300 Subject: [PATCH] ui: slatepack message input and tx finalization scan and show qr code buttons --- src/gui/views/wallets/wallet/messages.rs | 282 ++++++++++++----------- src/gui/views/wallets/wallet/txs.rs | 114 +++++---- 2 files changed, 220 insertions(+), 176 deletions(-) diff --git a/src/gui/views/wallets/wallet/messages.rs b/src/gui/views/wallets/wallet/messages.rs index 7661331..14cf50e 100644 --- a/src/gui/views/wallets/wallet/messages.rs +++ b/src/gui/views/wallets/wallet/messages.rs @@ -22,7 +22,7 @@ use log::error; use parking_lot::RwLock; use crate::gui::Colors; -use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, DOWNLOAD_SIMPLE, PROHIBIT, UPLOAD_SIMPLE}; +use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, DOWNLOAD_SIMPLE, PROHIBIT, QR_CODE, SCAN, UPLOAD_SIMPLE}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; use crate::gui::views::types::{ModalPosition, TextEditOptions}; @@ -362,8 +362,7 @@ impl WalletMessages { } // Draw buttons to clear/copy/paste. - let fields_empty = self.message_edit.is_empty() && self.response_edit.is_empty(); - let columns_num = if fields_empty || self.message_loading { 1 } else { 2 }; + let columns_num = if self.message_loading { 1 } else { 2 }; let mut show_dandelion = false; ui.scope(|ui| { // Setup spacing between buttons. @@ -373,6 +372,7 @@ impl WalletMessages { let first_column_content = |ui: &mut egui::Ui| { if self.message_slate.is_some() { if self.response_edit.is_empty() { + // Draw button to clear message input. let clear_text = format!("{} {}", BROOM, t!("clear")); View::button(ui, clear_text, Colors::BUTTON, || { self.message_edit.clear(); @@ -381,122 +381,21 @@ impl WalletMessages { self.message_slate = None; }); } else { - let cancel = format!("{} {}", PROHIBIT, t!("modal.cancel")); - View::colored_text_button(ui, cancel, Colors::RED, Colors::BUTTON, || { - let slate = self.message_slate.clone().unwrap(); - if let Some(tx) = wallet.tx_by_slate(&slate) { - wallet.cancel(tx.data.id); - self.message_edit.clear(); - self.response_edit.clear(); - self.message_slate = None; - } + let copy_text = format!("{} {}", COPY, t!("copy")); + View::button(ui, copy_text, Colors::BUTTON, || { + cb.copy_string_to_buffer(self.response_edit.clone()); + self.message_edit.clear(); + self.response_edit.clear(); + self.message_slate = None; }); } } else { if self.message_loading { View::small_loading_spinner(ui); - - // Check receive pay result. - let has_finalize_post_result = { - let r_res = self.final_post_result.read(); - r_res.is_some() - }; - if has_finalize_post_result { - let resp = { - let r_res = self.final_post_result.read(); - r_res.as_ref().unwrap().clone() - }; - if resp.is_ok() { - self.message_edit.clear(); - self.message_slate = None; - } else { - self.message_error = Some( - MessageError::Finalize( - t!("wallets.finalize_slatepack_err") - ) - ); - } - self.message_loading = false; - } - - // Check receive pay result. - let has_receive_pay_result = { - let r_res = self.receive_pay_result.read(); - r_res.is_some() - }; - if has_receive_pay_result { - let (slate, resp) = { - let r_res = self.receive_pay_result.read(); - r_res.as_ref().unwrap().clone() - }; - if resp.is_ok() { - self.response_edit = resp.as_ref().unwrap().clone(); - } else { - let err = resp.as_ref().err().unwrap(); - match err { - // Set already canceled transaction error message. - Error::TransactionWasCancelled {..} - => { - self.message_error = Some( - MessageError::Response( - t!("wallets.resp_canceled_err") - ) - ); - } - // Set an error when there is not enough funds to pay. - Error::NotEnoughFunds {..} => { - let m = t!( - "wallets.pay_balance_error", - "amount" => amount_to_hr_string(slate.amount, true) - ); - self.message_error = Some(MessageError::Response(m)); - } - // Set default error message. - _ => { - self.message_error = Some( - MessageError::Response( - t!("wallets.resp_slatepack_err") - ) - ); - } - } - // Check if tx with same slate id already exists. - if self.message_error.is_none() { - let exists_tx = wallet.tx_by_slate(&slate).is_some(); - if exists_tx { - let mut sl = slate.clone(); - sl.state = if sl.state == SlateState::Standard1 { - SlateState::Standard2 - } else { - SlateState::Invoice2 - }; - match wallet.read_slatepack(&sl) { - None => { - self.message_error = Some( - MessageError::Response( - t!("wallets.resp_slatepack_err") - ) - ); - } - Some(sp) => { - self.response_edit = sp; - } - } - } - } - } - // Setup message slate. - if self.message_error.is_none() { - self.message_slate = Some(slate); - } - // Clear message loading result and status. - { - let mut w_res = self.receive_pay_result.write(); - *w_res = None; - } - self.message_loading = false; - } + // Check loading result. + self.check_message_loading_result(wallet); } else { + // Draw button to paste text from clipboard. let paste = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); View::button(ui, paste, Colors::BUTTON, || { let buf = cb.get_string_from_buffer(); @@ -517,12 +416,10 @@ impl WalletMessages { columns[1].vertical_centered_justified(|ui| { if self.message_slate.is_some() { if !self.response_edit.is_empty() { - let copy_text = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_text, Colors::BUTTON, || { - cb.copy_string_to_buffer(self.response_edit.clone()); - self.message_edit.clear(); - self.response_edit.clear(); - self.message_slate = None; + // Draw button to show Slatepack message as QR code. + let qr_text = format!("{} {}", QR_CODE, t!("qr_code")); + View::button(ui, qr_text, Colors::BUTTON, || { + //TODO: show qr. }); } else { show_dandelion = true; @@ -555,12 +452,10 @@ impl WalletMessages { }); } } else { - let clear_text = format!("{} {}", BROOM, t!("clear")); - View::button(ui, clear_text, Colors::BUTTON, || { - self.message_error = None; - self.message_edit.clear(); - self.response_edit.clear(); - self.message_slate = None; + // Draw button to scan Slatepack message QR code. + let scan_text = format!("{} {}", SCAN, t!("scan")); + View::button(ui, scan_text, Colors::BUTTON, || { + //TODO: scan code }); } }); @@ -569,15 +464,30 @@ impl WalletMessages { ui.add_space(12.0); - // Draw clear button on response. - if !self.response_edit.is_empty() && self.message_slate.is_some() { - let clear_text = format!("{} {}", BROOM, t!("clear")); - View::button(ui, clear_text, Colors::BUTTON, || { - self.message_error = None; - self.message_edit.clear(); - self.response_edit.clear(); - self.message_slate = None; - }); + // Draw clear button on message input or cancel and clear buttons on response. + if !self.message_loading { + if self.message_slate.is_none() && !self.message_edit.is_empty() { + // Draw button to clear message input. + let clear_text = format!("{} {}", BROOM, t!("clear")); + View::button(ui, clear_text, Colors::BUTTON, || { + self.message_edit.clear(); + self.response_edit.clear(); + self.message_error = None; + self.message_slate = None; + }); + } else if !self.response_edit.is_empty() && self.message_slate.is_some() { + // Draw cancel button. + let cancel = format!("{} {}", PROHIBIT, t!("modal.cancel")); + View::colored_text_button(ui, cancel, Colors::RED, Colors::BUTTON, || { + let slate = self.message_slate.clone().unwrap(); + if let Some(tx) = wallet.tx_by_slate(&slate) { + wallet.cancel(tx.data.id); + self.message_edit.clear(); + self.response_edit.clear(); + self.message_slate = None; + } + }); + } } }); @@ -591,6 +501,110 @@ impl WalletMessages { } } + /// Check Slatepack message request loading result. + fn check_message_loading_result(&mut self, wallet: &Wallet) { + // Check finalize post pay result. + let has_finalize_post_result = { + let r_res = self.final_post_result.read(); + r_res.is_some() + }; + if has_finalize_post_result { + let resp = { + let r_res = self.final_post_result.read(); + r_res.as_ref().unwrap().clone() + }; + if resp.is_ok() { + self.message_edit.clear(); + self.message_slate = None; + } else { + self.message_error = Some( + MessageError::Finalize( + t!("wallets.finalize_slatepack_err") + ) + ); + } + self.message_loading = false; + } + + // Check receive pay result. + let has_receive_pay_result = { + let r_res = self.receive_pay_result.read(); + r_res.is_some() + }; + if has_receive_pay_result { + let (slate, resp) = { + let r_res = self.receive_pay_result.read(); + r_res.as_ref().unwrap().clone() + }; + if resp.is_ok() { + self.response_edit = resp.as_ref().unwrap().clone(); + } else { + let err = resp.as_ref().err().unwrap(); + match err { + // Set already canceled transaction error message. + Error::TransactionWasCancelled {..} + => { + self.message_error = Some( + MessageError::Response( + t!("wallets.resp_canceled_err") + ) + ); + } + // Set an error when there is not enough funds to pay. + Error::NotEnoughFunds {..} => { + let m = t!( + "wallets.pay_balance_error", + "amount" => amount_to_hr_string(slate.amount, true) + ); + self.message_error = Some(MessageError::Response(m)); + } + // Set default error message. + _ => { + self.message_error = Some( + MessageError::Response( + t!("wallets.resp_slatepack_err") + ) + ); + } + } + // Check if tx with same slate id already exists. + if self.message_error.is_none() { + let exists_tx = wallet.tx_by_slate(&slate).is_some(); + if exists_tx { + let mut sl = slate.clone(); + sl.state = if sl.state == SlateState::Standard1 { + SlateState::Standard2 + } else { + SlateState::Invoice2 + }; + match wallet.read_slatepack(&sl) { + None => { + self.message_error = Some( + MessageError::Response( + t!("wallets.resp_slatepack_err") + ) + ); + } + Some(sp) => { + self.response_edit = sp; + } + } + } + } + } + // Setup message slate. + if self.message_error.is_none() { + self.message_slate = Some(slate); + } + // Clear message loading result and status. + { + let mut w_res = self.receive_pay_result.write(); + *w_res = None; + } + self.message_loading = false; + } + } + /// Parse message input into [`Slate`] updating slate and response input. pub fn parse_message(&mut self, wallet: &mut Wallet) { self.message_error = None; diff --git a/src/gui/views/wallets/wallet/txs.rs b/src/gui/views/wallets/wallet/txs.rs index 84c7587..76bdb03 100644 --- a/src/gui/views/wallets/wallet/txs.rs +++ b/src/gui/views/wallets/wallet/txs.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use std::thread; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea}; use egui::scroll_area::ScrollBarVisibility; use egui_pull_to_refresh::PullToRefresh; @@ -24,7 +24,7 @@ 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}; +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, QR_CODE, SCAN, X_CIRCLE}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; use crate::gui::views::types::ModalPosition; @@ -309,8 +309,9 @@ impl WalletTransactions { } // Draw cancel button for tx that can be reposted and canceled. + let wallet_loaded = wallet.foreign_api_port().is_some(); if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && - (tx.can_repost(data) || tx.can_cancel()) { + (tx.can_repost(data) || tx.can_cancel()) && wallet_loaded { let cancel_rounding = if can_show_info { Rounding::default() } else { @@ -333,7 +334,8 @@ impl WalletTransactions { } // Draw finalization button for tx that can be finalized. - if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && tx.can_finalize { + if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && tx.can_finalize && + wallet_loaded { let (icon, color) = if !can_show_info && self.tx_info_finalize { (FILE_TEXT, None) } else { @@ -354,7 +356,7 @@ impl WalletTransactions { } // Draw button to repost transaction. - if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && + if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && wallet_loaded && tx.can_repost(data) { View::item_button(ui, Rounding::default(), @@ -686,15 +688,16 @@ impl WalletTransactions { }); ui.add_space(4.0); - ui.vertical_centered(|ui| { - let message_edit = if self.tx_info_finalize { - &mut self.tx_info_finalize_edit - } else { - &mut self.tx_info_response_edit - }; - let message_before = message_edit.clone(); + // Setup message input value. + let message_edit = if self.tx_info_finalize { + &mut self.tx_info_finalize_edit + } else { + &mut self.tx_info_response_edit + }; + let message_before = message_edit.clone(); - // Draw Slatepack message text input or output. + // Draw Slatepack message text input or output. + ui.vertical_centered(|ui| { let input_id = Id::from("tx_info_slatepack_message").with(slate.id).with(tx.data.id); View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(3.0); @@ -714,39 +717,66 @@ impl WalletTransactions { .show(ui); ui.add_space(6.0); }); - ui.add_space(2.0); - 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")); - View::button(ui, paste_text, Colors::BUTTON, || { - self.tx_info_finalize_edit = cb.get_string_from_buffer(); - }); + ui.add_space(2.0); + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(8.0); - // Callback on finalization message input change. - if message_before != self.tx_info_finalize_edit { - self.on_finalization_input_change(tx, wallet, modal); - } - } else { - // Draw copy button. - let copy_text = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_text, Colors::BUTTON, || { - cb.copy_string_to_buffer(self.tx_info_response_edit.clone()); - self.tx_info_finalize_edit = "".to_string(); - if tx.can_finalize { - self.tx_info_finalize = true; - } else { - modal.close(); + // Do not show buttons on finalization. + if self.tx_info_finalizing { + return; + } + + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); + + if self.tx_info_finalize { + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + // Draw paste button. + let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); + View::button(ui, paste_text, Colors::BUTTON, || { + self.tx_info_finalize_edit = cb.get_string_from_buffer(); + }); + + // Callback on finalization message input change. + if message_before != self.tx_info_finalize_edit { + self.on_finalization_input_change(tx, wallet, modal); } }); - } - }); + columns[1].vertical_centered_justified(|ui| { + // Draw button to scan Slatepack message QR code. + let qr_text = format!("{} {}", SCAN, t!("scan")); + View::button(ui, qr_text, Colors::BUTTON, || { + //TODO: scan qr. + }); + }); + }); + } else { + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + // Draw copy button. + let copy_text = format!("{} {}", COPY, t!("copy")); + View::button(ui, copy_text, Colors::BUTTON, || { + cb.copy_string_to_buffer(self.tx_info_response_edit.clone()); + self.tx_info_finalize_edit = "".to_string(); + if tx.can_finalize { + self.tx_info_finalize = true; + } else { + modal.close(); + } + }); + }); + columns[1].vertical_centered_justified(|ui| { + // Draw button to show Slatepack message as QR code. + let qr_text = format!("{} {}", QR_CODE, t!("qr_code")); + View::button(ui, qr_text, Colors::BUTTON, || { + //TODO: show qr. + }); + }); + }); + } } /// Parse Slatepack message on transaction finalization input change.