make AccountManagementView stateless

Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
kernelkind
2024-09-09 13:55:33 -04:00
committed by William Casarin
parent dda7256f51
commit 3a9c7607f3
3 changed files with 135 additions and 120 deletions

View File

@@ -2,8 +2,11 @@ use std::cmp::Ordering;
use enostr::{FilledKeypair, Keypair}; use enostr::{FilledKeypair, Keypair};
use crate::key_storage::{KeyStorage, KeyStorageResponse, KeyStorageType};
pub use crate::user_account::UserAccount; pub use crate::user_account::UserAccount;
use crate::{
key_storage::{KeyStorage, KeyStorageResponse, KeyStorageType},
ui::account_management::AccountManagementViewResponse,
};
use tracing::info; use tracing::info;
/// The interface for managing the user's accounts. /// The interface for managing the user's accounts.
@@ -116,3 +119,17 @@ impl AccountManager {
self.currently_selected_account = None 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);
}
}
}

View File

@@ -1,55 +1,91 @@
use crate::colors::PINK; use crate::colors::PINK;
use crate::imgcache::ImageCache;
use crate::{ use crate::{
account_manager::AccountManager, account_manager::AccountManager,
app_style::NotedeckTextStyle, ui::{Preview, PreviewConfig, View},
ui,
ui::{profile_preview_controller, Preview, PreviewConfig, View},
Damus, 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::preview::SimpleProfilePreview;
use super::profile::ProfilePreviewOp; use super::profile::ProfilePreviewOp;
use super::profile_preview_controller::profile_preview_view;
pub struct AccountManagementView {} pub struct AccountManagementView {}
impl AccountManagementView { pub enum AccountManagementViewResponse {
pub fn ui(app: &mut Damus, ui: &mut egui::Ui) -> Response { SelectAccount(usize),
Frame::none() RemoveAccount(usize),
.outer_margin(12.0) }
.show(ui, |ui| {
Self::top_section_buttons_widget(ui);
ui.add_space(8.0); impl AccountManagementView {
scroll_area().show(ui, |ui| Self::show_accounts(app, ui)); pub fn ui(
}) ui: &mut Ui,
.response 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( ui.allocate_ui_with_layout(
Vec2::new(ui.available_size_before_wrap().x, 32.0), Vec2::new(ui.available_size_before_wrap().x, 32.0),
Layout::top_down(egui::Align::Min), Layout::top_down(egui::Align::Min),
|ui| { |ui| {
// create all account 'cards' and get the indicies the user requested to remove let txn = Transaction::new(ndb).ok()?;
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 for i in 0..account_manager.num_accounts() {
if let Some(indicies_to_remove) = maybe_remove { let account_pubkey = account_manager
Self::remove_accounts(&mut app.account_manager, indicies_to_remove); .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
}, },
); )
} .inner
fn remove_accounts(manager: &mut AccountManager, account_indices: Vec<usize>) {
account_indices
.iter()
.for_each(|index| manager.remove_account(*index));
} }
fn top_section_buttons_widget(ui: &mut egui::Ui) -> egui::Response { 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, ui: &mut egui::Ui,
preview: SimpleProfilePreview, preview: SimpleProfilePreview,
width: f32, width: f32,
is_selected: bool, is_selected: bool,
) -> Option<ProfilePreviewOp> { ) -> 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| { ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| {
Frame::none() Frame::none()
.show(ui, |ui| { .show(ui, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.add(preview); ui.add(preview);
ui.with_layout(Layout::right_to_left(Align::Center), |ui| { ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
if is_selected { if is_selected {
ui.add(selected_widget()); ui.add(selected_widget());
} else { } else {
if ui if ui
.add(switch_button(ui.style().visuals.dark_mode)) .add(switch_button(ui.style().visuals.dark_mode))
.clicked() .clicked()
{ {
op = Some(ProfilePreviewOp::SwitchTo); op = Some(ProfilePreviewOp::SwitchTo);
}
if ui.add(sign_out_button(ui)).clicked() {
op = Some(ProfilePreviewOp::RemoveAccount)
}
} }
}); if ui.add(sign_out_button(ui)).clicked() {
op = Some(ProfilePreviewOp::RemoveAccount)
}
}
}); });
}) });
.response })
}); .response
ui.add_space(16.0); });
op ui.add_space(16.0);
} op
} }
fn scroll_area() -> ScrollArea { fn scroll_area() -> ScrollArea {
@@ -160,7 +194,7 @@ fn selected_widget() -> impl egui::Widget {
mod preview { mod preview {
use super::*; use super::*;
use crate::test_data; use crate::{account_manager::process_view_response, test_data};
pub struct AccountManagementPreview { pub struct AccountManagementPreview {
app: Damus, app: Damus,
@@ -177,7 +211,16 @@ mod preview {
impl View for AccountManagementPreview { impl View for AccountManagementPreview {
fn ui(&mut self, ui: &mut egui::Ui) { fn ui(&mut self, ui: &mut egui::Ui) {
ui.add_space(24.0); 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)
}
} }
} }

View File

@@ -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::{ use super::{
preview::{get_display_name, get_profile_url, SimpleProfilePreview}, preview::{get_display_name, get_profile_url, SimpleProfilePreview},
@@ -13,64 +16,16 @@ pub enum ProfilePreviewOp {
SwitchTo, SwitchTo,
} }
pub fn set_profile_previews( pub fn profile_preview_view(
app: &mut Damus, ui: &mut Ui,
ui: &mut egui::Ui, profile: Option<&'_ ProfileRecord<'_>>,
add_preview_ui: fn( img_cache: &mut ImageCache,
ui: &mut egui::Ui, is_selected: bool,
preview: SimpleProfilePreview, ) -> Option<ProfilePreviewOp> {
width: f32,
is_selected: bool,
) -> Option<ProfilePreviewOp>,
) -> Option<Vec<usize>> {
let mut to_remove: Option<Vec<usize>> = None;
let width = ui.available_width(); let width = ui.available_width();
let txn = if let Ok(txn) = Transaction::new(&app.ndb) { let preview = SimpleProfilePreview::new(profile, img_cache);
txn show_profile_card(ui, preview, width, is_selected)
} 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
} }
pub fn view_profile_previews( pub fn view_profile_previews(