cadmus_core/view/settings_editor/kinds/
dictionary.rs1use super::{SettingData, SettingIdentity, SettingKind, WidgetKind};
4use crate::fl;
5use crate::settings::Settings;
6use crate::view::{EntryId, EntryKind, Event};
7
8pub struct DictionaryInfo {
17 pub lang: String,
19 pub is_installed: bool,
21 pub update_available: bool,
23 pub is_installing: bool,
25}
26
27impl SettingKind for DictionaryInfo {
28 fn identity(&self) -> SettingIdentity {
29 SettingIdentity::DictionaryInfo(self.lang.clone())
30 }
31
32 fn label(&self, _settings: &Settings) -> String {
33 self.lang.clone()
34 }
35
36 fn handle(
37 &self,
38 evt: &Event,
39 _settings: &mut Settings,
40 _bus: &mut crate::view::Bus,
41 ) -> (Option<String>, bool) {
42 match evt {
43 Event::Select(entry) => match entry {
44 EntryId::DownloadDictionary(lang) if lang == &self.lang => {
45 (Some(fl!("settings-dictionaries-downloading")), false)
46 }
47 _ => (None, false),
48 },
49 _ => (None, false),
50 }
51 }
52
53 fn fetch(&self, _settings: &Settings) -> SettingData {
54 if self.is_installing {
55 return SettingData {
56 value: fl!("settings-dictionaries-downloading"),
57 widget: WidgetKind::None,
58 };
59 }
60
61 if self.is_installed {
62 let mut entries = Vec::new();
63
64 if self.update_available {
65 entries.push(EntryKind::Command(
66 fl!("settings-dictionaries-update"),
67 EntryId::RequestDictionaryDownload(self.lang.clone()),
68 ));
69 } else {
70 entries.push(EntryKind::Command(
71 fl!("settings-dictionaries-re-download"),
72 EntryId::RequestDictionaryDownload(self.lang.clone()),
73 ));
74 }
75
76 entries.push(EntryKind::Command(
77 fl!("settings-dictionaries-delete"),
78 EntryId::DeleteDictionary(self.lang.clone()),
79 ));
80
81 let value = if self.update_available {
82 fl!("settings-dictionaries-update-available")
83 } else {
84 fl!("settings-dictionaries-installed")
85 };
86
87 SettingData {
88 value,
89 widget: WidgetKind::SubMenu(entries),
90 }
91 } else {
92 SettingData {
93 value: fl!("settings-dictionaries-download"),
94 widget: WidgetKind::ActionLabel(Event::Select(EntryId::RequestDictionaryDownload(
95 self.lang.clone(),
96 ))),
97 }
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::settings::Settings;
106 use crate::view::Bus;
107 use std::collections::VecDeque;
108
109 fn make_settings() -> Settings {
110 Settings::default()
111 }
112
113 mod fetch {
114 use super::*;
115
116 #[test]
117 fn uninstalled_yields_action_label_with_request_event() {
118 let info = DictionaryInfo {
119 lang: "en".to_string(),
120 is_installed: false,
121 update_available: false,
122 is_installing: false,
123 };
124 let data = info.fetch(&make_settings());
125
126 assert!(matches!(
127 data.widget,
128 WidgetKind::ActionLabel(Event::Select(EntryId::RequestDictionaryDownload(ref l)))
129 if l == "en"
130 ));
131 }
132
133 #[test]
134 fn installed_yields_submenu_with_redownload_and_delete() {
135 let info = DictionaryInfo {
136 lang: "fr".to_string(),
137 is_installed: true,
138 update_available: false,
139 is_installing: false,
140 };
141 let data = info.fetch(&make_settings());
142
143 let WidgetKind::SubMenu(entries) = data.widget else {
144 panic!("expected SubMenu");
145 };
146 assert_eq!(entries.len(), 2);
147 assert!(matches!(
148 &entries[0],
149 EntryKind::Command(_, EntryId::RequestDictionaryDownload(l)) if l == "fr"
150 ));
151 assert!(matches!(
152 &entries[1],
153 EntryKind::Command(_, EntryId::DeleteDictionary(l)) if l == "fr"
154 ));
155 }
156
157 #[test]
158 fn update_available_yields_submenu_with_update_first() {
159 let info = DictionaryInfo {
160 lang: "de".to_string(),
161 is_installed: true,
162 update_available: true,
163 is_installing: false,
164 };
165 let data = info.fetch(&make_settings());
166
167 let WidgetKind::SubMenu(entries) = data.widget else {
168 panic!("expected SubMenu");
169 };
170 assert_eq!(entries.len(), 2);
171 assert!(matches!(
172 &entries[0],
173 EntryKind::Command(label, EntryId::RequestDictionaryDownload(l))
174 if l == "de" && label == "Update"
175 ));
176 assert!(matches!(
177 &entries[1],
178 EntryKind::Command(_, EntryId::DeleteDictionary(l)) if l == "de"
179 ));
180 assert_eq!(data.value, "Update Available");
181 }
182
183 #[test]
184 fn is_installing_yields_none_widget() {
185 let info = DictionaryInfo {
186 lang: "es".to_string(),
187 is_installed: false,
188 update_available: false,
189 is_installing: true,
190 };
191 let data = info.fetch(&make_settings());
192
193 assert!(matches!(data.widget, WidgetKind::None));
194 }
195
196 #[test]
197 fn is_installing_takes_priority_over_installed() {
198 let info = DictionaryInfo {
199 lang: "es".to_string(),
200 is_installed: true,
201 update_available: true,
202 is_installing: true,
203 };
204 let data = info.fetch(&make_settings());
205
206 assert!(matches!(data.widget, WidgetKind::None));
207 }
208 }
209
210 mod handle {
211 use super::*;
212
213 #[test]
214 fn download_event_returns_downloading_string() {
215 let info = DictionaryInfo {
216 lang: "en".to_string(),
217 is_installed: false,
218 update_available: false,
219 is_installing: false,
220 };
221 let mut settings = make_settings();
222 let mut bus: Bus = VecDeque::new();
223 let event = Event::Select(EntryId::DownloadDictionary("en".to_string()));
224
225 let (display, consumed) = info.handle(&event, &mut settings, &mut bus);
226
227 assert!(display.is_some());
228 assert!(!consumed);
229 }
230
231 #[test]
232 fn request_event_returns_none() {
233 let info = DictionaryInfo {
234 lang: "en".to_string(),
235 is_installed: true,
236 update_available: false,
237 is_installing: false,
238 };
239 let mut settings = make_settings();
240 let mut bus: Bus = VecDeque::new();
241 let event = Event::Select(EntryId::RequestDictionaryDownload("en".to_string()));
242
243 let (display, consumed) = info.handle(&event, &mut settings, &mut bus);
244
245 assert!(display.is_none());
246 assert!(!consumed);
247 }
248
249 #[test]
250 fn event_for_different_lang_returns_none() {
251 let info = DictionaryInfo {
252 lang: "en".to_string(),
253 is_installed: false,
254 update_available: false,
255 is_installing: false,
256 };
257 let mut settings = make_settings();
258 let mut bus: Bus = VecDeque::new();
259 let event = Event::Select(EntryId::DownloadDictionary("fr".to_string()));
260
261 let (display, _) = info.handle(&event, &mut settings, &mut bus);
262
263 assert!(display.is_none());
264 }
265
266 #[test]
267 fn unrelated_event_returns_none() {
268 let info = DictionaryInfo {
269 lang: "en".to_string(),
270 is_installed: false,
271 update_available: false,
272 is_installing: false,
273 };
274 let mut settings = make_settings();
275 let mut bus: Bus = VecDeque::new();
276
277 let (display, _) = info.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
278
279 assert!(display.is_none());
280 }
281 }
282}