shared/domain/module/body/
embed.rs1use 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#[derive(Default, Clone, Serialize, Deserialize, Debug)]
14pub struct ModuleData {
15 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#[derive(Default, Clone, Serialize, Deserialize, Debug)]
102pub struct Content {
103 pub editor_state: EditorState,
105
106 pub mode: Mode,
108
109 pub base: BaseContent,
111}
112
113#[derive(Default, Clone, Serialize, Deserialize, Debug)]
115pub struct EditorState {
116 pub step: Step,
118
119 pub steps_completed: HashSet<Step>,
121}
122
123#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash, EnumIter)]
124pub enum Mode {
126 Quiz,
128 Worksheets,
130 ProjectBasedLearning,
132 ClassProject,
134 Portfolio,
136 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
183pub enum Step {
184 One,
186 Two,
188 Three,
190 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 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}