From 92983da8fa0504b2b642df7b155967e69c6cca97 Mon Sep 17 00:00:00 2001 From: Wynd Date: Wed, 18 Jun 2025 16:08:46 +0300 Subject: [PATCH] Replaced the finished/restart flags with proper enum states and made the restarts functional --- src/main.rs | 91 ++++++++++++++++++++++++++++++++------------------- src/models.rs | 27 +++++++++++++-- 2 files changed, 83 insertions(+), 35 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6b26cb9..307a6a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ use dioxus::desktop::{Config, LogicalSize, WindowBuilder}; use dioxus::{logger::tracing, prelude::*}; #[cfg(feature = "bundled")] use include_dir::{Dir, include_dir}; -use models::{Question, Questions}; -use rand::seq::SliceRandom; +use models::{Phase, Question, QuestionState, Questions}; +use rand::{rngs::ThreadRng, seq::SliceRandom}; #[cfg(feature = "desktop")] use std::{env, fs}; #[cfg(not(feature = "web"))] @@ -78,14 +78,12 @@ fn get_questions() -> Questions { .clone() } -fn get_rand_questions() -> Vec { - let mut questions = get_questions().questions; +fn get_rand_questions() -> Questions { + let mut questions = get_questions(); let mut rng = rand::rng(); // Randomize the answers - questions - .iter_mut() - .for_each(|q| q.answers.shuffle(&mut rng)); + randomize_answers(&mut rng, &mut questions); // Randomize the questions list questions.shuffle(&mut rng); @@ -93,6 +91,10 @@ fn get_rand_questions() -> Vec { questions } +fn randomize_answers(rng: &mut ThreadRng, questions: &mut [Question]) { + questions.iter_mut().for_each(|q| q.answers.shuffle(rng)); +} + fn main() { #[cfg(feature = "desktop")] { @@ -122,41 +124,59 @@ fn App() -> Element { let mut correct_questions = use_signal(|| 0); let mut wrong_questions = use_signal(|| 0); - let mut has_finished = use_signal(|| false); - let mut has_restart = use_signal(|| false); + let mut phase = use_signal(|| Phase::Running); + let mut next_phase = use_signal(|| Phase::Running); use_effect(move || { - let has_restart = has_restart(); - if has_restart { - let mut questions_lock = questions.write(); + let current_phase = phase(); + match current_phase { + Phase::Restart => { + let mut questions_lock = questions.write(); - *questions_lock = get_rand_questions(); + *questions_lock = get_rand_questions(); - correct_questions.set(0); - wrong_questions.set(0); + correct_questions.set(0); + wrong_questions.set(0); - has_finished.set(false); + next_phase.set(Phase::Running); + } + Phase::RestartWrongs => { + let mut questions_lock = questions.write(); + + let wrongs = questions_lock.wrong_questions.to_vec(); + + questions_lock.questions = wrongs; + questions_lock.wrong_questions.clear(); + + let mut rng = rand::rng(); + randomize_answers(&mut rng, &mut questions_lock); + + correct_questions.set(0); + wrong_questions.set(0); + + next_phase.set(Phase::Running); + } + _ => {} } }); + // I am not a fan of this..._reactivity_ use_effect(move || { - let has_finished = has_finished(); - if !has_finished { - has_restart.set(false); - } + let next_phase = next_phase(); + phase.set(next_phase); }); rsx! { document::Link { rel: "stylesheet", href: MAIN_CSS } - if !has_finished() { - QuestionForm { questions, correct_questions, wrong_questions, has_finished, has_restart } + if phase() == Phase::Running { + QuestionForm { questions, correct_questions, wrong_questions, phase } } - else if has_finished() { + else if phase() != Phase::Running { Report { questions: questions(), correct_questions: correct_questions(), wrong_questions: wrong_questions(), - has_restart, + phase, } } } @@ -165,13 +185,12 @@ fn App() -> Element { #[allow(clippy::redundant_closure)] #[component] pub fn QuestionForm( - questions: Signal>, + questions: Signal, correct_questions: Signal, wrong_questions: Signal, - has_finished: Signal, - has_restart: Signal, + phase: Signal, ) -> Element { - let mut current = use_signal(move || questions()[0].clone()); + let mut current = use_signal(move || Question::default()); use_effect(move || { let _correct_count = correct_questions(); @@ -180,7 +199,7 @@ pub fn QuestionForm( let mut questions_lock = questions.write(); if questions_lock.is_empty() { - has_finished.set(true); + phase.set(Phase::Finished); } else { let new_question = questions_lock.remove(0); current.set(new_question); @@ -223,6 +242,7 @@ pub fn QuestionForm( sleep(Duration::from_millis(600)).await; let mut current_lock = current.write(); + let mut questions_lock = questions.write(); let mut correct_questions_lock = correct_questions.write(); let mut wrong_questions_lock = wrong_questions.write(); @@ -237,6 +257,8 @@ pub fn QuestionForm( *correct_questions_lock += 1; } else if is_wrong { *wrong_questions_lock += 1; + let current_question = current_lock.clone(); + questions_lock.wrong_questions.push(current_question); } // Reset animation flags @@ -353,7 +375,7 @@ pub fn Result(is_correct: bool, is_wrong: bool) -> Element { #[allow(clippy::redundant_closure)] #[component] pub fn Info( - questions: Signal>, + questions: Signal, correct_questions: Signal, wrong_questions: Signal, ) -> Element { @@ -381,10 +403,10 @@ pub fn Info( #[component] pub fn Report( - questions: Vec, + questions: Questions, correct_questions: i32, wrong_questions: i32, - has_restart: Signal, + phase: Signal, ) -> Element { let questions_size = questions.len(); @@ -404,11 +426,14 @@ pub fn Report( div { button { onclick: move |_| { - has_restart.set(true); + phase.set(Phase::Restart); }, "Restart" }, button { + onclick: move |_| { + phase.set(Phase::RestartWrongs); + }, "Restart with only wrong questions" } } diff --git a/src/models.rs b/src/models.rs index e6d5273..5bec4aa 100644 --- a/src/models.rs +++ b/src/models.rs @@ -2,9 +2,21 @@ use std::ops::{AddAssign, Deref, DerefMut}; use serde::Deserialize; -#[derive(Debug, Default, Clone, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq)] +pub enum Phase { + #[default] + Running, + Finished, + Restart, + RestartWrongs, +} + +#[derive(Debug, Default, Clone, PartialEq, Deserialize)] pub struct Questions { pub questions: Vec, + + #[serde(default, skip)] + pub wrong_questions: Vec, } impl AddAssign for Questions { @@ -27,10 +39,21 @@ impl DerefMut for Questions { } } -#[derive(Debug, Clone, PartialEq, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq)] +pub enum QuestionState { + #[default] + None, + Correct, + Wrong, +} + +#[derive(Debug, Default, Clone, PartialEq, Deserialize)] pub struct Question { pub message: String, pub answers: Vec, + + #[serde(default, skip)] + pub state: QuestionState, } #[derive(Debug, Clone, PartialEq, Deserialize)]