shared/domain/module/body/
embed.rs

1use crate::domain::module::{
2    body::{Body, BodyExt, ModeExt, StepExt, ThemeId, _groups::design::*},
3    ModuleKind,
4};
5use serde::{Deserialize, Serialize};
6use std::collections::HashSet;
7use strum::IntoEnumIterator;
8use strum_macros::EnumIter;
9
10use super::BodyConvert;
11
12/// The body for [`Embed`](crate::domain::module::ModuleKind::Embed) modules.
13#[derive(Default, Clone, Serialize, Deserialize, Debug)]
14pub struct ModuleData {
15    /// The content
16    pub content: Option<Content>,
17}
18
19impl BodyExt<Mode, Step> for ModuleData {
20    fn as_body(&self) -> Body {
21        Body::Embed(self.clone())
22    }
23
24    fn is_complete(&self) -> bool {
25        self.content.is_some()
26    }
27
28    fn kind() -> ModuleKind {
29        ModuleKind::Embed
30    }
31
32    fn new_with_mode_and_theme(mode: Mode, theme: ThemeId) -> Self {
33        ModuleData {
34            content: Some(Content {
35                mode,
36                base: BaseContent {
37                    theme,
38                    ..Default::default()
39                },
40                ..Default::default()
41            }),
42        }
43    }
44
45    fn mode(&self) -> Option<Mode> {
46        self.content.as_ref().map(|c| c.mode.clone())
47    }
48
49    fn requires_choose_mode(&self) -> bool {
50        self.content.is_none()
51    }
52
53    fn set_editor_state_step(&mut self, step: Step) {
54        if let Some(content) = self.content.as_mut() {
55            content.editor_state.step = step;
56        }
57    }
58    fn set_editor_state_steps_completed(&mut self, steps_completed: HashSet<Step>) {
59        if let Some(content) = self.content.as_mut() {
60            content.editor_state.steps_completed = steps_completed;
61        }
62    }
63
64    fn get_editor_state_step(&self) -> Option<Step> {
65        self.content
66            .as_ref()
67            .map(|content| content.editor_state.step)
68    }
69
70    fn get_editor_state_steps_completed(&self) -> Option<HashSet<Step>> {
71        self.content
72            .as_ref()
73            .map(|content| content.editor_state.steps_completed.clone())
74    }
75
76    fn set_theme(&mut self, theme_id: ThemeId) {
77        if let Some(content) = self.content.as_mut() {
78            content.base.theme = theme_id;
79        }
80    }
81
82    fn get_theme(&self) -> Option<ThemeId> {
83        self.content.as_ref().map(|content| content.base.theme)
84    }
85}
86
87impl BodyConvert for ModuleData {}
88
89impl TryFrom<Body> for ModuleData {
90    type Error = &'static str;
91
92    fn try_from(body: Body) -> Result<Self, Self::Error> {
93        match body {
94            Body::Embed(data) => Ok(data),
95            _ => Err("cannot convert body to embed!"),
96        }
97    }
98}
99
100/// The body for [`Embed`](crate::domain::module::ModuleKind::Embed) modules.
101#[derive(Default, Clone, Serialize, Deserialize, Debug)]
102pub struct Content {
103    /// The editor state
104    pub editor_state: EditorState,
105
106    /// The mode
107    pub mode: Mode,
108
109    /// The base content for all design modules
110    pub base: BaseContent,
111}
112
113/// Editor state
114#[derive(Default, Clone, Serialize, Deserialize, Debug)]
115pub struct EditorState {
116    /// the current step
117    pub step: Step,
118
119    /// the completed steps
120    pub steps_completed: HashSet<Step>,
121}
122
123#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash, EnumIter)]
124/// The mode
125pub enum Mode {
126    /// Class quiz
127    Quiz,
128    /// Worksheets
129    Worksheets,
130    /// Project-based learning
131    ProjectBasedLearning,
132    /// Class project
133    ClassProject,
134    /// Portfolio
135    Portfolio,
136    /// Forms
137    Forms,
138}
139
140impl Default for Mode {
141    fn default() -> Self {
142        Self::Quiz
143    }
144}
145
146impl ModeExt for Mode {
147    fn get_list() -> Vec<Self> {
148        Self::iter().collect()
149    }
150
151    fn as_str_id(&self) -> &'static str {
152        match self {
153            Self::Quiz => "quiz",
154            Self::Worksheets => "worksheets",
155            Self::ProjectBasedLearning => "project-based-learning",
156            Self::ClassProject => "class-project",
157            Self::Portfolio => "portfolio",
158            Self::Forms => "forms",
159        }
160    }
161
162    fn label(&self) -> &'static str {
163        const STR_QUIZ: &str = "Class quiz";
164        const STR_WORKSHEETS: &str = "Worksheets";
165        const STR_PROJECT_BASED_LEARNING: &str = "Project-based learning";
166        const STR_CLASS_PROJECT: &str = "Class project";
167        const STR_DIGITAL_PORTFOLIO: &str = "Digital portfolio";
168        const STR_COLLABORATIVE_FORMS: &str = "Collaborative forms";
169
170        match self {
171            Mode::Quiz => STR_QUIZ,
172            Mode::Worksheets => STR_WORKSHEETS,
173            Mode::ProjectBasedLearning => STR_PROJECT_BASED_LEARNING,
174            Mode::ClassProject => STR_CLASS_PROJECT,
175            Mode::Portfolio => STR_DIGITAL_PORTFOLIO,
176            Mode::Forms => STR_COLLABORATIVE_FORMS,
177        }
178    }
179}
180
181/// The Steps
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
183pub enum Step {
184    /// Step 1
185    One,
186    /// Step 2
187    Two,
188    /// Step 3
189    Three,
190    /// Step 4
191    Four,
192}
193
194impl Default for Step {
195    fn default() -> Self {
196        Self::One
197    }
198}
199
200impl StepExt for Step {
201    fn next(&self) -> Option<Self> {
202        match self {
203            Self::One => Some(Self::Two),
204            Self::Two => Some(Self::Three),
205            Self::Three => Some(Self::Four),
206            Self::Four => None,
207        }
208    }
209
210    fn as_number(&self) -> usize {
211        match self {
212            Self::One => 1,
213            Self::Two => 2,
214            Self::Three => 3,
215            Self::Four => 4,
216        }
217    }
218
219    fn label(&self) -> &'static str {
220        //TODO - localizaton
221        const STR_BACKGROUND: &'static str = "Design";
222        const STR_CONTENT: &'static str = "Content";
223        const STR_SETTINGS: &'static str = "Settings";
224        const STR_PREVIEW: &'static str = "Preview";
225
226        match self {
227            Self::One => STR_BACKGROUND,
228            Self::Two => STR_CONTENT,
229            Self::Three => STR_SETTINGS,
230            Self::Four => STR_PREVIEW,
231        }
232    }
233
234    fn get_list() -> Vec<Self> {
235        vec![Self::One, Self::Two, Self::Three, Self::Four]
236    }
237    fn get_preview() -> Self {
238        Self::Four
239    }
240}