shared/domain/module/body/
card_quiz.rs1use crate::domain::module::{
2 body::{Body, BodyConvert, BodyExt, ThemeId, _groups::cards::*},
3 ModuleKind,
4};
5use serde::{Deserialize, Serialize};
6use std::collections::HashSet;
7
8#[derive(Default, Clone, Serialize, Deserialize, Debug)]
10pub struct ModuleData {
11 pub content: Option<Content>,
13}
14
15#[derive(Default, Clone, Serialize, Deserialize, Debug)]
17pub struct Content {
18 pub base: BaseContent,
20 pub player_settings: PlayerSettings,
22}
23
24#[derive(Clone, Serialize, Deserialize, Debug)]
26pub struct PlayerSettings {
27 pub n_choices: u8,
29
30 pub swap: bool,
32
33 pub n_rounds: u32,
35
36 pub time_limit: Option<u32>,
38}
39
40impl Default for PlayerSettings {
41 fn default() -> Self {
42 Self {
43 n_choices: 3,
44 swap: false,
45 n_rounds: 3,
46 time_limit: None,
47 }
48 }
49}
50impl BodyExt<Mode, Step> for ModuleData {
52 fn as_body(&self) -> Body {
53 Body::CardQuiz(self.clone())
54 }
55
56 fn is_complete(&self) -> bool {
57 self.content
58 .as_ref()
59 .map_or(false, |content| content.base.is_valid())
60 }
61
62 fn kind() -> ModuleKind {
63 ModuleKind::CardQuiz
64 }
65
66 fn new_with_mode_and_theme(mode: Mode, theme: ThemeId) -> Self {
67 ModuleData {
68 content: Some(Content {
69 base: BaseContent {
70 mode,
71 theme,
72 ..Default::default()
73 },
74 ..Default::default()
75 }),
76 }
77 }
78
79 fn mode(&self) -> Option<Mode> {
80 self.content.as_ref().map(|c| c.base.mode.clone())
81 }
82
83 fn requires_choose_mode(&self) -> bool {
84 self.content.is_none()
85 }
86
87 fn set_editor_state_step(&mut self, step: Step) {
88 if let Some(content) = self.content.as_mut() {
89 content.base.editor_state.step = step;
90 }
91 }
92 fn set_editor_state_steps_completed(&mut self, steps_completed: HashSet<Step>) {
93 if let Some(content) = self.content.as_mut() {
94 content.base.editor_state.steps_completed = steps_completed;
95 }
96 }
97
98 fn get_editor_state_step(&self) -> Option<Step> {
99 self.content
100 .as_ref()
101 .map(|content| content.base.editor_state.step)
102 }
103
104 fn get_editor_state_steps_completed(&self) -> Option<HashSet<Step>> {
105 self.content
106 .as_ref()
107 .map(|content| content.base.editor_state.steps_completed.clone())
108 }
109
110 fn set_theme(&mut self, theme_id: ThemeId) {
111 if let Some(content) = self.content.as_mut() {
112 content.base.theme = theme_id;
113 }
114 }
115
116 fn get_theme(&self) -> Option<ThemeId> {
117 self.content.as_ref().map(|content| content.base.theme)
118 }
119}
120
121impl BodyConvert for ModuleData {
122 fn convertable_list() -> Vec<ModuleKind> {
123 vec![
124 ModuleKind::Memory,
125 ModuleKind::Matching,
126 ModuleKind::Flashcards,
127 ]
128 }
129
130 fn convert_to_memory(&self) -> Result<super::memory::ModuleData, &'static str> {
131 Ok(super::memory::ModuleData {
132 content: self.content.as_ref().map(|content| super::memory::Content {
133 base: content.base.clone(),
134 player_settings: super::memory::PlayerSettings::default(),
135 }),
136 })
137 }
138 fn convert_to_matching(&self) -> Result<super::matching::ModuleData, &'static str> {
139 Ok(super::matching::ModuleData {
140 content: self
141 .content
142 .as_ref()
143 .map(|content| super::matching::Content {
144 base: content.base.clone(),
145 player_settings: super::matching::PlayerSettings::default(),
146 }),
147 })
148 }
149
150 fn convert_to_flashcards(&self) -> Result<super::flashcards::ModuleData, &'static str> {
151 Ok(super::flashcards::ModuleData {
152 content: self
153 .content
154 .as_ref()
155 .map(|content| super::flashcards::Content {
156 base: content.base.clone(),
157 player_settings: super::flashcards::PlayerSettings::default(),
158 }),
159 })
160 }
161}
162
163impl TryFrom<Body> for ModuleData {
164 type Error = &'static str;
165
166 fn try_from(body: Body) -> Result<Self, Self::Error> {
167 match body {
168 Body::CardQuiz(data) => Ok(data),
169 _ => Err("cannot convert body to flashcards!"),
170 }
171 }
172}