account_management.rs (8024B)
1 use crate::colors::PINK; 2 use crate::{ 3 account_manager::AccountManager, 4 app_style::NotedeckTextStyle, 5 ui::{profile_preview_controller, Preview, PreviewConfig, View}, 6 Damus, 7 }; 8 use egui::{Align, Button, Frame, Image, Layout, Response, RichText, ScrollArea, Vec2}; 9 10 use super::profile::preview::SimpleProfilePreview; 11 use super::profile::ProfilePreviewOp; 12 13 pub struct AccountManagementView {} 14 15 impl AccountManagementView { 16 pub fn ui(app: &mut Damus, ui: &mut egui::Ui) -> Option<Response> { 17 if app.is_mobile() { 18 AccountManagementView::show_mobile(app, ui); 19 None 20 } else { 21 Some(AccountManagementView::show(app, ui)) 22 } 23 } 24 25 fn show(app: &mut Damus, ui: &mut egui::Ui) -> Response { 26 Frame::none() 27 .outer_margin(24.0) 28 .show(ui, |ui| { 29 Self::top_section_buttons_widget(ui); 30 ui.add_space(8.0); 31 scroll_area().show(ui, |ui| { 32 Self::show_accounts(app, ui); 33 }); 34 }) 35 .response 36 } 37 38 fn show_accounts(app: &mut Damus, ui: &mut egui::Ui) { 39 let maybe_remove = 40 profile_preview_controller::set_profile_previews(app, ui, account_card_ui()); 41 42 Self::maybe_remove_accounts(&mut app.account_manager, maybe_remove); 43 } 44 45 fn show_accounts_mobile(app: &mut Damus, ui: &mut egui::Ui) { 46 ui.allocate_ui_with_layout( 47 Vec2::new(ui.available_size_before_wrap().x, 32.0), 48 Layout::top_down(egui::Align::Min), 49 |ui| { 50 // create all account 'cards' and get the indicies the user requested to remove 51 let maybe_remove = profile_preview_controller::set_profile_previews( 52 app, 53 ui, 54 account_card_ui(), // closure for creating an account 'card' 55 ); 56 57 // remove all account indicies user requested 58 Self::maybe_remove_accounts(&mut app.account_manager, maybe_remove); 59 }, 60 ); 61 } 62 63 fn maybe_remove_accounts(manager: &mut AccountManager, account_indices: Option<Vec<usize>>) { 64 if let Some(to_remove) = account_indices { 65 to_remove 66 .iter() 67 .for_each(|index| manager.remove_account(*index)); 68 } 69 } 70 71 fn show_mobile(app: &mut Damus, ui: &mut egui::Ui) { 72 mobile_title(ui); 73 Self::top_section_buttons_widget(ui); 74 75 ui.add_space(8.0); 76 scroll_area().show(ui, |ui| Self::show_accounts_mobile(app, ui)); 77 } 78 79 fn top_section_buttons_widget(ui: &mut egui::Ui) -> egui::Response { 80 ui.horizontal(|ui| { 81 ui.allocate_ui_with_layout( 82 Vec2::new(ui.available_size_before_wrap().x, 32.0), 83 Layout::left_to_right(egui::Align::Center), 84 |ui| { 85 if ui.add(add_account_button()).clicked() { 86 // TODO: route to AccountLoginView 87 } 88 }, 89 ); 90 91 // UNCOMMENT FOR LOGOUTALL BUTTON 92 // ui.allocate_ui_with_layout( 93 // Vec2::new(ui.available_size_before_wrap().x, 32.0), 94 // Layout::right_to_left(egui::Align::Center), 95 // |ui| { 96 // if ui.add(logout_all_button()).clicked() { 97 // for index in (0..self.account_manager.num_accounts()).rev() { 98 // self.account_manager.remove_account(index); 99 // } 100 // } 101 // }, 102 // ); 103 }) 104 .response 105 } 106 } 107 108 fn account_card_ui() -> fn( 109 ui: &mut egui::Ui, 110 preview: SimpleProfilePreview, 111 width: f32, 112 is_selected: bool, 113 ) -> Option<ProfilePreviewOp> { 114 |ui, preview, width, is_selected| { 115 let mut op: Option<ProfilePreviewOp> = None; 116 117 ui.add_sized(Vec2::new(width, 50.0), |ui: &mut egui::Ui| { 118 Frame::none() 119 .show(ui, |ui| { 120 ui.horizontal(|ui| { 121 ui.add(preview); 122 123 ui.with_layout(Layout::right_to_left(Align::Center), |ui| { 124 if is_selected { 125 ui.add(selected_widget()); 126 } else { 127 if ui 128 .add(switch_button(ui.style().visuals.dark_mode)) 129 .clicked() 130 { 131 op = Some(ProfilePreviewOp::SwitchTo); 132 } 133 if ui.add(sign_out_button(ui)).clicked() { 134 op = Some(ProfilePreviewOp::RemoveAccount) 135 } 136 } 137 }); 138 }); 139 }) 140 .response 141 }); 142 ui.add_space(16.0); 143 op 144 } 145 } 146 147 fn mobile_title(ui: &mut egui::Ui) -> egui::Response { 148 ui.vertical_centered(|ui| { 149 ui.label( 150 RichText::new("Account Management") 151 .text_style(NotedeckTextStyle::Heading2.text_style()) 152 .strong(), 153 ); 154 }) 155 .response 156 } 157 158 fn scroll_area() -> ScrollArea { 159 egui::ScrollArea::vertical() 160 .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden) 161 .auto_shrink([false; 2]) 162 } 163 164 fn add_account_button() -> Button<'static> { 165 let img_data = egui::include_image!("../../assets/icons/add_account_icon_4x.png"); 166 let img = Image::new(img_data).fit_to_exact_size(Vec2::new(48.0, 48.0)); 167 Button::image_and_text( 168 img, 169 RichText::new(" Add account") 170 .size(16.0) 171 // TODO: this color should not be hard coded. Find some way to add it to the visuals 172 .color(PINK), 173 ) 174 .frame(false) 175 } 176 177 fn sign_out_button(ui: &egui::Ui) -> egui::Button<'static> { 178 let img_data = egui::include_image!("../../assets/icons/signout_icon_4x.png"); 179 let img = Image::new(img_data).fit_to_exact_size(Vec2::new(16.0, 16.0)); 180 181 egui::Button::image_and_text( 182 img, 183 RichText::new("Sign out").color(ui.visuals().noninteractive().fg_stroke.color), 184 ) 185 .frame(false) 186 } 187 188 fn switch_button(dark_mode: bool) -> egui::Button<'static> { 189 let _ = dark_mode; 190 191 egui::Button::new("Switch").min_size(Vec2::new(76.0, 32.0)) 192 } 193 194 fn selected_widget() -> impl egui::Widget { 195 |ui: &mut egui::Ui| { 196 Frame::none() 197 .show(ui, |ui| { 198 ui.label(RichText::new("Selected").size(13.0).color(PINK)); 199 let img_data = egui::include_image!("../../assets/icons/select_icon_3x.png"); 200 let img = Image::new(img_data).max_size(Vec2::new(16.0, 16.0)); 201 ui.add(img); 202 }) 203 .response 204 } 205 } 206 207 // fn logout_all_button() -> egui::Button<'static> { 208 // egui::Button::new("Logout all") 209 // } 210 211 // PREVIEWS 212 213 mod preview { 214 215 use super::*; 216 use crate::test_data; 217 218 pub struct AccountManagementPreview { 219 is_mobile: bool, 220 app: Damus, 221 } 222 223 impl AccountManagementPreview { 224 fn new(is_mobile: bool) -> Self { 225 let app = test_data::test_app(is_mobile); 226 227 AccountManagementPreview { is_mobile, app } 228 } 229 } 230 231 impl View for AccountManagementPreview { 232 fn ui(&mut self, ui: &mut egui::Ui) { 233 ui.add_space(24.0); 234 if self.is_mobile { 235 AccountManagementView::show_mobile(&mut self.app, ui); 236 } else { 237 AccountManagementView::show(&mut self.app, ui); 238 } 239 } 240 } 241 242 impl Preview for AccountManagementView { 243 type Prev = AccountManagementPreview; 244 245 fn preview(cfg: PreviewConfig) -> Self::Prev { 246 AccountManagementPreview::new(cfg.is_mobile) 247 } 248 } 249 }