notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 3a9c7607f330e53eb6fa06b117742bc87f7edba2
parent dda7256f51426624fbaa486034d728de07f4c245
Author: kernelkind <kernelkind@gmail.com>
Date:   Mon,  9 Sep 2024 13:55:33 -0400

make AccountManagementView stateless

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Msrc/account_manager.rs | 19++++++++++++++++++-
Msrc/ui/account_management.rs | 169+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/ui/profile/profile_preview_controller.rs | 71+++++++++++++----------------------------------------------------------
3 files changed, 137 insertions(+), 122 deletions(-)

diff --git a/src/account_manager.rs b/src/account_manager.rs @@ -2,8 +2,11 @@ use std::cmp::Ordering; use enostr::{FilledKeypair, Keypair}; -use crate::key_storage::{KeyStorage, KeyStorageResponse, KeyStorageType}; pub use crate::user_account::UserAccount; +use crate::{ + key_storage::{KeyStorage, KeyStorageResponse, KeyStorageType}, + ui::account_management::AccountManagementViewResponse, +}; use tracing::info; /// The interface for managing the user's accounts. @@ -116,3 +119,17 @@ impl AccountManager { self.currently_selected_account = None } } + +pub fn process_view_response( + manager: &mut AccountManager, + response: AccountManagementViewResponse, +) { + match response { + AccountManagementViewResponse::RemoveAccount(index) => { + manager.remove_account(index); + } + AccountManagementViewResponse::SelectAccount(index) => { + manager.select_account(index); + } + } +} diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs @@ -1,55 +1,91 @@ use crate::colors::PINK; +use crate::imgcache::ImageCache; use crate::{ account_manager::AccountManager, - app_style::NotedeckTextStyle, - ui, - ui::{profile_preview_controller, Preview, PreviewConfig, View}, + ui::{Preview, PreviewConfig, View}, Damus, }; -use egui::{Align, Button, Frame, Image, Layout, Response, RichText, ScrollArea, Vec2}; +use egui::{Align, Button, Frame, Image, InnerResponse, Layout, RichText, ScrollArea, Ui, Vec2}; +use nostrdb::{Ndb, Transaction}; use super::profile::preview::SimpleProfilePreview; use super::profile::ProfilePreviewOp; +use super::profile_preview_controller::profile_preview_view; pub struct AccountManagementView {} -impl AccountManagementView { - pub fn ui(app: &mut Damus, ui: &mut egui::Ui) -> Response { - Frame::none() - .outer_margin(12.0) - .show(ui, |ui| { - Self::top_section_buttons_widget(ui); +pub enum AccountManagementViewResponse { + SelectAccount(usize), + RemoveAccount(usize), +} - ui.add_space(8.0); - scroll_area().show(ui, |ui| Self::show_accounts(app, ui)); - }) - .response +impl AccountManagementView { + pub fn ui( + ui: &mut Ui, + account_manager: &AccountManager, + ndb: &Ndb, + img_cache: &mut ImageCache, + ) -> InnerResponse<Option<AccountManagementViewResponse>> { + Frame::none().outer_margin(12.0).show(ui, |ui| { + Self::top_section_buttons_widget(ui); + + ui.add_space(8.0); + scroll_area() + .show(ui, |ui| { + Self::show_accounts(ui, account_manager, ndb, img_cache) + }) + .inner + }) } - fn show_accounts(app: &mut Damus, ui: &mut egui::Ui) { + fn show_accounts( + ui: &mut Ui, + account_manager: &AccountManager, + ndb: &Ndb, + img_cache: &mut ImageCache, + ) -> Option<AccountManagementViewResponse> { ui.allocate_ui_with_layout( Vec2::new(ui.available_size_before_wrap().x, 32.0), Layout::top_down(egui::Align::Min), |ui| { - // create all account 'cards' and get the indicies the user requested to remove - let maybe_remove = profile_preview_controller::set_profile_previews( - app, - ui, - account_card_ui(), // closure for creating an account 'card' - ); - - // remove all account indicies user requested - if let Some(indicies_to_remove) = maybe_remove { - Self::remove_accounts(&mut app.account_manager, indicies_to_remove); + let txn = Transaction::new(ndb).ok()?; + + for i in 0..account_manager.num_accounts() { + let account_pubkey = account_manager + .get_account(i) + .map(|account| account.pubkey.bytes()); + + let account_pubkey = if let Some(pubkey) = account_pubkey { + pubkey + } else { + continue; + }; + + let profile = ndb.get_profile_by_pubkey(&txn, account_pubkey).ok(); + let is_selected = + if let Some(selected) = account_manager.get_selected_account_index() { + i == selected + } else { + false + }; + + if let Some(op) = + profile_preview_view(ui, profile.as_ref(), img_cache, is_selected) + { + return Some(match op { + ProfilePreviewOp::SwitchTo => { + AccountManagementViewResponse::SelectAccount(i) + } + ProfilePreviewOp::RemoveAccount => { + AccountManagementViewResponse::RemoveAccount(i) + } + }); + } } + None }, - ); - } - - fn remove_accounts(manager: &mut AccountManager, account_indices: Vec<usize>) { - account_indices - .iter() - .for_each(|index| manager.remove_account(*index)); + ) + .inner } fn top_section_buttons_widget(ui: &mut egui::Ui) -> egui::Response { @@ -68,43 +104,41 @@ impl AccountManagementView { } } -fn account_card_ui() -> fn( +pub fn show_profile_card( ui: &mut egui::Ui, preview: SimpleProfilePreview, width: f32, is_selected: bool, ) -> Option<ProfilePreviewOp> { - |ui, preview, width, is_selected| { - let mut op: Option<ProfilePreviewOp> = None; + let mut op: Option<ProfilePreviewOp> = None; - ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| { - Frame::none() - .show(ui, |ui| { - ui.horizontal(|ui| { - ui.add(preview); - - ui.with_layout(Layout::right_to_left(Align::Center), |ui| { - if is_selected { - ui.add(selected_widget()); - } else { - if ui - .add(switch_button(ui.style().visuals.dark_mode)) - .clicked() - { - op = Some(ProfilePreviewOp::SwitchTo); - } - if ui.add(sign_out_button(ui)).clicked() { - op = Some(ProfilePreviewOp::RemoveAccount) - } + ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| { + Frame::none() + .show(ui, |ui| { + ui.horizontal(|ui| { + ui.add(preview); + + ui.with_layout(Layout::right_to_left(Align::Center), |ui| { + if is_selected { + ui.add(selected_widget()); + } else { + if ui + .add(switch_button(ui.style().visuals.dark_mode)) + .clicked() + { + op = Some(ProfilePreviewOp::SwitchTo); } - }); + if ui.add(sign_out_button(ui)).clicked() { + op = Some(ProfilePreviewOp::RemoveAccount) + } + } }); - }) - .response - }); - ui.add_space(16.0); - op - } + }); + }) + .response + }); + ui.add_space(16.0); + op } fn scroll_area() -> ScrollArea { @@ -160,7 +194,7 @@ fn selected_widget() -> impl egui::Widget { mod preview { use super::*; - use crate::test_data; + use crate::{account_manager::process_view_response, test_data}; pub struct AccountManagementPreview { app: Damus, @@ -177,7 +211,16 @@ mod preview { impl View for AccountManagementPreview { fn ui(&mut self, ui: &mut egui::Ui) { ui.add_space(24.0); - AccountManagementView::ui(&mut self.app, ui); + if let Some(response) = AccountManagementView::ui( + ui, + &self.app.account_manager, + &self.app.ndb, + &mut self.app.img_cache, + ) + .inner + { + process_view_response(&mut self.app.account_manager, response) + } } } diff --git a/src/ui/profile/profile_preview_controller.rs b/src/ui/profile/profile_preview_controller.rs @@ -1,6 +1,9 @@ -use nostrdb::{Ndb, Transaction}; +use egui::Ui; +use nostrdb::{Ndb, ProfileRecord, Transaction}; -use crate::{Damus, DisplayName, Result}; +use crate::{ + imgcache::ImageCache, ui::account_management::show_profile_card, Damus, DisplayName, Result, +}; use super::{ preview::{get_display_name, get_profile_url, SimpleProfilePreview}, @@ -13,64 +16,16 @@ pub enum ProfilePreviewOp { SwitchTo, } -pub fn set_profile_previews( - app: &mut Damus, - ui: &mut egui::Ui, - add_preview_ui: fn( - ui: &mut egui::Ui, - preview: SimpleProfilePreview, - width: f32, - is_selected: bool, - ) -> Option<ProfilePreviewOp>, -) -> Option<Vec<usize>> { - let mut to_remove: Option<Vec<usize>> = None; - +pub fn profile_preview_view( + ui: &mut Ui, + profile: Option<&'_ ProfileRecord<'_>>, + img_cache: &mut ImageCache, + is_selected: bool, +) -> Option<ProfilePreviewOp> { let width = ui.available_width(); - let txn = if let Ok(txn) = Transaction::new(&app.ndb) { - txn - } else { - return None; - }; - - for i in 0..app.accounts.num_accounts() { - let account = if let Some(account) = app.accounts.get_account(i) { - account - } else { - continue; - }; - - let profile = app - .ndb - .get_profile_by_pubkey(&txn, account.pubkey.bytes()) - .ok(); - - let preview = SimpleProfilePreview::new(profile.as_ref(), &mut app.img_cache); - - let is_selected = if let Some(selected) = app.accounts.get_selected_account_index() { - i == selected - } else { - false - }; - - let op = if let Some(op) = add_preview_ui(ui, preview, width, is_selected) { - op - } else { - continue; - }; - - match op { - ProfilePreviewOp::RemoveAccount => { - if to_remove.is_none() { - to_remove = Some(Vec::new()); - } - to_remove.as_mut().unwrap().push(i); - } - ProfilePreviewOp::SwitchTo => app.accounts.select_account(i), - } - } - - to_remove + let preview = SimpleProfilePreview::new(profile, img_cache); + show_profile_card(ui, preview, width, is_selected) } pub fn view_profile_previews(