wallet + ui: sending and receiving rework, ability to use dandelion on broadcast, remove node restart modal, fix txs statuses
This commit is contained in:
parent
fa71dc2ada
commit
7e2e08530b
15 changed files with 469 additions and 392 deletions
|
@ -64,19 +64,27 @@ wallets:
|
|||
tx_cancelling: Cancelling
|
||||
tx_canceled: Canceled
|
||||
tx_confirmed: Confirmed
|
||||
manually: Manually
|
||||
receive_slatepack_desc: 'Enter Slatepack message received from the sender to create response or finalize the transaction:'
|
||||
receive_send_slatepack: 'Send Slatepack message to the sender to finalize the transaction:'
|
||||
receive_slatepack_err: 'An error occurred during creation of the response, check input data:'
|
||||
create_response: Create response
|
||||
invoice: Invoice
|
||||
issue_invoice: Issue invoice
|
||||
issue_invoice_desc: 'Create a request to receive funds by entering the required amount:'
|
||||
invoice_desc: 'You have created a request to receive %{amount} ツ. Send Slatepack message to the sender:'
|
||||
txs: Transactions
|
||||
messages: Messages
|
||||
transport: Transport
|
||||
input_slatepack_desc: 'Enter received message to create a response or finalize the transaction:'
|
||||
send_slatepack_desc: 'Send message to the receiver to finalize the transaction:'
|
||||
parse_slatepack_err: 'An error occurred during handling of the message, check input data:'
|
||||
parse_i1_slatepack_desc: 'To pay %{amount} ツ send message to the receiver:'
|
||||
parse_i2_slatepack_desc: 'Finalize transaction to receive %{amount} ツ'
|
||||
parse_s1_slatepack_desc: 'To receive %{amount} ツ send message to the sender:'
|
||||
parse_s2_slatepack_desc: 'Finalize transaction to send %{amount} ツ'
|
||||
response_slatepack_err: 'An error occurred during creation of the response, check input data:'
|
||||
create_request_desc: 'Create a request to send or receive the funds:'
|
||||
send_request_desc: 'You have created a request to send %{amount} ツ. Send message to the receiver of the funds:'
|
||||
send_slatepack_err: An error occurred during creation of request to send funds, check input data.
|
||||
invoice_desc: 'You have created a request to receive %{amount} ツ. Send message to the sender of the funds:'
|
||||
invoice_slatepack_err: An error occurred during issuing of the invoice, check input data.
|
||||
finalize_slatepack_err: 'An error occurred during finalization of the transaction, check input data:'
|
||||
finalize_slatepack_err: 'An error occurred during finalization, check input data:'
|
||||
finalize: Finalize
|
||||
enter_amount: 'Enter amount:'
|
||||
use_dandelion: Use Dandelion
|
||||
enter_amount_send: 'You have %{amount} ツ. Enter amount to send:'
|
||||
enter_amount_receive: 'Enter amount to receive:'
|
||||
recovery: Recovery
|
||||
repair_wallet: Repair wallet
|
||||
repair_desc: Check a wallet, repairing and restoring missing outputs if required. This operation will take time.
|
||||
|
|
|
@ -64,19 +64,27 @@ wallets:
|
|||
tx_cancelling: Отмена
|
||||
tx_canceled: Отменено
|
||||
tx_confirmed: Подтверждено
|
||||
manually: Вручную
|
||||
receive_slatepack_desc: 'Введите Slatepack сообщение, полученное от отправителя, для создания ответа или завершения транзакции:'
|
||||
receive_send_slatepack: 'Отправьте Slatepack сообщение отправителю для завершения транзакции:'
|
||||
receive_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:'
|
||||
create_response: Создать ответ
|
||||
invoice: Инвойс
|
||||
issue_invoice: Выставить счёт
|
||||
issue_invoice_desc: 'Создайте запрос на получение средств, введя требуемое количество:'
|
||||
invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте Slatepack сообщение отправителю:'
|
||||
txs: Транзакции
|
||||
messages: Сообщения
|
||||
transport: Транспорт
|
||||
input_slatepack_desc: 'Введите полученное сообщение для создания ответа или завершения транзакции:'
|
||||
send_slatepack_desc: 'Отправьте сообщение получателю средств для завершения транзакции:'
|
||||
parse_slatepack_err: 'Во время обработки сообщения произошла ошибка, проверьте входные данные:'
|
||||
parse_i1_slatepack_desc: 'Для оплаты %{amount} ツ отправьте сообщение получателю:'
|
||||
parse_i2_slatepack_desc: 'Завершите транзакцию для получения %{amount} ツ'
|
||||
parse_s1_slatepack_desc: 'Для получения %{amount} ツ отправьте сообщение отправителю:'
|
||||
parse_s2_slatepack_desc: 'Завершите транзакцию для отправки %{amount} ツ'
|
||||
response_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:'
|
||||
create_request_desc: 'Cоздать запрос на получение или отправку средств:'
|
||||
send_request_desc: 'Вы создали запрос на отправку %{amount} ツ. Отправьте сообщение получателю средств:'
|
||||
send_slatepack_err: Во время создания запроса на отправку средств произошла ошибка, проверьте входные данные.
|
||||
invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте сообщение отправителю средств:'
|
||||
invoice_slatepack_err: Во время выставления счёта произошла ошибка, проверьте входные данные.
|
||||
finalize_slatepack_err: 'Во время завершения транзакции произошла ошибка, проверьте входные данные:'
|
||||
finalize_slatepack_err: 'Во время завершения произошла ошибка, проверьте входные данные:'
|
||||
finalize: Завершить
|
||||
enter_amount: 'Введите количество:'
|
||||
use_dandelion: Использовать Dandelion
|
||||
enter_amount_send: 'У вас есть %{amount} ツ. Введите количество для отправки:'
|
||||
enter_amount_receive: 'Введите количество для получения:'
|
||||
recovery: Восстановление
|
||||
repair_wallet: Починить кошелёк
|
||||
repair_desc: Проверить кошелёк, исправляя и восстанавливая недостающие выходы, если это необходимо. Эта операция займёт время.
|
||||
|
|
|
@ -40,8 +40,6 @@ pub struct NetworkSettings {
|
|||
modal_ids: Vec<&'static str>
|
||||
}
|
||||
|
||||
/// Identifier for node restart confirmation [`Modal`].
|
||||
pub const NODE_RESTART_REQUIRED_MODAL: &'static str = "node_restart_required";
|
||||
/// Identifier for settings reset confirmation [`Modal`].
|
||||
pub const RESET_SETTINGS_MODAL: &'static str = "reset_settings";
|
||||
|
||||
|
@ -54,7 +52,6 @@ impl Default for NetworkSettings {
|
|||
pool: PoolSetup::default(),
|
||||
dandelion: DandelionSetup::default(),
|
||||
modal_ids: vec![
|
||||
NODE_RESTART_REQUIRED_MODAL,
|
||||
RESET_SETTINGS_MODAL
|
||||
]
|
||||
}
|
||||
|
@ -72,7 +69,6 @@ impl ModalContainer for NetworkSettings {
|
|||
modal: &Modal,
|
||||
_: &dyn PlatformCallbacks) {
|
||||
match modal.id {
|
||||
NODE_RESTART_REQUIRED_MODAL => node_restart_required_modal(ui, modal),
|
||||
RESET_SETTINGS_MODAL => reset_settings_confirmation_modal(ui, modal),
|
||||
_ => {}
|
||||
}
|
||||
|
@ -147,17 +143,6 @@ impl NetworkSettings {
|
|||
}
|
||||
}
|
||||
|
||||
/// Show [`Modal`] to ask node restart if setting is changed on enabled node.
|
||||
pub fn show_node_restart_required_modal() {
|
||||
if Node::is_running() {
|
||||
// Show modal to apply changes by node restart.
|
||||
Modal::new(NODE_RESTART_REQUIRED_MODAL)
|
||||
.position(ModalPosition::Center)
|
||||
.title(t!("network.settings"))
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw IP addresses as radio buttons.
|
||||
pub fn ip_addrs_ui(ui: &mut egui::Ui,
|
||||
saved_ip: &String,
|
||||
|
@ -209,38 +194,6 @@ impl NetworkSettings {
|
|||
}
|
||||
}
|
||||
|
||||
/// Node restart reminder modal content.
|
||||
fn node_restart_required_modal(ui: &mut egui::Ui, modal: &Modal) {
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(RichText::new(t!("network_settings.restart_node_required"))
|
||||
.size(17.0)
|
||||
.color(Colors::GRAY));
|
||||
ui.add_space(8.0);
|
||||
});
|
||||
|
||||
// Show modal buttons.
|
||||
ui.scope(|ui| {
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("network_settings.restart"), Colors::WHITE, || {
|
||||
Node::restart();
|
||||
modal.close();
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
|
||||
modal.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw button to reset integrated node settings to default values.
|
||||
fn reset_settings_ui(ui: &mut egui::Ui) {
|
||||
ui.vertical_centered(|ui| {
|
||||
|
|
|
@ -243,7 +243,9 @@ impl NodeSetup {
|
|||
|
||||
if saved_chain_type != selected_chain_type {
|
||||
AppConfig::change_chain_type(&selected_chain_type);
|
||||
NetworkSettings::show_node_restart_required_modal();
|
||||
if Node::is_running() {
|
||||
Node::restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,7 +522,9 @@ impl NodeSetup {
|
|||
let validate = NodeConfig::is_full_chain_validation();
|
||||
View::checkbox(ui, validate, t!("network_settings.full_validation"), || {
|
||||
NodeConfig::toggle_full_chain_validation();
|
||||
NetworkSettings::show_node_restart_required_modal();
|
||||
if Node::is_running() {
|
||||
Node::restart();
|
||||
}
|
||||
});
|
||||
ui.add_space(4.0);
|
||||
ui.label(RichText::new(t!("network_settings.full_validation_description"))
|
||||
|
@ -534,7 +538,9 @@ impl NodeSetup {
|
|||
let archive_mode = NodeConfig::is_archive_mode();
|
||||
View::checkbox(ui, archive_mode, t!("network_settings.archive_mode"), || {
|
||||
NodeConfig::toggle_archive_mode();
|
||||
NetworkSettings::show_node_restart_required_modal();
|
||||
if Node::is_running() {
|
||||
Node::restart();
|
||||
}
|
||||
});
|
||||
ui.add_space(4.0);
|
||||
ui.label(RichText::new(t!("network_settings.archive_mode_desc"))
|
||||
|
|
|
@ -363,13 +363,10 @@ impl View {
|
|||
let mut r = range.clone();
|
||||
|
||||
let mut index = r.primary.index;
|
||||
println!("insert_str {} {}", index, w_input.as_str());
|
||||
|
||||
value.insert_text(w_input.as_str(), index);
|
||||
index = index + 1;
|
||||
|
||||
println!("12345 {} {}", value, r.primary.index);
|
||||
|
||||
if index == 0 {
|
||||
r.primary.index = value.len();
|
||||
r.secondary.index = r.primary.index;
|
||||
|
|
|
@ -160,15 +160,15 @@ impl WalletsContent {
|
|||
});
|
||||
|
||||
// Flag to check if wallet list is hidden on the screen.
|
||||
let list_hidden = content_width == 0.0
|
||||
let list_hidden = content_width == 0.0 || empty_list || create_wallet
|
||||
|| (dual_panel && show_wallet && !self.show_wallets_at_dual_panel)
|
||||
|| (!dual_panel && show_wallet);
|
||||
|
||||
// Setup flag to show wallets bottom panel if wallet is not showing
|
||||
// at non-dual panel mode and network is no open or showing at dual panel mode.
|
||||
let show_bottom_panel =
|
||||
(!show_wallet && !dual_panel && !Root::is_network_panel_open()) ||
|
||||
(dual_panel && show_wallet);
|
||||
let show_bottom_panel = !list_hidden &&
|
||||
((!show_wallet && !dual_panel && !Root::is_network_panel_open()) ||
|
||||
(dual_panel && show_wallet));
|
||||
|
||||
// Show wallets bottom panel.
|
||||
egui::TopBottomPanel::bottom("wallets_bottom_panel")
|
||||
|
@ -183,7 +183,7 @@ impl WalletsContent {
|
|||
},
|
||||
..Default::default()
|
||||
})
|
||||
.show_animated_inside(ui, !create_wallet && !list_hidden && show_bottom_panel, |ui| {
|
||||
.show_animated_inside(ui, show_bottom_panel, |ui| {
|
||||
// Setup vertical padding inside buttons.
|
||||
ui.style_mut().spacing.button_padding = egui::vec2(10.0, 4.0);
|
||||
|
||||
|
@ -195,8 +195,8 @@ impl WalletsContent {
|
|||
});
|
||||
});
|
||||
|
||||
// Show non-empty list if wallet is not creating.
|
||||
if !empty_list && !create_wallet {
|
||||
// Show non-empty list if wallet is not creating and list not hidden.
|
||||
if !list_hidden {
|
||||
// Show wallet list panel.
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame {
|
||||
|
@ -219,10 +219,6 @@ impl WalletsContent {
|
|||
..Default::default()
|
||||
})
|
||||
.show_inside(ui, |ui| {
|
||||
// Do not draw content when list is hidden.
|
||||
if list_hidden {
|
||||
return;
|
||||
}
|
||||
// Show list of wallets.
|
||||
self.wallet_list_ui(ui, dual_panel, cb);
|
||||
});
|
||||
|
@ -336,7 +332,7 @@ impl WalletsContent {
|
|||
ui.style_mut().visuals.widgets.hovered.bg_fill = Colors::STROKE;
|
||||
|
||||
// Draw list of wallets.
|
||||
let scroll = ScrollArea::vertical()
|
||||
ScrollArea::vertical()
|
||||
.id_source("wallet_list")
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
|
|
|
@ -20,11 +20,11 @@ use grin_core::core::amount_to_hr_string;
|
|||
|
||||
use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CHECK, CHECK_FAT, DOWNLOAD, FILE_ARCHIVE, GEAR_FINE, LIST, PACKAGE, PLUS, POWER, REPEAT, UPLOAD, WALLET};
|
||||
use crate::gui::icons::{BRIDGE, CHAT_CIRCLE_TEXT, CHECK, CHECK_FAT, FILE_ARCHIVE, GEAR_FINE, LIST, PACKAGE, PLUS, POWER, REPEAT, WALLET};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, Root, View};
|
||||
use crate::gui::views::types::{ModalPosition, TextEditOptions};
|
||||
use crate::gui::views::wallets::{WalletInfo, WalletReceive, WalletSend, WalletSettings};
|
||||
use crate::gui::views::wallets::{WalletInfo, WalletMessages, WalletTransport, WalletSettings};
|
||||
use crate::gui::views::wallets::types::{GRIN, WalletTab, WalletTabType};
|
||||
use crate::node::Node;
|
||||
use crate::wallet::{Wallet, WalletConfig};
|
||||
|
@ -351,18 +351,18 @@ impl WalletContent {
|
|||
let current_type = self.current_tab.get_type();
|
||||
ui.columns(4, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, WALLET, current_type == WalletTabType::Info, || {
|
||||
View::tab_button(ui, WALLET, current_type == WalletTabType::Txs, || {
|
||||
self.current_tab = Box::new(WalletInfo::default());
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, DOWNLOAD, current_type == WalletTabType::Receive, || {
|
||||
self.current_tab = Box::new(WalletReceive::default());
|
||||
View::tab_button(ui, CHAT_CIRCLE_TEXT, current_type == WalletTabType::Messages, || {
|
||||
self.current_tab = Box::new(WalletMessages::default());
|
||||
});
|
||||
});
|
||||
columns[2].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, UPLOAD, current_type == WalletTabType::Send, || {
|
||||
self.current_tab = Box::new(WalletSend::default());
|
||||
View::tab_button(ui, BRIDGE, current_type == WalletTabType::Transport, || {
|
||||
self.current_tab = Box::new(WalletTransport::default());
|
||||
});
|
||||
});
|
||||
columns[3].vertical_centered_justified(|ui| {
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
use egui::{Id, Margin, RichText, ScrollArea};
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use grin_core::core::{amount_from_hr_string, amount_to_hr_string};
|
||||
use grin_wallet_libwallet::{Slate, SlateState, TxLogEntry};
|
||||
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, HAND_COINS, RECEIPT};
|
||||
use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, DOWNLOAD, UPLOAD};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, Root, View};
|
||||
use crate::gui::views::types::{ModalPosition, TextEditOptions};
|
||||
|
@ -25,52 +26,58 @@ use crate::gui::views::wallets::wallet::types::{SLATEPACK_MESSAGE_HINT, WalletTa
|
|||
use crate::gui::views::wallets::wallet::WalletContent;
|
||||
use crate::wallet::Wallet;
|
||||
|
||||
/// Receiving tab content.
|
||||
pub struct WalletReceive {
|
||||
/// Flag to check if there is invoice transaction type.
|
||||
is_invoice: bool,
|
||||
/// Slatepacks messages interaction tab content.
|
||||
pub struct WalletMessages {
|
||||
/// Flag to check if send or receive request was opened.
|
||||
send_request: bool,
|
||||
|
||||
/// Slatepack message from sender to create response message.
|
||||
/// Slatepack message to create response message.
|
||||
message_edit: String,
|
||||
/// Generated Slatepack response message for sender.
|
||||
/// Parsed Slatepack message.
|
||||
message_slate: Option<Slate>,
|
||||
/// Flag to check if there is an error happened on response creation.
|
||||
parse_error: bool,
|
||||
/// Generated Slatepack response message.
|
||||
response_edit: String,
|
||||
/// Flag to check if there is an error happened on response creation.
|
||||
response_error: bool,
|
||||
/// Flag to check if there is an error happened on transaction finalization.
|
||||
finalize_error: bool,
|
||||
/// Flag to check if Dandelion is needed to finalize transaction.
|
||||
use_dandelion: Option<bool>,
|
||||
|
||||
/// Amount to receive for invoice transaction type.
|
||||
/// Amount to send or receive.
|
||||
amount_edit: String,
|
||||
/// Generated Slatepack message for invoice transaction.
|
||||
/// Generated Slatepack message as request to send or receive funds.
|
||||
request_edit: String,
|
||||
/// Flag to check if there is an error happened on invoice creation.
|
||||
request_error: bool,
|
||||
/// Slatepack message from sender to finalize transaction.
|
||||
finalization_edit: String,
|
||||
/// Flag to check if there is an error happened on transaction finalization.
|
||||
finalization_error: bool,
|
||||
}
|
||||
|
||||
/// Identifier for invoice amount [`Modal`].
|
||||
const INVOICE_AMOUNT_MODAL: &'static str = "invoice_amount_modal";
|
||||
const AMOUNT_MODAL: &'static str = "amount_modal";
|
||||
|
||||
impl Default for WalletReceive {
|
||||
impl Default for WalletMessages {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
is_invoice: false,
|
||||
send_request: false,
|
||||
message_edit: "".to_string(),
|
||||
message_slate: None,
|
||||
parse_error: false,
|
||||
response_edit: "".to_string(),
|
||||
response_error: false,
|
||||
finalize_error: false,
|
||||
use_dandelion: None,
|
||||
amount_edit: "".to_string(),
|
||||
request_edit: "".to_string(),
|
||||
request_error: false,
|
||||
finalization_edit: "".to_string(),
|
||||
finalization_error: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletTab for WalletReceive {
|
||||
impl WalletTab for WalletMessages {
|
||||
fn get_type(&self) -> WalletTabType {
|
||||
WalletTabType::Receive
|
||||
WalletTabType::Messages
|
||||
}
|
||||
|
||||
fn ui(&mut self,
|
||||
|
@ -85,7 +92,7 @@ impl WalletTab for WalletReceive {
|
|||
// Show modal content for this ui container.
|
||||
self.modal_content_ui(ui, wallet, cb);
|
||||
|
||||
// Show receiving content panel.
|
||||
// Show manual wallet content panel.
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame {
|
||||
stroke: View::ITEM_STROKE,
|
||||
|
@ -101,12 +108,12 @@ impl WalletTab for WalletReceive {
|
|||
.show_inside(ui, |ui| {
|
||||
ScrollArea::vertical()
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible)
|
||||
.id_source(Id::from("wallet_receive").with(wallet.get_config().id))
|
||||
.id_source(Id::from("wallet_manual").with(wallet.get_config().id))
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.vertical_centered(|ui| {
|
||||
View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||
self.receive_ui(ui, wallet, cb);
|
||||
self.ui(ui, wallet, cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -114,18 +121,25 @@ impl WalletTab for WalletReceive {
|
|||
}
|
||||
}
|
||||
|
||||
impl WalletReceive {
|
||||
/// Draw receiving content.
|
||||
pub fn receive_ui(&mut self,
|
||||
impl WalletMessages {
|
||||
/// Draw manual wallet transaction interaction content.
|
||||
pub fn ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &mut Wallet,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
ui.add_space(2.0);
|
||||
View::sub_title(ui, format!("{} {}", HAND_COINS, t!("wallets.manually")));
|
||||
ui.add_space(4.0);
|
||||
|
||||
// Show creation of request to send or receive funds.
|
||||
self.request_ui(ui, cb);
|
||||
|
||||
ui.add_space(12.0);
|
||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||
ui.add_space(3.0);
|
||||
// Show manual receiving content.
|
||||
self.manual_ui(ui, wallet, cb);
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Show Slatepack message input field.
|
||||
self.input_slatepack_ui(ui, wallet, cb);
|
||||
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
|
||||
/// Draw [`Modal`] content for this ui container.
|
||||
|
@ -137,9 +151,9 @@ impl WalletReceive {
|
|||
None => {}
|
||||
Some(id) => {
|
||||
match id {
|
||||
INVOICE_AMOUNT_MODAL => {
|
||||
AMOUNT_MODAL => {
|
||||
Modal::ui(ui.ctx(), |ui, modal| {
|
||||
self.invoice_amount_modal(ui, wallet, modal, cb);
|
||||
self.amount_modal_ui(ui, wallet, modal, cb);
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
|
@ -148,73 +162,67 @@ impl WalletReceive {
|
|||
}
|
||||
}
|
||||
|
||||
/// Draw manual receiving content.
|
||||
fn manual_ui(&mut self, ui: &mut egui::Ui, wallet: &mut Wallet, cb: &dyn PlatformCallbacks) {
|
||||
ui.add_space(10.0);
|
||||
ui.columns(2, |columns| {
|
||||
let mut is_invoice = self.is_invoice;
|
||||
columns[0].vertical_centered(|ui| {
|
||||
View::radio_value(ui, &mut is_invoice, false, t!("wallets.receive"));
|
||||
});
|
||||
columns[1].vertical_centered(|ui| {
|
||||
View::radio_value(ui, &mut is_invoice, true, t!("wallets.invoice"));
|
||||
});
|
||||
if is_invoice != self.is_invoice {
|
||||
self.is_invoice = is_invoice;
|
||||
// Reset fields to default values on mode change.
|
||||
if is_invoice {
|
||||
self.amount_edit = "".to_string();
|
||||
self.request_edit = "".to_string();
|
||||
self.request_error = false;
|
||||
self.finalization_edit = "".to_string();
|
||||
self.finalization_error = false;
|
||||
} else {
|
||||
self.message_edit = "".to_string();
|
||||
self.response_edit = "".to_string();
|
||||
self.response_error = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.add_space(10.0);
|
||||
|
||||
if self.is_invoice {
|
||||
// Show invoice creation content.
|
||||
self.manual_invoice_ui(ui, wallet, cb);
|
||||
} else {
|
||||
// Show manual transaction receiving content.
|
||||
self.manual_receive_ui(ui, wallet, cb);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw manual receiving content.
|
||||
fn manual_receive_ui(&mut self,
|
||||
/// Draw Slatepack message input content.
|
||||
fn input_slatepack_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &mut Wallet,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
// Setup description.
|
||||
let response_empty = self.response_edit.is_empty();
|
||||
|
||||
if self.response_error {
|
||||
ui.label(RichText::new(t!("wallets.receive_slatepack_err"))
|
||||
if self.parse_error {
|
||||
ui.label(RichText::new(t!("wallets.parse_slatepack_err"))
|
||||
.size(16.0)
|
||||
.color(Colors::RED));
|
||||
} else if self.response_error {
|
||||
ui.label(RichText::new(t!("wallets.response_slatepack_err"))
|
||||
.size(16.0)
|
||||
.color(Colors::RED));
|
||||
} else if self.finalize_error {
|
||||
ui.label(RichText::new(t!("wallets.finalize_slatepack_err"))
|
||||
.size(16.0)
|
||||
.color(Colors::RED));
|
||||
} else {
|
||||
let desc_text = if response_empty {
|
||||
t!("wallets.receive_slatepack_desc")
|
||||
let desc_text = if response_empty && self.message_slate.is_none() {
|
||||
t!("wallets.input_slatepack_desc")
|
||||
} else {
|
||||
t!("wallets.receive_send_slatepack")
|
||||
let slate = self.message_slate.as_ref().unwrap();
|
||||
let amount = amount_to_hr_string(slate.amount, true);
|
||||
match slate.state {
|
||||
SlateState::Standard1 => {
|
||||
t!("wallets.parse_s1_slatepack_desc","amount" => amount)
|
||||
}
|
||||
SlateState::Standard2 => {
|
||||
t!("wallets.parse_s2_slatepack_desc","amount" => amount)
|
||||
}
|
||||
SlateState::Standard3 => {t!("wallets.input_slatepack_desc")}
|
||||
SlateState::Invoice1 => {
|
||||
let a_f = u64::from(slate.fee_fields) + slate.amount;
|
||||
let a = amount_to_hr_string(a_f, true);
|
||||
t!("wallets.parse_i1_slatepack_desc","amount" => a)
|
||||
}
|
||||
SlateState::Invoice2 => {
|
||||
t!("wallets.parse_i2_slatepack_desc","amount" => amount)
|
||||
}
|
||||
SlateState::Invoice3 => {t!("wallets.input_slatepack_desc")}
|
||||
_ => {
|
||||
t!("wallets.input_slatepack_desc")
|
||||
}
|
||||
}
|
||||
};
|
||||
ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT));
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
ui.add_space(7.0);
|
||||
|
||||
// Setup Slatepack message text input.
|
||||
let message = if response_empty {
|
||||
let mut message = if response_empty {
|
||||
&mut self.message_edit
|
||||
} else {
|
||||
&mut self.response_edit
|
||||
};
|
||||
|
||||
// Save message to check for changes.
|
||||
let message_before = message.clone();
|
||||
|
||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||
ui.add_space(3.0);
|
||||
ScrollArea::vertical()
|
||||
|
@ -223,7 +231,6 @@ impl WalletReceive {
|
|||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(7.0);
|
||||
let message_before = message.clone();
|
||||
egui::TextEdit::multiline(message)
|
||||
.font(egui::TextStyle::Small)
|
||||
.desired_rows(5)
|
||||
|
@ -231,10 +238,6 @@ impl WalletReceive {
|
|||
.hint_text(SLATEPACK_MESSAGE_HINT)
|
||||
.desired_width(f32::INFINITY)
|
||||
.show(ui);
|
||||
// Clear an error when message changed.
|
||||
if &message_before != message {
|
||||
self.response_error = false;
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
ui.add_space(2.0);
|
||||
|
@ -242,26 +245,21 @@ impl WalletReceive {
|
|||
ui.add_space(10.0);
|
||||
|
||||
// Draw buttons to clear/copy/paste.
|
||||
let field_is_empty = self.message_edit.is_empty() && self.response_edit.is_empty();
|
||||
let columns_num = if !field_is_empty { 2 } else { 1 };
|
||||
let fields_empty = self.message_edit.is_empty() && self.response_edit.is_empty();
|
||||
let columns_num = if fields_empty { 1 } else { 2 };
|
||||
let mut show_dandelion = false;
|
||||
ui.scope(|ui| {
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
ui.columns(columns_num, |columns| {
|
||||
let first_column_content = |ui: &mut egui::Ui| {
|
||||
if !self.response_edit.is_empty() && !self.response_error {
|
||||
let clear_text = format!("{} {}", BROOM, t!("clear"));
|
||||
View::button(ui, clear_text, Colors::BUTTON, || {
|
||||
self.response_error = false;
|
||||
self.message_edit.clear();
|
||||
self.response_edit.clear();
|
||||
});
|
||||
if self.message_slate.is_some() && !self.response_error && !self.parse_error {
|
||||
self.clear_message_button_ui(ui);
|
||||
} else {
|
||||
let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste"));
|
||||
View::button(ui, paste_text, Colors::BUTTON, || {
|
||||
self.message_edit = cb.get_string_from_buffer();
|
||||
self.response_error = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -270,30 +268,25 @@ impl WalletReceive {
|
|||
} else {
|
||||
columns[0].vertical_centered_justified(first_column_content);
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
if self.response_error {
|
||||
let clear_text = format!("{} {}", BROOM, t!("clear"));
|
||||
View::button(ui, clear_text, Colors::BUTTON, || {
|
||||
self.response_error = false;
|
||||
self.message_edit.clear();
|
||||
self.response_edit.clear();
|
||||
});
|
||||
if self.finalize_error || self.response_error || self.parse_error {
|
||||
self.clear_message_button_ui(ui);
|
||||
} else 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());
|
||||
});
|
||||
} else {
|
||||
View::button(ui, t!("wallets.create_response"), Colors::GOLD, || {
|
||||
match wallet.receive(self.message_edit.clone()) {
|
||||
Ok(response) => {
|
||||
self.response_edit = response.trim().to_string();
|
||||
show_dandelion = true;
|
||||
View::button(ui, t!("wallets.finalize"), Colors::GOLD, || {
|
||||
let message = self.message_edit.clone();
|
||||
match wallet.finalize(message, self.use_dandelion.unwrap()) {
|
||||
Ok(_) => {
|
||||
self.message_edit.clear();
|
||||
cb.copy_string_to_buffer(response);
|
||||
self.message_slate = None;
|
||||
},
|
||||
Err(e) => {
|
||||
wallet.sync();
|
||||
println!("error {}", e);
|
||||
self.response_error = true
|
||||
self.finalize_error = true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -302,100 +295,156 @@ impl WalletReceive {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Draw setup of ability to post transaction with Dandelion.
|
||||
if show_dandelion {
|
||||
if self.use_dandelion.is_none() {
|
||||
self.use_dandelion = if let Some(u) = wallet.get_config().use_dandelion {
|
||||
Some(u)
|
||||
} else {
|
||||
Some(true)
|
||||
};
|
||||
}
|
||||
let use_dandelion = self.use_dandelion.unwrap();
|
||||
View::checkbox(ui, use_dandelion, t!("wallets.use_dandelion"), || {
|
||||
self.use_dandelion = Some(!use_dandelion);
|
||||
wallet.update_use_dandelion(use_dandelion);
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw invoice creation content.
|
||||
fn manual_invoice_ui(&mut self,
|
||||
// Parse Slatepack message if input field was changed to setup response input.
|
||||
message = if response_empty {
|
||||
&mut self.message_edit
|
||||
} else {
|
||||
&mut self.response_edit
|
||||
};
|
||||
if &message_before != message {
|
||||
if message.is_empty() {
|
||||
self.message_slate = None;
|
||||
}
|
||||
|
||||
self.response_error = false;
|
||||
self.parse_error = false;
|
||||
if !self.message_edit.is_empty() {
|
||||
match wallet.parse_slatepack(self.message_edit.clone()) {
|
||||
Ok(mut slate) => {
|
||||
// Try to get amount from transaction by id.
|
||||
if slate.amount == 0 {
|
||||
let _ = wallet.get_data().unwrap().txs.clone().iter().map(|tx| {
|
||||
if tx.tx_slate_id == Some(slate.id) {
|
||||
slate.amount = if tx.amount_debited > tx.amount_credited {
|
||||
tx.amount_debited - tx.amount_credited
|
||||
} else {
|
||||
tx.amount_credited - tx.amount_debited
|
||||
}
|
||||
}
|
||||
tx
|
||||
}).collect::<Vec<&TxLogEntry>>();
|
||||
}
|
||||
println!("SLATE: {}", slate);
|
||||
self.message_slate = Some(slate.clone());
|
||||
match slate.state {
|
||||
SlateState::Unknown => {}
|
||||
SlateState::Standard1 => {
|
||||
match wallet.receive(self.message_edit.clone()) {
|
||||
Ok(resp) => {
|
||||
self.response_edit = resp;
|
||||
}
|
||||
Err(_) => {
|
||||
self.response_error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
SlateState::Standard2 => {}
|
||||
SlateState::Standard3 => {}
|
||||
SlateState::Invoice1 => {
|
||||
match wallet.pay(self.message_edit.clone()) {
|
||||
Ok(resp) => {
|
||||
self.response_edit = resp;
|
||||
}
|
||||
Err(_) => {
|
||||
self.response_error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
SlateState::Invoice2 => {
|
||||
|
||||
}
|
||||
SlateState::Invoice3 => {}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
self.message_slate = None;
|
||||
self.parse_error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw button to clear entered message, slate and errors.
|
||||
fn clear_message_button_ui(&mut self, ui: &mut egui::Ui) {
|
||||
let clear_text = format!("{} {}", BROOM, t!("clear"));
|
||||
View::button(ui, clear_text, Colors::BUTTON, || {
|
||||
self.response_error = false;
|
||||
self.parse_error = false;
|
||||
self.finalize_error = false;
|
||||
self.message_edit.clear();
|
||||
self.response_edit.clear();
|
||||
self.message_slate = None;
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw creation of request to send or receive funds.
|
||||
fn request_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &mut Wallet,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
ui.label(RichText::new(t!("wallets.issue_invoice_desc"))
|
||||
ui.label(RichText::new(t!("wallets.create_request_desc"))
|
||||
.size(16.0)
|
||||
.color(Colors::INACTIVE_TEXT));
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Draw invoice creation button.
|
||||
let invoice_text = format!("{} {}", RECEIPT, t!("wallets.issue_invoice"));
|
||||
View::button(ui, invoice_text, Colors::BUTTON, || {
|
||||
// Reset modal values.
|
||||
self.amount_edit = "".to_string();
|
||||
self.request_error = false;
|
||||
// Show invoice amount modal.
|
||||
Modal::new(INVOICE_AMOUNT_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("wallets.issue_invoice"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
|
||||
ui.add_space(12.0);
|
||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||
ui.add_space(6.0);
|
||||
ui.label(RichText::new(t!("wallets.receive_slatepack_desc"))
|
||||
.size(16.0)
|
||||
.color(Colors::INACTIVE_TEXT));
|
||||
ui.add_space(6.0);
|
||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||
ui.add_space(3.0);
|
||||
|
||||
// Draw invoice finalization text input.
|
||||
ScrollArea::vertical()
|
||||
.max_height(128.0)
|
||||
.id_source(Id::from("receive_input").with(wallet.get_config().id))
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(7.0);
|
||||
let finalization_before = self.finalization_edit.clone();
|
||||
egui::TextEdit::multiline(&mut self.finalization_edit)
|
||||
.font(egui::TextStyle::Small)
|
||||
.desired_rows(5)
|
||||
.interactive(true)
|
||||
.hint_text(SLATEPACK_MESSAGE_HINT)
|
||||
.desired_width(f32::INFINITY)
|
||||
.show(ui);
|
||||
// Clear an error when message changed.
|
||||
if finalization_before != self.finalization_edit {
|
||||
self.finalization_error = false;
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
ui.add_space(2.0);
|
||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||
ui.add_space(10.0);
|
||||
|
||||
// Draw buttons to clear/paste.
|
||||
ui.scope(|ui| {
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste"));
|
||||
View::button(ui, paste_text, Colors::BUTTON, || {
|
||||
self.finalization_edit = cb.get_string_from_buffer();
|
||||
self.response_error = false;
|
||||
// Draw send request creation button.
|
||||
let send_text = format!("{} {}", UPLOAD, t!("wallets.send"));
|
||||
View::button(ui, send_text.clone(), Colors::BUTTON, || {
|
||||
// Setup modal values.
|
||||
self.send_request = true;
|
||||
self.amount_edit = "".to_string();
|
||||
self.request_error = false;
|
||||
// Show send amount modal.
|
||||
Modal::new(AMOUNT_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("wallets.send"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("wallets.finalize"), Colors::GOLD, || {
|
||||
wallet.finalize();
|
||||
//TODO: finalize
|
||||
// Draw invoice request creation button.
|
||||
let receive_text = format!("{} {}", DOWNLOAD, t!("wallets.receive"));
|
||||
View::button(ui, receive_text.clone(), Colors::BUTTON, || {
|
||||
// Setup modal values.
|
||||
self.send_request = false;
|
||||
self.amount_edit = "".to_string();
|
||||
self.request_error = false;
|
||||
// Show receive amount modal.
|
||||
Modal::new(AMOUNT_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("wallets.receive"))
|
||||
.show();
|
||||
cb.show_keyboard();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if self.finalization_error {
|
||||
ui.add_space(8.0);
|
||||
ui.label(RichText::new(t!("wallets.finalize_slatepack_err"))
|
||||
.size(16.0)
|
||||
.color(Colors::RED));
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
}
|
||||
|
||||
/// Draw invoice amount [`Modal`] content.
|
||||
fn invoice_amount_modal(&mut self,
|
||||
fn amount_modal_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &mut Wallet,
|
||||
modal: &Modal,
|
||||
|
@ -403,7 +452,14 @@ impl WalletReceive {
|
|||
ui.add_space(6.0);
|
||||
if self.request_edit.is_empty() {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(RichText::new(t!("wallets.enter_amount"))
|
||||
let enter_text = if self.send_request {
|
||||
let data = wallet.get_data().unwrap();
|
||||
let amount = amount_to_hr_string(data.info.amount_currently_spendable, true);
|
||||
t!("wallets.enter_amount_send","amount" => amount)
|
||||
} else {
|
||||
t!("wallets.enter_amount_receive")
|
||||
};
|
||||
ui.label(RichText::new(enter_text)
|
||||
.size(17.0)
|
||||
.color(Colors::GRAY));
|
||||
});
|
||||
|
@ -447,10 +503,16 @@ impl WalletReceive {
|
|||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
// Button to create Slatepack message for request.
|
||||
View::button(ui, t!("continue"), Colors::WHITE, || {
|
||||
match amount_from_hr_string(self.amount_edit.as_str()) {
|
||||
Ok(amount) => {
|
||||
match wallet.issue_invoice(amount) {
|
||||
let message = if self.send_request {
|
||||
wallet.send(amount)
|
||||
} else {
|
||||
wallet.issue_invoice(amount)
|
||||
};
|
||||
match message {
|
||||
Ok(message) => {
|
||||
self.request_edit = message;
|
||||
cb.hide_keyboard();
|
||||
|
@ -473,16 +535,25 @@ impl WalletReceive {
|
|||
ui.vertical_centered(|ui| {
|
||||
let amount = amount_from_hr_string(self.amount_edit.as_str()).unwrap();
|
||||
let amount_format = amount_to_hr_string(amount, true);
|
||||
let desc_text = t!("wallets.invoice_desc","amount" => amount_format);
|
||||
let desc_text = if self.send_request {
|
||||
t!("wallets.send_request_desc","amount" => amount_format)
|
||||
} else {
|
||||
t!("wallets.invoice_desc","amount" => amount_format)
|
||||
};
|
||||
ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT));
|
||||
ui.add_space(6.0);
|
||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||
ui.add_space(3.0);
|
||||
|
||||
// Draw invoice request text.
|
||||
// Draw output Slatepack message text.
|
||||
let input_id = if self.send_request {
|
||||
Id::from("send_request_output").with(wallet.get_config().id)
|
||||
} else {
|
||||
Id::from("receive_request_output").with(wallet.get_config().id)
|
||||
};
|
||||
ScrollArea::vertical()
|
||||
.max_height(128.0)
|
||||
.id_source(Id::from("receive_input").with(wallet.get_config().id))
|
||||
.id_source(input_id)
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(7.0);
|
|
@ -14,14 +14,14 @@
|
|||
|
||||
pub mod types;
|
||||
|
||||
mod info;
|
||||
pub use info::WalletInfo;
|
||||
mod txs;
|
||||
pub use txs::WalletInfo;
|
||||
|
||||
mod receive;
|
||||
pub use receive::WalletReceive;
|
||||
mod messages;
|
||||
pub use messages::WalletMessages;
|
||||
|
||||
mod send;
|
||||
pub use send::WalletSend;
|
||||
mod transport;
|
||||
pub use transport::WalletTransport;
|
||||
|
||||
mod settings;
|
||||
pub use settings::WalletSettings;
|
||||
|
|
|
@ -22,11 +22,11 @@ use crate::wallet::Wallet;
|
|||
|
||||
/// Sending tab content.
|
||||
#[derive(Default)]
|
||||
pub struct WalletSend;
|
||||
pub struct WalletTransport;
|
||||
|
||||
impl WalletTab for WalletSend {
|
||||
impl WalletTab for WalletTransport {
|
||||
fn get_type(&self) -> WalletTabType {
|
||||
WalletTabType::Send
|
||||
WalletTabType::Transport
|
||||
}
|
||||
|
||||
fn ui(&mut self,
|
||||
|
@ -38,7 +38,7 @@ impl WalletTab for WalletSend {
|
|||
return;
|
||||
}
|
||||
|
||||
// Show sending content panel.
|
||||
// Show transport content panel.
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame {
|
||||
stroke: View::ITEM_STROKE,
|
||||
|
@ -52,14 +52,14 @@ impl WalletTab for WalletSend {
|
|||
..Default::default()
|
||||
})
|
||||
.show_inside(ui, |ui| {
|
||||
self.send_ui(ui, wallet);
|
||||
self.transport_ui(ui, wallet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSend {
|
||||
/// Draw sending content.
|
||||
pub fn send_ui(&self, ui: &mut egui::Ui, wallet: &mut Wallet) {
|
||||
impl WalletTransport {
|
||||
/// Draw transport content.
|
||||
pub fn transport_ui(&self, ui: &mut egui::Ui, wallet: &mut Wallet) {
|
||||
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ pub struct WalletInfo;
|
|||
|
||||
impl WalletTab for WalletInfo {
|
||||
fn get_type(&self) -> WalletTabType {
|
||||
WalletTabType::Info
|
||||
WalletTabType::Txs
|
||||
}
|
||||
|
||||
fn ui(&mut self,
|
||||
|
@ -203,11 +203,12 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
|||
ui.vertical(|ui| {
|
||||
// Setup transaction amount.
|
||||
ui.add_space(3.0);
|
||||
let amount = amount_to_hr_string(tx.amount_credited - tx.amount_debited, true);
|
||||
let amount_text = if tx.amount_credited > tx.amount_debited {
|
||||
format!("+{}", amount)
|
||||
format!("+{}",
|
||||
amount_to_hr_string(tx.amount_credited - tx.amount_debited, true))
|
||||
} else {
|
||||
amount
|
||||
format!("-{}",
|
||||
amount_to_hr_string(tx.amount_debited - tx.amount_credited, true))
|
||||
};
|
||||
|
||||
// Setup amount color.
|
||||
|
@ -254,17 +255,17 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
|||
} else {
|
||||
format!("{} {}",
|
||||
DOTS_THREE_CIRCLE,
|
||||
t!("wallets.tx_awaiting_conf"))
|
||||
t!("wallets.tx_confirming"))
|
||||
}
|
||||
},
|
||||
TxLogEntryType::TxSent => {
|
||||
if last_height - tx_height > min_confirmations {
|
||||
format!("{} {}", ARROW_CIRCLE_DOWN, t!("wallets.tx_sent"))
|
||||
format!("{} {}", ARROW_CIRCLE_UP, t!("wallets.tx_sent"))
|
||||
} else {
|
||||
format!("{} {}", DOTS_THREE_CIRCLE, t!("wallets.tx_confirming"))
|
||||
}
|
||||
},
|
||||
_ => format!("{} {}", ARROW_CIRCLE_UP, t!("wallets.canceled"))
|
||||
_ => format!("{} {}", X_CIRCLE, t!("wallets.canceled"))
|
||||
}
|
||||
};
|
||||
|
|
@ -33,9 +33,9 @@ pub trait WalletTab {
|
|||
/// Type of [`WalletTab`] content.
|
||||
#[derive(PartialEq)]
|
||||
pub enum WalletTabType {
|
||||
Info,
|
||||
Receive,
|
||||
Send,
|
||||
Txs,
|
||||
Messages,
|
||||
Transport,
|
||||
Settings
|
||||
}
|
||||
|
||||
|
@ -43,9 +43,9 @@ impl WalletTabType {
|
|||
/// Name of wallet tab to show at ui.
|
||||
pub fn name(&self) -> String {
|
||||
match *self {
|
||||
WalletTabType::Info => t!("wallets.wallet"),
|
||||
WalletTabType::Receive => t!("wallets.receive"),
|
||||
WalletTabType::Send => t!("wallets.send"),
|
||||
WalletTabType::Txs => t!("wallets.txs"),
|
||||
WalletTabType::Messages => t!("wallets.messages"),
|
||||
WalletTabType::Transport => t!("wallets.transport"),
|
||||
WalletTabType::Settings => t!("wallets.settings")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,6 +214,6 @@ fn setup_i18n() {
|
|||
locale.as_str()
|
||||
};
|
||||
if _rust_i18n_available_locales().contains(&locale_str) {
|
||||
rust_i18n::set_locale(locale_str);
|
||||
rust_i18n::set_locale(DEFAULT_LOCALE);
|
||||
}
|
||||
}
|
|
@ -36,7 +36,9 @@ pub struct WalletConfig {
|
|||
/// External connection identifier.
|
||||
pub ext_conn_id: Option<i64>,
|
||||
/// Minimal amount of confirmations.
|
||||
pub min_confirmations: u64
|
||||
pub min_confirmations: u64,
|
||||
/// Flag to use Dandelion to broadcast transactions.
|
||||
pub use_dandelion: Option<bool>
|
||||
}
|
||||
|
||||
/// Base wallets directory name.
|
||||
|
@ -69,7 +71,8 @@ impl WalletConfig {
|
|||
ConnectionMethod::Integrated => None,
|
||||
ConnectionMethod::External(id) => Some(*id)
|
||||
},
|
||||
min_confirmations: MIN_CONFIRMATIONS_DEFAULT
|
||||
min_confirmations: MIN_CONFIRMATIONS_DEFAULT,
|
||||
use_dandelion: Some(true),
|
||||
};
|
||||
Settings::write_to_file(&config, config_path);
|
||||
config
|
||||
|
|
|
@ -22,8 +22,8 @@ use std::sync::{Arc, mpsc, RwLock};
|
|||
use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU8, Ordering};
|
||||
use std::thread::Thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use futures::channel::oneshot;
|
||||
|
||||
use grin_api::{ApiServer, Router};
|
||||
use grin_chain::SyncStatus;
|
||||
use grin_core::global;
|
||||
|
@ -35,7 +35,7 @@ use grin_wallet_controller::command::parse_slatepack;
|
|||
use grin_wallet_controller::controller;
|
||||
use grin_wallet_controller::controller::ForeignAPIHandlerV2;
|
||||
use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient};
|
||||
use grin_wallet_libwallet::{Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, RetrieveTxQueryArgs, Slate, StatusMessage, TxLogEntry, TxLogEntryType, WalletInst, WalletLCProvider};
|
||||
use grin_wallet_libwallet::{Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, Slate, SlatepackAddress, StatusMessage, TxLogEntry, TxLogEntryType, WalletInst, WalletLCProvider};
|
||||
use grin_wallet_libwallet::api_impl::owner::{cancel_tx, retrieve_summary_info, retrieve_txs};
|
||||
|
||||
use crate::node::{Node, NodeConfig};
|
||||
|
@ -226,6 +226,13 @@ impl Wallet {
|
|||
w_config.save();
|
||||
}
|
||||
|
||||
/// Update usage of Dandelion to broadcast transactions.
|
||||
pub fn update_use_dandelion(&self, use_dandelion: bool) {
|
||||
let mut w_config = self.config.write().unwrap();
|
||||
w_config.use_dandelion = Some(use_dandelion);
|
||||
w_config.save();
|
||||
}
|
||||
|
||||
/// Update minimal amount of confirmations.
|
||||
pub fn update_min_confirmations(&self, min_confirmations: u64) {
|
||||
let mut w_config = self.config.write().unwrap();
|
||||
|
@ -460,6 +467,19 @@ impl Wallet {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse Slatepack message into [`Slate`].
|
||||
pub fn parse_slatepack(&self, message: String) -> Result<Slate, Error> {
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
return match parse_slatepack(&mut api, None, None, Some(message.clone())) {
|
||||
Ok((slate, _)) => {
|
||||
Ok(slate)
|
||||
}
|
||||
Err(_) => {
|
||||
Err(Error::SlatepackDeser("Slatepack parse error".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create Slatepack message from provided slate.
|
||||
fn create_slatepack_message(&self, slate: Slate) -> Result<String, Error> {
|
||||
let mut message = "".to_string();
|
||||
|
@ -481,44 +501,22 @@ impl Wallet {
|
|||
Ok(message)
|
||||
}
|
||||
|
||||
/// Receive transaction via Slatepack message, return response to sender.
|
||||
pub fn receive(&self, message: String) -> Result<String, Error> {
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
match parse_slatepack(&mut api, None, None, Some(message.clone())) {
|
||||
Ok((mut slate, _)) => {
|
||||
let config = self.get_config();
|
||||
controller::foreign_single_use(api.wallet_inst.clone(), None, |api| {
|
||||
slate = api.receive_tx(&slate, Some(config.account.as_str()), None)?;
|
||||
Ok(())
|
||||
})?;
|
||||
// Create Slatepack message response.
|
||||
let response = self.create_slatepack_message(slate)?;
|
||||
|
||||
// Sync wallet info.
|
||||
self.sync();
|
||||
Ok(response)
|
||||
}
|
||||
Err(_) => {
|
||||
Err(Error::GenericError("Parsing error".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// S transaction via Slatepack message and return response to sender.
|
||||
pub fn pay(&self, message: String) -> Result<String, Error> {
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
match parse_slatepack(&mut api, None, None, Some(message.clone())) {
|
||||
Ok((mut slate, _)) => {
|
||||
/// Initialize a transaction to send amount, return request for funds receiver.
|
||||
pub fn send(&self, amount: u64) -> Result<String, Error> {
|
||||
let config = self.get_config();
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: slate.amount,
|
||||
src_acct_name: Some(config.account),
|
||||
amount,
|
||||
minimum_confirmations: config.min_confirmations,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: false,
|
||||
..Default::default()
|
||||
};
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
let slate = api.process_invoice_tx(None, &slate, args)?;
|
||||
let slate = api.init_send_tx(None, args)?;
|
||||
|
||||
// Lock outputs to for this transaction.
|
||||
api.tx_lock_outputs(None, &slate)?;
|
||||
|
||||
// Create Slatepack message response.
|
||||
let response = self.create_slatepack_message(slate)?;
|
||||
|
@ -528,13 +526,8 @@ impl Wallet {
|
|||
|
||||
Ok(response)
|
||||
}
|
||||
Err(_) => {
|
||||
Err(Error::GenericError("Parsing error".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize an invoice transaction.
|
||||
/// Initialize an invoice transaction to receive amount, return request for funds sender.
|
||||
pub fn issue_invoice(&self, amount: u64) -> Result<String, Error> {
|
||||
let args = IssueInvoiceTxArgs {
|
||||
dest_acct_name: None,
|
||||
|
@ -553,8 +546,57 @@ impl Wallet {
|
|||
Ok(response)
|
||||
}
|
||||
|
||||
pub fn send(&self) {
|
||||
/// Handle message from the invoice issuer to send founds, return response for funds receiver.
|
||||
pub fn pay(&self, message: String) -> Result<String, Error> {
|
||||
let slate = self.parse_slatepack(message)?;
|
||||
let config = self.get_config();
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: slate.amount,
|
||||
minimum_confirmations: config.min_confirmations,
|
||||
selection_strategy_is_use_all: false,
|
||||
..Default::default()
|
||||
};
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
let slate = api.process_invoice_tx(None, &slate, args)?;
|
||||
api.tx_lock_outputs(None, &slate)?;
|
||||
|
||||
// Create Slatepack message response.
|
||||
let response = self.create_slatepack_message(slate)?;
|
||||
|
||||
// Sync wallet info.
|
||||
self.sync();
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// Handle message to receive funds, return response to sender.
|
||||
pub fn receive(&self, message: String) -> Result<String, Error> {
|
||||
let mut slate = self.parse_slatepack(message)?;
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
controller::foreign_single_use(api.wallet_inst.clone(), None, |api| {
|
||||
slate = api.receive_tx(&slate, Some(self.get_config().account.as_str()), None)?;
|
||||
Ok(())
|
||||
})?;
|
||||
// Create Slatepack message response.
|
||||
let response = self.create_slatepack_message(slate)?;
|
||||
|
||||
// Sync wallet info.
|
||||
self.sync();
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// Finalize transaction from provided message as sender or invoice issuer with Dandelion.
|
||||
pub fn finalize(&self, message: String, dandelion: bool) -> Result<Slate, Error> {
|
||||
let mut slate = self.parse_slatepack(message)?;
|
||||
let mut api = Owner::new(self.instance.clone().unwrap(), None);
|
||||
slate = api.finalize_tx(None, &slate)?;
|
||||
api.post_tx(None, &slate, dandelion)?;
|
||||
// Sync wallet info.
|
||||
self.sync();
|
||||
|
||||
Ok(slate)
|
||||
}
|
||||
|
||||
/// Cancel transaction.
|
||||
|
@ -581,11 +623,6 @@ impl Wallet {
|
|||
cancelling_r.contains(id)
|
||||
}
|
||||
|
||||
/// Finalize transaction from provided Slatepack message.
|
||||
pub fn finalize(&self) {
|
||||
|
||||
}
|
||||
|
||||
/// Change wallet password.
|
||||
pub fn change_password(&self, old: String, new: String) -> Result<(), Error> {
|
||||
let instance = self.instance.clone().unwrap();
|
||||
|
@ -889,6 +926,7 @@ fn sync_wallet_data(wallet: &Wallet) {
|
|||
}).collect::<Vec<TxLogEntry>>();
|
||||
// Update txs statuses.
|
||||
for tx in &txs {
|
||||
println!("{}", serde_json::to_string(tx).unwrap());
|
||||
if tx.tx_type == TxLogEntryType::TxSentCancelled
|
||||
|| tx.tx_type == TxLogEntryType::TxReceivedCancelled {
|
||||
// Remove cancelling status.
|
||||
|
@ -903,15 +941,11 @@ fn sync_wallet_data(wallet: &Wallet) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error on retrieve_txs {}", e);
|
||||
Err(e) => println!("error on retrieve_txs {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error on retrieve_summary_info {}", e);
|
||||
}
|
||||
Err(e) => println!("error on retrieve_summary_info {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue