shared/domain/module/body/
flashcards.rs

1use crate::domain::module::{
2    body::{Body, BodyConvert, BodyExt, ModeExt, ThemeId, _groups::cards::*},
3    ModuleKind,
4};
5use serde::{Deserialize, Serialize};
6use std::collections::HashSet;
7
8/// The body for [`Flashcards`](crate::domain::module::ModuleKind::Flashcards) modules.
9#[derive(Default, Clone, Serialize, Deserialize, Debug)]
10pub struct ModuleData {
11    /// The content
12    pub content: Option<Content>,
13}
14
15/// The content for [`Flashcards`](crate::domain::module::ModuleKind::Flashcards) modules.
16#[derive(Default, Clone, Serialize, Deserialize, Debug)]
17pub struct Content {
18    /// The base content for all cards modules
19    pub base: BaseContent,
20    /// Settings for playback
21    pub player_settings: PlayerSettings,
22}
23
24/// Player settings
25#[derive(Default, Clone, Serialize, Deserialize, Debug)]
26pub struct PlayerSettings {
27    /// display mode
28    pub display_mode: DisplayMode,
29
30    /// view pairs
31    #[serde(default)]
32    pub view_pairs: Option<u32>,
33
34    /// swap the display to be primary left vs. right
35    #[serde(default)]
36    pub swap: bool,
37}
38
39/// Display Mode
40#[derive(Clone, Copy, Serialize, Deserialize, Debug, Eq, PartialEq)]
41pub enum DisplayMode {
42    /// Single sided cards
43    Single,
44    /// Double sided cards
45    Double,
46}
47
48impl Default for DisplayMode {
49    fn default() -> Self {
50        Self::Double
51    }
52}
53
54impl DisplayMode {
55    /// Get it as a string
56    pub fn as_str_id(&self) -> &'static str {
57        match self {
58            Self::Single => "single",
59            Self::Double => "double",
60        }
61    }
62}
63
64impl BodyExt<Mode, Step> for ModuleData {
65    fn as_body(&self) -> Body {
66        Body::Flashcards(self.clone())
67    }
68
69    fn choose_mode_list() -> Vec<Mode> {
70        Mode::get_list()
71            .into_iter()
72            .filter(|mode| *mode != Mode::Duplicate)
73            .collect()
74    }
75
76    fn is_complete(&self) -> bool {
77        self.content
78            .as_ref()
79            .map_or(false, |content| content.base.is_valid())
80    }
81
82    fn kind() -> ModuleKind {
83        ModuleKind::Flashcards
84    }
85
86    fn new_with_mode_and_theme(mode: Mode, theme: ThemeId) -> Self {
87        ModuleData {
88            content: Some(Content {
89                base: BaseContent {
90                    mode,
91                    theme,
92                    ..Default::default()
93                },
94                ..Default::default()
95            }),
96        }
97    }
98
99    fn mode(&self) -> Option<Mode> {
100        self.content.as_ref().map(|c| c.base.mode.clone())
101    }
102
103    fn requires_choose_mode(&self) -> bool {
104        self.content.is_none()
105    }
106
107    fn set_editor_state_step(&mut self, step: Step) {
108        if let Some(content) = self.content.as_mut() {
109            content.base.editor_state.step = step;
110        }
111    }
112    fn set_editor_state_steps_completed(&mut self, steps_completed: HashSet<Step>) {
113        if let Some(content) = self.content.as_mut() {
114            content.base.editor_state.steps_completed = steps_completed;
115        }
116    }
117
118    fn get_editor_state_step(&self) -> Option<Step> {
119        self.content
120            .as_ref()
121            .map(|content| content.base.editor_state.step)
122    }
123
124    fn get_editor_state_steps_completed(&self) -> Option<HashSet<Step>> {
125        self.content
126            .as_ref()
127            .map(|content| content.base.editor_state.steps_completed.clone())
128    }
129
130    fn set_theme(&mut self, theme_id: ThemeId) {
131        if let Some(content) = self.content.as_mut() {
132            content.base.theme = theme_id;
133        }
134    }
135
136    fn get_theme(&self) -> Option<ThemeId> {
137        self.content.as_ref().map(|content| content.base.theme)
138    }
139}
140
141impl BodyConvert for ModuleData {
142    fn convertable_list() -> Vec<ModuleKind> {
143        vec![
144            ModuleKind::Memory,
145            ModuleKind::Matching,
146            ModuleKind::CardQuiz,
147        ]
148    }
149    fn convert_to_memory(&self) -> Result<super::memory::ModuleData, &'static str> {
150        Ok(super::memory::ModuleData {
151            content: self.content.as_ref().map(|content| super::memory::Content {
152                base: content.base.clone(),
153                player_settings: super::memory::PlayerSettings::default(),
154            }),
155        })
156    }
157    fn convert_to_matching(&self) -> Result<super::matching::ModuleData, &'static str> {
158        Ok(super::matching::ModuleData {
159            content: self
160                .content
161                .as_ref()
162                .map(|content| super::matching::Content {
163                    base: content.base.clone(),
164                    player_settings: super::matching::PlayerSettings::default(),
165                }),
166        })
167    }
168
169    fn convert_to_card_quiz(&self) -> Result<super::card_quiz::ModuleData, &'static str> {
170        Ok(super::card_quiz::ModuleData {
171            content: self
172                .content
173                .as_ref()
174                .map(|content| super::card_quiz::Content {
175                    base: content.base.clone(),
176                    player_settings: super::card_quiz::PlayerSettings::default(),
177                }),
178        })
179    }
180}
181
182impl TryFrom<Body> for ModuleData {
183    type Error = &'static str;
184
185    fn try_from(body: Body) -> Result<Self, Self::Error> {
186        match body {
187            Body::Flashcards(data) => Ok(data),
188            _ => Err("cannot convert body to flashcards!"),
189        }
190    }
191}