notedeck

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

commit 950a47119eb94364cee7036d914381d4dce49fbb
parent 3a9c7607f330e53eb6fa06b117742bc87f7edba2
Author: kernelkind <kernelkind@gmail.com>
Date:   Mon,  9 Sep 2024 18:31:05 -0400

implement stateful account management view

`./preview StatefulAccountManagementView`

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

Diffstat:
Msrc/account_manager.rs | 20+++++++++++++++++---
Msrc/ui/account_management.rs | 22+++++++++++++++-------
Msrc/ui/mod.rs | 1+
Asrc/ui/stateful_account_management.rs | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui_preview/main.rs | 2++
5 files changed, 166 insertions(+), 10 deletions(-)

diff --git a/src/account_manager.rs b/src/account_manager.rs @@ -1,11 +1,13 @@ use std::cmp::Ordering; -use enostr::{FilledKeypair, Keypair}; +use enostr::{FilledKeypair, FullKeypair, Keypair}; pub use crate::user_account::UserAccount; use crate::{ key_storage::{KeyStorage, KeyStorageResponse, KeyStorageType}, - ui::account_management::AccountManagementViewResponse, + ui::{ + account_login_view::AccountLoginResponse, account_management::AccountManagementViewResponse, + }, }; use tracing::info; @@ -120,7 +122,7 @@ impl AccountManager { } } -pub fn process_view_response( +pub fn process_management_view_response_stateless( manager: &mut AccountManager, response: AccountManagementViewResponse, ) { @@ -131,5 +133,17 @@ pub fn process_view_response( AccountManagementViewResponse::SelectAccount(index) => { manager.select_account(index); } + AccountManagementViewResponse::RouteToLogin => {} + } +} + +pub fn process_login_view_response(manager: &mut AccountManager, response: AccountLoginResponse) { + match response { + AccountLoginResponse::CreateNew => { + manager.add_account(FullKeypair::generate().to_keypair()); + } + AccountLoginResponse::LoginWith(keypair) => { + manager.add_account(keypair); + } } } diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs @@ -14,9 +14,11 @@ use super::profile_preview_controller::profile_preview_view; pub struct AccountManagementView {} +#[derive(Clone, Debug)] pub enum AccountManagementViewResponse { SelectAccount(usize), RemoveAccount(usize), + RouteToLogin, } impl AccountManagementView { @@ -27,7 +29,9 @@ impl AccountManagementView { img_cache: &mut ImageCache, ) -> InnerResponse<Option<AccountManagementViewResponse>> { Frame::none().outer_margin(12.0).show(ui, |ui| { - Self::top_section_buttons_widget(ui); + if let Some(resp) = Self::top_section_buttons_widget(ui).inner { + return Some(resp); + } ui.add_space(8.0); scroll_area() @@ -88,19 +92,23 @@ impl AccountManagementView { .inner } - fn top_section_buttons_widget(ui: &mut egui::Ui) -> egui::Response { + fn top_section_buttons_widget( + ui: &mut egui::Ui, + ) -> InnerResponse<Option<AccountManagementViewResponse>> { ui.horizontal(|ui| { ui.allocate_ui_with_layout( Vec2::new(ui.available_size_before_wrap().x, 32.0), Layout::left_to_right(egui::Align::Center), |ui| { if ui.add(add_account_button()).clicked() { - // TODO: route to AccountLoginView + Some(AccountManagementViewResponse::RouteToLogin) + } else { + None } }, - ); + ) + .inner }) - .response } } @@ -194,7 +202,7 @@ fn selected_widget() -> impl egui::Widget { mod preview { use super::*; - use crate::{account_manager::process_view_response, test_data}; + use crate::{account_manager::process_management_view_response_stateless, test_data}; pub struct AccountManagementPreview { app: Damus, @@ -219,7 +227,7 @@ mod preview { ) .inner { - process_view_response(&mut self.app.account_manager, response) + process_management_view_response_stateless(&mut self.app.account_manager, response) } } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs @@ -8,6 +8,7 @@ pub mod preview; pub mod profile; pub mod relay; pub mod side_panel; +pub mod stateful_account_management; pub mod thread; pub mod timeline; pub mod username; diff --git a/src/ui/stateful_account_management.rs b/src/ui/stateful_account_management.rs @@ -0,0 +1,131 @@ +use egui::Ui; +use egui_nav::{Nav, NavAction}; +use nostrdb::Ndb; + +use crate::{ + account_manager::{process_login_view_response, AccountManager}, + imgcache::ImageCache, + login_manager::LoginState, + routable_widget_state::RoutableWidgetState, + route::{ManageAccountRoute, ManageAcountRouteResponse}, + Damus, +}; + +use super::{ + account_login_view::AccountLoginView, account_management::AccountManagementViewResponse, + AccountManagementView, +}; + +pub struct StatefulAccountManagementView {} + +impl StatefulAccountManagementView { + pub fn show( + ui: &mut Ui, + account_management_state: &mut RoutableWidgetState<ManageAccountRoute>, + account_manager: &mut AccountManager, + img_cache: &mut ImageCache, + login_state: &mut LoginState, + ndb: &Ndb, + ) { + let routes = account_management_state.get_routes(); + + let nav_response = + Nav::new(routes) + .title(false) + .navigating(false) + .show_mut(ui, |ui, nav| match nav.top() { + ManageAccountRoute::AccountManagement => { + AccountManagementView::ui(ui, account_manager, ndb, img_cache) + .inner + .map(ManageAcountRouteResponse::AccountManagement) + } + ManageAccountRoute::AddAccount => AccountLoginView::new(login_state) + .ui(ui) + .inner + .map(ManageAcountRouteResponse::AddAccount), + }); + + if let Some(resp) = nav_response.inner { + match resp { + ManageAcountRouteResponse::AccountManagement(response) => { + process_management_view_response_stateful( + response, + account_manager, + account_management_state, + ); + } + ManageAcountRouteResponse::AddAccount(response) => { + process_login_view_response(account_manager, response); + *login_state = Default::default(); + account_management_state.go_back(); + } + } + } + if let Some(NavAction::Returned) = nav_response.action { + account_management_state.go_back(); + } + } +} + +pub fn process_management_view_response_stateful( + response: AccountManagementViewResponse, + manager: &mut AccountManager, + state: &mut RoutableWidgetState<ManageAccountRoute>, +) { + match response { + AccountManagementViewResponse::RemoveAccount(index) => { + manager.remove_account(index); + } + AccountManagementViewResponse::SelectAccount(index) => { + manager.select_account(index); + } + AccountManagementViewResponse::RouteToLogin => { + state.route_to(ManageAccountRoute::AddAccount); + } + } +} + +mod preview { + use crate::{ + test_data, + ui::{Preview, PreviewConfig, View}, + }; + + use super::*; + + pub struct StatefulAccountManagementPreview { + app: Damus, + } + + impl StatefulAccountManagementPreview { + fn new() -> Self { + let mut app = test_data::test_app(); + app.account_management_view_state + .route_to(ManageAccountRoute::AccountManagement); + + StatefulAccountManagementPreview { app } + } + } + + impl View for StatefulAccountManagementPreview { + fn ui(&mut self, ui: &mut egui::Ui) { + StatefulAccountManagementView::show( + ui, + &mut self.app.account_management_view_state, + &mut self.app.account_manager, + &mut self.app.img_cache, + &mut self.app.login_state, + &self.app.ndb, + ); + } + } + + impl Preview for StatefulAccountManagementView { + type Prev = StatefulAccountManagementPreview; + + fn preview(cfg: PreviewConfig) -> Self::Prev { + let _ = cfg; + StatefulAccountManagementPreview::new() + } + } +} diff --git a/src/ui_preview/main.rs b/src/ui_preview/main.rs @@ -2,6 +2,7 @@ use notedeck::app_creation::{ generate_mobile_emulator_native_options, generate_native_options, setup_cc, }; use notedeck::ui::account_login_view::AccountLoginView; +use notedeck::ui::stateful_account_management::StatefulAccountManagementView; use notedeck::ui::{ AccountManagementView, AccountSelectionWidget, DesktopSidePanel, PostView, Preview, PreviewApp, PreviewConfig, ProfilePic, ProfilePreview, RelayView, @@ -104,5 +105,6 @@ async fn main() { AccountSelectionWidget, DesktopSidePanel, PostView, + StatefulAccountManagementView, ); }