mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-13 02:08:54 +00:00
ui: wallet content container, accounts panel
This commit is contained in:
@@ -148,6 +148,11 @@ impl ContentContainer for WalletsContent {
|
||||
content.close_qr_scan();
|
||||
return false;
|
||||
}
|
||||
// Close account list.
|
||||
if content.account_list_showing() {
|
||||
content.close_qr_scan();
|
||||
return false;
|
||||
}
|
||||
// Close opened wallet.
|
||||
self.wallet_content = None;
|
||||
return false;
|
||||
@@ -384,6 +389,10 @@ impl WalletsContent {
|
||||
let show_list = AppConfig::show_wallets_at_dual_panel();
|
||||
let showing_settings = self.showing_settings();
|
||||
let creating_wallet = self.creating_wallet();
|
||||
let account_list_showing = show_wallet && self.wallet_content
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.account_list_showing();
|
||||
let qr_scan = {
|
||||
let mut scan = false;
|
||||
if show_wallet {
|
||||
@@ -396,7 +405,9 @@ impl WalletsContent {
|
||||
|| (dual_panel && !show_list)) && !creating_wallet && !showing_settings {
|
||||
let wallet_content = self.wallet_content.as_ref().unwrap();
|
||||
let wallet_tab_type = wallet_content.current_tab.get_type();
|
||||
let title_text = if qr_scan {
|
||||
let title_text = if account_list_showing {
|
||||
t!("wallets.accounts")
|
||||
} else if qr_scan {
|
||||
t!("scan_qr")
|
||||
} else {
|
||||
wallet_tab_type.name()
|
||||
@@ -422,7 +433,11 @@ impl WalletsContent {
|
||||
if dual_title {
|
||||
let wallet_content = self.wallet_content.as_ref().unwrap();
|
||||
let wallet_tab_type = wallet_content.current_tab.get_type();
|
||||
let wallet_title_text = wallet_tab_type.name();
|
||||
let wallet_title_text = if account_list_showing {
|
||||
t!("wallets.accounts")
|
||||
} else {
|
||||
wallet_tab_type.name()
|
||||
};
|
||||
let wallet_title_content = if wallet_tab_type == WalletTabType::Settings {
|
||||
TitleContentType::Title(wallet_title_text)
|
||||
} else {
|
||||
@@ -445,6 +460,7 @@ impl WalletsContent {
|
||||
});
|
||||
} else if show_wallet && !dual_panel {
|
||||
View::title_button_big(ui, ARROW_LEFT, |_| {
|
||||
// Close QR code scanner.
|
||||
let wallet_qr_scan = self.wallet_content
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -454,7 +470,11 @@ impl WalletsContent {
|
||||
self.wallet_content.as_mut().unwrap().close_qr_scan();
|
||||
return;
|
||||
}
|
||||
self.wallet_content = None;
|
||||
// Close account list.
|
||||
if account_list_showing {
|
||||
self.wallet_content.as_mut().unwrap().close_account_list();
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else if self.creating_wallet() {
|
||||
let mut close = false;
|
||||
|
||||
@@ -358,7 +358,7 @@ impl WalletCreationContent {
|
||||
if Node::is_running() && !Content::is_dual_panel_mode(ui.ctx()) {
|
||||
ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY);
|
||||
}
|
||||
self.network_setup.content_ui(ui, cb);
|
||||
self.network_setup.ui(ui, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,115 +19,79 @@ use grin_core::core::amount_to_hr_string;
|
||||
|
||||
use crate::gui::icons::{FOLDER_USER, PACKAGE, SCAN, SPINNER, USERS_THREE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::types::{ContentContainer, ModalPosition};
|
||||
use crate::gui::views::wallets::wallet::modals::WalletAccountsModal;
|
||||
use crate::gui::views::wallets::wallet::types::GRIN;
|
||||
use crate::gui::views::wallets::wallet::account::list::WalletAccountsContent;
|
||||
use crate::gui::views::wallets::wallet::types::{WalletContentContainer, GRIN};
|
||||
use crate::gui::views::{CameraContent, Content, Modal, View};
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::views::types::ModalPosition;
|
||||
use crate::gui::views::wallets::wallet::account::create::CreateAccountContent;
|
||||
use crate::wallet::{Wallet, WalletConfig};
|
||||
|
||||
/// Wallet account panel content.
|
||||
pub struct AccountContent {
|
||||
/// Wallet instance.
|
||||
wallet: Wallet,
|
||||
/// Account list content.
|
||||
accounts_content: Option<WalletAccountsContent>,
|
||||
|
||||
/// Wallet accounts [`Modal`] content.
|
||||
accounts_modal_content: WalletAccountsModal,
|
||||
/// Account creation [`Modal`] content.
|
||||
create_account_content: CreateAccountContent,
|
||||
|
||||
/// QR code scan content.
|
||||
qr_scan_content: Option<CameraContent>,
|
||||
}
|
||||
|
||||
/// Identifier for account list [`Modal`].
|
||||
const ACCOUNT_LIST_MODAL: &'static str = "account_list_modal";
|
||||
/// Account creation [`Modal`] identifier.
|
||||
const CREATE_MODAL_ID: &'static str = "create_account_modal";
|
||||
|
||||
impl ContentContainer for AccountContent {
|
||||
impl WalletContentContainer for AccountContent {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![
|
||||
ACCOUNT_LIST_MODAL,
|
||||
CREATE_MODAL_ID
|
||||
]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, modal: &Modal, cb: &dyn PlatformCallbacks) {
|
||||
match modal.id {
|
||||
ACCOUNT_LIST_MODAL => {
|
||||
self.accounts_modal_content.ui(ui, &self.wallet, modal, cb);
|
||||
}
|
||||
CREATE_MODAL_ID => self.create_account_content.ui(ui, wallet, modal, cb),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_back(&mut self, _: &dyn PlatformCallbacks) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
if self.qr_scan_content.is_some() {
|
||||
if let Some(result) = self.qr_scan_content.as_ref().unwrap().qr_scan_result() {
|
||||
// match result {
|
||||
// QrScanResult::Address(address) => {
|
||||
// self.current_tab =
|
||||
// Box::new(WalletTransport::new(Some(address.to_string())));
|
||||
// }
|
||||
// _ => {
|
||||
// self.current_tab =
|
||||
// Box::new(WalletMessages::new(Some(result.text())))
|
||||
// }
|
||||
// }
|
||||
// Stop camera and close scanning.
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
} else {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH, |ui| {
|
||||
self.qr_scan_content.as_mut().unwrap().ui(ui, cb);
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("close"), Colors::white_or_black(false), || {
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
}
|
||||
self.qr_scan_ui(ui, wallet, cb);
|
||||
} else {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||
self.account_ui(ui, cb);
|
||||
if self.accounts_content.is_some() {
|
||||
self.list_ui(ui, wallet);
|
||||
} else {
|
||||
self.account_ui(ui, wallet, cb);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountContent {
|
||||
/// Create new wallet account content.
|
||||
pub fn new(wallet: Wallet) -> Self {
|
||||
let accounts_modal = WalletAccountsModal::new(wallet.accounts());
|
||||
impl Default for AccountContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
wallet,
|
||||
accounts_modal_content: accounts_modal,
|
||||
accounts_content: None,
|
||||
create_account_content: CreateAccountContent::default(),
|
||||
qr_scan_content: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if QR code scanner is showing.
|
||||
pub fn qr_scan_showing(&self) -> bool {
|
||||
self.qr_scan_content.is_some()
|
||||
}
|
||||
|
||||
/// Close QR code scanner.
|
||||
pub fn close_qr_scan(&mut self) {
|
||||
self.qr_scan_content = None;
|
||||
}
|
||||
|
||||
impl AccountContent {
|
||||
/// Draw wallet account content.
|
||||
fn account_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
// Check wallet data.
|
||||
if self.wallet.get_data().is_none() {
|
||||
if wallet.get_data().is_none() {
|
||||
return;
|
||||
}
|
||||
let data = self.wallet.get_data().unwrap();
|
||||
let data = wallet.get_data().unwrap();
|
||||
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(75.0);
|
||||
@@ -148,11 +112,18 @@ impl AccountContent {
|
||||
|
||||
// Draw button to show list of accounts.
|
||||
View::item_button(ui, View::item_rounding(1, 3, true), USERS_THREE, None, || {
|
||||
self.accounts_modal_content = WalletAccountsModal::new(self.wallet.accounts());
|
||||
Modal::new(ACCOUNT_LIST_MODAL)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("wallets.accounts"))
|
||||
.show();
|
||||
let accounts = wallet.accounts();
|
||||
if accounts.len() == 1 {
|
||||
self.create_account_content = CreateAccountContent::default();
|
||||
Modal::new(CREATE_MODAL_ID)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("wallets.accounts"))
|
||||
.show();
|
||||
} else {
|
||||
self.accounts_content = Some(
|
||||
WalletAccountsContent::new(accounts, wallet.get_config().account)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let layout_size = ui.available_size();
|
||||
@@ -172,7 +143,7 @@ impl AccountContent {
|
||||
ui.add_space(-2.0);
|
||||
|
||||
// Show account label.
|
||||
let account = self.wallet.get_config().account;
|
||||
let account = wallet.get_config().account;
|
||||
let default_acc_label = WalletConfig::DEFAULT_ACCOUNT_LABEL.to_string();
|
||||
let acc_label = if account == default_acc_label {
|
||||
t!("wallets.default_account")
|
||||
@@ -183,15 +154,15 @@ impl AccountContent {
|
||||
View::ellipsize_text(ui, acc_text, 15.0, Colors::text(false));
|
||||
|
||||
// Show confirmed height or sync progress.
|
||||
let status_text = if !self.wallet.syncing() {
|
||||
let status_text = if !wallet.syncing() {
|
||||
format!("{} {}", PACKAGE, data.info.last_confirmed_height)
|
||||
} else {
|
||||
let info_progress = self.wallet.info_sync_progress();
|
||||
let info_progress = wallet.info_sync_progress();
|
||||
if info_progress == 100 || info_progress == 0 {
|
||||
format!("{} {}", SPINNER, t!("wallets.wallet_loading"))
|
||||
} else {
|
||||
if self.wallet.is_repairing() {
|
||||
let rep_progress = self.wallet.repairing_progress();
|
||||
if wallet.is_repairing() {
|
||||
let rep_progress = wallet.repairing_progress();
|
||||
if rep_progress == 0 {
|
||||
format!("{} {}", SPINNER, t!("wallets.wallet_checking"))
|
||||
} else {
|
||||
@@ -212,9 +183,104 @@ impl AccountContent {
|
||||
status_text,
|
||||
15.0,
|
||||
Colors::gray(),
|
||||
self.wallet.syncing());
|
||||
wallet.syncing());
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw account list content.
|
||||
fn list_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) {
|
||||
if let Some(accounts) = self.accounts_content.as_mut() {
|
||||
let mut selected = false;
|
||||
accounts.ui(ui, |acc| {
|
||||
let _ = wallet.set_active_account(&acc.label);
|
||||
selected = true;
|
||||
});
|
||||
if selected {
|
||||
self.accounts_content = None;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ui.add_space(2.0);
|
||||
View::horizontal_line(ui, Colors::item_stroke());
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Show modal buttons.
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
self.accounts_content = None;
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.add"), Colors::white_or_black(false), || {
|
||||
self.accounts_content = None;
|
||||
self.create_account_content = CreateAccountContent::default();
|
||||
Modal::new(CREATE_MODAL_ID)
|
||||
.position(ModalPosition::CenterTop)
|
||||
.title(t!("wallets.accounts"))
|
||||
.show();
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
|
||||
/// Draw QR code scanner content.
|
||||
fn qr_scan_ui(&mut self, ui: &mut egui::Ui, _: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
if let Some(_) = self.qr_scan_content.as_ref().unwrap().qr_scan_result() {
|
||||
// match result {
|
||||
// QrScanResult::Address(address) => {
|
||||
// self.current_tab =
|
||||
// Box::new(WalletTransport::new(Some(address.to_string())));
|
||||
// }
|
||||
// _ => {
|
||||
// self.current_tab =
|
||||
// Box::new(WalletMessages::new(Some(result.text())))
|
||||
// }
|
||||
// }
|
||||
// Stop camera and close scanning.
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
} else {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH, |ui| {
|
||||
self.qr_scan_content.as_mut().unwrap().ui(ui, cb);
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("close"), Colors::white_or_black(false), || {
|
||||
cb.stop_camera();
|
||||
self.qr_scan_content = None;
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if account list is showing.
|
||||
pub fn account_list_showing(&self) -> bool {
|
||||
self.accounts_content.is_some()
|
||||
}
|
||||
|
||||
/// Close account list.
|
||||
pub fn close_account_list(&mut self) {
|
||||
self.accounts_content = None;
|
||||
}
|
||||
|
||||
/// Check if QR code scanner is showing.
|
||||
pub fn qr_scan_showing(&self) -> bool {
|
||||
self.qr_scan_content.is_some()
|
||||
}
|
||||
|
||||
/// Close QR code scanner.
|
||||
pub fn close_qr_scan(&mut self) {
|
||||
self.qr_scan_content = None;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2025 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use egui::{Id, RichText};
|
||||
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, TextEdit, View};
|
||||
use crate::gui::Colors;
|
||||
use crate::wallet::Wallet;
|
||||
|
||||
/// Account creation [`Modal`] content.
|
||||
pub struct CreateAccountContent {
|
||||
/// Account label value.
|
||||
account_label_edit: String,
|
||||
/// Flag to check if error occurred during account creation.
|
||||
account_creation_error: bool,
|
||||
}
|
||||
|
||||
impl Default for CreateAccountContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
account_label_edit: "".to_string(),
|
||||
account_creation_error: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateAccountContent {
|
||||
/// Draw account creation [`Modal`] content.
|
||||
pub fn ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
modal: &Modal,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
let on_create = |m: &mut CreateAccountContent| {
|
||||
if m.account_label_edit.is_empty() {
|
||||
return;
|
||||
}
|
||||
let label = &m.account_label_edit;
|
||||
match wallet.create_account(label) {
|
||||
Ok(_) => {
|
||||
let _ = wallet.set_active_account(label);
|
||||
Modal::close();
|
||||
},
|
||||
Err(_) => m.account_creation_error = true
|
||||
};
|
||||
};
|
||||
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(RichText::new(t!("wallets.new_account_desc"))
|
||||
.size(17.0)
|
||||
.color(Colors::gray()));
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Draw account name edit.
|
||||
let mut name_edit = TextEdit::new(Id::from(modal.id).with(wallet.get_config().id));
|
||||
name_edit.ui(ui, &mut self.account_label_edit, cb);
|
||||
if name_edit.enter_pressed {
|
||||
on_create(self);
|
||||
}
|
||||
|
||||
// Show error occurred during account creation.
|
||||
if self.account_creation_error {
|
||||
ui.add_space(12.0);
|
||||
ui.label(RichText::new(t!("error"))
|
||||
.size(17.0)
|
||||
.color(Colors::red()));
|
||||
}
|
||||
ui.add_space(12.0);
|
||||
});
|
||||
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Show modal buttons.
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
// Close modal.
|
||||
Modal::close();
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("create"), Colors::white_or_black(false), || {
|
||||
on_create(self);
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2025 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::gui::icons::{CHECK, CHECK_FAT, FOLDER_USER, PATH};
|
||||
use crate::gui::views::wallets::wallet::types::GRIN;
|
||||
use crate::gui::views::View;
|
||||
use crate::gui::Colors;
|
||||
use crate::wallet::types::WalletAccount;
|
||||
use crate::wallet::WalletConfig;
|
||||
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use egui::{Align, Layout, RichText, ScrollArea, StrokeKind};
|
||||
use grin_core::core::amount_to_hr_string;
|
||||
|
||||
/// Wallet account list content.
|
||||
pub struct WalletAccountsContent {
|
||||
/// List of wallet accounts.
|
||||
accounts: Vec<WalletAccount>,
|
||||
/// Current wallet account label.
|
||||
current_label: String,
|
||||
}
|
||||
|
||||
const ACCOUNT_ITEM_HEIGHT: f32 = 75.0;
|
||||
|
||||
impl WalletAccountsContent {
|
||||
/// Create new accounts content.
|
||||
pub fn new(accounts: Vec<WalletAccount>, current: String) -> Self {
|
||||
Self { accounts, current_label: current }
|
||||
}
|
||||
|
||||
/// Draw account list content.
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui, mut on_select: impl FnMut(WalletAccount)) {
|
||||
let size = self.accounts.len();
|
||||
ScrollArea::vertical()
|
||||
.id_salt("account_list_scroll")
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden)
|
||||
.max_height(266.0)
|
||||
.auto_shrink([true; 2])
|
||||
.show_rows(ui, ACCOUNT_ITEM_HEIGHT, size, |ui, row_range| {
|
||||
for index in row_range {
|
||||
// Add space before the first item.
|
||||
if index == 0 {
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
let acc = self.accounts.get(index).unwrap().clone();
|
||||
self.account_item_ui(ui, &acc, index, size, || {
|
||||
on_select(acc.clone());
|
||||
});
|
||||
if index == size - 1 {
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw account item.
|
||||
fn account_item_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
acc: &WalletAccount,
|
||||
index: usize,
|
||||
size: usize,
|
||||
mut on_select: impl FnMut()) {
|
||||
// Setup layout size.
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(ACCOUNT_ITEM_HEIGHT);
|
||||
|
||||
// Draw round background.
|
||||
let bg_rect = rect.clone();
|
||||
let item_rounding = View::item_rounding(index, size, false);
|
||||
ui.painter().rect(bg_rect,
|
||||
item_rounding,
|
||||
Colors::fill(),
|
||||
View::item_stroke(),
|
||||
StrokeKind::Middle);
|
||||
|
||||
ui.vertical(|ui| {
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
// Draw button to select account.
|
||||
let is_current_account = self.current_label == acc.label;
|
||||
if !is_current_account {
|
||||
let button_rounding = View::item_rounding(index, size, true);
|
||||
View::item_button(ui, button_rounding, CHECK, None, || {
|
||||
on_select();
|
||||
});
|
||||
} else {
|
||||
ui.add_space(12.0);
|
||||
ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green()));
|
||||
}
|
||||
|
||||
let layout_size = ui.available_size();
|
||||
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||
ui.add_space(6.0);
|
||||
ui.vertical(|ui| {
|
||||
ui.add_space(4.0);
|
||||
// Show spendable amount.
|
||||
let amount = amount_to_hr_string(acc.spendable_amount, true);
|
||||
let amount_text = format!("{} {}", amount, GRIN);
|
||||
ui.label(RichText::new(amount_text)
|
||||
.size(18.0)
|
||||
.color(Colors::white_or_black(true)));
|
||||
ui.add_space(-2.0);
|
||||
|
||||
// Show account name.
|
||||
let default_acc_label = WalletConfig::DEFAULT_ACCOUNT_LABEL.to_string();
|
||||
let acc_label = if acc.label == default_acc_label {
|
||||
t!("wallets.default_account")
|
||||
} else {
|
||||
acc.label.to_owned()
|
||||
};
|
||||
let acc_name = format!("{} {}", FOLDER_USER, acc_label);
|
||||
View::ellipsize_text(ui, acc_name, 15.0, Colors::text(false));
|
||||
|
||||
// Show account BIP32 derivation path.
|
||||
let acc_path = format!("{} {}", PATH, acc.path);
|
||||
ui.label(RichText::new(acc_path).size(15.0).color(Colors::gray()));
|
||||
ui.add_space(3.0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
mod content;
|
||||
mod list;
|
||||
mod create;
|
||||
|
||||
pub use content::*;
|
||||
@@ -30,6 +30,7 @@ use crate::node::Node;
|
||||
use crate::wallet::types::ConnectionMethod;
|
||||
use crate::wallet::{ExternalConnection, Wallet};
|
||||
use crate::AppConfig;
|
||||
use crate::gui::views::wallets::wallet::types::WalletContentContainer;
|
||||
|
||||
/// Wallet content.
|
||||
pub struct WalletContent {
|
||||
@@ -38,19 +39,16 @@ pub struct WalletContent {
|
||||
/// Current tab content to show.
|
||||
pub current_tab: Box<dyn WalletTab>,
|
||||
|
||||
/// Account panel content.
|
||||
account_content: AccountContent,
|
||||
}
|
||||
|
||||
impl ContentContainer for WalletContent {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![]
|
||||
}
|
||||
fn modal_ids(&self) -> Vec<&'static str> { vec![] }
|
||||
|
||||
fn modal_ui(&mut self, _: &mut egui::Ui, _: &Modal, _: &dyn PlatformCallbacks) {}
|
||||
|
||||
fn on_back(&mut self, _: &dyn PlatformCallbacks) -> bool {
|
||||
true
|
||||
}
|
||||
fn on_back(&mut self, _: &dyn PlatformCallbacks) -> bool { true }
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
ui.ctx().request_repaint_after(Duration::from_millis(1000));
|
||||
@@ -62,11 +60,11 @@ impl ContentContainer for WalletContent {
|
||||
let wallet_id = wallet.identifier();
|
||||
let data = wallet.get_data();
|
||||
let show_qr_scan = self.account_content.qr_scan_showing();
|
||||
let hide_tabs = Self::block_navigation_on_sync(wallet);
|
||||
let block_nav = Self::block_navigation_on_sync(wallet);
|
||||
|
||||
// Show wallet account panel not on settings tab when navigation is not blocked and QR code
|
||||
// scanner is not showing and wallet data is not empty.
|
||||
let mut show_account = self.current_tab.get_type() != WalletTabType::Settings && !hide_tabs
|
||||
let mut show_account = self.current_tab.get_type() != WalletTabType::Settings && !block_nav
|
||||
&& !wallet.sync_error() && data.is_some();
|
||||
if wallet.get_current_connection() == ConnectionMethod::Integrated && !Node::is_running() {
|
||||
show_account = false;
|
||||
@@ -89,7 +87,7 @@ impl ContentContainer for WalletContent {
|
||||
})
|
||||
.show_animated_inside(ui, show_account, |ui| {
|
||||
let rect = ui.available_rect_before_wrap();
|
||||
self.account_content.ui(ui, cb);
|
||||
self.account_content.ui(ui, wallet, cb);
|
||||
// Draw content divider lines.
|
||||
let r = {
|
||||
let mut r = rect.clone();
|
||||
@@ -105,7 +103,7 @@ impl ContentContainer for WalletContent {
|
||||
});
|
||||
|
||||
// Show wallet tabs.
|
||||
let show_tabs = !hide_tabs && !self.account_content.qr_scan_showing();
|
||||
let show_tabs = !block_nav && !self.qr_scan_showing() && !self.account_list_showing();
|
||||
egui::TopBottomPanel::bottom("wallet_tabs")
|
||||
.frame(egui::Frame {
|
||||
inner_margin: Margin {
|
||||
@@ -148,7 +146,7 @@ impl ContentContainer for WalletContent {
|
||||
.show_inside(ui, |ui| {
|
||||
let rect = ui.available_rect_before_wrap();
|
||||
let tab_type = self.current_tab.get_type();
|
||||
let show_sync = (tab_type != WalletTabType::Settings || hide_tabs) &&
|
||||
let show_sync = (tab_type != WalletTabType::Settings || block_nav) &&
|
||||
sync_ui(ui, &self.wallet);
|
||||
if !show_sync {
|
||||
if tab_type != WalletTabType::Txs {
|
||||
@@ -175,11 +173,12 @@ impl ContentContainer for WalletContent {
|
||||
r.max.y += 4.0;
|
||||
r
|
||||
};
|
||||
// Draw cover when QR code scanner is active.
|
||||
if show_qr_scan {
|
||||
View::content_cover_ui(ui, rect, "wallet_tab", || {
|
||||
// Draw cover when account list or QR code scanner is active.
|
||||
if !show_sync && (self.account_list_showing() || self.qr_scan_showing()) {
|
||||
View::content_cover_ui(ui, rect, "wallet_content_cover", || {
|
||||
cb.stop_camera();
|
||||
self.account_content.close_qr_scan();
|
||||
self.account_content.close_account_list();
|
||||
});
|
||||
}
|
||||
// Draw content divider line.
|
||||
@@ -193,7 +192,7 @@ impl ContentContainer for WalletContent {
|
||||
impl WalletContent {
|
||||
/// Create new instance with optional data.
|
||||
pub fn new(wallet: Wallet, data: Option<String>) -> Self {
|
||||
let account_content = AccountContent::new(wallet.clone());
|
||||
let account_content = AccountContent::default();
|
||||
let mut content = Self {
|
||||
wallet,
|
||||
current_tab: Box::new(WalletTransactions::default()),
|
||||
@@ -205,6 +204,16 @@ impl WalletContent {
|
||||
content
|
||||
}
|
||||
|
||||
/// Check account list is showing.
|
||||
pub fn account_list_showing(&self) -> bool {
|
||||
self.account_content.account_list_showing()
|
||||
}
|
||||
|
||||
/// Close QR code scanner.
|
||||
pub fn close_account_list(&mut self) {
|
||||
self.account_content.close_account_list();
|
||||
}
|
||||
|
||||
/// Check if QR code scanner is opened.
|
||||
pub fn qr_scan_showing(&self) -> bool {
|
||||
self.account_content.qr_scan_showing()
|
||||
@@ -368,4 +377,4 @@ fn sync_progress_ui(ui: &mut egui::Ui, wallet: &Wallet) {
|
||||
ui.label(RichText::new(text).size(16.0).color(Colors::inactive_text()));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ impl MessageRequestModal {
|
||||
|
||||
// Draw content on request loading.
|
||||
if self.request_loading {
|
||||
self.loading_request_ui(ui, wallet, modal);
|
||||
self.loading_request_ui(ui, modal);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ impl MessageRequestModal {
|
||||
}
|
||||
|
||||
/// Draw loading request content.
|
||||
fn loading_request_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, modal: &Modal) {
|
||||
fn loading_request_ui(&mut self, ui: &mut egui::Ui, modal: &Modal) {
|
||||
ui.add_space(34.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
View::big_loading_spinner(ui);
|
||||
|
||||
@@ -29,5 +29,4 @@ pub use transport::WalletTransport;
|
||||
mod content;
|
||||
pub use content::WalletContent;
|
||||
|
||||
mod modals;
|
||||
mod account;
|
||||
@@ -1,239 +0,0 @@
|
||||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use egui::{Align, Id, Layout, RichText, ScrollArea, StrokeKind};
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use grin_core::core::amount_to_hr_string;
|
||||
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CHECK, CHECK_FAT, FOLDER_USER, PATH};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, TextEdit, View};
|
||||
use crate::gui::views::wallets::wallet::types::GRIN;
|
||||
use crate::wallet::types::WalletAccount;
|
||||
use crate::wallet::{Wallet, WalletConfig};
|
||||
|
||||
/// Wallet accounts [`Modal`] content.
|
||||
pub struct WalletAccountsModal {
|
||||
/// List of wallet accounts.
|
||||
accounts: Vec<WalletAccount>,
|
||||
/// Flag to check if account is creating.
|
||||
account_creating: bool,
|
||||
/// Account label value.
|
||||
account_label_edit: String,
|
||||
/// Flag to check if error occurred during account creation.
|
||||
account_creation_error: bool,
|
||||
}
|
||||
|
||||
impl Default for WalletAccountsModal {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
accounts: vec![],
|
||||
account_creating: false,
|
||||
account_label_edit: "".to_string(),
|
||||
account_creation_error: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletAccountsModal {
|
||||
/// Create new instance from wallet accounts.
|
||||
pub fn new(accounts: Vec<WalletAccount>) -> Self {
|
||||
Self {
|
||||
accounts,
|
||||
account_creating: false,
|
||||
account_label_edit: "".to_string(),
|
||||
account_creation_error: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw [`Modal`] content.
|
||||
pub fn ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
modal: &Modal,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
if self.account_creating {
|
||||
let on_create = |m: &mut WalletAccountsModal| {
|
||||
if m.account_label_edit.is_empty() {
|
||||
return;
|
||||
}
|
||||
let label = &m.account_label_edit;
|
||||
match wallet.create_account(label) {
|
||||
Ok(_) => {
|
||||
let _ = wallet.set_active_account(label);
|
||||
Modal::close();
|
||||
},
|
||||
Err(_) => m.account_creation_error = true
|
||||
};
|
||||
};
|
||||
|
||||
ui.add_space(6.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(RichText::new(t!("wallets.new_account_desc"))
|
||||
.size(17.0)
|
||||
.color(Colors::gray()));
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Draw account name edit.
|
||||
let mut name_edit = TextEdit::new(Id::from(modal.id).with(wallet.get_config().id));
|
||||
name_edit.ui(ui, &mut self.account_label_edit, cb);
|
||||
if name_edit.enter_pressed {
|
||||
on_create(self);
|
||||
}
|
||||
|
||||
// Show error occurred during account creation.
|
||||
if self.account_creation_error {
|
||||
ui.add_space(12.0);
|
||||
ui.label(RichText::new(t!("error"))
|
||||
.size(17.0)
|
||||
.color(Colors::red()));
|
||||
}
|
||||
ui.add_space(12.0);
|
||||
});
|
||||
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Show modal buttons.
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
// Close modal.
|
||||
Modal::close();
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("create"), Colors::white_or_black(false), || {
|
||||
on_create(self);
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
} else {
|
||||
ui.add_space(3.0);
|
||||
|
||||
// Show list of accounts.
|
||||
let size = self.accounts.len();
|
||||
ScrollArea::vertical()
|
||||
.id_salt("account_list_modal_scroll")
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden)
|
||||
.max_height(266.0)
|
||||
.auto_shrink([true; 2])
|
||||
.show_rows(ui, ACCOUNT_ITEM_HEIGHT, size, |ui, row_range| {
|
||||
for index in row_range {
|
||||
// Add space before the first item.
|
||||
if index == 0 {
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
let acc = self.accounts.get(index).unwrap();
|
||||
account_item_ui(ui, wallet, acc, index, size);
|
||||
if index == size - 1 {
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(2.0);
|
||||
View::horizontal_line(ui, Colors::item_stroke());
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Setup spacing between buttons.
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||
|
||||
// Show modal buttons.
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
Modal::close();
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("create"), Colors::white_or_black(false), || {
|
||||
self.account_creating = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const ACCOUNT_ITEM_HEIGHT: f32 = 75.0;
|
||||
|
||||
/// Draw account item.
|
||||
fn account_item_ui(ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
acc: &WalletAccount,
|
||||
index: usize,
|
||||
size: usize) {
|
||||
// Setup layout size.
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(ACCOUNT_ITEM_HEIGHT);
|
||||
|
||||
// Draw round background.
|
||||
let bg_rect = rect.clone();
|
||||
let item_rounding = View::item_rounding(index, size, false);
|
||||
ui.painter().rect(bg_rect,
|
||||
item_rounding,
|
||||
Colors::fill(),
|
||||
View::item_stroke(),
|
||||
StrokeKind::Middle);
|
||||
|
||||
ui.vertical(|ui| {
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
// Draw button to select account.
|
||||
let is_current_account = wallet.get_config().account == acc.label;
|
||||
if !is_current_account {
|
||||
let button_rounding = View::item_rounding(index, size, true);
|
||||
View::item_button(ui, button_rounding, CHECK, None, || {
|
||||
let _ = wallet.set_active_account(&acc.label);
|
||||
Modal::close();
|
||||
});
|
||||
} else {
|
||||
ui.add_space(12.0);
|
||||
ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green()));
|
||||
}
|
||||
|
||||
let layout_size = ui.available_size();
|
||||
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||
ui.add_space(6.0);
|
||||
ui.vertical(|ui| {
|
||||
ui.add_space(4.0);
|
||||
// Show spendable amount.
|
||||
let amount = amount_to_hr_string(acc.spendable_amount, true);
|
||||
let amount_text = format!("{} {}", amount, GRIN);
|
||||
ui.label(RichText::new(amount_text).size(18.0).color(Colors::white_or_black(true)));
|
||||
ui.add_space(-2.0);
|
||||
|
||||
// Show account name.
|
||||
let default_acc_label = WalletConfig::DEFAULT_ACCOUNT_LABEL.to_string();
|
||||
let acc_label = if acc.label == default_acc_label {
|
||||
t!("wallets.default_account")
|
||||
} else {
|
||||
acc.label.to_owned()
|
||||
};
|
||||
let acc_name = format!("{} {}", FOLDER_USER, acc_label);
|
||||
View::ellipsize_text(ui, acc_name, 15.0, Colors::text(false));
|
||||
|
||||
// Show account BIP32 derivation path.
|
||||
let acc_path = format!("{} {}", PATH, acc.path);
|
||||
ui.label(RichText::new(acc_path).size(15.0).color(Colors::gray()));
|
||||
ui.add_space(3.0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod accounts;
|
||||
pub use accounts::*;
|
||||
@@ -19,6 +19,7 @@ use crate::gui::icons::{CLOCK_COUNTDOWN, PASSWORD, PENCIL};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, TextEdit, View};
|
||||
use crate::gui::views::types::ModalPosition;
|
||||
use crate::gui::views::wallets::wallet::types::WalletContentContainer;
|
||||
use crate::wallet::Wallet;
|
||||
|
||||
/// Common wallet settings content.
|
||||
@@ -44,24 +45,35 @@ const PASS_EDIT_MODAL: &'static str = "wallet_pass_edit_modal";
|
||||
/// Identifier for minimum confirmations [`Modal`].
|
||||
const MIN_CONFIRMATIONS_EDIT_MODAL: &'static str = "wallet_min_conf_edit_modal";
|
||||
|
||||
impl Default for CommonSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name_edit: "".to_string(),
|
||||
wrong_pass: false,
|
||||
old_pass_edit: "".to_string(),
|
||||
new_pass_edit: "".to_string(),
|
||||
min_confirmations_edit: "".to_string(),
|
||||
impl WalletContentContainer for CommonSettings {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![
|
||||
NAME_EDIT_MODAL,
|
||||
PASS_EDIT_MODAL,
|
||||
MIN_CONFIRMATIONS_EDIT_MODAL
|
||||
]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
modal: &Modal,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
match modal.id {
|
||||
NAME_EDIT_MODAL => {
|
||||
self.name_modal_ui(ui, wallet, modal, cb);
|
||||
}
|
||||
PASS_EDIT_MODAL => {
|
||||
self.pass_modal_ui(ui, wallet, modal, cb);
|
||||
}
|
||||
MIN_CONFIRMATIONS_EDIT_MODAL => {
|
||||
self.min_conf_modal_ui(ui, wallet, modal, cb);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommonSettings {
|
||||
/// Draw common wallet settings content.
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
// Show modal content for this container.
|
||||
self.modal_content_ui(ui, wallet, cb);
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, _: &dyn PlatformCallbacks) {
|
||||
ui.vertical_centered(|ui| {
|
||||
let config = wallet.get_config();
|
||||
// Show wallet name.
|
||||
@@ -135,37 +147,21 @@ impl CommonSettings {
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw [`Modal`] content for this ui container.
|
||||
fn modal_content_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
match Modal::opened() {
|
||||
None => {}
|
||||
Some(id) => {
|
||||
match id {
|
||||
NAME_EDIT_MODAL => {
|
||||
Modal::ui(ui.ctx(), cb, |ui, modal, cb| {
|
||||
self.name_modal_ui(ui, wallet, modal, cb);
|
||||
});
|
||||
}
|
||||
PASS_EDIT_MODAL => {
|
||||
Modal::ui(ui.ctx(), cb, |ui, modal, cb| {
|
||||
self.pass_modal_ui(ui, wallet, modal, cb);
|
||||
});
|
||||
}
|
||||
MIN_CONFIRMATIONS_EDIT_MODAL => {
|
||||
Modal::ui(ui.ctx(), cb, |ui, modal, cb| {
|
||||
self.min_conf_modal_ui(ui, wallet, modal, cb);
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
impl Default for CommonSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name_edit: "".to_string(),
|
||||
wrong_pass: false,
|
||||
old_pass_edit: "".to_string(),
|
||||
new_pass_edit: "".to_string(),
|
||||
min_confirmations_edit: "".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommonSettings {
|
||||
/// Draw wallet name [`Modal`] content.
|
||||
fn name_modal_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
|
||||
use egui::{Align, Layout, RichText, StrokeKind};
|
||||
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CHECK, CHECK_CIRCLE, CHECK_FAT, DOTS_THREE_CIRCLE, GLOBE, GLOBE_SIMPLE, PLUS_CIRCLE, X_CIRCLE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, View};
|
||||
use crate::gui::views::network::ConnectionsContent;
|
||||
use crate::gui::views::network::modals::ExternalConnectionModal;
|
||||
use crate::gui::views::network::ConnectionsContent;
|
||||
use crate::gui::views::types::{ContentContainer, ModalPosition};
|
||||
use crate::wallet::{ConnectionsConfig, ExternalConnection, Wallet};
|
||||
use crate::gui::views::{Modal, View};
|
||||
use crate::gui::Colors;
|
||||
use crate::wallet::types::ConnectionMethod;
|
||||
use crate::wallet::{ConnectionsConfig, ExternalConnection};
|
||||
|
||||
/// Wallet connection settings content.
|
||||
pub struct ConnectionSettings {
|
||||
@@ -65,32 +65,7 @@ impl ContentContainer for ConnectionSettings {
|
||||
true
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, _: &mut egui::Ui, _: &dyn PlatformCallbacks) {}
|
||||
}
|
||||
|
||||
impl ConnectionSettings {
|
||||
/// Draw existing wallet connection setup content.
|
||||
pub fn wallet_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
self.method = wallet.get_current_connection();
|
||||
|
||||
// Draw setup content.
|
||||
let changed = self.content_ui(ui, cb);
|
||||
|
||||
if changed {
|
||||
wallet.update_connection(&self.method);
|
||||
// Reopen wallet if connection changed.
|
||||
if !wallet.reopen_needed() {
|
||||
wallet.set_reopen(true);
|
||||
wallet.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw connection setup content, returning `true` if connection was changed.
|
||||
pub fn content_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) -> bool {
|
||||
self.ui(ui, cb);
|
||||
let mut changed = false;
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, _: &dyn PlatformCallbacks) {
|
||||
ui.add_space(2.0);
|
||||
View::sub_title(ui, format!("{} {}", GLOBE, t!("wallets.conn_method")));
|
||||
View::horizontal_line(ui, Colors::stroke());
|
||||
@@ -104,7 +79,6 @@ impl ConnectionSettings {
|
||||
if !is_current_method {
|
||||
View::item_button(ui, View::item_rounding(0, 1, true), CHECK, None, || {
|
||||
self.method = ConnectionMethod::Integrated;
|
||||
changed = true;
|
||||
});
|
||||
} else {
|
||||
ui.add_space(14.0);
|
||||
@@ -163,15 +137,15 @@ impl ConnectionSettings {
|
||||
};
|
||||
Self::ext_conn_item_ui(ui, c, is_current, i, ext_size, || {
|
||||
self.method = ConnectionMethod::External(c.id, c.url.clone());
|
||||
changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectionSettings {
|
||||
/// Draw external connection item content.
|
||||
fn ext_conn_item_ui(ui: &mut egui::Ui,
|
||||
conn: &ExternalConnection,
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::types::ContentContainer;
|
||||
use crate::gui::views::wallets::{CommonSettings, ConnectionSettings, RecoverySettings};
|
||||
use crate::gui::views::wallets::types::{WalletTab, WalletTabType};
|
||||
use crate::gui::views::wallets::wallet::types::WalletContentContainer;
|
||||
use crate::wallet::Wallet;
|
||||
|
||||
/// Wallet settings tab content.
|
||||
@@ -48,8 +50,20 @@ impl WalletTab for WalletSettings {
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
// Show common wallet setup.
|
||||
self.common_setup.ui(ui, wallet, cb);
|
||||
|
||||
// Show wallet connections setup.
|
||||
self.conn_setup.wallet_ui(ui, wallet, cb);
|
||||
self.conn_setup.method = wallet.get_current_connection();
|
||||
let method = self.conn_setup.method.clone();
|
||||
self.conn_setup.ui(ui, cb);
|
||||
if method != self.conn_setup.method {
|
||||
wallet.update_connection(&self.conn_setup.method);
|
||||
// Reopen wallet if connection changed.
|
||||
if !wallet.reopen_needed() {
|
||||
wallet.set_reopen(true);
|
||||
wallet.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Show wallet recovery setup.
|
||||
self.recovery_setup.ui(ui, wallet, cb);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::gui::icons::{EYE, LIFEBUOY, STETHOSCOPE, TRASH, WRENCH};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, TextEdit, View};
|
||||
use crate::gui::views::types::ModalPosition;
|
||||
use crate::gui::views::wallets::wallet::types::WalletContentContainer;
|
||||
use crate::node::Node;
|
||||
use crate::wallet::types::ConnectionMethod;
|
||||
use crate::wallet::Wallet;
|
||||
@@ -41,21 +42,30 @@ const RECOVERY_PHRASE_MODAL: &'static str = "recovery_phrase_modal";
|
||||
/// Identifier to confirm wallet deletion [`Modal`].
|
||||
const DELETE_CONFIRMATION_MODAL: &'static str = "delete_wallet_confirmation_modal";
|
||||
|
||||
impl Default for RecoverySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
wrong_pass: false,
|
||||
pass_edit: "".to_string(),
|
||||
recovery_phrase: None,
|
||||
impl WalletContentContainer for RecoverySettings {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![
|
||||
RECOVERY_PHRASE_MODAL,
|
||||
DELETE_CONFIRMATION_MODAL
|
||||
]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
modal: &Modal, cb: &dyn PlatformCallbacks) {
|
||||
match modal.id {
|
||||
RECOVERY_PHRASE_MODAL => {
|
||||
self.recovery_phrase_modal_ui(ui, wallet, modal, cb);
|
||||
}
|
||||
DELETE_CONFIRMATION_MODAL => {
|
||||
self.deletion_modal_ui(ui, wallet);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RecoverySettings {
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
// Show modal content for this ui container.
|
||||
self.modal_content_ui(ui, wallet, cb);
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, _: &dyn PlatformCallbacks) {
|
||||
ui.add_space(10.0);
|
||||
View::horizontal_line(ui, Colors::stroke());
|
||||
ui.add_space(6.0);
|
||||
@@ -97,8 +107,8 @@ impl RecoverySettings {
|
||||
format!("{} {}", LIFEBUOY, t!("wallets.recover")),
|
||||
Colors::green(),
|
||||
Colors::white_or_black(false), || {
|
||||
wallet.delete_db(true);
|
||||
});
|
||||
wallet.delete_db(true);
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
ui.label(RichText::new(t!("wallets.restore_wallet_desc"))
|
||||
.size(16.0)
|
||||
@@ -129,40 +139,27 @@ impl RecoverySettings {
|
||||
format!("{} {}", TRASH, t!("wallets.delete")),
|
||||
Colors::red(),
|
||||
Colors::white_or_black(false), || {
|
||||
Modal::new(DELETE_CONFIRMATION_MODAL)
|
||||
.position(ModalPosition::Center)
|
||||
.title(t!("confirmation"))
|
||||
.show();
|
||||
});
|
||||
Modal::new(DELETE_CONFIRMATION_MODAL)
|
||||
.position(ModalPosition::Center)
|
||||
.title(t!("confirmation"))
|
||||
.show();
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw [`Modal`] content for this ui container.
|
||||
fn modal_content_ui(&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
wallet: &Wallet,
|
||||
cb: &dyn PlatformCallbacks) {
|
||||
match Modal::opened() {
|
||||
None => {}
|
||||
Some(id) => {
|
||||
match id {
|
||||
RECOVERY_PHRASE_MODAL => {
|
||||
Modal::ui(ui.ctx(), cb, |ui, modal, cb| {
|
||||
self.recovery_phrase_modal_ui(ui, wallet, modal, cb);
|
||||
});
|
||||
}
|
||||
DELETE_CONFIRMATION_MODAL => {
|
||||
Modal::ui(ui.ctx(), cb, |ui, _, _| {
|
||||
self.deletion_modal_ui(ui, wallet);
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
impl Default for RecoverySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
wrong_pass: false,
|
||||
pass_edit: "".to_string(),
|
||||
recovery_phrase: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RecoverySettings {
|
||||
/// Show recovery phrase [`Modal`].
|
||||
fn show_recovery_phrase_modal(&mut self) {
|
||||
// Setup modal values.
|
||||
|
||||
@@ -78,7 +78,7 @@ impl TransportSendModal {
|
||||
|
||||
// Draw sending content, progress or an error.
|
||||
if self.sending {
|
||||
self.progress_ui(ui, wallet);
|
||||
self.progress_ui(ui);
|
||||
} else if self.error {
|
||||
self.error_ui(ui, wallet, modal);
|
||||
} else {
|
||||
@@ -320,7 +320,7 @@ impl TransportSendModal {
|
||||
}
|
||||
|
||||
/// Draw sending progress content.
|
||||
fn progress_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) {
|
||||
fn progress_ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.add_space(16.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
View::small_loading_spinner(ui);
|
||||
|
||||
@@ -253,7 +253,7 @@ impl WalletTransactions {
|
||||
});
|
||||
}
|
||||
CANCEL_TX_CONFIRMATION_MODAL => {
|
||||
Modal::ui(ui.ctx(), cb, |ui, _, cb| {
|
||||
Modal::ui(ui.ctx(), cb, |ui, _, _| {
|
||||
self.cancel_confirmation_modal(ui, wallet);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
use crate::gui::icons::{FOLDER_LOCK, FOLDER_OPEN, SPINNER, WARNING_CIRCLE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::Modal;
|
||||
use crate::wallet::Wallet;
|
||||
|
||||
/// GRIN coin symbol.
|
||||
@@ -21,6 +22,28 @@ pub const GRIN: &str = "ツ";
|
||||
/// Hint for Slatepack message input.
|
||||
pub const SLATEPACK_MESSAGE_HINT: &'static str = "BEGINSLATEPACK.\n...\n...\n...\nENDSLATEPACK.";
|
||||
|
||||
/// Content container to simplify modals management and navigation.
|
||||
pub trait WalletContentContainer {
|
||||
/// List of allowed [`Modal`] identifiers.
|
||||
fn modal_ids(&self) -> Vec<&'static str>;
|
||||
/// Draw modal content.
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, modal: &Modal, cb: &dyn PlatformCallbacks);
|
||||
/// Draw container content.
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks);
|
||||
/// Draw content, to call by parent container.
|
||||
fn ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
// Draw modal content.
|
||||
if let Some(id) = Modal::opened() {
|
||||
if self.modal_ids().contains(&id) {
|
||||
Modal::ui(ui.ctx(), cb, |ui, modal, cb| {
|
||||
self.modal_ui(ui, wallet, modal, cb);
|
||||
});
|
||||
}
|
||||
}
|
||||
self.container_ui(ui, wallet, cb);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wallet tab content interface.
|
||||
pub trait WalletTab {
|
||||
fn get_type(&self) -> WalletTabType;
|
||||
|
||||
Reference in New Issue
Block a user