notedeck

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

settings.rs (20130B)


      1 use egui::{vec2, Button, Color32, ComboBox, Frame, Margin, RichText, ThemePreference};
      2 use notedeck::{tr, Images, LanguageIdentifier, Localization, NotedeckTextStyle, ThemeHandler};
      3 use notedeck_ui::NoteOptions;
      4 use strum::Display;
      5 
      6 use crate::{nav::RouterAction, Damus, Route};
      7 
      8 #[derive(Clone, Copy, PartialEq, Eq, Display)]
      9 pub enum ShowNoteClientOptions {
     10     Hide,
     11     Top,
     12     Bottom,
     13 }
     14 
     15 pub enum SettingsAction {
     16     SetZoom(f32),
     17     SetTheme(ThemePreference),
     18     SetShowNoteClient(ShowNoteClientOptions),
     19     SetLocale(LanguageIdentifier),
     20     OpenRelays,
     21     OpenCacheFolder,
     22     ClearCacheFolder,
     23 }
     24 
     25 impl SettingsAction {
     26     pub fn process_settings_action<'a>(
     27         self,
     28         app: &mut Damus,
     29         theme_handler: &'a mut ThemeHandler,
     30         i18n: &'a mut Localization,
     31         img_cache: &mut Images,
     32         ctx: &egui::Context,
     33     ) -> Option<RouterAction> {
     34         let mut route_action: Option<RouterAction> = None;
     35 
     36         match self {
     37             SettingsAction::OpenRelays => {
     38                 route_action = Some(RouterAction::route_to(Route::Relays));
     39             }
     40             SettingsAction::SetZoom(zoom_level) => {
     41                 ctx.set_zoom_factor(zoom_level);
     42             }
     43             SettingsAction::SetShowNoteClient(newvalue) => match newvalue {
     44                 ShowNoteClientOptions::Hide => {
     45                     app.note_options.set(NoteOptions::ShowNoteClientTop, false);
     46                     app.note_options
     47                         .set(NoteOptions::ShowNoteClientBottom, false);
     48                 }
     49                 ShowNoteClientOptions::Bottom => {
     50                     app.note_options.set(NoteOptions::ShowNoteClientTop, false);
     51                     app.note_options
     52                         .set(NoteOptions::ShowNoteClientBottom, true);
     53                 }
     54                 ShowNoteClientOptions::Top => {
     55                     app.note_options.set(NoteOptions::ShowNoteClientTop, true);
     56                     app.note_options
     57                         .set(NoteOptions::ShowNoteClientBottom, false);
     58                 }
     59             },
     60             SettingsAction::SetTheme(theme) => {
     61                 ctx.options_mut(|o| {
     62                     o.theme_preference = theme;
     63                 });
     64                 theme_handler.save(theme);
     65             }
     66             SettingsAction::SetLocale(language) => {
     67                 _ = i18n.set_locale(language);
     68             }
     69             SettingsAction::OpenCacheFolder => {
     70                 use opener;
     71                 let _ = opener::open(img_cache.base_path.clone());
     72             }
     73             SettingsAction::ClearCacheFolder => {
     74                 let _ = img_cache.clear_folder_contents();
     75             }
     76         }
     77         route_action
     78     }
     79 }
     80 
     81 pub struct SettingsView<'a> {
     82     theme: &'a mut String,
     83     selected_language: &'a mut String,
     84     show_note_client: &'a mut ShowNoteClientOptions,
     85     i18n: &'a mut Localization,
     86     img_cache: &'a mut Images,
     87 }
     88 
     89 impl<'a> SettingsView<'a> {
     90     pub fn new(
     91         img_cache: &'a mut Images,
     92         selected_language: &'a mut String,
     93         theme: &'a mut String,
     94         show_note_client: &'a mut ShowNoteClientOptions,
     95         i18n: &'a mut Localization,
     96     ) -> Self {
     97         Self {
     98             show_note_client,
     99             theme,
    100             img_cache,
    101             selected_language,
    102             i18n,
    103         }
    104     }
    105 
    106     pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<SettingsAction> {
    107         let id = ui.id();
    108         let mut action = None;
    109 
    110         Frame::default()
    111             .inner_margin(Margin::symmetric(10, 10))
    112             .show(ui, |ui| {
    113                 Frame::group(ui.style())
    114                     .fill(ui.style().visuals.widgets.open.bg_fill)
    115                     .inner_margin(10.0)
    116                     .show(ui, |ui| {
    117                         ui.vertical(|ui| {
    118                             ui.label(
    119                                 RichText::new(tr!(
    120                                     self.i18n,
    121                                     "Appearance",
    122                                     "Label for appearance settings section"
    123                                 ))
    124                                 .text_style(NotedeckTextStyle::Body.text_style()),
    125                             );
    126                             ui.separator();
    127                             ui.spacing_mut().item_spacing = vec2(10.0, 10.0);
    128 
    129                             let current_zoom = ui.ctx().zoom_factor();
    130 
    131                             ui.horizontal(|ui| {
    132                                 ui.label(
    133                                     RichText::new(tr!(
    134                                         self.i18n,
    135                                         "Zoom Level:",
    136                                         "Label for zoom level, Appearance settings section"
    137                                     ))
    138                                     .text_style(NotedeckTextStyle::Small.text_style()),
    139                                 );
    140 
    141                                 if ui
    142                                     .button(
    143                                         RichText::new("-")
    144                                             .text_style(NotedeckTextStyle::Small.text_style()),
    145                                     )
    146                                     .clicked()
    147                                 {
    148                                     let new_zoom = (current_zoom - 0.1).max(0.1);
    149                                     action = Some(SettingsAction::SetZoom(new_zoom));
    150                                 };
    151 
    152                                 ui.label(
    153                                     RichText::new(format!("{:.0}%", current_zoom * 100.0))
    154                                         .text_style(NotedeckTextStyle::Small.text_style()),
    155                                 );
    156 
    157                                 if ui
    158                                     .button(
    159                                         RichText::new("+")
    160                                             .text_style(NotedeckTextStyle::Small.text_style()),
    161                                     )
    162                                     .clicked()
    163                                 {
    164                                     let new_zoom = (current_zoom + 0.1).min(10.0);
    165                                     action = Some(SettingsAction::SetZoom(new_zoom));
    166                                 };
    167 
    168                                 if ui
    169                                     .button(
    170                                         RichText::new(tr!(
    171                                             self.i18n,
    172                                             "Reset",
    173                                             "Label for reset zoom level, Appearance settings section"
    174                                         ))
    175                                         .text_style(NotedeckTextStyle::Small.text_style()),
    176                                     )
    177                                     .clicked()
    178                                 {
    179                                     action = Some(SettingsAction::SetZoom(1.0));
    180                                 }
    181                             });
    182 
    183                             ui.horizontal(|ui| {
    184                                 ui.label(
    185                                     RichText::new(tr!(
    186                                             self.i18n,
    187                                             "Language:",
    188                                             "Label for language, Appearance settings section"
    189                                         ))
    190                                         .text_style(NotedeckTextStyle::Small.text_style()),
    191                                 );
    192                                 ComboBox::from_label("")
    193                                     .selected_text(self.selected_language.to_owned())
    194                                     .show_ui(ui, |ui| {
    195                                         for lang in self.i18n.get_available_locales() {
    196                                             if ui
    197                                                 .selectable_value(
    198                                                     self.selected_language,
    199                                                     lang.to_string(),
    200                                                     lang.to_string(),
    201                                                 )
    202                                                 .clicked()
    203                                             {
    204                                                 action =
    205                                                     Some(SettingsAction::SetLocale(lang.to_owned()))
    206                                             }
    207                                         }
    208                                     })
    209                             });
    210 
    211                             ui.horizontal(|ui| {
    212                                 ui.label(
    213                                     RichText::new(tr!(
    214                                             self.i18n,
    215                                             "Theme:",
    216                                             "Label for theme, Appearance settings section"
    217                                         ))
    218                                         .text_style(NotedeckTextStyle::Small.text_style()),
    219                                 );
    220                                 if ui
    221                                     .selectable_value(
    222                                         self.theme,
    223                                         "Light".into(),
    224                                         RichText::new(tr!(
    225                                             self.i18n,
    226                                             "Light",
    227                                             "Label for Theme Light, Appearance settings section"
    228                                         ))
    229                                             .text_style(NotedeckTextStyle::Small.text_style()),
    230                                     )
    231                                     .clicked()
    232                                 {
    233                                     action = Some(SettingsAction::SetTheme(ThemePreference::Light));
    234                                 }
    235                                 if ui
    236                                     .selectable_value(
    237                                         self.theme,
    238                                         "Dark".into(),
    239                                         RichText::new(tr!(
    240                                             self.i18n,
    241                                             "Dark",
    242                                             "Label for Theme Dark, Appearance settings section"
    243                                         ))
    244                                             .text_style(NotedeckTextStyle::Small.text_style()),
    245                                     )
    246                                     .clicked()
    247                                 {
    248                                     action = Some(SettingsAction::SetTheme(ThemePreference::Dark));
    249                                 }
    250                             });
    251                         });
    252                     });
    253 
    254                 ui.add_space(5.0);
    255 
    256                 Frame::group(ui.style())
    257                     .fill(ui.style().visuals.widgets.open.bg_fill)
    258                     .inner_margin(10.0)
    259                     .show(ui, |ui| {
    260                         ui.label(
    261                             RichText::new(tr!(
    262                                             self.i18n,
    263                                             "Storage",
    264                                             "Label for storage settings section"
    265                                         ))
    266                                 .text_style(NotedeckTextStyle::Body.text_style()),
    267                         );
    268                         ui.separator();
    269 
    270                         ui.vertical(|ui| {
    271                             ui.spacing_mut().item_spacing = vec2(10.0, 10.0);
    272 
    273                             ui.horizontal_wrapped(|ui| {
    274                                 let static_imgs_size = self
    275                                     .img_cache
    276                                     .static_imgs
    277                                     .cache_size
    278                                     .lock()
    279                                     .unwrap();
    280 
    281                                 let gifs_size = self.img_cache.gifs.cache_size.lock().unwrap();
    282 
    283                                 ui.label(
    284                                     RichText::new(format!("{} {}",
    285                                         tr!(
    286                                             self.i18n,
    287                                             "Image cache size:",
    288                                             "Label for Image cache size, Storage settings section"
    289                                         ),
    290                                         format_size(
    291                                             [static_imgs_size, gifs_size]
    292                                                 .iter()
    293                                                 .fold(0_u64, |acc, cur| acc
    294                                                     + cur.unwrap_or_default())
    295                                         )
    296                                     ))
    297                                     .text_style(NotedeckTextStyle::Small.text_style()),
    298                                 );
    299 
    300                                 ui.end_row();
    301 
    302                                 if !notedeck::ui::is_compiled_as_mobile() &&
    303                                     ui.button(RichText::new(tr!(self.i18n, "View folder:", "Label for view folder button, Storage settings section"))
    304                                         .text_style(NotedeckTextStyle::Small.text_style())).clicked() {
    305                                     action = Some(SettingsAction::OpenCacheFolder);
    306                                 }
    307 
    308                                 let clearcache_resp = ui.button(
    309                                     RichText::new(tr!(
    310                                             self.i18n,
    311                                             "Clear cache",
    312                                             "Label for clear cache button, Storage settings section"
    313                                         ))
    314                                         .text_style(NotedeckTextStyle::Small.text_style())
    315                                         .color(Color32::LIGHT_RED),
    316                                 );
    317 
    318                                 let id_clearcache = id.with("clear_cache");
    319                                 if clearcache_resp.clicked() {
    320                                     ui.data_mut(|d| d.insert_temp(id_clearcache, true));
    321                                 }
    322 
    323                                 if ui.data_mut(|d| *d.get_temp_mut_or_default(id_clearcache)) {
    324                                     let mut confirm_pressed = false;
    325                                     clearcache_resp.show_tooltip_ui(|ui| {
    326                                         let confirm_resp = ui.button(tr!(
    327                                             self.i18n,
    328                                             "Confirm",
    329                                             "Label for confirm clear cache, Storage settings section"
    330                                         ));
    331                                         if confirm_resp.clicked() {
    332                                             confirm_pressed = true;
    333                                         }
    334 
    335                                         if confirm_resp.clicked() || ui.button(tr!(
    336                                             self.i18n,
    337                                             "Cancel",
    338                                             "Label for cancel clear cache, Storage settings section"
    339                                         )).clicked() {
    340                                             ui.data_mut(|d| d.insert_temp(id_clearcache, false));
    341                                         }
    342                                     });
    343 
    344                                     if confirm_pressed {
    345                                         action = Some(SettingsAction::ClearCacheFolder);
    346                                     } else if !confirm_pressed
    347                                         && clearcache_resp.clicked_elsewhere()
    348                                     {
    349                                         ui.data_mut(|d| d.insert_temp(id_clearcache, false));
    350                                     }
    351                                 };
    352                             });
    353                         });
    354                     });
    355 
    356                 ui.add_space(5.0);
    357 
    358                 Frame::group(ui.style())
    359                     .fill(ui.style().visuals.widgets.open.bg_fill)
    360                     .inner_margin(10.0)
    361                     .show(ui, |ui| {
    362                         ui.label(
    363                             RichText::new(tr!(
    364                                             self.i18n,
    365                                             "Others",
    366                                          "Label for others settings section"
    367                                         ))
    368                                 .text_style(NotedeckTextStyle::Body.text_style()),
    369                         );
    370                         ui.separator();
    371                         ui.vertical(|ui| {
    372                             ui.spacing_mut().item_spacing = vec2(10.0, 10.0);
    373 
    374                             ui.horizontal_wrapped(|ui| {
    375                                 ui.label(
    376                                     RichText::new(
    377                                     tr!(
    378                                             self.i18n,
    379                                             "Show source client",
    380                                             "Label for Show source client, others settings section"
    381                                         ))
    382                                         .text_style(NotedeckTextStyle::Small.text_style()),
    383                                 );
    384 
    385                                 for option in [
    386                                     ShowNoteClientOptions::Hide,
    387                                     ShowNoteClientOptions::Top,
    388                                     ShowNoteClientOptions::Bottom,
    389                                 ] {
    390                                     let label = option.clone().to_string();
    391 
    392                                     if ui
    393                                         .selectable_value(
    394                                             self.show_note_client,
    395                                             option,
    396                                             RichText::new(label)
    397                                                 .text_style(NotedeckTextStyle::Small.text_style()),
    398                                         )
    399                                         .changed()
    400                                     {
    401                                         action = Some(SettingsAction::SetShowNoteClient(option));
    402                                     }
    403                                 }
    404                             });
    405                         });
    406                     });
    407 
    408                 ui.add_space(10.0);
    409 
    410                 if ui
    411                     .add_sized(
    412                         [ui.available_width(), 30.0],
    413                         Button::new(
    414                             RichText::new(tr!(
    415                                             self.i18n,
    416                                             "Configure relays",
    417                                             "Label for configure relays, settings section"
    418                                         ))
    419                                 .text_style(NotedeckTextStyle::Small.text_style()),
    420                         ),
    421                     )
    422                     .clicked()
    423                 {
    424                     action = Some(SettingsAction::OpenRelays);
    425                 }
    426             });
    427 
    428         action
    429     }
    430 }
    431 
    432 pub fn format_size(size_bytes: u64) -> String {
    433     const KB: f64 = 1024.0;
    434     const MB: f64 = KB * 1024.0;
    435     const GB: f64 = MB * 1024.0;
    436 
    437     let size = size_bytes as f64;
    438 
    439     if size < KB {
    440         format!("{size:.0} Bytes")
    441     } else if size < MB {
    442         format!("{:.1} KB", size / KB)
    443     } else if size < GB {
    444         format!("{:.1} MB", size / MB)
    445     } else {
    446         format!("{:.2} GB", size / GB)
    447     }
    448 }