shared/domain/module/body/
poster.rs

1use crate::domain::module::{
2    body::{Body, BodyConvert, BodyExt, ModeExt, StepExt, ThemeId, _groups::design::*},
3    ModuleKind,
4};
5use serde::{Deserialize, Serialize};
6use std::collections::HashSet;
7
8use super::Audio;
9
10/// The body for [`Poster`](crate::domain::module::ModuleKind::Poster) modules.
11#[derive(Default, Clone, Serialize, Deserialize, Debug)]
12pub struct ModuleData {
13    /// The content
14    pub content: Option<Content>,
15}
16
17impl BodyExt<Mode, Step> for ModuleData {
18    fn as_body(&self) -> Body {
19        Body::Poster(self.clone())
20    }
21
22    fn is_complete(&self) -> bool {
23        self.content.is_some()
24    }
25
26    fn kind() -> ModuleKind {
27        ModuleKind::Poster
28    }
29
30    fn new_with_mode_and_theme(mode: Mode, theme: ThemeId) -> Self {
31        ModuleData {
32            content: Some(Content {
33                mode,
34                base: BaseContent {
35                    theme,
36                    ..Default::default()
37                },
38                ..Default::default()
39            }),
40        }
41    }
42
43    fn mode(&self) -> Option<Mode> {
44        self.content.as_ref().map(|c| c.mode.clone())
45    }
46
47    fn requires_choose_mode(&self) -> bool {
48        self.content.is_none()
49    }
50
51    fn set_editor_state_step(&mut self, step: Step) {
52        if let Some(content) = self.content.as_mut() {
53            content.editor_state.step = step;
54        }
55    }
56    fn set_editor_state_steps_completed(&mut self, steps_completed: HashSet<Step>) {
57        if let Some(content) = self.content.as_mut() {
58            content.editor_state.steps_completed = steps_completed;
59        }
60    }
61
62    fn get_editor_state_step(&self) -> Option<Step> {
63        self.content
64            .as_ref()
65            .map(|content| content.editor_state.step)
66    }
67
68    fn get_editor_state_steps_completed(&self) -> Option<HashSet<Step>> {
69        self.content
70            .as_ref()
71            .map(|content| content.editor_state.steps_completed.clone())
72    }
73
74    fn set_theme(&mut self, theme_id: ThemeId) {
75        if let Some(content) = self.content.as_mut() {
76            content.base.theme = theme_id;
77        }
78    }
79
80    fn get_theme(&self) -> Option<ThemeId> {
81        self.content.as_ref().map(|content| content.base.theme)
82    }
83}
84
85impl BodyConvert for ModuleData {}
86
87impl TryFrom<Body> for ModuleData {
88    type Error = &'static str;
89
90    fn try_from(body: Body) -> Result<Self, Self::Error> {
91        match body {
92            Body::Poster(data) => Ok(data),
93            _ => Err("cannot convert body to poster!"),
94        }
95    }
96}
97
98/// The body for [`Poster`](crate::domain::module::ModuleKind::Poster) modules.
99#[derive(Default, Clone, Serialize, Deserialize, Debug)]
100pub struct Content {
101    /// The editor state
102    pub editor_state: EditorState,
103    /// The mode
104    pub mode: Mode,
105    /// Optional audio for the activity
106    #[serde(default)]
107    pub audio: Option<Audio>,
108    /// The base content for all design modules
109    pub base: BaseContent,
110    /// play settings
111    #[serde(default)]
112    pub play_settings: PlaySettings,
113}
114
115/// Editor state
116#[derive(Default, Clone, Serialize, Deserialize, Debug)]
117pub struct EditorState {
118    /// the current step
119    pub step: Step,
120
121    /// the completed steps
122    pub steps_completed: HashSet<Step>,
123}
124
125#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
126/// The mode
127pub enum Mode {
128    /// Printables
129    Printables,
130    /// TalkingPictures
131    TalkingPictures,
132    /// Teach a word
133    TeachAWord,
134    /// Storytime
135    StoryTime,
136    /// Map
137    Map,
138    /// Poster
139    Poster,
140    /// Hear a song
141    HearASong,
142}
143
144impl Default for Mode {
145    fn default() -> Self {
146        Self::Poster
147    }
148}
149
150impl ModeExt for Mode {
151    fn get_list() -> Vec<Self> {
152        vec![
153            Self::Printables,
154            Self::TalkingPictures,
155            Self::TeachAWord,
156            Self::StoryTime,
157            Self::Map,
158            Self::Poster,
159            Self::HearASong,
160        ]
161    }
162
163    fn as_str_id(&self) -> &'static str {
164        match self {
165            Self::Printables => "printables",
166            Self::TalkingPictures => "talking-pictures",
167            Self::TeachAWord => "teach-a-word",
168            Self::StoryTime => "story-time",
169            Self::Map => "map",
170            Self::Poster => "poster",
171            Self::HearASong => "hear-a-song",
172        }
173    }
174
175    fn label(&self) -> &'static str {
176        const STR_PRINTABLES_LABEL: &'static str = "Printables";
177        const STR_TALKING_PICTURES_LABEL: &'static str = "Talking Picture";
178        const STR_TEACH_A_WORD_LABEL: &'static str = "Teach a Word";
179        const STR_STORY_TIME_LABEL: &'static str = "Storytime";
180        const STR_MAP_LABEL: &'static str = "Map";
181        const STR_POSTER_LABEL: &'static str = "Poster";
182        const STR_HEAR_A_SONG_LABEL: &'static str = "Hear a song";
183
184        match self {
185            Self::Printables => STR_PRINTABLES_LABEL,
186            Self::TalkingPictures => STR_TALKING_PICTURES_LABEL,
187            Self::TeachAWord => STR_TEACH_A_WORD_LABEL,
188            Self::StoryTime => STR_STORY_TIME_LABEL,
189            Self::Map => STR_MAP_LABEL,
190            Self::Poster => STR_POSTER_LABEL,
191            Self::HearASong => STR_HEAR_A_SONG_LABEL,
192        }
193    }
194}
195
196/// The Steps
197#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
198pub enum Step {
199    /// Step 1
200    One,
201    /// Step 2
202    Two,
203    /// Step 3
204    Three,
205    /// Step 4
206    Four,
207}
208
209impl Default for Step {
210    fn default() -> Self {
211        Self::One
212    }
213}
214
215impl StepExt for Step {
216    fn next(&self) -> Option<Self> {
217        match self {
218            Self::One => Some(Self::Two),
219            Self::Two => Some(Self::Three),
220            Self::Three => Some(Self::Four),
221            Self::Four => None,
222        }
223    }
224
225    fn as_number(&self) -> usize {
226        match self {
227            Self::One => 1,
228            Self::Two => 2,
229            Self::Three => 3,
230            Self::Four => 4,
231        }
232    }
233
234    fn label(&self) -> &'static str {
235        const STR_DESIGN: &'static str = "Design";
236        const STR_CONTENT: &'static str = "Content";
237        const STR_SETTINGS: &'static str = "Settings";
238        const STR_PREVIEW: &'static str = "Preview";
239
240        match self {
241            Self::One => STR_DESIGN,
242            Self::Two => STR_CONTENT,
243            Self::Three => STR_SETTINGS,
244            Self::Four => STR_PREVIEW,
245        }
246    }
247
248    fn get_list() -> Vec<Self> {
249        vec![Self::One, Self::Two, Self::Three, Self::Four]
250    }
251    fn get_preview() -> Self {
252        Self::Four
253    }
254}
255
256/// Play settings
257#[derive(Clone, Default, Serialize, Deserialize, Debug)]
258pub struct PlaySettings {
259    /// next style
260    pub next: Next,
261}
262
263/// Next
264#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
265pub enum Next {
266    /// After audio has played
267    AfterAudio,
268    /// Student clicks next
269    ClickNext,
270}
271
272impl Default for Next {
273    fn default() -> Self {
274        Self::ClickNext
275    }
276}