From f489ed3b9e816d16f2fd49a131f65f8963add9b8 Mon Sep 17 00:00:00 2001 From: kernelkind Date: Wed, 22 May 2024 17:25:06 -0400 Subject: [PATCH] Migrate to new AccountManagementView conception Signed-off-by: kernelkind --- assets/icons/add_account_icon_4x.png | Bin 0 -> 3081 bytes assets/icons/select_icon_3x.png | Bin 0 -> 1405 bytes assets/icons/signout_icon_4x.png | Bin 0 -> 1420 bytes src/account_manager.rs | 20 +- src/ui/account_management.rs | 183 ++++++++++--------- src/ui/global_popup.rs | 2 +- src/ui/profile/mod.rs | 2 +- src/ui/profile/profile_preview_controller.rs | 37 +++- 8 files changed, 150 insertions(+), 94 deletions(-) create mode 100644 assets/icons/add_account_icon_4x.png create mode 100644 assets/icons/select_icon_3x.png create mode 100644 assets/icons/signout_icon_4x.png diff --git a/assets/icons/add_account_icon_4x.png b/assets/icons/add_account_icon_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..1f11a71c3115c4b781068c7e0829f9789920a81e GIT binary patch literal 3081 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 a+`=!ohTfO2dL*p?0000 { + self.select_account(selected_index - 1); + } + Ordering::Equal => { + self.clear_selected_account(); + } + Ordering::Less => {} + } + } } } @@ -84,4 +96,8 @@ impl AccountManager { self.currently_selected_account = Some(index) } } + + pub fn clear_selected_account(&mut self) { + self.currently_selected_account = None + } } diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs index 4d86cac..974e0ef 100644 --- a/src/ui/account_management.rs +++ b/src/ui/account_management.rs @@ -4,12 +4,13 @@ use crate::{ app_style::NotedeckTextStyle, ui::{self, Preview, View}, }; -use egui::{Align, Button, Frame, Id, Layout, Margin, RichText, ScrollArea, Sense, Vec2}; +use egui::{ + Align, Button, Color32, Frame, Id, Image, Layout, Margin, RichText, ScrollArea, Sense, Vec2, +}; use super::global_popup::GlobalPopupType; use super::profile::preview::SimpleProfilePreview; -use super::profile::SimpleProfilePreviewController; -use super::state_in_memory::STATE_ACCOUNT_MANAGEMENT; +use super::profile::{ProfilePreviewOp, SimpleProfilePreviewController}; pub struct AccountManagementView<'a> { account_manager: &'a mut AccountManager, @@ -38,24 +39,23 @@ impl<'a> AccountManagementView<'a> { } fn show(&mut self, ui: &mut egui::Ui) { - ui.add(self.buttons_widget()); - ui.add_space(8.0); - scroll_area().show(ui, |ui| { - self.show_accounts(ui); + Frame::none().outer_margin(24.0).show(ui, |ui| { + ui.add(self.top_section_buttons_widget()); + ui.add_space(8.0); + scroll_area().show(ui, |ui| { + self.show_accounts(ui); + }); }); } fn show_accounts(&mut self, ui: &mut egui::Ui) { - ui.horizontal_wrapped(|ui| { - let maybe_remove = self.simple_preview_controller.set_profile_previews( - self.account_manager, - ui, - STATE_ACCOUNT_MANAGEMENT.get_state(ui.ctx()), - desktop_account_card_ui(), - ); + let maybe_remove = self.simple_preview_controller.set_profile_previews( + self.account_manager, + ui, + account_card_ui(), + ); - self.maybe_remove_accounts(maybe_remove); - }); + self.maybe_remove_accounts(maybe_remove); } fn show_accounts_mobile(&mut self, ui: &mut egui::Ui) { @@ -67,8 +67,7 @@ impl<'a> AccountManagementView<'a> { let maybe_remove = self.simple_preview_controller.set_profile_previews( self.account_manager, ui, - STATE_ACCOUNT_MANAGEMENT.get_state(ui.ctx()), - mobile_account_card_ui(), // closure for creating an account 'card' + account_card_ui(), // closure for creating an account 'card' ); // remove all account indicies user requested @@ -89,7 +88,7 @@ impl<'a> AccountManagementView<'a> { egui::CentralPanel::default() .show(ui.ctx(), |ui| { ui.add(mobile_title()); - ui.add(self.buttons_widget()); + ui.add(self.top_section_buttons_widget()); ui.add_space(8.0); scroll_area().show(ui, |ui| { self.show_accounts_mobile(ui); @@ -98,84 +97,73 @@ impl<'a> AccountManagementView<'a> { .response } - fn buttons_widget(&mut self) -> impl egui::Widget + '_ { + fn top_section_buttons_widget(&mut self) -> impl egui::Widget + '_ { |ui: &mut egui::Ui| { 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 STATE_ACCOUNT_MANAGEMENT.get_state(ui.ctx()) { - if ui.add(done_account_button()).clicked() { - STATE_ACCOUNT_MANAGEMENT.set_state(ui.ctx(), false); - } - } else if ui.add(edit_account_button()).clicked() { - STATE_ACCOUNT_MANAGEMENT.set_state(ui.ctx(), true); - } - }, - ); - - ui.allocate_ui_with_layout( - Vec2::new(ui.available_size_before_wrap().x, 32.0), - Layout::right_to_left(egui::Align::Center), |ui| { if ui.add(add_account_button()).clicked() { // TODO: route to AccountLoginView } }, ); + + // UNCOMMENT FOR LOGOUTALL BUTTON + // ui.allocate_ui_with_layout( + // Vec2::new(ui.available_size_before_wrap().x, 32.0), + // Layout::right_to_left(egui::Align::Center), + // |ui| { + // if ui.add(logout_all_button()).clicked() { + // for index in (0..self.account_manager.num_accounts()).rev() { + // self.account_manager.remove_account(index); + // } + // } + // }, + // ); }) .response } } } -fn mobile_account_card_ui( -) -> fn(ui: &mut egui::Ui, preview: SimpleProfilePreview, edit_mode: bool) -> bool { - |ui, preview, edit_mode| { - let mut should_remove = false; +fn account_card_ui() -> fn( + ui: &mut egui::Ui, + preview: SimpleProfilePreview, + width: f32, + is_selected: bool, +) -> Option { + |ui, preview, width, is_selected| { + let mut op: Option = None; - ui.add_sized( - Vec2::new(ui.available_width(), 50.0), - |ui: &mut egui::Ui| { - Frame::none() - .show(ui, |ui| { - ui.horizontal(|ui| { - ui.add(preview); - if edit_mode { - ui.with_layout(Layout::right_to_left(Align::Center), |ui| { - should_remove = - ui.add(delete_button(ui.visuals().dark_mode)).clicked(); - }); + 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); - should_remove - } -} - -fn desktop_account_card_ui( -) -> fn(ui: &mut egui::Ui, preview: SimpleProfilePreview, edit_mode: bool) -> bool { - |ui: &mut egui::Ui, preview, edit_mode| { - let mut should_remove = false; - - ui.add_sized(preview.dimensions(), |ui: &mut egui::Ui| { - simple_preview_frame(ui) - .show(ui, |ui| { - ui.vertical_centered(|ui| { - ui.add(preview); - if edit_mode { - should_remove = ui.add(delete_button(ui.visuals().dark_mode)).clicked(); - } }); }) .response }); - should_remove + ui.add_space(16.0); + op } } @@ -216,24 +204,55 @@ fn scroll_area() -> ScrollArea { .auto_shrink([false; 2]) } +static PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9); + fn add_account_button() -> Button<'static> { - Button::new("Add Account").min_size(Vec2::new(0.0, 32.0)) + let img_data = egui::include_image!("../../assets/icons/add_account_icon_4x.png"); + let img = Image::new(img_data).fit_to_exact_size(Vec2::new(48.0, 48.0)); + Button::image_and_text( + img, + RichText::new(" Add account") + .size(16.0) + // TODO: this color should not be hard coded. Find some way to add it to the visuals + .color(PINK), + ) + .frame(false) } -fn edit_account_button() -> Button<'static> { - Button::new("Edit").min_size(Vec2::new(0.0, 32.0)) +fn sign_out_button(ui: &egui::Ui) -> egui::Button<'static> { + let img_data = egui::include_image!("../../assets/icons/signout_icon_4x.png"); + let img = Image::new(img_data).fit_to_exact_size(Vec2::new(16.0, 16.0)); + + egui::Button::image_and_text( + img, + RichText::new("Sign out").color(ui.visuals().noninteractive().fg_stroke.color), + ) + .frame(false) } -fn done_account_button() -> Button<'static> { - Button::new("Done").min_size(Vec2::new(0.0, 32.0)) +fn switch_button(dark_mode: bool) -> egui::Button<'static> { + let _ = dark_mode; + + egui::Button::new("Switch").min_size(Vec2::new(76.0, 32.0)) } -fn delete_button(_dark_mode: bool) -> egui::Button<'static> { - let img_data = egui::include_image!("../../assets/icons/delete_icon_4x.png"); - - egui::Button::image(egui::Image::new(img_data).max_width(30.0)).frame(true) +fn selected_widget() -> impl egui::Widget { + |ui: &mut egui::Ui| { + Frame::none() + .show(ui, |ui| { + ui.label(RichText::new("Selected").size(13.0).color(PINK)); + let img_data = egui::include_image!("../../assets/icons/select_icon_3x.png"); + let img = Image::new(img_data).max_size(Vec2::new(16.0, 16.0)); + ui.add(img); + }) + .response + } } +// fn logout_all_button() -> egui::Button<'static> { +// egui::Button::new("Logout all") +// } + pub struct AccountSelectionWidget<'a> { account_manager: &'a mut AccountManager, simple_preview_controller: SimpleProfilePreviewController<'a>, diff --git a/src/ui/global_popup.rs b/src/ui/global_popup.rs index b0355d8..75edd85 100644 --- a/src/ui/global_popup.rs +++ b/src/ui/global_popup.rs @@ -12,7 +12,7 @@ pub enum GlobalPopupType { AccountManagement, } -static ACCOUNT_MANAGEMENT_TITLE: &str = "Account Management"; +static ACCOUNT_MANAGEMENT_TITLE: &str = "Manage accounts"; impl GlobalPopupType { pub fn title(&self) -> &'static str { diff --git a/src/ui/profile/mod.rs b/src/ui/profile/mod.rs index c388add..e67b2d0 100644 --- a/src/ui/profile/mod.rs +++ b/src/ui/profile/mod.rs @@ -4,4 +4,4 @@ mod profile_preview_controller; pub use picture::ProfilePic; pub use preview::ProfilePreview; -pub use profile_preview_controller::SimpleProfilePreviewController; +pub use profile_preview_controller::{ProfilePreviewOp, SimpleProfilePreviewController}; diff --git a/src/ui/profile/profile_preview_controller.rs b/src/ui/profile/profile_preview_controller.rs index 8eb3a94..a6e93fb 100644 --- a/src/ui/profile/profile_preview_controller.rs +++ b/src/ui/profile/profile_preview_controller.rs @@ -9,6 +9,12 @@ pub struct SimpleProfilePreviewController<'a> { img_cache: &'a mut ImageCache, } +#[derive(Debug)] +pub enum ProfilePreviewOp { + RemoveAccount, + SwitchTo, +} + impl<'a> SimpleProfilePreviewController<'a> { pub fn new(ndb: &'a Ndb, img_cache: &'a mut ImageCache) -> Self { SimpleProfilePreviewController { ndb, img_cache } @@ -16,17 +22,19 @@ impl<'a> SimpleProfilePreviewController<'a> { pub fn set_profile_previews( &mut self, - account_manager: &AccountManager, + account_manager: &mut AccountManager, ui: &mut egui::Ui, - edit_mode: bool, add_preview_ui: fn( ui: &mut egui::Ui, preview: SimpleProfilePreview, - edit_mode: bool, - ) -> bool, + width: f32, + is_selected: bool, + ) -> Option, ) -> Option> { let mut to_remove: Option> = None; + let width = ui.available_width(); + for i in 0..account_manager.num_accounts() { if let Some(account) = account_manager.get_account(i) { if let Ok(txn) = Transaction::new(self.ndb) { @@ -37,11 +45,24 @@ impl<'a> SimpleProfilePreviewController<'a> { if let Ok(profile) = profile { let preview = SimpleProfilePreview::new(&profile, self.img_cache); - if add_preview_ui(ui, preview, edit_mode) { - if to_remove.is_none() { - to_remove = Some(Vec::new()); + let is_selected = if let Some(selected) = + account_manager.get_currently_selected_account() + { + i == selected + } else { + false + }; + + if let Some(op) = add_preview_ui(ui, preview, width, is_selected) { + match op { + ProfilePreviewOp::RemoveAccount => { + if to_remove.is_none() { + to_remove = Some(Vec::new()); + } + to_remove.as_mut().unwrap().push(i); + } + ProfilePreviewOp::SwitchTo => account_manager.select_account(i), } - to_remove.as_mut().unwrap().push(i); } }; }