Skip to main content

cadmus_core/view/settings_editor/kinds/
general.rs

1//! Setting kinds for the General category.
2
3use super::{
4    InputSettingKind, SettingData, SettingIdentity, SettingKind, ToggleSettings, WidgetKind,
5};
6use crate::device::CURRENT_DEVICE;
7use crate::fl;
8use crate::i18n::I18nDisplay;
9use crate::settings::Settings;
10use crate::view::{Bus, EntryId, EntryKind, Event, ToggleEvent, ViewId};
11use anyhow::Error;
12use std::fs;
13
14/// Language and locale selection setting
15pub struct Locale;
16
17impl SettingKind for Locale {
18    fn identity(&self) -> SettingIdentity {
19        SettingIdentity::Locale
20    }
21
22    fn label(&self, _settings: &Settings) -> String {
23        fl!("settings-general-language")
24    }
25
26    fn fetch(&self, settings: &Settings) -> SettingData {
27        let current = settings.locale.as_ref().map(|l| l.to_string());
28        let display = current
29            .as_deref()
30            .unwrap_or(crate::i18n::DEFAULT_LOCALE)
31            .to_string();
32
33        let entries = crate::i18n::AVAILABLE_LOCALES
34            .iter()
35            .map(|&tag| {
36                let lang_id: Option<unic_langid::LanguageIdentifier> = tag.parse().ok();
37                EntryKind::RadioButton(
38                    tag.to_string(),
39                    EntryId::SetLocale(lang_id),
40                    current.as_deref() == Some(tag),
41                )
42            })
43            .collect::<Vec<_>>();
44
45        SettingData {
46            value: display,
47            widget: WidgetKind::SubMenu(entries),
48        }
49    }
50
51    fn handle(
52        &self,
53        evt: &Event,
54        settings: &mut Settings,
55        _bus: &mut Bus,
56    ) -> (Option<String>, bool) {
57        if let Event::Select(EntryId::SetLocale(locale)) = evt {
58            settings.locale = locale.clone();
59            crate::i18n::init(locale.as_ref());
60            let display = locale
61                .as_ref()
62                .map(|l| l.to_string())
63                .unwrap_or_else(|| crate::i18n::DEFAULT_LOCALE.to_string());
64            return (Some(display), true);
65        }
66        (None, false)
67    }
68}
69
70/// Keyboard layout selection setting
71pub struct KeyboardLayout;
72
73impl SettingKind for KeyboardLayout {
74    fn identity(&self) -> SettingIdentity {
75        SettingIdentity::KeyboardLayout
76    }
77
78    fn label(&self, _settings: &Settings) -> String {
79        fl!("settings-general-keyboard-layout")
80    }
81
82    fn fetch(&self, settings: &Settings) -> SettingData {
83        let current_layout = settings.keyboard_layout.clone();
84        let available_layouts = get_available_layouts().unwrap_or_default();
85
86        let entries = available_layouts
87            .iter()
88            .map(|layout| {
89                EntryKind::RadioButton(
90                    layout.clone(),
91                    EntryId::SetKeyboardLayout(layout.clone()),
92                    current_layout == *layout,
93                )
94            })
95            .collect::<Vec<_>>();
96
97        SettingData {
98            value: current_layout,
99            widget: WidgetKind::SubMenu(entries),
100        }
101    }
102
103    fn handle(
104        &self,
105        evt: &Event,
106        settings: &mut Settings,
107        _bus: &mut Bus,
108    ) -> (Option<String>, bool) {
109        if let Event::Select(EntryId::SetKeyboardLayout(layout)) = evt {
110            settings.keyboard_layout = layout.clone();
111            return (Some(layout.clone()), true);
112        }
113        (None, false)
114    }
115}
116
117/// Auto suspend timeout setting
118pub struct AutoSuspend;
119
120impl SettingKind for AutoSuspend {
121    fn identity(&self) -> SettingIdentity {
122        SettingIdentity::AutoSuspend
123    }
124
125    fn label(&self, _settings: &Settings) -> String {
126        fl!("settings-general-auto-suspend")
127    }
128
129    fn fetch(&self, settings: &Settings) -> SettingData {
130        let value = if settings.auto_suspend == 0.0 {
131            fl!("settings-general-never")
132        } else {
133            format!("{:.1}", settings.auto_suspend)
134        };
135
136        SettingData {
137            value,
138            widget: WidgetKind::ActionLabel(Event::Select(EntryId::EditAutoSuspend)),
139        }
140    }
141
142    fn as_input_kind(&self) -> Option<&dyn InputSettingKind> {
143        Some(self)
144    }
145}
146
147impl InputSettingKind for AutoSuspend {
148    fn submit_view_id(&self) -> ViewId {
149        ViewId::AutoSuspendInput
150    }
151
152    fn open_entry_id(&self) -> EntryId {
153        EntryId::EditAutoSuspend
154    }
155
156    fn input_label(&self) -> String {
157        fl!("settings-general-auto-suspend-input")
158    }
159
160    fn input_max_chars(&self) -> usize {
161        10
162    }
163
164    fn current_text(&self, settings: &Settings) -> String {
165        if settings.auto_suspend == 0.0 {
166            "0".to_string()
167        } else {
168            format!("{:.1}", settings.auto_suspend)
169        }
170    }
171
172    fn apply_text(&self, text: &str, settings: &mut Settings) -> String {
173        if let Ok(value) = text.parse::<f32>() {
174            settings.auto_suspend = value;
175        }
176        if settings.auto_suspend == 0.0 {
177            fl!("settings-general-never")
178        } else {
179            format!("{:.1}", settings.auto_suspend)
180        }
181    }
182}
183
184/// Auto power off timeout setting
185pub struct AutoPowerOff;
186
187impl SettingKind for AutoPowerOff {
188    fn identity(&self) -> SettingIdentity {
189        SettingIdentity::AutoPowerOff
190    }
191
192    fn label(&self, _settings: &Settings) -> String {
193        fl!("settings-general-auto-power-off")
194    }
195
196    fn fetch(&self, settings: &Settings) -> SettingData {
197        let value = if settings.auto_power_off == 0.0 {
198            fl!("settings-general-never")
199        } else {
200            format!("{:.1}", settings.auto_power_off)
201        };
202
203        SettingData {
204            value,
205            widget: WidgetKind::ActionLabel(Event::Select(EntryId::EditAutoPowerOff)),
206        }
207    }
208
209    fn as_input_kind(&self) -> Option<&dyn InputSettingKind> {
210        Some(self)
211    }
212}
213
214impl InputSettingKind for AutoPowerOff {
215    fn submit_view_id(&self) -> ViewId {
216        ViewId::AutoPowerOffInput
217    }
218
219    fn open_entry_id(&self) -> EntryId {
220        EntryId::EditAutoPowerOff
221    }
222
223    fn input_label(&self) -> String {
224        fl!("settings-general-auto-power-off-input")
225    }
226
227    fn input_max_chars(&self) -> usize {
228        10
229    }
230
231    fn current_text(&self, settings: &Settings) -> String {
232        if settings.auto_power_off == 0.0 {
233            "0".to_string()
234        } else {
235            format!("{:.1}", settings.auto_power_off)
236        }
237    }
238
239    fn apply_text(&self, text: &str, settings: &mut Settings) -> String {
240        if let Ok(value) = text.parse::<f32>() {
241            settings.auto_power_off = value;
242        }
243        if settings.auto_power_off == 0.0 {
244            fl!("settings-general-never")
245        } else {
246            format!("{:.1}", settings.auto_power_off)
247        }
248    }
249}
250
251/// Sleep cover enable/disable toggle setting
252pub struct SleepCover;
253
254impl SettingKind for SleepCover {
255    fn identity(&self) -> SettingIdentity {
256        SettingIdentity::SleepCover
257    }
258
259    fn label(&self, _settings: &Settings) -> String {
260        fl!("settings-general-enable-sleep-cover")
261    }
262
263    fn fetch(&self, settings: &Settings) -> SettingData {
264        SettingData {
265            value: settings.sleep_cover.to_string(),
266            widget: WidgetKind::Toggle {
267                left_label: fl!("settings-general-toggle-on"),
268                right_label: fl!("settings-general-toggle-off"),
269                enabled: settings.sleep_cover,
270                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::SleepCover)),
271            },
272        }
273    }
274
275    fn handle(
276        &self,
277        evt: &Event,
278        settings: &mut Settings,
279        _bus: &mut Bus,
280    ) -> (Option<String>, bool) {
281        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::SleepCover)) = evt {
282            settings.sleep_cover = !settings.sleep_cover;
283            return (Some(settings.sleep_cover.to_string()), true);
284        }
285        (None, false)
286    }
287}
288
289/// Auto share enable/disable toggle setting
290pub struct AutoShare;
291
292impl SettingKind for AutoShare {
293    fn identity(&self) -> SettingIdentity {
294        SettingIdentity::AutoShare
295    }
296
297    fn label(&self, _settings: &Settings) -> String {
298        fl!("settings-general-enable-auto-share")
299    }
300
301    fn fetch(&self, settings: &Settings) -> SettingData {
302        SettingData {
303            value: settings.auto_share.to_string(),
304            widget: WidgetKind::Toggle {
305                left_label: fl!("settings-general-toggle-on"),
306                right_label: fl!("settings-general-toggle-off"),
307                enabled: settings.auto_share,
308                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::AutoShare)),
309            },
310        }
311    }
312
313    fn handle(
314        &self,
315        evt: &Event,
316        settings: &mut Settings,
317        _bus: &mut Bus,
318    ) -> (Option<String>, bool) {
319        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::AutoShare)) = evt {
320            settings.auto_share = !settings.auto_share;
321            return (Some(settings.auto_share.to_string()), true);
322        }
323        (None, false)
324    }
325}
326
327/// Auto time sync enable/disable toggle setting
328pub struct AutoTime;
329
330impl SettingKind for AutoTime {
331    fn identity(&self) -> SettingIdentity {
332        SettingIdentity::AutoTime
333    }
334
335    fn label(&self, _settings: &Settings) -> String {
336        fl!("settings-general-auto-time")
337    }
338
339    fn fetch(&self, settings: &Settings) -> SettingData {
340        SettingData {
341            value: settings.auto_time.to_string(),
342            widget: WidgetKind::Toggle {
343                left_label: fl!("settings-general-toggle-on"),
344                right_label: fl!("settings-general-toggle-off"),
345                enabled: settings.auto_time,
346                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::AutoTime)),
347            },
348        }
349    }
350
351    fn handle(
352        &self,
353        evt: &Event,
354        settings: &mut Settings,
355        _bus: &mut Bus,
356    ) -> (Option<String>, bool) {
357        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::AutoTime)) = evt {
358            settings.auto_time = !settings.auto_time;
359            return (Some(settings.auto_time.to_string()), true);
360        }
361        (None, false)
362    }
363}
364
365/// Button scheme (natural/inverted) toggle setting
366pub struct ButtonScheme;
367
368impl SettingKind for ButtonScheme {
369    fn identity(&self) -> SettingIdentity {
370        SettingIdentity::ButtonScheme
371    }
372
373    fn label(&self, _settings: &Settings) -> String {
374        fl!("settings-general-button-scheme")
375    }
376
377    fn fetch(&self, settings: &Settings) -> SettingData {
378        let enabled = settings.button_scheme == crate::settings::ButtonScheme::Natural;
379        SettingData {
380            value: settings.button_scheme.to_i18n_string(),
381            widget: WidgetKind::Toggle {
382                left_label: crate::settings::ButtonScheme::Natural.to_i18n_string(),
383                right_label: crate::settings::ButtonScheme::Inverted.to_i18n_string(),
384                enabled,
385                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::ButtonScheme)),
386            },
387        }
388    }
389
390    fn handle(
391        &self,
392        evt: &Event,
393        settings: &mut Settings,
394        bus: &mut Bus,
395    ) -> (Option<String>, bool) {
396        let new_scheme = match evt {
397            Event::Toggle(ToggleEvent::Setting(ToggleSettings::ButtonScheme)) => {
398                match settings.button_scheme {
399                    crate::settings::ButtonScheme::Natural => {
400                        Some(crate::settings::ButtonScheme::Inverted)
401                    }
402                    crate::settings::ButtonScheme::Inverted => {
403                        Some(crate::settings::ButtonScheme::Natural)
404                    }
405                }
406            }
407            Event::Select(EntryId::SetButtonScheme(scheme)) => Some(*scheme),
408            _ => None,
409        };
410
411        if let Some(scheme) = new_scheme {
412            settings.button_scheme = scheme;
413            bus.push_back(Event::Select(EntryId::SetButtonScheme(scheme)));
414            return (Some(settings.button_scheme.to_i18n_string()), true);
415        }
416        (None, false)
417    }
418}
419
420/// Settings retention count setting
421pub struct SettingsRetention;
422
423impl SettingKind for SettingsRetention {
424    fn identity(&self) -> SettingIdentity {
425        SettingIdentity::SettingsRetention
426    }
427
428    fn label(&self, _settings: &Settings) -> String {
429        fl!("settings-general-settings-retention")
430    }
431
432    fn fetch(&self, settings: &Settings) -> SettingData {
433        SettingData {
434            value: settings.settings_retention.to_string(),
435            widget: WidgetKind::ActionLabel(Event::Select(EntryId::EditSettingsRetention)),
436        }
437    }
438
439    fn as_input_kind(&self) -> Option<&dyn InputSettingKind> {
440        Some(self)
441    }
442}
443
444impl InputSettingKind for SettingsRetention {
445    fn submit_view_id(&self) -> ViewId {
446        ViewId::SettingsRetentionInput
447    }
448
449    fn open_entry_id(&self) -> EntryId {
450        EntryId::EditSettingsRetention
451    }
452
453    fn input_label(&self) -> String {
454        fl!("settings-general-settings-retention")
455    }
456
457    fn input_max_chars(&self) -> usize {
458        3
459    }
460
461    fn current_text(&self, settings: &Settings) -> String {
462        settings.settings_retention.to_string()
463    }
464
465    fn apply_text(&self, text: &str, settings: &mut Settings) -> String {
466        if let Ok(value) = text.parse::<usize>() {
467            settings.settings_retention = value;
468        }
469        settings.settings_retention.to_string()
470    }
471}
472
473/// Scans the keyboard-layouts directory for available keyboard layouts
474fn get_available_layouts() -> Result<Vec<String>, Error> {
475    let layouts_dir = CURRENT_DEVICE.install_path("keyboard-layouts");
476    let mut layouts = Vec::new();
477
478    if layouts_dir.exists() {
479        for entry in fs::read_dir(&layouts_dir)? {
480            let entry = entry?;
481            let path = entry.path();
482
483            if path.extension().and_then(|s| s.to_str()) == Some("json") {
484                if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
485                    let layout_name = stem
486                        .chars()
487                        .enumerate()
488                        .map(|(i, c)| {
489                            if i == 0 {
490                                c.to_uppercase().collect::<String>()
491                            } else {
492                                c.to_string()
493                            }
494                        })
495                        .collect::<String>();
496                    layouts.push(layout_name);
497                }
498            }
499        }
500    }
501
502    layouts.sort();
503    Ok(layouts)
504}
505
506#[cfg(test)]
507mod tests {
508    use super::*;
509    use crate::settings::Settings;
510    use crate::view::settings_editor::kinds::{InputSettingKind, ToggleSettings};
511    use crate::view::{Bus, EntryId, Event, ToggleEvent};
512    use std::collections::VecDeque;
513
514    mod locale {
515        use super::*;
516
517        #[test]
518        fn handle_set_locale_updates_settings() {
519            let setting = Locale;
520            let mut settings = Settings::default();
521            let mut bus: Bus = VecDeque::new();
522            let locale: Option<unic_langid::LanguageIdentifier> = Some("de-DE".parse().unwrap());
523            let event = Event::Select(EntryId::SetLocale(locale.clone()));
524
525            let result = setting.handle(&event, &mut settings, &mut bus);
526
527            assert!(result.0.is_some());
528            assert_eq!(result.0.unwrap(), "de-DE");
529            assert_eq!(settings.locale, locale);
530        }
531
532        #[test]
533        fn handle_returns_none_for_wrong_event() {
534            let setting = Locale;
535            let mut settings = Settings::default();
536            let mut bus: Bus = VecDeque::new();
537
538            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
539
540            assert!(result.0.is_none());
541        }
542    }
543
544    mod keyboard_layout {
545        use super::*;
546
547        #[test]
548        fn handle_set_layout_updates_settings() {
549            let setting = KeyboardLayout;
550            let mut settings = Settings::default();
551            let mut bus: Bus = VecDeque::new();
552            let event = Event::Select(EntryId::SetKeyboardLayout("German".to_string()));
553
554            let result = setting.handle(&event, &mut settings, &mut bus);
555
556            assert!(result.0.is_some());
557            assert_eq!(result.0.unwrap(), "German");
558            assert_eq!(settings.keyboard_layout, "German");
559        }
560
561        #[test]
562        fn handle_returns_none_for_wrong_event() {
563            let setting = KeyboardLayout;
564            let mut settings = Settings::default();
565            let mut bus: Bus = VecDeque::new();
566
567            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
568
569            assert!(result.0.is_none());
570        }
571    }
572
573    mod auto_suspend {
574        use super::*;
575
576        #[test]
577        fn apply_text_parses_and_updates() {
578            let setting = AutoSuspend;
579            let mut settings = Settings::default();
580
581            let display = setting.apply_text("60.0", &mut settings);
582
583            assert_eq!(display, "60.0");
584            assert_eq!(settings.auto_suspend, 60.0);
585        }
586
587        #[test]
588        fn apply_text_returns_never_for_zero() {
589            let setting = AutoSuspend;
590            let mut settings = Settings::default();
591
592            let display = setting.apply_text("0", &mut settings);
593
594            assert_eq!(display, "Never");
595            assert_eq!(settings.auto_suspend, 0.0);
596        }
597
598        #[test]
599        fn apply_text_ignores_invalid_input() {
600            let setting = AutoSuspend;
601            let mut settings = Settings {
602                auto_suspend: 30.0,
603                ..Default::default()
604            };
605
606            let display = setting.apply_text("invalid", &mut settings);
607
608            assert_eq!(settings.auto_suspend, 30.0);
609            assert_eq!(display, "30.0");
610        }
611    }
612
613    mod auto_power_off {
614        use super::*;
615
616        #[test]
617        fn apply_text_parses_and_updates() {
618            let setting = AutoPowerOff;
619            let mut settings = Settings::default();
620
621            let display = setting.apply_text("14.0", &mut settings);
622
623            assert_eq!(display, "14.0");
624            assert_eq!(settings.auto_power_off, 14.0);
625        }
626
627        #[test]
628        fn apply_text_returns_never_for_zero() {
629            let setting = AutoPowerOff;
630            let mut settings = Settings::default();
631
632            let display = setting.apply_text("0", &mut settings);
633
634            assert_eq!(display, "Never");
635            assert_eq!(settings.auto_power_off, 0.0);
636        }
637
638        #[test]
639        fn apply_text_ignores_invalid_input() {
640            let setting = AutoPowerOff;
641            let mut settings = Settings {
642                auto_power_off: 7.0,
643                ..Default::default()
644            };
645
646            let display = setting.apply_text("invalid", &mut settings);
647
648            assert_eq!(settings.auto_power_off, 7.0);
649            assert_eq!(display, "7.0");
650        }
651    }
652
653    mod sleep_cover {
654        use super::*;
655
656        #[test]
657        fn handle_toggle_event_toggles_value() {
658            let setting = SleepCover;
659            let mut settings = Settings {
660                sleep_cover: true,
661                ..Default::default()
662            };
663            let mut bus: Bus = VecDeque::new();
664            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::SleepCover));
665
666            let result = setting.handle(&event, &mut settings, &mut bus);
667
668            assert!(result.0.is_some());
669            assert_eq!(result.0.unwrap(), "false");
670            assert!(!settings.sleep_cover);
671        }
672
673        #[test]
674        fn handle_returns_none_for_wrong_event() {
675            let setting = SleepCover;
676            let mut settings = Settings::default();
677            let mut bus: Bus = VecDeque::new();
678
679            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
680
681            assert!(result.0.is_none());
682        }
683    }
684
685    mod auto_share {
686        use super::*;
687
688        #[test]
689        fn handle_toggle_event_toggles_value() {
690            let setting = AutoShare;
691            let mut settings = Settings {
692                auto_share: false,
693                ..Default::default()
694            };
695            let mut bus: Bus = VecDeque::new();
696            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::AutoShare));
697
698            let result = setting.handle(&event, &mut settings, &mut bus);
699
700            assert!(result.0.is_some());
701            assert_eq!(result.0.unwrap(), "true");
702            assert!(settings.auto_share);
703        }
704
705        #[test]
706        fn handle_returns_none_for_wrong_event() {
707            let setting = AutoShare;
708            let mut settings = Settings::default();
709            let mut bus: Bus = VecDeque::new();
710
711            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
712
713            assert!(result.0.is_none());
714        }
715    }
716
717    mod button_scheme {
718        use super::*;
719        use crate::settings::ButtonScheme;
720
721        #[test]
722        fn handle_toggle_event_switches_natural_to_inverted() {
723            let setting = ButtonScheme;
724            let mut settings = Settings {
725                button_scheme: ButtonScheme::Natural,
726                ..Default::default()
727            };
728            let mut bus: Bus = VecDeque::new();
729            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::ButtonScheme));
730
731            let result = setting.handle(&event, &mut settings, &mut bus);
732
733            assert_eq!(settings.button_scheme, ButtonScheme::Inverted);
734            assert_eq!(bus.len(), 1);
735            assert!(result.0.is_some());
736        }
737
738        #[test]
739        fn handle_toggle_event_switches_inverted_to_natural() {
740            let setting = ButtonScheme;
741            let mut settings = Settings {
742                button_scheme: ButtonScheme::Inverted,
743                ..Default::default()
744            };
745            let mut bus: Bus = VecDeque::new();
746            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::ButtonScheme));
747
748            let result = setting.handle(&event, &mut settings, &mut bus);
749
750            assert_eq!(settings.button_scheme, ButtonScheme::Natural);
751            assert_eq!(bus.len(), 1);
752            assert!(result.0.is_some());
753        }
754
755        #[test]
756        fn handle_set_scheme_event_applies_directly() {
757            let setting = ButtonScheme;
758            let mut settings = Settings {
759                button_scheme: ButtonScheme::Natural,
760                ..Default::default()
761            };
762            let mut bus: Bus = VecDeque::new();
763            let event = Event::Select(EntryId::SetButtonScheme(ButtonScheme::Inverted));
764
765            let result = setting.handle(&event, &mut settings, &mut bus);
766
767            assert_eq!(settings.button_scheme, ButtonScheme::Inverted);
768            assert!(result.0.is_some());
769        }
770
771        #[test]
772        fn handle_returns_none_for_wrong_event() {
773            let setting = ButtonScheme;
774            let mut settings = Settings::default();
775            let mut bus: Bus = VecDeque::new();
776
777            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
778
779            assert!(result.0.is_none());
780        }
781    }
782
783    mod settings_retention {
784        use super::*;
785
786        #[test]
787        fn apply_text_parses_and_updates() {
788            let setting = SettingsRetention;
789            let mut settings = Settings::default();
790
791            let display = setting.apply_text("10", &mut settings);
792
793            assert_eq!(display, "10");
794            assert_eq!(settings.settings_retention, 10);
795        }
796
797        #[test]
798        fn apply_text_ignores_invalid_input() {
799            let setting = SettingsRetention;
800            let mut settings = Settings {
801                settings_retention: 3,
802                ..Default::default()
803            };
804
805            let display = setting.apply_text("invalid", &mut settings);
806
807            assert_eq!(settings.settings_retention, 3);
808            assert_eq!(display, "3");
809        }
810    }
811}