1use crate::domain::module::body::{
2 Audio, Background, HoverAnimation, Image, ModuleAssist, StickerHidden, ThemeId, Transform,
3};
4use derive_setters::Setters;
5use serde::{Deserialize, Serialize};
6
7pub const DEFAULT_TEXT_VALUE: &str = "Shalom שָׁלוֹם";
9
10#[derive(Clone, Serialize, Deserialize, Debug)]
12pub struct BaseContent {
13 pub instructions: ModuleAssist,
15
16 #[serde(default)]
18 pub feedback: ModuleAssist,
19
20 pub theme: ThemeId,
22
23 pub backgrounds: Backgrounds,
25
26 pub stickers: Vec<Sticker>,
28}
29
30impl Default for BaseContent {
31 fn default() -> Self {
32 Self {
33 instructions: Default::default(),
34 feedback: Default::default(),
35 theme: Default::default(),
36 backgrounds: Default::default(),
37 stickers: vec![Sticker::Text(Default::default())],
38 }
39 }
40}
41
42#[derive(Clone, Default, Serialize, Deserialize, Debug)]
43pub struct Backgrounds {
48 pub layer_1: Option<Background>,
50 pub layer_2: Option<Background>,
52}
53
54#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
55pub enum Sticker {
57 #[serde(alias = "sprite")]
59 Sprite(Sprite),
60 #[serde(alias = "text")]
62 Text(Text),
63 #[serde(alias = "embed")]
65 Embed(Embed),
66}
67
68impl Sticker {
69 pub fn transform(&self) -> &Transform {
71 match self {
72 Self::Sprite(sprite) => &sprite.transform,
73 Self::Text(text) => &text.transform,
74 Self::Embed(embed) => &embed.transform,
75 }
76 }
77}
78
79#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
80pub struct Text {
82 pub value: String,
84 pub transform: Transform,
86 #[serde(default)]
88 pub hover_animation: Option<HoverAnimation>,
89 #[serde(default)]
91 pub hidden: Option<StickerHidden>,
92}
93
94impl Default for Text {
95 fn default() -> Self {
96 Self::from_str(DEFAULT_TEXT_VALUE)
97 }
98}
99
100impl Text {
101 pub fn from_str(text: &str) -> Self {
105 Self::from_value(Self::value_from_str(text))
106 }
107
108 pub fn from_value(value: String) -> Self {
110 Self {
111 value,
112 transform: Transform::identity(),
113 hover_animation: None,
114 hidden: None,
115 }
116 }
117
118 pub fn value_from_str(text: &str) -> String {
120 format!(
121 r#"{{"version":"0.1.0","content":[{{"children":[{{"text":"{}","element":"H1"}}]}}]}}"#,
122 text
123 )
124 }
125}
126
127#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
128pub struct Sprite {
130 pub image: Image,
132 pub transform: Transform,
134 pub effects: Vec<SpriteEffect>,
136
137 pub flip_horizontal: bool,
139
140 pub flip_vertical: bool,
142
143 #[serde(default)]
145 pub hover_animation: Option<HoverAnimation>,
146 #[serde(default)]
148 pub hidden: Option<StickerHidden>,
149}
150
151#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
152#[serde(rename_all = "snake_case")]
153pub enum SpriteEffect {
155 RemoveWhite,
157}
158
159#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
160pub struct Embed {
163 pub host: EmbedHost,
165
166 pub transform: Transform,
168}
169
170#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
172pub enum DoneAction {
173 Loop,
175
176 Next,
178}
179
180#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
181pub enum EmbedHost {
183 #[serde(alias = "youtube")]
185 Youtube(YoutubeEmbed),
186
187 Vimeo(VimeoEmbed),
189
190 GoogleDoc(GoogleDocsEmbed),
192
193 GoogleForm(GoogleFormsEmbed),
195
196 GoogleSheet(GoogleSheetsEmbed),
198
199 GoogleSlide(GoogleSlidesEmbed),
201
202 Edpuzzle(EdpuzzleEmbed),
204
205 Puzzel(PuzzelEmbed),
207
208 Quizlet(QuizletEmbed),
210
211 Thinglink(ThinglinkEmbed),
213
214 Sutori(SutoriEmbed),
216}
217
218#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Setters)]
219pub struct YoutubeEmbed {
221 pub url: YoutubeUrl,
223
224 pub start_at: Option<u32>,
226
227 pub end_at: Option<u32>,
229
230 pub captions: bool,
232
233 pub muted: bool,
235
236 pub autoplay: bool,
238
239 pub done_action: Option<DoneAction>,
241}
242
243impl YoutubeEmbed {
244 pub fn new(url: YoutubeUrl) -> Self {
246 Self {
247 url,
248 start_at: None,
249 end_at: None,
250 captions: false,
251 muted: false,
252 autoplay: false,
253 done_action: None,
254 }
255 }
256}
257
258#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
259pub struct YoutubeUrl(pub String);
261
262#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Setters)]
263pub struct VimeoEmbed {
265 pub url: VimeoUrl,
267
268 pub start_at: Option<u32>,
270
271 pub end_at: Option<u32>,
273
274 pub captions: bool,
276
277 pub muted: bool,
279
280 pub autoplay: bool,
282
283 pub done_action: Option<DoneAction>,
285}
286
287impl VimeoEmbed {
288 pub fn new(url: VimeoUrl) -> Self {
290 Self {
291 url,
292 start_at: None,
293 end_at: None,
294 captions: false,
295 muted: false,
296 autoplay: false,
297 done_action: None,
298 }
299 }
300}
301
302#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
303pub struct VimeoUrl(pub String);
305
306impl EmbedHost {
307 pub fn get_url_string(&self) -> String {
309 match &self {
310 EmbedHost::Youtube(youtube_video) => {
311 let YoutubeUrl(url) = &youtube_video.url;
312 url.to_string()
313 }
314 EmbedHost::Vimeo(vimeo_video) => {
315 let VimeoUrl(url) = &vimeo_video.url;
316 url.to_string()
317 }
318 EmbedHost::GoogleDoc(google_doc) => {
319 let GoogleDocId(url) = &google_doc.url;
320 url.to_string()
321 }
322 EmbedHost::GoogleForm(google_form) => {
323 let GoogleFormId(url) = &google_form.url;
324 url.to_string()
325 }
326 EmbedHost::GoogleSheet(google_sheet) => {
327 let GoogleSheetId(url) = &google_sheet.url;
328 url.to_string()
329 }
330 EmbedHost::GoogleSlide(google_slide) => {
331 let GoogleSlideId(url) = &google_slide.url;
332 url.to_string()
333 }
334 EmbedHost::Edpuzzle(_) => todo!(),
335 EmbedHost::Puzzel(_) => todo!(),
336 EmbedHost::Quizlet(quizlet) => {
337 let QuizletId(url) = &quizlet.url;
338 url.to_string()
339 }
340 EmbedHost::Thinglink(thinglink) => {
341 let ThinglinkId(url) = &thinglink.url;
342 url.to_string()
343 }
344 EmbedHost::Sutori(sutori) => {
345 let SutoriId(url) = &sutori.url;
346 url.to_string()
347 }
348 }
349 }
350}
351
352#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
353pub struct GoogleDocsEmbed {
355 pub url: GoogleDocId,
357}
358
359#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
360pub struct GoogleDocId(pub String);
362
363#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
364pub struct GoogleFormsEmbed {
366 pub url: GoogleFormId,
368}
369
370#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
371pub struct GoogleFormId(pub String);
373
374#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
375pub struct GoogleSheetsEmbed {
377 pub url: GoogleSheetId,
379}
380
381#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
382pub struct GoogleSheetId(pub String);
384
385#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
386pub struct GoogleSlidesEmbed {
388 pub url: GoogleSlideId,
390}
391
392#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
393pub struct GoogleSlideId(pub String);
395
396#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
397pub struct EdpuzzleEmbed {
399 pub url: EdpuzzleId,
401}
402
403#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
404pub struct EdpuzzleId(pub String);
406
407#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
408pub struct PuzzelEmbed {
410 pub url: PuzzelId,
412}
413
414#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
415pub struct PuzzelId(pub String);
417
418#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
419pub struct QuizletEmbed {
421 pub url: QuizletId,
423}
424
425#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
426pub struct QuizletId(pub String);
428
429#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
430pub struct ThinglinkEmbed {
432 pub url: ThinglinkId,
434}
435
436#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
437pub struct ThinglinkId(pub String);
439
440#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
441pub struct SutoriEmbed {
443 pub url: SutoriId,
445}
446
447#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
448pub struct SutoriId(pub String);
450
451#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
452pub struct Trace {
454 pub transform: Transform,
456 pub shape: TraceShape,
458 pub kind: TraceKind,
460 pub audio: Option<Audio>,
462 pub text: Option<String>,
464}
465
466#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq)]
467pub enum TraceKind {
469 #[serde(alias = "wrong")]
471 Wrong,
472 #[serde(alias = "correct")]
474 Correct,
475 #[serde(alias = "regular")]
477 Regular,
478}
479
480impl AsRef<Trace> for Trace {
481 fn as_ref(&self) -> &Trace {
482 self
483 }
484}
485
486#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
487pub enum TraceShape {
489 #[serde(alias = "rect")]
491 Rect(f64, f64),
492 #[serde(alias = "ellipse")]
494 Ellipse(f64, f64),
495 #[serde(alias = "path")]
497 Path(Vec<(f64, f64)>),
498 #[serde(alias = "pathCommands")]
502 PathCommands(Vec<(PathCommand, bool)>),
503}
504
505#[allow(missing_docs)]
506#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
507pub enum PathCommand {
508 MoveTo(f64, f64),
510 ClosePath,
512 LineTo(f64, f64),
514 HorizontalLineTo(f64),
516 VerticalLineTo(f64),
518 CurveTo(f64, f64, f64, f64, f64, f64),
520 SmoothCurveTo(f64, f64, f64, f64),
522 QuadCurveTo(f64, f64, f64, f64),
524 SmoothQuadCurveTo(f64, f64),
526 ArcTo(f64, f64, f64, f64, f64, f64, f64),
528}