Skip to main content

cadmus_core/view/settings_editor/kinds/
import.rs

1//! Setting kinds for the Import category.
2
3use super::{SettingData, SettingIdentity, SettingKind, ToggleSettings, WidgetKind};
4use crate::fl;
5use crate::settings::{FileExtension, Settings};
6use crate::view::{Bus, EntryId, EntryKind, Event, ToggleEvent};
7
8/// Force full library re-import action setting.
9pub struct ForceFullImport;
10
11impl SettingKind for ForceFullImport {
12    fn identity(&self) -> SettingIdentity {
13        SettingIdentity::ForceFullImport
14    }
15
16    fn label(&self, _settings: &Settings) -> String {
17        fl!("settings-import-force-full-import")
18    }
19
20    fn fetch(&self, _settings: &Settings) -> SettingData {
21        SettingData {
22            value: fl!("settings-general-trigger"),
23            widget: WidgetKind::ActionLabel(Event::Select(EntryId::RequestForceImport)),
24        }
25    }
26
27    fn handle(
28        &self,
29        _evt: &Event,
30        _settings: &mut Settings,
31        _bus: &mut Bus,
32    ) -> (Option<String>, bool) {
33        (None, false)
34    }
35}
36
37/// Sync metadata toggle setting
38pub struct ImportSyncMetadata;
39
40impl SettingKind for ImportSyncMetadata {
41    fn identity(&self) -> SettingIdentity {
42        SettingIdentity::ImportSyncMetadata
43    }
44
45    fn label(&self, _settings: &Settings) -> String {
46        fl!("settings-import-sync-metadata")
47    }
48
49    fn fetch(&self, settings: &Settings) -> SettingData {
50        SettingData {
51            value: settings.import.sync_metadata.to_string(),
52            widget: WidgetKind::Toggle {
53                left_label: fl!("settings-general-toggle-on"),
54                right_label: fl!("settings-general-toggle-off"),
55                enabled: settings.import.sync_metadata,
56                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::ImportSyncMetadata)),
57            },
58        }
59    }
60
61    fn handle(
62        &self,
63        evt: &Event,
64        settings: &mut Settings,
65        _bus: &mut Bus,
66    ) -> (Option<String>, bool) {
67        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::ImportSyncMetadata)) = evt {
68            settings.import.sync_metadata = !settings.import.sync_metadata;
69            return (Some(settings.import.sync_metadata.to_string()), true);
70        }
71        (None, false)
72    }
73}
74
75/// Allowed file extensions setting.
76pub struct AllowedKindsSetting;
77
78impl SettingKind for AllowedKindsSetting {
79    fn identity(&self) -> SettingIdentity {
80        SettingIdentity::AllowedKinds
81    }
82
83    fn label(&self, _settings: &Settings) -> String {
84        fl!("settings-import-allowed-kinds")
85    }
86
87    fn fetch(&self, settings: &Settings) -> SettingData {
88        let entries = FileExtension::all()
89            .iter()
90            .copied()
91            .map(|kind| {
92                EntryKind::CheckBox(
93                    kind.to_string().to_uppercase(),
94                    EntryId::ToggleAllowedKind(kind),
95                    settings.import.allowed_kinds.contains(&kind),
96                )
97            })
98            .collect();
99
100        SettingData {
101            value: kinds_summary(settings.import.allowed_kinds.len()),
102            widget: WidgetKind::SubMenu(entries),
103        }
104    }
105
106    fn handle(
107        &self,
108        evt: &Event,
109        settings: &mut Settings,
110        _bus: &mut Bus,
111    ) -> (Option<String>, bool) {
112        if let Event::Select(EntryId::ToggleAllowedKind(kind)) = evt {
113            if !settings.import.allowed_kinds.remove(kind) {
114                settings.import.allowed_kinds.insert(*kind);
115            }
116
117            return (
118                Some(kinds_summary(settings.import.allowed_kinds.len())),
119                true,
120            );
121        }
122
123        (None, false)
124    }
125
126    fn keep_menu_open(&self) -> bool {
127        true
128    }
129}
130
131fn kinds_summary(selected: usize) -> String {
132    format!("{selected} / {}", FileExtension::all().len())
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138    use crate::settings::{FileExtension, Settings};
139    use crate::view::{Bus, EntryKind, Event};
140    use std::collections::VecDeque;
141
142    mod force_full_import {
143        use super::*;
144
145        #[test]
146        fn identity_returns_force_full_import() {
147            let setting = ForceFullImport;
148            assert_eq!(setting.identity(), SettingIdentity::ForceFullImport);
149        }
150
151        #[test]
152        fn fetch_builds_action_label_requesting_force_import() {
153            let setting = ForceFullImport;
154            let settings = Settings::default();
155            let data = setting.fetch(&settings);
156
157            match data.widget {
158                WidgetKind::ActionLabel(Event::Select(EntryId::RequestForceImport)) => {}
159                other => panic!("expected ActionLabel(RequestForceImport), got {other:?}"),
160            }
161        }
162
163        #[test]
164        fn handle_ignores_events() {
165            let setting = ForceFullImport;
166            let mut settings = Settings::default();
167            let mut bus: Bus = VecDeque::new();
168
169            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
170
171            assert!(result.0.is_none());
172            assert!(!result.1);
173        }
174    }
175
176    mod import_sync_metadata {
177        use super::*;
178
179        #[test]
180        fn handle_toggle_disables_when_enabled() {
181            let setting = ImportSyncMetadata;
182            let mut settings = Settings::default();
183            settings.import.sync_metadata = true;
184            let mut bus: Bus = VecDeque::new();
185            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::ImportSyncMetadata));
186
187            let result = setting.handle(&event, &mut settings, &mut bus);
188
189            assert!(result.0.is_some());
190            assert!(!settings.import.sync_metadata);
191        }
192
193        #[test]
194        fn handle_toggle_enables_when_disabled() {
195            let setting = ImportSyncMetadata;
196            let mut settings = Settings::default();
197            settings.import.sync_metadata = false;
198            let mut bus: Bus = VecDeque::new();
199            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::ImportSyncMetadata));
200
201            let result = setting.handle(&event, &mut settings, &mut bus);
202
203            assert!(result.0.is_some());
204            assert!(settings.import.sync_metadata);
205        }
206
207        #[test]
208        fn handle_returns_none_for_wrong_event() {
209            let setting = ImportSyncMetadata;
210            let mut settings = Settings::default();
211            let mut bus: Bus = VecDeque::new();
212            use crate::view::EntryId;
213
214            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
215
216            assert!(result.0.is_none());
217        }
218
219        #[test]
220        fn handle_returns_none_for_wrong_toggle() {
221            let setting = ImportSyncMetadata;
222            let mut settings = Settings::default();
223            let mut bus: Bus = VecDeque::new();
224
225            let result = setting.handle(
226                &Event::Toggle(ToggleEvent::Setting(ToggleSettings::SleepCover)),
227                &mut settings,
228                &mut bus,
229            );
230
231            assert!(result.0.is_none());
232        }
233    }
234
235    mod allowed_kinds_setting {
236        use super::*;
237
238        #[test]
239        fn fetch_builds_checkbox_submenu_for_all_extensions() {
240            let setting = AllowedKindsSetting;
241            let settings = Settings::default();
242
243            let data = setting.fetch(&settings);
244
245            assert_eq!(
246                data.value,
247                kinds_summary(settings.import.allowed_kinds.len())
248            );
249            let WidgetKind::SubMenu(entries) = data.widget else {
250                panic!("expected submenu widget");
251            };
252            assert_eq!(entries.len(), FileExtension::all().len());
253            assert!(matches!(
254                entries.first(),
255                Some(EntryKind::CheckBox(_, EntryId::ToggleAllowedKind(_), _))
256            ));
257        }
258
259        #[test]
260        fn handle_toggle_adds_and_removes_extensions() {
261            let setting = AllowedKindsSetting;
262            let mut settings = Settings::default();
263            settings.import.allowed_kinds.remove(&FileExtension::Cbr);
264            let mut bus: Bus = VecDeque::new();
265
266            let add = setting.handle(
267                &Event::Select(EntryId::ToggleAllowedKind(FileExtension::Cbr)),
268                &mut settings,
269                &mut bus,
270            );
271            assert_eq!(
272                add.0,
273                Some(kinds_summary(settings.import.allowed_kinds.len()))
274            );
275            assert!(settings.import.allowed_kinds.contains(&FileExtension::Cbr));
276
277            let remove = setting.handle(
278                &Event::Select(EntryId::ToggleAllowedKind(FileExtension::Cbr)),
279                &mut settings,
280                &mut bus,
281            );
282            assert_eq!(
283                remove.0,
284                Some(kinds_summary(settings.import.allowed_kinds.len()))
285            );
286            assert!(!settings.import.allowed_kinds.contains(&FileExtension::Cbr));
287        }
288    }
289}