From 63a8f189d81c593012b1ac8e7c6e1b3419646efd Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Mon, 9 Jan 2023 12:02:39 +0000 Subject: [PATCH 1/7] read value from clipboard, next parse into slatepack --- locale/de.json | 2 +- locale/en.json | 2 +- src/gui/element/wallet/operation/apply_tx.rs | 219 +++++++++++++++---- src/gui/mod.rs | 2 +- src/gui/update.rs | 29 ++- 5 files changed, 193 insertions(+), 61 deletions(-) diff --git a/locale/de.json b/locale/de.json index 6585c95..3244e38 100644 --- a/locale/de.json +++ b/locale/de.json @@ -219,7 +219,7 @@ "wallet-create-tx": "Send", "wallet-apply-tx": "Receive", "wallet-home": "Wallet - Set Name Here TBD", - "apply-tx": "Progress Transaction", + "apply-tx": "Apply Transaction", "create-tx": "Start Transaction", "slatepack-address-name": "This Wallet's Slatepack Address", "address-instruction": "Provide this address to others to allow them to send you funds", diff --git a/locale/en.json b/locale/en.json index 4f7e556..03e983b 100644 --- a/locale/en.json +++ b/locale/en.json @@ -229,7 +229,7 @@ "wallet-create-tx": "Send", "wallet-apply-tx": "Receive", "wallet-home": "Wallet - Set Name Here TBD", - "apply-tx": "Progress Transaction", + "apply-tx": "Apply Transaction", "create-tx": "Start Transaction", "slatepack-address-name": "This Wallet's Slatepack Address", "address-instruction": "Provide this address to others to allow them to send you funds", diff --git a/src/gui/element/wallet/operation/apply_tx.rs b/src/gui/element/wallet/operation/apply_tx.rs index 4ec6098..528a20d 100644 --- a/src/gui/element/wallet/operation/apply_tx.rs +++ b/src/gui/element/wallet/operation/apply_tx.rs @@ -13,18 +13,22 @@ use std::path::PathBuf; use super::tx_list::{HeaderState, TxList}; use { - super::super::super::{DEFAULT_FONT_SIZE, DEFAULT_HEADER_FONT_SIZE, SMALLER_FONT_SIZE, DEFAULT_PADDING}, + super::super::super::{ + BUTTON_HEIGHT, BUTTON_WIDTH, DEFAULT_FONT_SIZE, DEFAULT_HEADER_FONT_SIZE, DEFAULT_PADDING, + SMALLER_FONT_SIZE, + }, crate::gui::{GrinGui, Interaction, Message}, crate::localization::localized_string, crate::Result, anyhow::Context, + grin_gui_core::theme::{ + Button, Column, Container, Element, Header, PickList, Row, Scrollable, TableRow, Text, + TextInput, + }, grin_gui_core::wallet::{StatusMessage, WalletInfo, WalletInterface}, grin_gui_core::{node::amount_to_hr_string, theme::ColorPalette}, - grin_gui_core::theme::{Container, Button, Element, Column, PickList, Row, Scrollable, Text, TextInput, Header, TableRow}, + iced::widget::{button, pick_list, scrollable, text_input, Checkbox, Space}, iced::{alignment, Alignment, Command, Length}, - iced::widget::{ - button, pick_list, scrollable, text_input,Checkbox, Space, - }, serde::{Deserialize, Serialize}, std::sync::{Arc, RwLock}, }; @@ -34,6 +38,8 @@ pub struct StateContainer { // pub copy_address_button_state: button::State, // pub address_state: text_input::State, pub address_value: String, + // Value read from clipboard + pub read_slatepack_from_clipboard: String, } impl Default for StateContainer { @@ -43,6 +49,7 @@ impl Default for StateContainer { // copy_address_button_state: Default::default(), // address_state: Default::default(), address_value: Default::default(), + read_slatepack_from_clipboard: Default::default(), } } } @@ -54,6 +61,9 @@ pub enum Action {} pub enum LocalViewInteraction { Back, Address(String), + ApplyTransaction(String), + ReadFromClipboardSuccess(String), + ReadFromClipboardFailure, } pub fn handle_message<'a>( @@ -71,46 +81,44 @@ pub fn handle_message<'a>( grin_gui.wallet_state.operation_state.mode = crate::gui::element::wallet::operation::Mode::Home; } - LocalViewInteraction::Address(_) => { - + LocalViewInteraction::ReadFromClipboardSuccess(value) => { + debug!("Read from clipboard: {}", value); + } + LocalViewInteraction::ReadFromClipboardFailure => { + error!("Failed to read from clipboard"); } + LocalViewInteraction::Address(_) => {} + LocalViewInteraction::ApplyTransaction(_) => {} } Ok(Command::none()) } -pub fn data_container<'a>( - config: &'a Config, - state: &'a StateContainer, -) -> Container<'a, Message> { +pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Container<'a, Message> { + let unit_spacing = 15; + // Title row let title = Text::new(localized_string("apply-tx")) .size(DEFAULT_HEADER_FONT_SIZE) .horizontal_alignment(alignment::Horizontal::Center); - let title_container = - Container::new(title).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + let title_container = Container::new(title) + .style(grin_gui_core::theme::ContainerStyle::BrightBackground) + .padding(iced::Padding::from([ + 2, // top + 0, // right + 2, // bottom + 5, // left + ])); - let back_button_label_container = - Container::new(Text::new(localized_string("back")).size(DEFAULT_FONT_SIZE)) - .height(Length::Units(20)) - .align_y(alignment::Vertical::Bottom) - .align_x(alignment::Horizontal::Center); + // push more items on to header here: e.g. other buttons, things that belong on the header + let header_row = Row::new().push(title_container); - let back_button: Element = - Button::new( back_button_label_container) - .style(grin_gui_core::theme::ButtonStyle::NormalText) - .on_press(Interaction::WalletOperationApplyTxViewInteraction( - LocalViewInteraction::Back, - )) - .into(); - - let title_row = Row::new() - .push(title_container) - .push(back_button.map(Message::Interaction)) - //.push(Space::new(Length::Fill, Length::Units(0))) - .align_items(Alignment::Center) - .padding(6) - .spacing(20); + let header_container = Container::new(header_row).padding(iced::Padding::from([ + 0, // top + 0, // right + DEFAULT_PADDING, // bottom + 0, // left + ])); let address_name = Text::new(localized_string("slatepack-address-name")) .size(DEFAULT_FONT_SIZE) @@ -119,7 +127,7 @@ pub fn data_container<'a>( let address_name_container = Container::new(address_name).style(grin_gui_core::theme::ContainerStyle::NormalBackground); - let address_input = TextInput::new( "", &state.address_value, |s| { + let address_input = TextInput::new("", &state.address_value, |s| { Interaction::WalletOperationApplyTxViewInteraction(LocalViewInteraction::Address(s)) }) .size(DEFAULT_FONT_SIZE) @@ -136,16 +144,14 @@ pub fn data_container<'a>( .horizontal_alignment(alignment::Horizontal::Center), ) .style(grin_gui_core::theme::ButtonStyle::NormalText) - .on_press(Interaction::WriteToClipboard( - state.address_value.clone(), - )); + .on_press(Interaction::WriteToClipboard(state.address_value.clone())); let copy_address_button: Element = copy_address_button.into(); let address_row = Row::new() - .push(address_input) - .push(copy_address_button) - .spacing(DEFAULT_PADDING); + .push(address_input) + .push(copy_address_button) + .spacing(DEFAULT_PADDING); let address_row: Element = address_row.into(); @@ -153,20 +159,137 @@ pub fn data_container<'a>( .size(SMALLER_FONT_SIZE) .horizontal_alignment(alignment::Horizontal::Left); - let address_instruction_container = - Container::new(address_instruction_container).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + let address_instruction_container = Container::new(address_instruction_container) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let slatepack_paste_name = Text::new(localized_string("paste-transaction-here")) + .size(DEFAULT_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Left); + + let slatepack_paste_name_container = + Container::new(slatepack_paste_name).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let slatepack_text_area = Text::new("SLATEPACK TEXT GO HERE").size(DEFAULT_FONT_SIZE) + .width(Length::Units(400)); + + let paste_slatepack_button = Button::new( + // &mut state.copy_address_button_state, + Text::new(localized_string("paste-from-clipboard")) + .size(SMALLER_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Center), + ) + .style(grin_gui_core::theme::ButtonStyle::NormalText) + .on_press(Interaction::ReadSlatepackFromClipboard); + + let paste_slatepack_button: Element = paste_slatepack_button.into(); + + let paste_slatepack_row = Row::new() + .push(slatepack_text_area) + .push(paste_slatepack_button.map(Message::Interaction)) + .spacing(DEFAULT_PADDING); + + let slatepack_area = Column::new() + .push(slatepack_paste_name_container) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(paste_slatepack_row); + + let slatepack_area_container = Container::new(slatepack_area); + + let button_height = Length::Units(BUTTON_HEIGHT); + let button_width = Length::Units(BUTTON_WIDTH); + + let submit_button_label_container = + Container::new(Text::new(localized_string("tx-create-submit")).size(DEFAULT_FONT_SIZE)) + .width(button_width) + .height(button_height) + .center_x() + .center_y() + .align_x(alignment::Horizontal::Center); + + let mut submit_button = Button::new(submit_button_label_container) + .style(grin_gui_core::theme::ButtonStyle::Primary); + let submit_button = + submit_button.on_press(Interaction::WalletOperationApplyTxViewInteraction( + LocalViewInteraction::ApplyTransaction("_".into()), + )); + + let submit_button: Element = submit_button.into(); + let cancel_button_label_container = + Container::new(Text::new(localized_string("cancel")).size(DEFAULT_FONT_SIZE)) + .width(button_width) + .height(button_height) + .center_x() + .center_y() + .align_x(alignment::Horizontal::Center); + + let cancel_button: Element = Button::new(cancel_button_label_container) + .style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::WalletOperationApplyTxViewInteraction( + LocalViewInteraction::Back, + )) + .into(); + + let submit_container = Container::new(submit_button.map(Message::Interaction)).padding(1); + let submit_container = Container::new(submit_container) + .style(grin_gui_core::theme::ContainerStyle::Segmented) + .padding(1); + + let cancel_container = Container::new(cancel_button.map(Message::Interaction)).padding(1); + let cancel_container = Container::new(cancel_container) + .style(grin_gui_core::theme::ContainerStyle::Segmented) + .padding(1); + + let button_row = Row::new() + .push(submit_container) + .push(Space::new(Length::Units(unit_spacing), Length::Units(0))) + .push(cancel_container); let column = Column::new() - .push(title_row) .push(address_name_container) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) .push(address_instruction_container) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) .push(address_row.map(Message::Interaction)) - .spacing(DEFAULT_PADDING) - .align_items(Alignment::Start); + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(slatepack_area_container) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(button_row) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(Space::new( + Length::Units(0), + Length::Units(unit_spacing + 10), + )); - Container::new(column) - .center_y() - .center_x() + let form_container = Container::new(column) .width(Length::Fill) + .padding(iced::Padding::from([ + 0, // top + 0, // right + 0, // bottom + 5, // left + ])); + + // form container should be scrollable in tiny windows + let scrollable = Scrollable::new(form_container) + .height(Length::Fill) + .style(grin_gui_core::theme::ScrollableStyle::Primary); + + let content = Container::new(scrollable) + .width(Length::Fill) + .height(Length::Shrink) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let wrapper_column = Column::new() + .height(Length::Fill) + .push(header_container) + .push(content); + + // Returns the final container. + Container::new(wrapper_column).padding(iced::Padding::from([ + DEFAULT_PADDING, // top + DEFAULT_PADDING, // right + DEFAULT_PADDING, // bottom + DEFAULT_PADDING, // left + ])) } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index a32ea46..3f0b016 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -412,7 +412,7 @@ pub enum Interaction { CloseErrorModal, /// Clipboard copy WriteToClipboard(String), - ReadFromClipboard(String), + ReadSlatepackFromClipboard, /// View interactions MenuViewInteraction(element::menu::LocalViewInteraction), SettingsViewInteraction(element::settings::LocalViewInteraction), diff --git a/src/gui/update.rs b/src/gui/update.rs index f5cef8c..ff63a17 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -1,7 +1,10 @@ use { super::{GrinGui, Interaction, Message, Mode}, crate::{gui::element, log_error, Result}, - grin_gui_core::{fs::PersistentData, node::subscriber::UIMessage, node::ChainTypes::Testnet, node::ChainTypes::Mainnet}, + grin_gui_core::{ + fs::PersistentData, node::subscriber::UIMessage, node::ChainTypes::Mainnet, + node::ChainTypes::Testnet, + }, iced::{clipboard, Command}, //grin_gui_widgets::header::ResizeEvent, std::path::PathBuf, @@ -53,12 +56,12 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result Result {} Message::Interaction(Interaction::CloseErrorModal) => {} Message::Interaction(Interaction::WriteToClipboard(_)) => {} + Message::Interaction(Interaction::ReadSlatepackFromClipboard) => {} Message::Interaction(_) => { grin_gui.error.take(); } @@ -108,14 +112,19 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result grin_gui.modal_state.show(true), - Message::Interaction(Interaction::CloseErrorModal) => { - grin_gui.modal_state.show(false) - } + Message::Interaction(Interaction::CloseErrorModal) => grin_gui.modal_state.show(false), // Clipboard messages Message::Interaction(Interaction::WriteToClipboard(contents)) => { return Ok(clipboard::write::(contents)); } - // Top level menu + Message::Interaction(Interaction::ReadSlatepackFromClipboard) => { + return Ok(clipboard::read::(|value| { + match value { + Some(v) => return Message::Interaction(Interaction::WalletOperationApplyTxViewInteraction(element::wallet::operation::apply_tx::LocalViewInteraction::ReadFromClipboardSuccess(v))), + None => return Message::Interaction(Interaction::WalletOperationApplyTxViewInteraction(element::wallet::operation::apply_tx::LocalViewInteraction::ReadFromClipboardFailure)) + } + })) + } // Top level menu Message::Interaction(Interaction::MenuViewInteraction(l)) => { let _ = element::menu::handle_message(grin_gui, l); } @@ -168,7 +177,7 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result { return element::wallet::operation::tx_list_display::handle_message(grin_gui, l); } - // Wallet -> Operation -> TxList + // Wallet -> Operation -> TxList Message::Interaction(Interaction::WalletOperationTxListInteraction(l)) => { return element::wallet::operation::tx_list::handle_message(grin_gui, l); } @@ -180,7 +189,7 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result { return element::wallet::operation::create_tx_success::handle_message(grin_gui, l); } - // Wallet -> Operation -> Home -> Action + // Wallet -> Operation -> Home -> Action Message::Interaction(Interaction::WalletOperationApplyTxViewInteraction(l)) => { return element::wallet::operation::apply_tx::handle_message(grin_gui, l); } @@ -188,7 +197,7 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result { return element::wallet::operation::action_menu::handle_message(grin_gui, l); } - Message::Interaction(Interaction::ModeSelected(mode)) => { + Message::Interaction(Interaction::ModeSelected(mode)) => { log::debug!("Interaction::ModeSelected({:?})", mode); // Set Mode grin_gui.mode = mode; From bf26c9c61af898866a4cbbeecf56687bde53df2a Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Tue, 10 Jan 2023 09:43:52 +0000 Subject: [PATCH 2/7] Attempt to read / decrypt slatepack --- crates/core/src/wallet/mod.rs | 16 +++++- locale/de.json | 6 ++- locale/en.json | 8 ++- src/gui/element/wallet/operation/apply_tx.rs | 55 +++++++++++--------- 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 82842c0..9f298f5 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -21,7 +21,7 @@ use dirs; pub use global::ChainTypes; pub use grin_wallet_impls::HTTPNodeClient; pub use grin_wallet_libwallet::{ - InitTxArgs, RetrieveTxQueryArgs, RetrieveTxQuerySortOrder, Slate, SlatepackAddress, + InitTxArgs, RetrieveTxQueryArgs, RetrieveTxQuerySortOrder, Slate, SlatepackAddress, Slatepack, StatusMessage, TxLogEntry, TxLogEntryType, WalletInfo, }; @@ -369,6 +369,20 @@ where Ok(api.create_slatepack_message(None, &unenc_slate, Some(0), recipients)?) } + /// Attempt to decode and decrypt a given slatepack + pub fn decrypt_slatepace( + wallet_interface: Arc>>, + slatepack: String, + ) -> Result { + let w = wallet_interface.read().unwrap(); + if let Some(o) = &w.owner_api { + let res = o.decode_slatepack_message(None, slatepack, vec![0])?; + return Ok(res) + } else { + return Err(GrinWalletInterfaceError::OwnerAPINotInstantiated); + } + } + pub async fn get_wallet_info( wallet_interface: Arc>>, ) -> Result<(bool, WalletInfo), GrinWalletInterfaceError> { diff --git a/locale/de.json b/locale/de.json index 3244e38..6584db4 100644 --- a/locale/de.json +++ b/locale/de.json @@ -235,6 +235,10 @@ "tx-list": "Transactions", "tx-outstanding": "Outstanding", "tx-recent": "Most Recent", - "tx-details": "Details" + "tx-details": "Details", + "tx-slatepack-paste-transaction-here": "Paste Transaction from Clipboard", + "tx-slatepack-read-result-default": "Ensure the clipboard contains the encrypted slatepack contents and press 'Continue'", + "tx-slatepack-read-failure": "Clipboard does not contain a slatepack that can be decrypted by this wallet", + "tx-continue": "Continue" } \ No newline at end of file diff --git a/locale/en.json b/locale/en.json index 03e983b..c69b501 100644 --- a/locale/en.json +++ b/locale/en.json @@ -244,5 +244,11 @@ "tx-recent": "Most Recent", "tx-details": "Details", "tx-create-success-title": "Encrypted Transaction", - "tx-create-success-desc": "Copy/Paste this encrypted transaction to the recipient via a channel of your choosing" + "tx-create-success-desc": "Copy/Paste this encrypted transaction to the recipient via a channel of your choosing", + "tx-slatepack-paste-transaction-here": "Paste Transaction from Clipboard", + "tx-slatepack-read-result-default": "Ensure the clipboard contains the encrypted slatepack contents and press 'Continue'", + "tx-slatepack-read-failure": "Clipboard does not contain a slatepack that can be decrypted by this wallet", + "tx-continue": "Continue" + + } \ No newline at end of file diff --git a/src/gui/element/wallet/operation/apply_tx.rs b/src/gui/element/wallet/operation/apply_tx.rs index 528a20d..ffa4301 100644 --- a/src/gui/element/wallet/operation/apply_tx.rs +++ b/src/gui/element/wallet/operation/apply_tx.rs @@ -38,8 +38,8 @@ pub struct StateContainer { // pub copy_address_button_state: button::State, // pub address_state: text_input::State, pub address_value: String, - // Value read from clipboard - pub read_slatepack_from_clipboard: String, + // Slatepack read result + pub slatepack_read_result: String, } impl Default for StateContainer { @@ -49,7 +49,7 @@ impl Default for StateContainer { // copy_address_button_state: Default::default(), // address_state: Default::default(), address_value: Default::default(), - read_slatepack_from_clipboard: Default::default(), + slatepack_read_result: localized_string("tx-slatepack-read-result-default"), } } } @@ -70,11 +70,7 @@ pub fn handle_message<'a>( grin_gui: &mut GrinGui, message: LocalViewInteraction, ) -> Result> { - /*let state = &mut grin_gui - .wallet_state - .operation_state - .home_state - .action_menu_state;*/ + let state = &mut grin_gui.wallet_state.operation_state.apply_tx_state; match message { LocalViewInteraction::Back => { log::debug!("Interaction::WalletOperationApplyTxViewInteraction(Back)"); @@ -83,6 +79,16 @@ pub fn handle_message<'a>( } LocalViewInteraction::ReadFromClipboardSuccess(value) => { debug!("Read from clipboard: {}", value); + let w = grin_gui.wallet_interface.clone(); + let decode_res = WalletInterface::decrypt_slatepace(w, value); + match decode_res { + Err(e) => { + state.slatepack_read_result = localized_string("tx-slatepack-read-failure") + } + Ok(s) => { + debug!("{}", s); + } + } } LocalViewInteraction::ReadFromClipboardFailure => { error!("Failed to read from clipboard"); @@ -162,30 +168,31 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont let address_instruction_container = Container::new(address_instruction_container) .style(grin_gui_core::theme::ContainerStyle::NormalBackground); - let slatepack_paste_name = Text::new(localized_string("paste-transaction-here")) + let slatepack_paste_name = Text::new(localized_string("tx-slatepack-paste-transaction-here")) .size(DEFAULT_FONT_SIZE) .horizontal_alignment(alignment::Horizontal::Left); - let slatepack_paste_name_container = - Container::new(slatepack_paste_name).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + let slatepack_paste_name_container = Container::new(slatepack_paste_name) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); - let slatepack_text_area = Text::new("SLATEPACK TEXT GO HERE").size(DEFAULT_FONT_SIZE) - .width(Length::Units(400)); + let slatepack_text_area = Text::new(state.slatepack_read_result.clone()) + .size(DEFAULT_FONT_SIZE) + .width(Length::Units(400)); - let paste_slatepack_button = Button::new( + /*let paste_slatepack_button = Button::new( // &mut state.copy_address_button_state, - Text::new(localized_string("paste-from-clipboard")) + Text::new(localized_string("tx-slatepack-paste-from-clipboard")) .size(SMALLER_FONT_SIZE) .horizontal_alignment(alignment::Horizontal::Center), ) .style(grin_gui_core::theme::ButtonStyle::NormalText) .on_press(Interaction::ReadSlatepackFromClipboard); - let paste_slatepack_button: Element = paste_slatepack_button.into(); + let paste_slatepack_button: Element = paste_slatepack_button.into();*/ let paste_slatepack_row = Row::new() .push(slatepack_text_area) - .push(paste_slatepack_button.map(Message::Interaction)) + //.push(paste_slatepack_button.map(Message::Interaction)) .spacing(DEFAULT_PADDING); let slatepack_area = Column::new() @@ -199,7 +206,7 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont let button_width = Length::Units(BUTTON_WIDTH); let submit_button_label_container = - Container::new(Text::new(localized_string("tx-create-submit")).size(DEFAULT_FONT_SIZE)) + Container::new(Text::new(localized_string("tx-continue")).size(DEFAULT_FONT_SIZE)) .width(button_width) .height(button_height) .center_x() @@ -207,11 +214,11 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont .align_x(alignment::Horizontal::Center); let mut submit_button = Button::new(submit_button_label_container) - .style(grin_gui_core::theme::ButtonStyle::Primary); - let submit_button = - submit_button.on_press(Interaction::WalletOperationApplyTxViewInteraction( - LocalViewInteraction::ApplyTransaction("_".into()), - )); + .style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::ReadSlatepackFromClipboard); + /*let submit_button = submit_button.on_press(Interaction::WalletOperationApplyTxViewInteraction( + LocalViewInteraction::ApplyTransaction("_".into()), + ));*/ let submit_button: Element = submit_button.into(); @@ -269,7 +276,7 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont 0, // bottom 5, // left ])); - + // form container should be scrollable in tiny windows let scrollable = Scrollable::new(form_container) .height(Length::Fill) From 5153c62221364e5c85d74a26343bcfee8ea24c69 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Tue, 10 Jan 2023 16:11:23 +0000 Subject: [PATCH 3/7] adding confirmation screen/dialogue for transaction progression --- crates/core/src/wallet/mod.rs | 7 ++++--- locale/de.json | 5 ++++- locale/en.json | 7 ++++--- src/gui/element/wallet/operation/apply_tx.rs | 5 ++++- src/gui/element/wallet/operation/mod.rs | 9 ++++++++- src/gui/mod.rs | 1 + src/gui/update.rs | 4 ++++ 7 files changed, 29 insertions(+), 9 deletions(-) diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 9f298f5..4ded818 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -373,11 +373,12 @@ where pub fn decrypt_slatepace( wallet_interface: Arc>>, slatepack: String, - ) -> Result { + ) -> Result<(Slatepack, Slate), GrinWalletInterfaceError> { let w = wallet_interface.read().unwrap(); if let Some(o) = &w.owner_api { - let res = o.decode_slatepack_message(None, slatepack, vec![0])?; - return Ok(res) + let sp= o.decode_slatepack_message(None, slatepack.clone(), vec![0])?; + let slate = o.slate_from_slatepack_message(None, slatepack, vec![0])?; + return Ok((sp, slate)) } else { return Err(GrinWalletInterfaceError::OwnerAPINotInstantiated); } diff --git a/locale/de.json b/locale/de.json index 6584db4..981b299 100644 --- a/locale/de.json +++ b/locale/de.json @@ -239,6 +239,9 @@ "tx-slatepack-paste-transaction-here": "Paste Transaction from Clipboard", "tx-slatepack-read-result-default": "Ensure the clipboard contains the encrypted slatepack contents and press 'Continue'", "tx-slatepack-read-failure": "Clipboard does not contain a slatepack that can be decrypted by this wallet", - "tx-continue": "Continue" + "tx-continue": "Continue", + "apply-tx-confirm": "Confirm Transaction Details", + "tx-sender-name": "Sender", + "apply-tx-amount": "Incoming amount" } \ No newline at end of file diff --git a/locale/en.json b/locale/en.json index c69b501..b712a31 100644 --- a/locale/en.json +++ b/locale/en.json @@ -248,7 +248,8 @@ "tx-slatepack-paste-transaction-here": "Paste Transaction from Clipboard", "tx-slatepack-read-result-default": "Ensure the clipboard contains the encrypted slatepack contents and press 'Continue'", "tx-slatepack-read-failure": "Clipboard does not contain a slatepack that can be decrypted by this wallet", - "tx-continue": "Continue" - - + "tx-continue": "Continue", + "apply-tx-confirm": "Confirm Transaction Details", + "tx-sender-name": "Sender", + "apply-tx-amount": "Incoming amount" } \ No newline at end of file diff --git a/src/gui/element/wallet/operation/apply_tx.rs b/src/gui/element/wallet/operation/apply_tx.rs index ffa4301..153aeca 100644 --- a/src/gui/element/wallet/operation/apply_tx.rs +++ b/src/gui/element/wallet/operation/apply_tx.rs @@ -86,7 +86,10 @@ pub fn handle_message<'a>( state.slatepack_read_result = localized_string("tx-slatepack-read-failure") } Ok(s) => { - debug!("{}", s); + debug!("{}", s.0); + grin_gui.wallet_state.operation_state.apply_tx_confirm_state.slatepack_parsed = Some(s); + grin_gui.wallet_state.operation_state.mode = + crate::gui::element::wallet::operation::Mode::ApplyTxConfirm; } } } diff --git a/src/gui/element/wallet/operation/mod.rs b/src/gui/element/wallet/operation/mod.rs index d60344c..49b173c 100644 --- a/src/gui/element/wallet/operation/mod.rs +++ b/src/gui/element/wallet/operation/mod.rs @@ -5,6 +5,7 @@ pub mod tx_list; pub mod create_tx; pub mod create_tx_success; pub mod apply_tx; +pub mod apply_tx_confirm; pub mod chart; pub mod tx_list_display; @@ -26,6 +27,7 @@ pub struct StateContainer { pub create_tx_state: create_tx::StateContainer, pub create_tx_success_state: create_tx_success::StateContainer, pub apply_tx_state: apply_tx::StateContainer, + pub apply_tx_confirm_state: apply_tx_confirm::StateContainer, // When changed to true, this should stay false until a wallet is opened with a password has_wallet_open_check_failed_one_time: bool, } @@ -36,7 +38,8 @@ pub enum Mode { Home, CreateTx, CreateTxSuccess, - ApplyTx + ApplyTx, + ApplyTxConfirm } impl Default for StateContainer { @@ -48,6 +51,7 @@ impl Default for StateContainer { create_tx_state: Default::default(), create_tx_success_state: Default::default(), apply_tx_state: Default::default(), + apply_tx_confirm_state: Default::default(), has_wallet_open_check_failed_one_time: false, } } @@ -98,6 +102,9 @@ pub fn data_container<'a>( Mode::ApplyTx => { apply_tx::data_container(config, &state.apply_tx_state) } + Mode::ApplyTxConfirm => { + apply_tx_confirm::data_container(config, &state.apply_tx_confirm_state) + } }; let column = Column::new() diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 3f0b016..9a6ad58 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -433,6 +433,7 @@ pub enum Interaction { WalletOperationCreateTxViewInteraction(element::wallet::operation::create_tx::LocalViewInteraction), WalletOperationCreateTxSuccessViewInteraction(element::wallet::operation::create_tx_success::LocalViewInteraction), WalletOperationApplyTxViewInteraction(element::wallet::operation::apply_tx::LocalViewInteraction), + WalletOperationApplyTxConfirmViewInteraction(element::wallet::operation::apply_tx_confirm::LocalViewInteraction), ViewInteraction(String, String), ModeSelected(Mode), ModeSelectedSettings(element::settings::Mode), diff --git a/src/gui/update.rs b/src/gui/update.rs index ff63a17..ab49b0c 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -194,6 +194,10 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result Operation -> Home -> Action + Message::Interaction(Interaction::WalletOperationApplyTxConfirmViewInteraction(l)) => { + return element::wallet::operation::apply_tx_confirm::handle_message(grin_gui, l); + } + // Wallet -> Operation -> Home -> Action Message::Interaction(Interaction::WalletOperationHomeActionMenuViewInteraction(l)) => { return element::wallet::operation::action_menu::handle_message(grin_gui, l); } From 9c0f6f9055e798a02b02af007970d36c49d80fe4 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Wed, 11 Jan 2023 09:28:03 +0000 Subject: [PATCH 4/7] added confirmation screen --- .../wallet/operation/apply_tx_confirm.rs | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 src/gui/element/wallet/operation/apply_tx_confirm.rs diff --git a/src/gui/element/wallet/operation/apply_tx_confirm.rs b/src/gui/element/wallet/operation/apply_tx_confirm.rs new file mode 100644 index 0000000..a0f5fba --- /dev/null +++ b/src/gui/element/wallet/operation/apply_tx_confirm.rs @@ -0,0 +1,317 @@ +use super::tx_list::{self, ExpandType}; +use crate::log_error; +use async_std::prelude::FutureExt; +use grin_gui_core::{ + config::Config, + wallet::{Slate, Slatepack, TxLogEntry, TxLogEntryType}, +}; +use grin_gui_widgets::widget::header; +use iced_aw::Card; +use iced_native::Widget; +use std::path::PathBuf; + +use super::tx_list::{HeaderState, TxList}; + +use { + super::super::super::{ + BUTTON_HEIGHT, BUTTON_WIDTH, DEFAULT_FONT_SIZE, DEFAULT_HEADER_FONT_SIZE, DEFAULT_PADDING, + SMALLER_FONT_SIZE, + }, + crate::gui::{GrinGui, Interaction, Message}, + crate::localization::localized_string, + crate::Result, + anyhow::Context, + grin_gui_core::theme::{ + Button, Column, Container, Element, Header, PickList, Row, Scrollable, TableRow, Text, + TextInput, + }, + grin_gui_core::wallet::{StatusMessage, WalletInfo, WalletInterface}, + grin_gui_core::{node::amount_to_hr_string, theme::ColorPalette}, + iced::widget::{button, pick_list, scrollable, text_input, Checkbox, Space}, + iced::{alignment, Alignment, Command, Length}, + serde::{Deserialize, Serialize}, + std::sync::{Arc, RwLock}, +}; + +pub struct StateContainer { + // pub back_button_state: button::State, + // pub copy_address_button_state: button::State, + // pub address_state: text_input::State, + pub address_value: String, + // Slatepack read result + pub slatepack_read_result: String, + // Actual read slatepack + pub slatepack_parsed: Option<(Slatepack, Slate)>, +} + +impl Default for StateContainer { + fn default() -> Self { + Self { + // back_button_state: Default::default(), + // copy_address_button_state: Default::default(), + // address_state: Default::default(), + address_value: Default::default(), + slatepack_read_result: localized_string("tx-slatepack-read-result-default"), + slatepack_parsed: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Action {} + +#[derive(Debug, Clone)] +pub enum LocalViewInteraction { + Back, + Address(String), + ApplyTransaction(String), + ReadFromClipboardSuccess(String), + ReadFromClipboardFailure, +} + +pub fn handle_message<'a>( + grin_gui: &mut GrinGui, + message: LocalViewInteraction, +) -> Result> { + let state = &mut grin_gui.wallet_state.operation_state.apply_tx_confirm_state; + match message { + LocalViewInteraction::Back => { + log::debug!("Interaction::WalletOperationApplyTxViewInteraction(Back)"); + grin_gui.wallet_state.operation_state.mode = + crate::gui::element::wallet::operation::Mode::Home; + } + LocalViewInteraction::ReadFromClipboardSuccess(value) => { + } + LocalViewInteraction::ReadFromClipboardFailure => { + error!("Failed to read from clipboard"); + } + LocalViewInteraction::Address(_) => {} + LocalViewInteraction::ApplyTransaction(_) => {} + } + Ok(Command::none()) +} + +pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Container<'a, Message> { + let unit_spacing = 15; + + if state.slatepack_parsed.is_none() { + return Container::new(Text::new( + "you should never see this - dev make sure slatepack is not None", + )); + } + + // Decode/parse/etc fields for display here + let (slatepack, slate) = state.slatepack_parsed.as_ref().unwrap(); + + let sp_sending_address = match &slatepack.sender { + None => "None".to_string(), + Some(s) => s.to_string(), + }; + + let amount = amount_to_hr_string(slate.amount, false); + + // TODO: What's displayed here should change based on the slate state + + // Title row + let title = Text::new(localized_string("apply-tx-confirm")) + .size(DEFAULT_HEADER_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Center); + + let title_container = Container::new(title) + .style(grin_gui_core::theme::ContainerStyle::BrightBackground) + .padding(iced::Padding::from([ + 2, // top + 0, // right + 2, // bottom + 5, // left + ])); + + // push more items on to header here: e.g. other buttons, things that belong on the header + let header_row = Row::new().push(title_container); + + let header_container = Container::new(header_row).padding(iced::Padding::from([ + 0, // top + 0, // right + DEFAULT_PADDING, // bottom + 0, // left + ])); + + let sender_name_label = Text::new(format!("{}: ", localized_string("tx-sender-name"))) + .size(DEFAULT_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Left); + + let sender_name_label_container = Container::new(sender_name_label) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let sender_name = Text::new(sp_sending_address).size(DEFAULT_FONT_SIZE); + //.width(Length::Units(400)) + //.style(grin_gui_core::theme::TextInputStyle::AddonsQuery); + + let sender_name_container = + Container::new(sender_name).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let sender_name_row = Row::new() + .push(sender_name_label_container) + .push(sender_name_container); + + let amount_label = Text::new(format!("{}: ", localized_string("apply-tx-amount"))) + .size(DEFAULT_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Left); + + let amount_label_container = Container::new(amount_label) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let amount = Text::new(amount).size(DEFAULT_FONT_SIZE); + //.width(Length::Units(400)) + //.style(grin_gui_core::theme::TextInputStyle::AddonsQuery); + + let amount_container = + Container::new(amount).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let amount_row = Row::new() + .push(amount_label_container) + .push(amount_container); + + + /*let address_row = Row::new() + .push(address_input) + .push(copy_address_button) + .spacing(DEFAULT_PADDING); + + let address_row: Element = address_row.into(); + + let address_instruction_container = Text::new(localized_string("address-instruction")) + .size(SMALLER_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Left); + + let address_instruction_container = Container::new(address_instruction_container) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let slatepack_paste_name = Text::new(localized_string("tx-slatepack-paste-transaction-here")) + .size(DEFAULT_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Left); + + let slatepack_paste_name_container = Container::new(slatepack_paste_name) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let slatepack_text_area = Text::new(state.slatepack_read_result.clone()) + .size(DEFAULT_FONT_SIZE) + .width(Length::Units(400));*/ + + /*let paste_slatepack_button = Button::new( + // &mut state.copy_address_button_state, + Text::new(localized_string("tx-slatepack-paste-from-clipboard")) + .size(SMALLER_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Center), + ) + .style(grin_gui_core::theme::ButtonStyle::NormalText) + .on_press(Interaction::ReadSlatepackFromClipboard); + + let paste_slatepack_button: Element = paste_slatepack_button.into();*/ + + /*let paste_slatepack_row = Row::new() + .push(slatepack_text_area) + //.push(paste_slatepack_button.map(Message::Interaction)) + .spacing(DEFAULT_PADDING); + + let slatepack_area = Column::new() + .push(slatepack_paste_name_container) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(paste_slatepack_row); + + let slatepack_area_container = Container::new(slatepack_area);*/ + + let button_height = Length::Units(BUTTON_HEIGHT); + let button_width = Length::Units(BUTTON_WIDTH); + + let submit_button_label_container = + Container::new(Text::new(localized_string("tx-continue")).size(DEFAULT_FONT_SIZE)) + .width(button_width) + .height(button_height) + .center_x() + .center_y() + .align_x(alignment::Horizontal::Center); + + let mut submit_button = Button::new(submit_button_label_container) + .style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::ReadSlatepackFromClipboard); + /*let submit_button = submit_button.on_press(Interaction::WalletOperationApplyTxViewInteraction( + LocalViewInteraction::ApplyTransaction("_".into()), + ));*/ + + let submit_button: Element = submit_button.into(); + + let cancel_button_label_container = + Container::new(Text::new(localized_string("cancel")).size(DEFAULT_FONT_SIZE)) + .width(button_width) + .height(button_height) + .center_x() + .center_y() + .align_x(alignment::Horizontal::Center); + + let cancel_button: Element = Button::new(cancel_button_label_container) + .style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::WalletOperationApplyTxConfirmViewInteraction( + LocalViewInteraction::Back, + )) + .into(); + + let submit_container = Container::new(submit_button.map(Message::Interaction)).padding(1); + let submit_container = Container::new(submit_container) + .style(grin_gui_core::theme::ContainerStyle::Segmented) + .padding(1); + + let cancel_container = Container::new(cancel_button.map(Message::Interaction)).padding(1); + let cancel_container = Container::new(cancel_container) + .style(grin_gui_core::theme::ContainerStyle::Segmented) + .padding(1); + + let button_row = Row::new() + .push(submit_container) + .push(Space::new(Length::Units(unit_spacing), Length::Units(0))) + .push(cancel_container); + + let column = Column::new() + .push(sender_name_row) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(amount_row) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(button_row) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(Space::new( + Length::Units(0), + Length::Units(unit_spacing + 10), + )); + + let form_container = Container::new(column) + .width(Length::Fill) + .padding(iced::Padding::from([ + 0, // top + 0, // right + 0, // bottom + 5, // left + ])); + + // form container should be scrollable in tiny windows + let scrollable = Scrollable::new(form_container) + .height(Length::Fill) + .style(grin_gui_core::theme::ScrollableStyle::Primary); + + let content = Container::new(scrollable) + .width(Length::Fill) + .height(Length::Shrink) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let wrapper_column = Column::new() + .height(Length::Fill) + .push(header_container) + .push(content); + + // Returns the final container. + Container::new(wrapper_column).padding(iced::Padding::from([ + DEFAULT_PADDING, // top + DEFAULT_PADDING, // right + DEFAULT_PADDING, // bottom + DEFAULT_PADDING, // left + ])) +} From fcb147161d436e9ffff7ebdae766d699aec478fd Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Wed, 11 Jan 2023 10:01:38 +0000 Subject: [PATCH 5/7] add some notion of state to the transaction application screen --- crates/core/src/wallet/mod.rs | 2 +- locale/de.json | 3 +- locale/en.json | 3 +- .../wallet/operation/apply_tx_confirm.rs | 139 ++++++------- .../wallet/operation/apply_tx_success.rs | 187 ++++++++++++++++++ 5 files changed, 253 insertions(+), 81 deletions(-) create mode 100644 src/gui/element/wallet/operation/apply_tx_success.rs diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 4ded818..8448b19 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -22,7 +22,7 @@ pub use global::ChainTypes; pub use grin_wallet_impls::HTTPNodeClient; pub use grin_wallet_libwallet::{ InitTxArgs, RetrieveTxQueryArgs, RetrieveTxQuerySortOrder, Slate, SlatepackAddress, Slatepack, - StatusMessage, TxLogEntry, TxLogEntryType, WalletInfo, + StatusMessage, SlateState, TxLogEntry, TxLogEntryType, WalletInfo, }; use crate::error::GrinWalletInterfaceError; diff --git a/locale/de.json b/locale/de.json index 981b299..91b140b 100644 --- a/locale/de.json +++ b/locale/de.json @@ -242,6 +242,7 @@ "tx-continue": "Continue", "apply-tx-confirm": "Confirm Transaction Details", "tx-sender-name": "Sender", - "apply-tx-amount": "Incoming amount" + "apply-tx-amount": "Incoming amount", + "tx-state": "Transaction Stage (this will be presented better)" } \ No newline at end of file diff --git a/locale/en.json b/locale/en.json index b712a31..cd6d10c 100644 --- a/locale/en.json +++ b/locale/en.json @@ -251,5 +251,6 @@ "tx-continue": "Continue", "apply-tx-confirm": "Confirm Transaction Details", "tx-sender-name": "Sender", - "apply-tx-amount": "Incoming amount" + "apply-tx-amount": "Incoming amount", + "tx-state": "Transaction Stage (this will be presented better)" } \ No newline at end of file diff --git a/src/gui/element/wallet/operation/apply_tx_confirm.rs b/src/gui/element/wallet/operation/apply_tx_confirm.rs index a0f5fba..963f4c0 100644 --- a/src/gui/element/wallet/operation/apply_tx_confirm.rs +++ b/src/gui/element/wallet/operation/apply_tx_confirm.rs @@ -3,7 +3,7 @@ use crate::log_error; use async_std::prelude::FutureExt; use grin_gui_core::{ config::Config, - wallet::{Slate, Slatepack, TxLogEntry, TxLogEntryType}, + wallet::{Slate, SlateState, Slatepack, TxLogEntry, TxLogEntryType}, }; use grin_gui_widgets::widget::header; use iced_aw::Card; @@ -63,10 +63,7 @@ pub enum Action {} #[derive(Debug, Clone)] pub enum LocalViewInteraction { Back, - Address(String), - ApplyTransaction(String), - ReadFromClipboardSuccess(String), - ReadFromClipboardFailure, + Accept, } pub fn handle_message<'a>( @@ -76,17 +73,15 @@ pub fn handle_message<'a>( let state = &mut grin_gui.wallet_state.operation_state.apply_tx_confirm_state; match message { LocalViewInteraction::Back => { - log::debug!("Interaction::WalletOperationApplyTxViewInteraction(Back)"); + log::debug!("Interaction::WalletOperationApplyTxConfirmViewInteraction(Cancel)"); grin_gui.wallet_state.operation_state.mode = crate::gui::element::wallet::operation::Mode::Home; } - LocalViewInteraction::ReadFromClipboardSuccess(value) => { - } - LocalViewInteraction::ReadFromClipboardFailure => { - error!("Failed to read from clipboard"); + LocalViewInteraction::Accept => { + log::debug!("Interaction::WalletOperationApplyTxConfirmViewInteraction(Accept)"); + grin_gui.wallet_state.operation_state.mode = + crate::gui::element::wallet::operation::Mode::Home; } - LocalViewInteraction::Address(_) => {} - LocalViewInteraction::ApplyTransaction(_) => {} } Ok(Command::none()) } @@ -110,7 +105,22 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont let amount = amount_to_hr_string(slate.amount, false); + let mut state_text = slate.state.to_string(); + // TODO: What's displayed here should change based on the slate state + let state_text_append = match slate.state { + SlateState::Standard1 => "You are the recipient - Standard workflow", + SlateState::Standard2 => { + "You are the payee, and are finalizing the transaction - Standard workflow" + } + SlateState::Standard3 => "This transaction is finalised - Standard workflow", + _ => "Support still in development", + }; + + state_text = format!("{} - {}", state_text, state_text_append); + + let hide_continue = + slate.state != SlateState::Standard1 && slate.state != SlateState::Standard2; // Title row let title = Text::new(localized_string("apply-tx-confirm")) @@ -136,30 +146,48 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont 0, // left ])); - let sender_name_label = Text::new(format!("{}: ", localized_string("tx-sender-name"))) + /// TX State (i.e. Stage) + let state_label = Text::new(format!("{}: ", localized_string("tx-state"))) + .size(DEFAULT_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Left); + + let state_label_container = + Container::new(state_label).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let state = Text::new(state_text).size(DEFAULT_FONT_SIZE); + //.width(Length::Units(400)) + //.style(grin_gui_core::theme::TextInputStyle::AddonsQuery); + + let state_container = + Container::new(state).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let state_row = Row::new().push(state_label_container).push(state_container); + + /// Sender address + let sender_address_label = Text::new(format!("{}: ", localized_string("tx-sender-name"))) .size(DEFAULT_FONT_SIZE) .horizontal_alignment(alignment::Horizontal::Left); - let sender_name_label_container = Container::new(sender_name_label) + let sender_address_label_container = Container::new(sender_address_label) .style(grin_gui_core::theme::ContainerStyle::NormalBackground); - let sender_name = Text::new(sp_sending_address).size(DEFAULT_FONT_SIZE); + let sender_address = Text::new(sp_sending_address).size(DEFAULT_FONT_SIZE); //.width(Length::Units(400)) //.style(grin_gui_core::theme::TextInputStyle::AddonsQuery); - let sender_name_container = - Container::new(sender_name).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + let sender_address_container = Container::new(sender_address) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); - let sender_name_row = Row::new() - .push(sender_name_label_container) - .push(sender_name_container); + let sender_address_row = Row::new() + .push(sender_address_label_container) + .push(sender_address_container); let amount_label = Text::new(format!("{}: ", localized_string("apply-tx-amount"))) .size(DEFAULT_FONT_SIZE) .horizontal_alignment(alignment::Horizontal::Left); - let amount_label_container = Container::new(amount_label) - .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + let amount_label_container = + Container::new(amount_label).style(grin_gui_core::theme::ContainerStyle::NormalBackground); let amount = Text::new(amount).size(DEFAULT_FONT_SIZE); //.width(Length::Units(400)) @@ -172,55 +200,6 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont .push(amount_label_container) .push(amount_container); - - /*let address_row = Row::new() - .push(address_input) - .push(copy_address_button) - .spacing(DEFAULT_PADDING); - - let address_row: Element = address_row.into(); - - let address_instruction_container = Text::new(localized_string("address-instruction")) - .size(SMALLER_FONT_SIZE) - .horizontal_alignment(alignment::Horizontal::Left); - - let address_instruction_container = Container::new(address_instruction_container) - .style(grin_gui_core::theme::ContainerStyle::NormalBackground); - - let slatepack_paste_name = Text::new(localized_string("tx-slatepack-paste-transaction-here")) - .size(DEFAULT_FONT_SIZE) - .horizontal_alignment(alignment::Horizontal::Left); - - let slatepack_paste_name_container = Container::new(slatepack_paste_name) - .style(grin_gui_core::theme::ContainerStyle::NormalBackground); - - let slatepack_text_area = Text::new(state.slatepack_read_result.clone()) - .size(DEFAULT_FONT_SIZE) - .width(Length::Units(400));*/ - - /*let paste_slatepack_button = Button::new( - // &mut state.copy_address_button_state, - Text::new(localized_string("tx-slatepack-paste-from-clipboard")) - .size(SMALLER_FONT_SIZE) - .horizontal_alignment(alignment::Horizontal::Center), - ) - .style(grin_gui_core::theme::ButtonStyle::NormalText) - .on_press(Interaction::ReadSlatepackFromClipboard); - - let paste_slatepack_button: Element = paste_slatepack_button.into();*/ - - /*let paste_slatepack_row = Row::new() - .push(slatepack_text_area) - //.push(paste_slatepack_button.map(Message::Interaction)) - .spacing(DEFAULT_PADDING); - - let slatepack_area = Column::new() - .push(slatepack_paste_name_container) - .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) - .push(paste_slatepack_row); - - let slatepack_area_container = Container::new(slatepack_area);*/ - let button_height = Length::Units(BUTTON_HEIGHT); let button_width = Length::Units(BUTTON_WIDTH); @@ -232,12 +211,14 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont .center_y() .align_x(alignment::Horizontal::Center); - let mut submit_button = Button::new(submit_button_label_container) - .style(grin_gui_core::theme::ButtonStyle::Primary) - .on_press(Interaction::ReadSlatepackFromClipboard); - /*let submit_button = submit_button.on_press(Interaction::WalletOperationApplyTxViewInteraction( - LocalViewInteraction::ApplyTransaction("_".into()), - ));*/ + let mut submit_button = Button::new(submit_button_label_container); + + if hide_continue { + submit_button = submit_button.style(grin_gui_core::theme::ButtonStyle::NormalText); + } else { + submit_button = submit_button.style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::WalletOperationApplyTxConfirmViewInteraction(LocalViewInteraction::Accept)); + } let submit_button: Element = submit_button.into(); @@ -272,7 +253,9 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont .push(cancel_container); let column = Column::new() - .push(sender_name_row) + .push(state_row) + .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) + .push(sender_address_row) .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) .push(amount_row) .push(Space::new(Length::Units(0), Length::Units(unit_spacing))) diff --git a/src/gui/element/wallet/operation/apply_tx_success.rs b/src/gui/element/wallet/operation/apply_tx_success.rs new file mode 100644 index 0000000..f4e5e98 --- /dev/null +++ b/src/gui/element/wallet/operation/apply_tx_success.rs @@ -0,0 +1,187 @@ +use { + super::super::super::{ + BUTTON_HEIGHT, BUTTON_WIDTH, DEFAULT_FONT_SIZE, DEFAULT_HEADER_FONT_SIZE, DEFAULT_PADDING, + SMALLER_FONT_SIZE, + }, + crate::gui::{GrinGui, Interaction, Message}, + crate::localization::localized_string, + crate::Result, + grin_gui_core::config::Config, + grin_gui_core::theme::ColorPalette, + grin_gui_core::theme::{ + Column, Container, Element, PickList, Row, Scrollable, Text, TextInput, + }, + iced::widget::{button, pick_list, scrollable, text_input, Button, Checkbox, Space}, + iced::{alignment, Alignment, Command, Length}, + iced_aw::Card, +}; + +pub struct StateContainer { + // Encrypted slate to send to recipient + pub encrypted_slate: String, +} + +impl Default for StateContainer { + fn default() -> Self { + Self { + encrypted_slate: Default::default(), + } + } +} + +#[derive(Debug, Clone)] +pub enum LocalViewInteraction { + Submit, +} + +pub fn handle_message( + grin_gui: &mut GrinGui, + message: LocalViewInteraction, +) -> Result> { + let state = &mut grin_gui.wallet_state.setup_state.setup_wallet_state; + match message { + LocalViewInteraction::Submit => { + grin_gui.wallet_state.operation_state.mode = + crate::gui::element::wallet::operation::Mode::Home; + } + } + Ok(Command::none()) +} + +pub fn data_container<'a>( + _config: &'a Config, + state: &'a StateContainer, +) -> Container<'a, Message> { + // Title row + let title = Text::new(localized_string("tx-create-success")) + .size(DEFAULT_HEADER_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Center); + + let title_container = Container::new(title) + .style(grin_gui_core::theme::ContainerStyle::BrightBackground) + .padding(iced::Padding::from([ + 2, // top + 0, // right + 2, // bottom + 5, // left + ])); + + // push more items on to header here: e.g. other buttons, things that belong on the header + let header_row = Row::new().push(title_container); + + let header_container = Container::new(header_row).padding(iced::Padding::from([ + 0, // top + 0, // right + DEFAULT_PADDING, // bottom + 0, // left + ])); + + let description = Text::new(localized_string("tx-create-success-desc")) + .size(DEFAULT_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Center); + let description_container = + Container::new(description).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let encrypted_slate_card = Card::new( + Text::new(localized_string("tx-create-success-title")) + .size(DEFAULT_HEADER_FONT_SIZE), + Text::new(&state.encrypted_slate).size(DEFAULT_FONT_SIZE), + ) + .foot( + Column::new() + .spacing(10) + .padding(5) + .width(Length::Fill) + .align_items(Alignment::Center) + .push( + Button::new( + Text::new(localized_string("copy-to-clipboard")) + .size(SMALLER_FONT_SIZE) + .horizontal_alignment(alignment::Horizontal::Center), + ) + .style(grin_gui_core::theme::ButtonStyle::NormalText) + .on_press(Message::Interaction(Interaction::WriteToClipboard( + state.encrypted_slate.clone(), + ))), + ), + ) + .max_width(400) + .style(grin_gui_core::theme::CardStyle::Normal); + + let unit_spacing = 15; + + let button_height = Length::Units(BUTTON_HEIGHT); + let button_width = Length::Units(BUTTON_WIDTH); + + let cancel_button_label_container = + Container::new(Text::new(localized_string("ok-caps")).size(DEFAULT_FONT_SIZE)) + .width(button_width) + .height(button_height) + .center_x() + .center_y() + .align_x(alignment::Horizontal::Center); + + let cancel_button: Element = Button::new(cancel_button_label_container) + .style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::WalletOperationCreateTxSuccessViewInteraction( + LocalViewInteraction::Submit, + )) + .into(); + + let cancel_container = Container::new(cancel_button.map(Message::Interaction)).padding(1); + let cancel_container = Container::new(cancel_container) + .style(grin_gui_core::theme::ContainerStyle::Segmented) + .padding(1); + + let unit_spacing = 15; + let button_row = Row::new().push(cancel_container); + + let column = Column::new() + .push(description_container) + .push(Space::new( + Length::Units(0), + Length::Units(unit_spacing + 5), + )) + .push(encrypted_slate_card) + .push(Space::new( + Length::Units(0), + Length::Units(unit_spacing + 10), + )) + .push(button_row) + .push(Space::new( + Length::Units(0), + Length::Units(unit_spacing + 10), + )); + + let form_container = Container::new(column) + .width(Length::Fill) + .padding(iced::Padding::from([ + 0, // top + 0, // right + 0, // bottom + 5, // left + ])); + + // form container should be scrollable in tiny windows + let scrollable = Scrollable::new(form_container) + .height(Length::Fill) + .style(grin_gui_core::theme::ScrollableStyle::Primary); + + let content = Container::new(scrollable) + .width(Length::Fill) + .height(Length::Shrink) + .style(grin_gui_core::theme::ContainerStyle::NormalBackground); + + let wrapper_column = Column::new() + .height(Length::Fill) + .push(header_container) + .push(content); + + // Returns the final container. + Container::new(wrapper_column).padding(iced::Padding::from([ + DEFAULT_PADDING, // top + DEFAULT_PADDING, // right + DEFAULT_PADDING, // bottom + DEFAULT_PADDING, // left + ])) +} From a2b8b7ab21425cc6248bf991b28675f9f29c650b Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Wed, 11 Jan 2023 14:31:15 +0000 Subject: [PATCH 6/7] everything up to confirming transaction, figure out why foreign api isn't instantiated --- crates/core/src/error.rs | 2 + crates/core/src/wallet/mod.rs | 50 +++++++++++- locale/de.json | 1 - src/gui/element/wallet/operation/apply_tx.rs | 2 +- .../wallet/operation/apply_tx_confirm.rs | 76 ++++++++++++++++++- .../wallet/operation/apply_tx_success.rs | 5 +- src/gui/element/wallet/operation/mod.rs | 47 +++++------- src/gui/mod.rs | 1 + src/gui/update.rs | 4 + 9 files changed, 152 insertions(+), 36 deletions(-) diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index c244184..a07090a 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -10,6 +10,8 @@ pub enum GrinWalletInterfaceError { WalletLibWallet(#[from] grin_wallet_libwallet::Error), #[error("Owner API not Instantiated")] OwnerAPINotInstantiated, + #[error("Foreign API not Instantiated")] + ForeignAPINotInstantiated, } #[derive(thiserror::Error, Debug)] diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 8448b19..387ca93 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -1,7 +1,7 @@ /// Placeholder for all wallet calls /// Should eventually feature async calls that work via local wallet or remote owner API use grin_wallet::cmd::wallet_args::inst_wallet; -use grin_wallet_api::Owner; +use grin_wallet_api::{Owner, Foreign}; use grin_wallet_config::{self, GlobalWalletConfig}; use grin_wallet_controller::command::InitArgs; use grin_wallet_impls::DefaultLCProvider; @@ -92,6 +92,8 @@ where pub config: Option, // owner api will hold instantiated/opened wallets pub owner_api: Option>, + // Also need reference to foreign API + pub foreign_api: Option>, // Simple flag to check whether wallet has been opened wallet_is_open: bool, // Hold on to check node foreign API secret for now @@ -112,6 +114,7 @@ where chain_type: None, config: None, owner_api: None, + foreign_api: None, wallet_is_open: false, check_node_foreign_api_secret_path: None, node_client, @@ -225,6 +228,24 @@ where Ok(()) } + fn inst_foreign_api( + wallet_interface: Arc>>, + chain_type: global::ChainTypes, + top_level_directory: PathBuf, + ) -> Result<(), GrinWalletInterfaceError> { + let wallet_inst = WalletInterface::inst_wallet( + wallet_interface.clone(), + chain_type, + top_level_directory, + )?; + let mut w = wallet_interface.write().unwrap(); + w.foreign_api = Some(Foreign::new(wallet_inst.clone(), None, None, false)); + global::set_local_chain_type(chain_type); + + Ok(()) + } + + pub async fn init( wallet_interface: Arc>>, password: String, @@ -239,6 +260,12 @@ where top_level_directory.clone(), )?; + WalletInterface::inst_foreign_api( + wallet_interface.clone(), + chain_type, + top_level_directory.clone(), + )?; + let w = wallet_interface.read().unwrap(); let recover_length = recovery_phrase.clone().map(|f| f.len()).unwrap_or(32); @@ -370,7 +397,7 @@ where } /// Attempt to decode and decrypt a given slatepack - pub fn decrypt_slatepace( + pub fn decrypt_slatepack( wallet_interface: Arc>>, slatepack: String, ) -> Result<(Slatepack, Slate), GrinWalletInterfaceError> { @@ -448,6 +475,25 @@ where } } + pub async fn receive_tx_from_s1( + wallet_interface: Arc>>, + slate: Slate, + dest_slatepack_address: String, + ) -> Result { + let w = wallet_interface.write().unwrap(); + let ret_slate; + if let Some(f) = &w.foreign_api { + ret_slate = f.receive_tx(&slate, None, None)?; + } else { + return Err(GrinWalletInterfaceError::ForeignAPINotInstantiated); + } + if let Some(o) = &w.owner_api { + return WalletInterface::encrypt_slatepack(o, &dest_slatepack_address, &ret_slate); + } else { + return Err(GrinWalletInterfaceError::OwnerAPINotInstantiated); + } + } + pub async fn cancel_tx( wallet_interface: Arc>>, id: u32, diff --git a/locale/de.json b/locale/de.json index 91b140b..41c6ab2 100644 --- a/locale/de.json +++ b/locale/de.json @@ -244,5 +244,4 @@ "tx-sender-name": "Sender", "apply-tx-amount": "Incoming amount", "tx-state": "Transaction Stage (this will be presented better)" - } \ No newline at end of file diff --git a/src/gui/element/wallet/operation/apply_tx.rs b/src/gui/element/wallet/operation/apply_tx.rs index 153aeca..d3d4bdf 100644 --- a/src/gui/element/wallet/operation/apply_tx.rs +++ b/src/gui/element/wallet/operation/apply_tx.rs @@ -80,7 +80,7 @@ pub fn handle_message<'a>( LocalViewInteraction::ReadFromClipboardSuccess(value) => { debug!("Read from clipboard: {}", value); let w = grin_gui.wallet_interface.clone(); - let decode_res = WalletInterface::decrypt_slatepace(w, value); + let decode_res = WalletInterface::decrypt_slatepack(w, value); match decode_res { Err(e) => { state.slatepack_read_result = localized_string("tx-slatepack-read-failure") diff --git a/src/gui/element/wallet/operation/apply_tx_confirm.rs b/src/gui/element/wallet/operation/apply_tx_confirm.rs index 963f4c0..5977634 100644 --- a/src/gui/element/wallet/operation/apply_tx_confirm.rs +++ b/src/gui/element/wallet/operation/apply_tx_confirm.rs @@ -64,6 +64,8 @@ pub enum Action {} pub enum LocalViewInteraction { Back, Accept, + TxAcceptSuccess(String), + TxAcceptFailure(Arc>>), } pub fn handle_message<'a>( @@ -78,9 +80,74 @@ pub fn handle_message<'a>( crate::gui::element::wallet::operation::Mode::Home; } LocalViewInteraction::Accept => { + grin_gui.error.take(); + log::debug!("Interaction::WalletOperationApplyTxConfirmViewInteraction(Accept)"); + if state.slatepack_parsed.is_none() { + log::debug!("you should never see this - dev make sure slatepack is not None"); + return Ok(Command::none()); + } + + let (slatepack, slate) = state.slatepack_parsed.as_ref().unwrap(); + + let sp_sending_address = match &slatepack.sender { + None => "None".to_string(), + Some(s) => s.to_string(), + }; + + let w = grin_gui.wallet_interface.clone(); + let out_slate = slate.clone(); + + // TODO: More states to consider here + let fut = match slate.state { + SlateState::Standard1 => Some(move || WalletInterface::receive_tx_from_s1( + w, + out_slate, + sp_sending_address, + )), + _ => None, + }; + + match fut { + Some(ff) => { + return Ok(Command::perform(ff(), |r| { + match r.context("Failed to Progress Transaction") { + Ok(ret) => Message::Interaction( + Interaction::WalletOperationApplyTxConfirmViewInteraction( + LocalViewInteraction::TxAcceptSuccess(ret), + ), + ), + Err(e) => Message::Interaction( + Interaction::WalletOperationApplyTxConfirmViewInteraction( + LocalViewInteraction::TxAcceptFailure(Arc::new(RwLock::new( + Some(e), + ))), + ), + ), + } + })) + } + None => { + log::error!("Slate state not yet supported"); + return Ok(Command::none()); + } + } + } + LocalViewInteraction::TxAcceptSuccess(slate) => { + log::debug!("{:?}", slate); + grin_gui + .wallet_state + .operation_state + .apply_tx_success_state + .encrypted_slate = slate.to_string(); grin_gui.wallet_state.operation_state.mode = - crate::gui::element::wallet::operation::Mode::Home; + crate::gui::element::wallet::operation::Mode::ApplyTxSuccess; + } + LocalViewInteraction::TxAcceptFailure(err) => { + grin_gui.error = err.write().unwrap().take(); + if let Some(e) = grin_gui.error.as_ref() { + log_error(e); + } } } Ok(Command::none()) @@ -216,8 +283,11 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont if hide_continue { submit_button = submit_button.style(grin_gui_core::theme::ButtonStyle::NormalText); } else { - submit_button = submit_button.style(grin_gui_core::theme::ButtonStyle::Primary) - .on_press(Interaction::WalletOperationApplyTxConfirmViewInteraction(LocalViewInteraction::Accept)); + submit_button = submit_button + .style(grin_gui_core::theme::ButtonStyle::Primary) + .on_press(Interaction::WalletOperationApplyTxConfirmViewInteraction( + LocalViewInteraction::Accept, + )); } let submit_button: Element = submit_button.into(); diff --git a/src/gui/element/wallet/operation/apply_tx_success.rs b/src/gui/element/wallet/operation/apply_tx_success.rs index f4e5e98..a4f4453 100644 --- a/src/gui/element/wallet/operation/apply_tx_success.rs +++ b/src/gui/element/wallet/operation/apply_tx_success.rs @@ -83,8 +83,7 @@ pub fn data_container<'a>( Container::new(description).style(grin_gui_core::theme::ContainerStyle::NormalBackground); let encrypted_slate_card = Card::new( - Text::new(localized_string("tx-create-success-title")) - .size(DEFAULT_HEADER_FONT_SIZE), + Text::new(localized_string("tx-create-success-title")).size(DEFAULT_HEADER_FONT_SIZE), Text::new(&state.encrypted_slate).size(DEFAULT_FONT_SIZE), ) .foot( @@ -123,7 +122,7 @@ pub fn data_container<'a>( let cancel_button: Element = Button::new(cancel_button_label_container) .style(grin_gui_core::theme::ButtonStyle::Primary) - .on_press(Interaction::WalletOperationCreateTxSuccessViewInteraction( + .on_press(Interaction::WalletOperationApplyTxSuccessViewInteraction( LocalViewInteraction::Submit, )) .into(); diff --git a/src/gui/element/wallet/operation/mod.rs b/src/gui/element/wallet/operation/mod.rs index 49b173c..e034395 100644 --- a/src/gui/element/wallet/operation/mod.rs +++ b/src/gui/element/wallet/operation/mod.rs @@ -1,23 +1,24 @@ -pub mod open; pub mod action_menu; -pub mod home; -pub mod tx_list; -pub mod create_tx; -pub mod create_tx_success; pub mod apply_tx; pub mod apply_tx_confirm; +pub mod apply_tx_success; pub mod chart; +pub mod create_tx; +pub mod create_tx_success; +pub mod home; +pub mod open; +pub mod tx_list; pub mod tx_list_display; use { crate::gui::{GrinGui, Message}, crate::Result, - grin_gui_core::theme::ColorPalette, grin_gui_core::config::Config, - iced::{Command, Length}, + grin_gui_core::theme::ColorPalette, grin_gui_core::theme::{ Button, Column, Container, Element, PickList, Row, Scrollable, Text, TextInput, }, + iced::{Command, Length}, }; pub struct StateContainer { @@ -28,6 +29,7 @@ pub struct StateContainer { pub create_tx_success_state: create_tx_success::StateContainer, pub apply_tx_state: apply_tx::StateContainer, pub apply_tx_confirm_state: apply_tx_confirm::StateContainer, + pub apply_tx_success_state: apply_tx_success::StateContainer, // When changed to true, this should stay false until a wallet is opened with a password has_wallet_open_check_failed_one_time: bool, } @@ -39,7 +41,8 @@ pub enum Mode { CreateTx, CreateTxSuccess, ApplyTx, - ApplyTxConfirm + ApplyTxConfirm, + ApplyTxSuccess } impl Default for StateContainer { @@ -52,6 +55,7 @@ impl Default for StateContainer { create_tx_success_state: Default::default(), apply_tx_state: Default::default(), apply_tx_confirm_state: Default::default(), + apply_tx_success_state: Default::default(), has_wallet_open_check_failed_one_time: false, } } @@ -72,7 +76,6 @@ impl StateContainer { } } - #[derive(Debug, Clone)] pub enum LocalViewInteraction {} @@ -80,35 +83,27 @@ pub fn handle_message( grin_gui: &mut GrinGui, message: LocalViewInteraction, ) -> Result> { - Ok(Command::none()) } -pub fn data_container<'a>( - state: &'a StateContainer, - config:&'a Config -) -> Container<'a, Message> { +pub fn data_container<'a>(state: &'a StateContainer, config: &'a Config) -> Container<'a, Message> { let content = match state.mode { Mode::Open => open::data_container(&state.open_state, config), - Mode::Home => { - home::data_container(config, &state.home_state) - } - Mode::CreateTx => { - create_tx::data_container(config, &state.create_tx_state) - } + Mode::Home => home::data_container(config, &state.home_state), + Mode::CreateTx => create_tx::data_container(config, &state.create_tx_state), Mode::CreateTxSuccess => { create_tx_success::data_container(config, &state.create_tx_success_state) } - Mode::ApplyTx => { - apply_tx::data_container(config, &state.apply_tx_state) - } - Mode::ApplyTxConfirm => { + Mode::ApplyTx => apply_tx::data_container(config, &state.apply_tx_state), + Mode::ApplyTxConfirm => { apply_tx_confirm::data_container(config, &state.apply_tx_confirm_state) } + Mode::ApplyTxSuccess => { + apply_tx_success::data_container(config, &state.apply_tx_success_state) + } }; - let column = Column::new() - .push(content); + let column = Column::new().push(content); Container::new(column) .center_y() diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 9a6ad58..cc776b6 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -434,6 +434,7 @@ pub enum Interaction { WalletOperationCreateTxSuccessViewInteraction(element::wallet::operation::create_tx_success::LocalViewInteraction), WalletOperationApplyTxViewInteraction(element::wallet::operation::apply_tx::LocalViewInteraction), WalletOperationApplyTxConfirmViewInteraction(element::wallet::operation::apply_tx_confirm::LocalViewInteraction), + WalletOperationApplyTxSuccessViewInteraction(element::wallet::operation::apply_tx_success::LocalViewInteraction), ViewInteraction(String, String), ModeSelected(Mode), ModeSelectedSettings(element::settings::Mode), diff --git a/src/gui/update.rs b/src/gui/update.rs index ab49b0c..3be024b 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -196,6 +196,10 @@ pub fn handle_message(grin_gui: &mut GrinGui, message: Message) -> Result Operation -> Home -> Action Message::Interaction(Interaction::WalletOperationApplyTxConfirmViewInteraction(l)) => { return element::wallet::operation::apply_tx_confirm::handle_message(grin_gui, l); + } + // Wallet -> Operation -> Home -> Action + Message::Interaction(Interaction::WalletOperationApplyTxSuccessViewInteraction(l)) => { + return element::wallet::operation::apply_tx_success::handle_message(grin_gui, l); } // Wallet -> Operation -> Home -> Action Message::Interaction(Interaction::WalletOperationHomeActionMenuViewInteraction(l)) => { From 826100f9880640b81d880570ac72cb4bc69af078 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Thu, 12 Jan 2023 13:25:47 +0000 Subject: [PATCH 7/7] add S2->S3 Post and confirmation functions --- crates/core/src/wallet/mod.rs | 49 ++++++++----------- .../wallet/operation/apply_tx_confirm.rs | 47 +++++++++++------- .../wallet/operation/apply_tx_success.rs | 11 +++-- .../wallet/operation/tx_list_display.rs | 4 +- 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 387ca93..44827cf 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -211,7 +211,7 @@ where Ok(wallet_inst) } - fn inst_owner_api( + fn inst_apis( wallet_interface: Arc>>, chain_type: global::ChainTypes, top_level_directory: PathBuf, @@ -223,29 +223,12 @@ where )?; let mut w = wallet_interface.write().unwrap(); w.owner_api = Some(Owner::new(wallet_inst.clone(), None)); - global::set_local_chain_type(chain_type); - - Ok(()) - } - - fn inst_foreign_api( - wallet_interface: Arc>>, - chain_type: global::ChainTypes, - top_level_directory: PathBuf, - ) -> Result<(), GrinWalletInterfaceError> { - let wallet_inst = WalletInterface::inst_wallet( - wallet_interface.clone(), - chain_type, - top_level_directory, - )?; - let mut w = wallet_interface.write().unwrap(); w.foreign_api = Some(Foreign::new(wallet_inst.clone(), None, None, false)); global::set_local_chain_type(chain_type); Ok(()) } - pub async fn init( wallet_interface: Arc>>, password: String, @@ -254,13 +237,7 @@ where chain_type: global::ChainTypes, recovery_phrase: Option, ) -> Result<(String, String, String, global::ChainTypes), GrinWalletInterfaceError> { - WalletInterface::inst_owner_api( - wallet_interface.clone(), - chain_type, - top_level_directory.clone(), - )?; - - WalletInterface::inst_foreign_api( + WalletInterface::inst_apis( wallet_interface.clone(), chain_type, top_level_directory.clone(), @@ -332,7 +309,7 @@ where top_level_directory: PathBuf, chain_type: global::ChainTypes, ) -> Result<(), GrinWalletInterfaceError> { - WalletInterface::inst_owner_api( + WalletInterface::inst_apis( wallet_interface.clone(), chain_type, top_level_directory.clone(), @@ -479,7 +456,7 @@ where wallet_interface: Arc>>, slate: Slate, dest_slatepack_address: String, - ) -> Result { + ) -> Result, GrinWalletInterfaceError> { let w = wallet_interface.write().unwrap(); let ret_slate; if let Some(f) = &w.foreign_api { @@ -488,12 +465,28 @@ where return Err(GrinWalletInterfaceError::ForeignAPINotInstantiated); } if let Some(o) = &w.owner_api { - return WalletInterface::encrypt_slatepack(o, &dest_slatepack_address, &ret_slate); + let encrypted = WalletInterface::encrypt_slatepack(o, &dest_slatepack_address, &ret_slate)?; + return Ok(Some(encrypted)) } else { return Err(GrinWalletInterfaceError::OwnerAPINotInstantiated); } } + pub async fn finalize_from_s2( + wallet_interface: Arc>>, + slate: Slate, + send_to_chain: bool, + ) -> Result, GrinWalletInterfaceError> { + let w = wallet_interface.write().unwrap(); + if let Some(o) = &w.owner_api { + let ret_slate = o.finalize_tx(None, &slate)?; + o.post_tx(None, &ret_slate, true)?; + return Ok(None) + } else { + return Err(GrinWalletInterfaceError::ForeignAPINotInstantiated); + } + } + pub async fn cancel_tx( wallet_interface: Arc>>, id: u32, diff --git a/src/gui/element/wallet/operation/apply_tx_confirm.rs b/src/gui/element/wallet/operation/apply_tx_confirm.rs index 5977634..dfccf5d 100644 --- a/src/gui/element/wallet/operation/apply_tx_confirm.rs +++ b/src/gui/element/wallet/operation/apply_tx_confirm.rs @@ -64,7 +64,7 @@ pub enum Action {} pub enum LocalViewInteraction { Back, Accept, - TxAcceptSuccess(String), + TxAcceptSuccess(Option), TxAcceptFailure(Arc>>), } @@ -97,20 +97,33 @@ pub fn handle_message<'a>( let w = grin_gui.wallet_interface.clone(); let out_slate = slate.clone(); + match slate.state { + SlateState::Standard1 => { + let fut = move || { + WalletInterface::receive_tx_from_s1(w, out_slate, sp_sending_address) + }; - // TODO: More states to consider here - let fut = match slate.state { - SlateState::Standard1 => Some(move || WalletInterface::receive_tx_from_s1( - w, - out_slate, - sp_sending_address, - )), - _ => None, - }; + return Ok(Command::perform(fut(), |r| { + match r.context("Failed to Progress Transaction") { + Ok(ret) => Message::Interaction( + Interaction::WalletOperationApplyTxConfirmViewInteraction( + LocalViewInteraction::TxAcceptSuccess(ret), + ), + ), + Err(e) => Message::Interaction( + Interaction::WalletOperationApplyTxConfirmViewInteraction( + LocalViewInteraction::TxAcceptFailure(Arc::new(RwLock::new( + Some(e), + ))), + ), + ), + } + })); + } + SlateState::Standard2 => { + let fut = move || WalletInterface::finalize_from_s2(w, out_slate, true); - match fut { - Some(ff) => { - return Ok(Command::perform(ff(), |r| { + return Ok(Command::perform(fut(), |r| { match r.context("Failed to Progress Transaction") { Ok(ret) => Message::Interaction( Interaction::WalletOperationApplyTxConfirmViewInteraction( @@ -125,9 +138,9 @@ pub fn handle_message<'a>( ), ), } - })) + })); } - None => { + _ => { log::error!("Slate state not yet supported"); return Ok(Command::none()); } @@ -139,7 +152,7 @@ pub fn handle_message<'a>( .wallet_state .operation_state .apply_tx_success_state - .encrypted_slate = slate.to_string(); + .encrypted_slate = slate; grin_gui.wallet_state.operation_state.mode = crate::gui::element::wallet::operation::Mode::ApplyTxSuccess; } @@ -178,7 +191,7 @@ pub fn data_container<'a>(config: &'a Config, state: &'a StateContainer) -> Cont let state_text_append = match slate.state { SlateState::Standard1 => "You are the recipient - Standard workflow", SlateState::Standard2 => { - "You are the payee, and are finalizing the transaction - Standard workflow" + "You are the payee, and are finalizing the transaction and sending it to the chain for validation - Standard workflow" } SlateState::Standard3 => "This transaction is finalised - Standard workflow", _ => "Support still in development", diff --git a/src/gui/element/wallet/operation/apply_tx_success.rs b/src/gui/element/wallet/operation/apply_tx_success.rs index a4f4453..40a41ed 100644 --- a/src/gui/element/wallet/operation/apply_tx_success.rs +++ b/src/gui/element/wallet/operation/apply_tx_success.rs @@ -18,7 +18,7 @@ use { pub struct StateContainer { // Encrypted slate to send to recipient - pub encrypted_slate: String, + pub encrypted_slate: Option, } impl Default for StateContainer { @@ -82,9 +82,14 @@ pub fn data_container<'a>( let description_container = Container::new(description).style(grin_gui_core::theme::ContainerStyle::NormalBackground); + let slate_card_content = match state.encrypted_slate.as_ref() { + Some(s) => s.clone(), + None => "Transaction was posted to chain".to_owned(), + }; + let encrypted_slate_card = Card::new( Text::new(localized_string("tx-create-success-title")).size(DEFAULT_HEADER_FONT_SIZE), - Text::new(&state.encrypted_slate).size(DEFAULT_FONT_SIZE), + Text::new(slate_card_content).size(DEFAULT_FONT_SIZE), ) .foot( Column::new() @@ -100,7 +105,7 @@ pub fn data_container<'a>( ) .style(grin_gui_core::theme::ButtonStyle::NormalText) .on_press(Message::Interaction(Interaction::WriteToClipboard( - state.encrypted_slate.clone(), + state.encrypted_slate.clone().unwrap_or("None".to_owned()), ))), ), ) diff --git a/src/gui/element/wallet/operation/tx_list_display.rs b/src/gui/element/wallet/operation/tx_list_display.rs index ce665f1..6a29a6f 100644 --- a/src/gui/element/wallet/operation/tx_list_display.rs +++ b/src/gui/element/wallet/operation/tx_list_display.rs @@ -179,7 +179,7 @@ pub fn handle_message<'a>( let credits = tx.amount_credited; let debits = tx.amount_debited; - datetime_sums.push((datetime, credits - debits)); + datetime_sums.push((datetime, credits as i64 - debits as i64)); } let mut sum = 0; @@ -195,7 +195,7 @@ pub fn handle_message<'a>( let txns = datetime_sums.iter().filter(|(date, _)| *date == dt); // sum up balance amount - sum = sum + txns.map(|x| x.1).collect::>().iter().sum::(); + sum = sum + txns.map(|x| x.1).collect::>().iter().sum::(); // convert to grin units let grin_sum = (sum as f64 / grin_gui_core::GRIN_BASE as f64) as f64;