shared/domain/module/body/
drag_drop.rsuse crate::domain::module::{
body::{
Audio, Body, BodyConvert, BodyExt, ModeExt, ModuleAssist, StepExt, ThemeId, Transform,
_groups::design::{Backgrounds, Sticker, Trace},
},
ModuleKind,
};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use strum_macros::EnumIs;
mod play_settings;
pub use play_settings::*;
use super::_groups::design::Text;
#[derive(Default, Clone, Serialize, Deserialize, Debug)]
pub struct ModuleData {
pub content: Option<Content>,
}
impl BodyExt<Mode, Step> for ModuleData {
fn as_body(&self) -> Body {
Body::DragDrop(self.clone())
}
fn is_complete(&self) -> bool {
self.content.is_some()
}
fn kind() -> ModuleKind {
ModuleKind::DragDrop
}
fn new_with_mode_and_theme(mode: Mode, theme: ThemeId) -> Self {
ModuleData {
content: Some(Content {
mode,
theme,
items: vec![Item {
sticker: Sticker::Text(Text::default()),
kind: ItemKind::Static,
}],
..Default::default()
}),
}
}
fn mode(&self) -> Option<Mode> {
self.content.as_ref().map(|c| c.mode.clone())
}
fn requires_choose_mode(&self) -> bool {
self.content.is_none()
}
fn set_editor_state_step(&mut self, step: Step) {
if let Some(content) = self.content.as_mut() {
content.editor_state.step = step;
}
}
fn set_editor_state_steps_completed(&mut self, steps_completed: HashSet<Step>) {
if let Some(content) = self.content.as_mut() {
content.editor_state.steps_completed = steps_completed;
}
}
fn get_editor_state_step(&self) -> Option<Step> {
self.content
.as_ref()
.map(|content| content.editor_state.step)
}
fn get_editor_state_steps_completed(&self) -> Option<HashSet<Step>> {
self.content
.as_ref()
.map(|content| content.editor_state.steps_completed.clone())
}
fn set_theme(&mut self, theme_id: ThemeId) {
if let Some(content) = self.content.as_mut() {
content.theme = theme_id;
}
}
fn get_theme(&self) -> Option<ThemeId> {
self.content.as_ref().map(|content| content.theme)
}
}
impl BodyConvert for ModuleData {}
impl TryFrom<Body> for ModuleData {
type Error = &'static str;
fn try_from(body: Body) -> Result<Self, Self::Error> {
match body {
Body::DragDrop(data) => Ok(data),
_ => Err("cannot convert body to drag & drop!"),
}
}
}
#[derive(Default, Clone, Serialize, Deserialize, Debug)]
pub struct Content {
pub instructions: ModuleAssist,
pub theme: ThemeId,
pub backgrounds: Backgrounds,
pub items: Vec<Item>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub item_targets: Vec<TargetTransform>,
pub editor_state: EditorState,
pub mode: Mode,
pub target_areas: Vec<TargetArea>,
pub play_settings: PlaySettings,
pub feedback: ModuleAssist,
}
#[derive(Default, Clone, Serialize, Deserialize, Debug)]
pub struct EditorState {
pub step: Step,
pub steps_completed: HashSet<Step>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Item {
pub sticker: Sticker,
pub kind: ItemKind,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct TargetTransform {
pub sticker_idx: usize,
pub transform: Transform,
pub trace_idx: usize,
}
#[derive(Clone, Serialize, Deserialize, Debug, EnumIs)]
pub enum ItemKind {
Static,
Interactive(Interactive),
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct Interactive {
pub audio: Option<Audio>,
pub target_transform: Option<Transform>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct TargetArea {
pub trace: Trace,
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
pub enum Mode {
#[allow(missing_docs)]
SettingTable,
#[allow(missing_docs)]
Sorting,
#[allow(missing_docs)]
WordBuilder,
SentenceBuilder,
#[allow(missing_docs)]
Matching,
#[allow(missing_docs)]
DressUp,
SceneBuilder,
}
impl Default for Mode {
fn default() -> Self {
Self::SettingTable
}
}
impl ModeExt for Mode {
fn get_list() -> Vec<Self> {
vec![
Self::SettingTable,
Self::Sorting,
Self::WordBuilder,
Self::SentenceBuilder,
Self::Matching,
Self::DressUp,
Self::SceneBuilder,
]
}
fn as_str_id(&self) -> &'static str {
match self {
Self::SettingTable => "setting-table",
Self::Sorting => "sorting",
Self::WordBuilder => "word-builder",
Self::SentenceBuilder => "sentence-builder",
Self::Matching => "matching",
Self::DressUp => "dress-up",
Self::SceneBuilder => "scene-builder",
}
}
fn label(&self) -> &'static str {
const STR_SETTING_TABLE: &'static str = "Set a Table";
const STR_SORTING: &'static str = "Sorting";
const STR_WORD_BUILDER: &'static str = "Build a Word";
const STR_SENTENCE_BUILDER: &'static str = "Build a Sentence";
const STR_MATCHING: &'static str = "Matching";
const STR_DRESS_UP: &'static str = "Dress Up";
const STR_SCENE_BUILDER: &'static str = "Build a Scene";
match self {
Self::SettingTable => STR_SETTING_TABLE,
Self::Sorting => STR_SORTING,
Self::WordBuilder => STR_WORD_BUILDER,
Self::SentenceBuilder => STR_SENTENCE_BUILDER,
Self::Matching => STR_MATCHING,
Self::DressUp => STR_DRESS_UP,
Self::SceneBuilder => STR_SCENE_BUILDER,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Step {
One,
Two,
Three,
Four,
Five,
}
impl Default for Step {
fn default() -> Self {
Self::One
}
}
impl StepExt for Step {
fn next(&self) -> Option<Self> {
match self {
Self::One => Some(Self::Two),
Self::Two => Some(Self::Three),
Self::Three => Some(Self::Four),
Self::Four => Some(Self::Five),
Self::Five => None,
}
}
fn as_number(&self) -> usize {
match self {
Self::One => 1,
Self::Two => 2,
Self::Three => 3,
Self::Four => 4,
Self::Five => 5,
}
}
fn label(&self) -> &'static str {
const STR_1: &'static str = "Design";
const STR_2: &'static str = "Content";
const STR_3: &'static str = "Interaction";
const STR_4: &'static str = "Settings";
const STR_5: &'static str = "Preview";
match self {
Self::One => STR_1,
Self::Two => STR_2,
Self::Three => STR_3,
Self::Four => STR_4,
Self::Five => STR_5,
}
}
fn get_list() -> Vec<Self> {
vec![Self::One, Self::Two, Self::Three, Self::Four, Self::Five]
}
fn get_preview() -> Self {
Self::Five
}
}