fix: hide account list panel on wallet change, do not store account list at content

This commit is contained in:
ardocrat
2026-03-09 20:48:00 +03:00
parent d043562058
commit 7fdb8d272b
6 changed files with 124 additions and 183 deletions
+3 -3
View File
@@ -160,9 +160,9 @@ impl ContentContainer for WalletsContent {
}
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
let is_android = OperatingSystem::from_target_os() == OperatingSystem::Android;
let account_list_showing = self.wallet_content.account_content.list_content.is_some();
// Small repaint delay is needed for Android back navigation and account list opening.
let is_android = OperatingSystem::from_target_os() == OperatingSystem::Android;
let account_list_showing = self.wallet_content.account_content.show_list;
ui.ctx().request_repaint_after(Duration::from_millis(if account_list_showing {
10
} else if is_android {
@@ -753,7 +753,7 @@ impl WalletsContent {
/// Select wallet to make some actions on it.
fn select_wallet(&mut self, w: &Wallet, data: Option<String>, cb: &dyn PlatformCallbacks) {
self.wallet_content.account_content.close_qr_scan(cb);
self.wallet_content.back(cb);
if let Some(data) = data {
w.task(WalletTask::OpenMessage(data));
}
+108 -33
View File
@@ -7,29 +7,29 @@
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distr1ibuted on an "AS IS" BASIS,
// 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, Layout, RichText, StrokeKind};
use egui::{Align, Layout, RichText, ScrollArea, StrokeKind};
use egui::scroll_area::ScrollBarVisibility;
use grin_core::core::amount_to_hr_string;
use crate::gui::icons::{FOLDER_USER, PACKAGE, SCAN, SPINNER, USERS_THREE, USER_PLUS};
use crate::gui::icons::{CHECK, FOLDER_USER, PACKAGE, PATH, SCAN, SPINNER, USERS_THREE, USER_PLUS};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::types::{ModalPosition, QrScanResult};
use crate::gui::views::wallets::wallet::account::create::CreateAccountContent;
use crate::gui::views::wallets::wallet::account::list::WalletAccountsContent;
use crate::gui::views::wallets::wallet::types::{WalletContentContainer, GRIN};
use crate::gui::views::{CameraContent, CameraScanContent, Content, Modal, View};
use crate::gui::Colors;
use crate::wallet::{Wallet, WalletConfig};
use crate::wallet::types::WalletTask;
use crate::wallet::types::{WalletAccount, WalletTask};
/// Wallet account panel content.
pub struct AccountContent {
/// Account list content.
pub list_content: Option<WalletAccountsContent>,
pub struct WalletAccountContent {
/// Flag to show account list content.
pub show_list: bool,
/// Account creation [`Modal`] content.
create_account_content: CreateAccountContent,
@@ -42,7 +42,7 @@ pub struct AccountContent {
/// Account creation [`Modal`] identifier.
const CREATE_MODAL_ID: &'static str = "create_account_modal";
impl WalletContentContainer for AccountContent {
impl WalletContentContainer for WalletAccountContent {
fn modal_ids(&self) -> Vec<&'static str> {
vec![
CREATE_MODAL_ID
@@ -65,7 +65,7 @@ impl WalletContentContainer for AccountContent {
self.qr_scan_ui(ui, wallet, cb);
} else {
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
if self.list_content.is_some() {
if self.show_list {
self.list_ui(ui, wallet);
} else {
// Show account content.
@@ -76,10 +76,10 @@ impl WalletContentContainer for AccountContent {
}
}
impl Default for AccountContent {
impl Default for WalletAccountContent {
fn default() -> Self {
Self {
list_content: None,
show_list: false,
create_account_content: CreateAccountContent::default(),
qr_scan_content: None,
qr_scan_result: None,
@@ -87,7 +87,9 @@ impl Default for AccountContent {
}
}
impl AccountContent {
const ACCOUNT_ITEM_HEIGHT: f32 = 75.0;
impl WalletAccountContent {
/// Check if QR code scanner was opened.
pub fn qr_scan_showing(&self) -> bool {
self.qr_scan_content.is_some() || self.qr_scan_result.is_some()
@@ -105,15 +107,15 @@ impl AccountContent {
/// Check if it's possible to go back at navigation stack.
pub fn can_back(&self) -> bool {
self.qr_scan_showing() || self.list_content.is_some()
self.qr_scan_showing() || self.show_list
}
/// Navigate back on navigation stack.
pub fn back(&mut self, cb: &dyn PlatformCallbacks) {
if self.qr_scan_showing() {
self.close_qr_scan(cb);
} else if self.list_content.is_some() {
self.list_content = None;
} else if self.show_list {
self.show_list = false;
}
}
@@ -170,9 +172,7 @@ impl AccountContent {
.title(t!("wallets.accounts"))
.show();
} else {
self.list_content = Some(
WalletAccountsContent::new(accounts, wallet.get_config().account)
);
self.show_list = true;
}
});
@@ -240,19 +240,26 @@ impl AccountContent {
/// Draw account list content.
fn list_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) {
if let Some(accounts) = self.list_content.as_mut() {
let mut selected = false;
accounts.ui(ui, |acc| {
let _ = wallet.set_active_account(&acc.label);
selected = true;
let accounts = wallet.accounts();
let size = accounts.len();
ScrollArea::vertical()
.id_salt("account_list_scroll")
.scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden)
.max_height(411.0)
.auto_shrink([true; 2])
.show_rows(ui, ACCOUNT_ITEM_HEIGHT, size, |ui, row_range| {
for index in row_range {
let acc = accounts.get(index).unwrap().clone();
let current = wallet.get_config().account == acc.label;
account_item_ui(ui, &acc, current, index, size, || {
let _ = wallet.set_active_account(&acc.label);
self.show_list = false;
});
if index == size - 1 {
ui.add_space(4.0);
}
}
});
if selected {
self.list_content = None;
return;
}
} else {
return;
}
ui.add_space(2.0);
View::horizontal_line(ui, Colors::item_stroke());
@@ -265,12 +272,12 @@ impl AccountContent {
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
self.list_content = None;
self.show_list = false;
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.add"), Colors::white_or_black(false), || {
self.list_content = None;
self.show_list = false;
self.create_account_content = CreateAccountContent::default();
Modal::new(CREATE_MODAL_ID)
.position(ModalPosition::CenterTop)
@@ -321,4 +328,72 @@ impl AccountContent {
ui.add_space(6.0);
});
}
}
/// Draw account item.
fn account_item_ui(ui: &mut egui::Ui,
acc: &WalletAccount,
current: bool,
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::Outside);
ui.vertical(|ui| {
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
// Draw button to select account.
if current {
View::selected_item_check(ui);
} else {
let button_rounding = View::item_rounding(index, size, true);
View::item_button(ui, button_rounding, CHECK, None, || {
on_select();
});
}
let layout_size = ui.available_size();
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
ui.add_space(8.0);
ui.vertical(|ui| {
ui.add_space(3.0);
// Show spendable amount.
let amount = amount_to_hr_string(acc.spendable_amount, true);
let amount_text = format!("{} {}", amount, GRIN);
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
ui.add_space(1.0);
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").into()
} 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,130 +0,0 @@
// 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::scroll_area::ScrollBarVisibility;
use egui::{Align, Layout, RichText, ScrollArea, StrokeKind};
use grin_core::core::amount_to_hr_string;
use crate::gui::icons::{CHECK, 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;
/// 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(411.0)
.auto_shrink([true; 2])
.show_rows(ui, ACCOUNT_ITEM_HEIGHT, size, |ui, row_range| {
for index in row_range {
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::Outside);
ui.vertical(|ui| {
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
// Draw button to select account.
if self.current_label == acc.label {
View::selected_item_check(ui);
} else {
let button_rounding = View::item_rounding(index, size, true);
View::item_button(ui, button_rounding, CHECK, None, || {
on_select();
});
}
let layout_size = ui.available_size();
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
ui.add_space(8.0);
ui.vertical(|ui| {
ui.add_space(3.0);
// Show spendable amount.
let amount = amount_to_hr_string(acc.spendable_amount, true);
let amount_text = format!("{} {}", amount, GRIN);
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
ui.add_space(1.0);
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").into()
} 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);
});
});
});
});
}
}
+2 -3
View File
@@ -13,7 +13,6 @@
// limitations under the License.
mod content;
mod list;
mod create;
pub use content::*;
pub use content::*;
mod create;
+11 -7
View File
@@ -19,7 +19,7 @@ use grin_chain::SyncStatus;
use crate::gui::icons::{ARROWS_CLOCKWISE, FILE_ARROW_DOWN, FILE_ARROW_UP, FILE_TEXT, GEAR_FINE, POWER, STACK};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::types::{LinePosition, ModalPosition};
use crate::gui::views::wallets::wallet::account::AccountContent;
use crate::gui::views::wallets::wallet::account::WalletAccountContent;
use crate::gui::views::wallets::wallet::message::MessageInputContent;
use crate::gui::views::wallets::wallet::request::{InvoiceRequestContent, SendRequestContent};
use crate::gui::views::wallets::wallet::transport::WalletTransportContent;
@@ -42,7 +42,7 @@ pub struct WalletContent {
pub settings_content: Option<WalletSettingsContent>,
/// Account panel content.
pub account_content: AccountContent,
pub account_content: WalletAccountContent,
/// Transport panel content.
pub transport_content: WalletTransportContent,
@@ -150,9 +150,13 @@ impl WalletContentContainer for WalletContent {
}
});
// Close scanner when account panel got hidden.
if !show_account && self.account_content.qr_scan_showing() {
self.account_content.close_qr_scan(cb);
// Close scanner or account list when account panel got hidden.
if !show_account {
if self.account_content.qr_scan_showing() {
self.account_content.close_qr_scan(cb);
} else {
self.account_content.show_list = false;
}
}
// Flag to check if account panel is opened.
@@ -302,7 +306,7 @@ impl Default for WalletContent {
Self {
txs_content: Some(WalletTransactionsContent::new(None)),
settings_content: None,
account_content: AccountContent::default(),
account_content: WalletAccountContent::default(),
transport_content: WalletTransportContent::default(),
invoice_content: None,
send_content: None,
@@ -316,7 +320,7 @@ impl WalletContent {
pub fn title(&self) -> impl Into<String> {
if self.account_content.qr_scan_showing() {
t!("scan_qr")
} else if self.account_content.list_content.is_some() {
} else if self.account_content.show_list {
t!("wallets.accounts")
} else if self.transport_content.settings_content.is_some() {
t!("wallets.transport")
@@ -40,13 +40,6 @@ impl WalletContentContainer for WalletTransportContent {
fn container_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
if let Some(content) = self.qr_address_content.as_mut() {
// Close panel on wallet change.
if let Some(address) = wallet.slatepack_address() {
if address != content.text {
self.qr_address_content = None;
return;
}
}
// Draw QR code content.
ui.add_space(6.0);
content.ui(ui, cb);