Migrate to new AccountManagementView conception

Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
kernelkind
2024-05-22 17:25:06 -04:00
committed by William Casarin
parent 2ca47edf4d
commit f489ed3b9e
8 changed files with 150 additions and 94 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,3 +1,5 @@
use std::cmp::Ordering;
use enostr::FullKeypair; use enostr::FullKeypair;
pub use crate::user_account::UserAccount; pub use crate::user_account::UserAccount;
@@ -51,9 +53,19 @@ impl AccountManager {
pub fn remove_account(&mut self, index: usize) { pub fn remove_account(&mut self, index: usize) {
if let Some(account) = self.accounts.get(index) { if let Some(account) = self.accounts.get(index) {
let _ = self.key_store.remove_key(&account.key); let _ = self.key_store.remove_key(&account.key);
}
if index < self.accounts.len() {
self.accounts.remove(index); self.accounts.remove(index);
if let Some(selected_index) = self.currently_selected_account {
match selected_index.cmp(&index) {
Ordering::Greater => {
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) self.currently_selected_account = Some(index)
} }
} }
pub fn clear_selected_account(&mut self) {
self.currently_selected_account = None
}
} }

View File

@@ -4,12 +4,13 @@ use crate::{
app_style::NotedeckTextStyle, app_style::NotedeckTextStyle,
ui::{self, Preview, View}, 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::global_popup::GlobalPopupType;
use super::profile::preview::SimpleProfilePreview; use super::profile::preview::SimpleProfilePreview;
use super::profile::SimpleProfilePreviewController; use super::profile::{ProfilePreviewOp, SimpleProfilePreviewController};
use super::state_in_memory::STATE_ACCOUNT_MANAGEMENT;
pub struct AccountManagementView<'a> { pub struct AccountManagementView<'a> {
account_manager: &'a mut AccountManager, account_manager: &'a mut AccountManager,
@@ -38,24 +39,23 @@ impl<'a> AccountManagementView<'a> {
} }
fn show(&mut self, ui: &mut egui::Ui) { fn show(&mut self, ui: &mut egui::Ui) {
ui.add(self.buttons_widget()); Frame::none().outer_margin(24.0).show(ui, |ui| {
ui.add_space(8.0); ui.add(self.top_section_buttons_widget());
scroll_area().show(ui, |ui| { ui.add_space(8.0);
self.show_accounts(ui); scroll_area().show(ui, |ui| {
self.show_accounts(ui);
});
}); });
} }
fn show_accounts(&mut self, ui: &mut egui::Ui) { fn show_accounts(&mut self, ui: &mut egui::Ui) {
ui.horizontal_wrapped(|ui| { let maybe_remove = self.simple_preview_controller.set_profile_previews(
let maybe_remove = self.simple_preview_controller.set_profile_previews( self.account_manager,
self.account_manager, ui,
ui, account_card_ui(),
STATE_ACCOUNT_MANAGEMENT.get_state(ui.ctx()), );
desktop_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) { 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( let maybe_remove = self.simple_preview_controller.set_profile_previews(
self.account_manager, self.account_manager,
ui, ui,
STATE_ACCOUNT_MANAGEMENT.get_state(ui.ctx()), account_card_ui(), // closure for creating an account 'card'
mobile_account_card_ui(), // closure for creating an account 'card'
); );
// remove all account indicies user requested // remove all account indicies user requested
@@ -89,7 +88,7 @@ impl<'a> AccountManagementView<'a> {
egui::CentralPanel::default() egui::CentralPanel::default()
.show(ui.ctx(), |ui| { .show(ui.ctx(), |ui| {
ui.add(mobile_title()); ui.add(mobile_title());
ui.add(self.buttons_widget()); ui.add(self.top_section_buttons_widget());
ui.add_space(8.0); ui.add_space(8.0);
scroll_area().show(ui, |ui| { scroll_area().show(ui, |ui| {
self.show_accounts_mobile(ui); self.show_accounts_mobile(ui);
@@ -98,84 +97,73 @@ impl<'a> AccountManagementView<'a> {
.response .response
} }
fn buttons_widget(&mut self) -> impl egui::Widget + '_ { fn top_section_buttons_widget(&mut self) -> impl egui::Widget + '_ {
|ui: &mut egui::Ui| { |ui: &mut egui::Ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
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::left_to_right(egui::Align::Center), 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| { |ui| {
if ui.add(add_account_button()).clicked() { if ui.add(add_account_button()).clicked() {
// TODO: route to AccountLoginView // 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 .response
} }
} }
} }
fn mobile_account_card_ui( fn account_card_ui() -> fn(
) -> fn(ui: &mut egui::Ui, preview: SimpleProfilePreview, edit_mode: bool) -> bool { ui: &mut egui::Ui,
|ui, preview, edit_mode| { preview: SimpleProfilePreview,
let mut should_remove = false; width: f32,
is_selected: bool,
) -> Option<ProfilePreviewOp> {
|ui, preview, width, is_selected| {
let mut op: Option<ProfilePreviewOp> = None;
ui.add_sized( ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| {
Vec2::new(ui.available_width(), 50.0), Frame::none()
|ui: &mut egui::Ui| { .show(ui, |ui| {
Frame::none() ui.horizontal(|ui| {
.show(ui, |ui| { ui.add(preview);
ui.horizontal(|ui| {
ui.add(preview); ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
if edit_mode { if is_selected {
ui.with_layout(Layout::right_to_left(Align::Center), |ui| { ui.add(selected_widget());
should_remove = } else {
ui.add(delete_button(ui.visuals().dark_mode)).clicked(); 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 .response
}); });
should_remove ui.add_space(16.0);
op
} }
} }
@@ -216,24 +204,55 @@ fn scroll_area() -> ScrollArea {
.auto_shrink([false; 2]) .auto_shrink([false; 2])
} }
static PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
fn add_account_button() -> Button<'static> { 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> { fn sign_out_button(ui: &egui::Ui) -> egui::Button<'static> {
Button::new("Edit").min_size(Vec2::new(0.0, 32.0)) 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> { fn switch_button(dark_mode: bool) -> egui::Button<'static> {
Button::new("Done").min_size(Vec2::new(0.0, 32.0)) let _ = dark_mode;
egui::Button::new("Switch").min_size(Vec2::new(76.0, 32.0))
} }
fn delete_button(_dark_mode: bool) -> egui::Button<'static> { fn selected_widget() -> impl egui::Widget {
let img_data = egui::include_image!("../../assets/icons/delete_icon_4x.png"); |ui: &mut egui::Ui| {
Frame::none()
egui::Button::image(egui::Image::new(img_data).max_width(30.0)).frame(true) .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> { pub struct AccountSelectionWidget<'a> {
account_manager: &'a mut AccountManager, account_manager: &'a mut AccountManager,
simple_preview_controller: SimpleProfilePreviewController<'a>, simple_preview_controller: SimpleProfilePreviewController<'a>,

View File

@@ -12,7 +12,7 @@ pub enum GlobalPopupType {
AccountManagement, AccountManagement,
} }
static ACCOUNT_MANAGEMENT_TITLE: &str = "Account Management"; static ACCOUNT_MANAGEMENT_TITLE: &str = "Manage accounts";
impl GlobalPopupType { impl GlobalPopupType {
pub fn title(&self) -> &'static str { pub fn title(&self) -> &'static str {

View File

@@ -4,4 +4,4 @@ mod profile_preview_controller;
pub use picture::ProfilePic; pub use picture::ProfilePic;
pub use preview::ProfilePreview; pub use preview::ProfilePreview;
pub use profile_preview_controller::SimpleProfilePreviewController; pub use profile_preview_controller::{ProfilePreviewOp, SimpleProfilePreviewController};

View File

@@ -9,6 +9,12 @@ pub struct SimpleProfilePreviewController<'a> {
img_cache: &'a mut ImageCache, img_cache: &'a mut ImageCache,
} }
#[derive(Debug)]
pub enum ProfilePreviewOp {
RemoveAccount,
SwitchTo,
}
impl<'a> SimpleProfilePreviewController<'a> { impl<'a> SimpleProfilePreviewController<'a> {
pub fn new(ndb: &'a Ndb, img_cache: &'a mut ImageCache) -> Self { pub fn new(ndb: &'a Ndb, img_cache: &'a mut ImageCache) -> Self {
SimpleProfilePreviewController { ndb, img_cache } SimpleProfilePreviewController { ndb, img_cache }
@@ -16,17 +22,19 @@ impl<'a> SimpleProfilePreviewController<'a> {
pub fn set_profile_previews( pub fn set_profile_previews(
&mut self, &mut self,
account_manager: &AccountManager, account_manager: &mut AccountManager,
ui: &mut egui::Ui, ui: &mut egui::Ui,
edit_mode: bool,
add_preview_ui: fn( add_preview_ui: fn(
ui: &mut egui::Ui, ui: &mut egui::Ui,
preview: SimpleProfilePreview, preview: SimpleProfilePreview,
edit_mode: bool, width: f32,
) -> bool, is_selected: bool,
) -> Option<ProfilePreviewOp>,
) -> Option<Vec<usize>> { ) -> Option<Vec<usize>> {
let mut to_remove: Option<Vec<usize>> = None; let mut to_remove: Option<Vec<usize>> = None;
let width = ui.available_width();
for i in 0..account_manager.num_accounts() { for i in 0..account_manager.num_accounts() {
if let Some(account) = account_manager.get_account(i) { if let Some(account) = account_manager.get_account(i) {
if let Ok(txn) = Transaction::new(self.ndb) { if let Ok(txn) = Transaction::new(self.ndb) {
@@ -37,11 +45,24 @@ impl<'a> SimpleProfilePreviewController<'a> {
if let Ok(profile) = profile { if let Ok(profile) = profile {
let preview = SimpleProfilePreview::new(&profile, self.img_cache); let preview = SimpleProfilePreview::new(&profile, self.img_cache);
if add_preview_ui(ui, preview, edit_mode) { let is_selected = if let Some(selected) =
if to_remove.is_none() { account_manager.get_currently_selected_account()
to_remove = Some(Vec::new()); {
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);
} }
}; };
} }