Compare commits

..

No commits in common. "7a847905d773d67bbb92cf09b24da6baec3e7cd7" and "fe7f626c01444a8a0db2e4d400f4a6a09e816b39" have entirely different histories.

2 changed files with 38 additions and 94 deletions

View File

@ -7,8 +7,8 @@ use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
use dioxus::{logger::tracing, prelude::*}; use dioxus::{logger::tracing, prelude::*};
#[cfg(feature = "bundled")] #[cfg(feature = "bundled")]
use include_dir::{Dir, include_dir}; use include_dir::{Dir, include_dir};
use models::{Phase, Question, QuestionState, Questions}; use models::{Question, Questions};
use rand::{rngs::ThreadRng, seq::SliceRandom}; use rand::seq::SliceRandom;
#[cfg(feature = "desktop")] #[cfg(feature = "desktop")]
use std::{env, fs}; use std::{env, fs};
#[cfg(not(feature = "web"))] #[cfg(not(feature = "web"))]
@ -78,25 +78,21 @@ fn get_questions() -> Questions {
.clone() .clone()
} }
fn get_rand_questions() -> Questions { fn get_rand_questions() -> Vec<Question> {
let mut questions = get_questions(); let mut questions = get_questions().questions;
let mut rng = rand::rng(); let mut rng = rand::rng();
// Randomize the answers // Randomize the answers
randomize_answers(&mut rng, &mut questions); questions
.iter_mut()
.for_each(|q| q.answers.shuffle(&mut rng));
// Randomize the questions list // Randomize the questions list
questions.shuffle(&mut rng); questions.shuffle(&mut rng);
questions.count = questions.questions.len();
questions questions
} }
fn randomize_answers(rng: &mut ThreadRng, questions: &mut [Question]) {
questions.iter_mut().for_each(|q| q.answers.shuffle(rng));
}
fn main() { fn main() {
#[cfg(feature = "desktop")] #[cfg(feature = "desktop")]
{ {
@ -126,13 +122,12 @@ fn App() -> Element {
let mut correct_questions = use_signal(|| 0); let mut correct_questions = use_signal(|| 0);
let mut wrong_questions = use_signal(|| 0); let mut wrong_questions = use_signal(|| 0);
let mut phase = use_signal(|| Phase::Running); let mut has_finished = use_signal(|| false);
let mut next_phase = use_signal(|| Phase::Running); let mut has_restart = use_signal(|| false);
use_effect(move || { use_effect(move || {
let current_phase = phase(); let has_restart = has_restart();
match current_phase { if has_restart {
Phase::Restart => {
let mut questions_lock = questions.write(); let mut questions_lock = questions.write();
*questions_lock = get_rand_questions(); *questions_lock = get_rand_questions();
@ -140,46 +135,28 @@ fn App() -> Element {
correct_questions.set(0); correct_questions.set(0);
wrong_questions.set(0); wrong_questions.set(0);
next_phase.set(Phase::Running); has_finished.set(false);
}
Phase::RestartWrongs => {
let mut questions_lock = questions.write();
let wrongs = questions_lock.wrong_questions.to_vec();
questions_lock.count = wrongs.len();
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 || { use_effect(move || {
let next_phase = next_phase(); let has_finished = has_finished();
phase.set(next_phase); if !has_finished {
has_restart.set(false);
}
}); });
rsx! { rsx! {
document::Link { rel: "stylesheet", href: MAIN_CSS } document::Link { rel: "stylesheet", href: MAIN_CSS }
if phase() == Phase::Running { if !has_finished() {
QuestionForm { questions, correct_questions, wrong_questions, phase } QuestionForm { questions, correct_questions, wrong_questions, has_finished, has_restart }
} }
else if phase() != Phase::Running { else if has_finished() {
Report { Report {
questions: questions(), questions: questions(),
correct_questions: correct_questions(), correct_questions: correct_questions(),
wrong_questions: wrong_questions(), wrong_questions: wrong_questions(),
phase, has_restart,
} }
} }
} }
@ -188,12 +165,13 @@ fn App() -> Element {
#[allow(clippy::redundant_closure)] #[allow(clippy::redundant_closure)]
#[component] #[component]
pub fn QuestionForm( pub fn QuestionForm(
questions: Signal<Questions>, questions: Signal<Vec<Question>>,
correct_questions: Signal<i32>, correct_questions: Signal<i32>,
wrong_questions: Signal<i32>, wrong_questions: Signal<i32>,
phase: Signal<Phase>, has_finished: Signal<bool>,
has_restart: Signal<bool>,
) -> Element { ) -> Element {
let mut current = use_signal(move || Question::default()); let mut current = use_signal(move || questions()[0].clone());
use_effect(move || { use_effect(move || {
let _correct_count = correct_questions(); let _correct_count = correct_questions();
@ -202,7 +180,7 @@ pub fn QuestionForm(
let mut questions_lock = questions.write(); let mut questions_lock = questions.write();
if questions_lock.is_empty() { if questions_lock.is_empty() {
phase.set(Phase::Finished); has_finished.set(true);
} else { } else {
let new_question = questions_lock.remove(0); let new_question = questions_lock.remove(0);
current.set(new_question); current.set(new_question);
@ -245,7 +223,6 @@ pub fn QuestionForm(
sleep(Duration::from_millis(600)).await; sleep(Duration::from_millis(600)).await;
let mut current_lock = current.write(); let mut current_lock = current.write();
let mut questions_lock = questions.write();
let mut correct_questions_lock = correct_questions.write(); let mut correct_questions_lock = correct_questions.write();
let mut wrong_questions_lock = wrong_questions.write(); let mut wrong_questions_lock = wrong_questions.write();
@ -260,8 +237,6 @@ pub fn QuestionForm(
*correct_questions_lock += 1; *correct_questions_lock += 1;
} else if is_wrong { } else if is_wrong {
*wrong_questions_lock += 1; *wrong_questions_lock += 1;
let current_question = current_lock.clone();
questions_lock.wrong_questions.push(current_question);
} }
// Reset animation flags // Reset animation flags
@ -378,11 +353,11 @@ pub fn Result(is_correct: bool, is_wrong: bool) -> Element {
#[allow(clippy::redundant_closure)] #[allow(clippy::redundant_closure)]
#[component] #[component]
pub fn Info( pub fn Info(
questions: Signal<Questions>, questions: Signal<Vec<Question>>,
correct_questions: Signal<i32>, correct_questions: Signal<i32>,
wrong_questions: Signal<i32>, wrong_questions: Signal<i32>,
) -> Element { ) -> Element {
let total_questions = questions().count; let total_questions = get_questions().len();
let current_question = use_memo(move || questions().len()); let current_question = use_memo(move || questions().len());
let left_questions = use_memo(move || total_questions - current_question()); let left_questions = use_memo(move || total_questions - current_question());
@ -406,10 +381,10 @@ pub fn Info(
#[component] #[component]
pub fn Report( pub fn Report(
questions: Questions, questions: Vec<Question>,
correct_questions: i32, correct_questions: i32,
wrong_questions: i32, wrong_questions: i32,
phase: Signal<Phase>, has_restart: Signal<bool>,
) -> Element { ) -> Element {
let questions_size = questions.len(); let questions_size = questions.len();
@ -429,19 +404,14 @@ pub fn Report(
div { div {
button { button {
onclick: move |_| { onclick: move |_| {
phase.set(Phase::Restart); has_restart.set(true);
}, },
"Restart" "Restart"
}, },
if wrong_questions > 0 {
button { button {
onclick: move |_| {
phase.set(Phase::RestartWrongs);
},
"Restart with only wrong questions" "Restart with only wrong questions"
} }
} }
} }
} }
} }
}

View File

@ -2,24 +2,9 @@ use std::ops::{AddAssign, Deref, DerefMut};
use serde::Deserialize; use serde::Deserialize;
#[derive(Debug, Default, Clone, PartialEq)] #[derive(Debug, Default, Clone, Deserialize)]
pub enum Phase {
#[default]
Running,
Finished,
Restart,
RestartWrongs,
}
#[derive(Debug, Default, Clone, PartialEq, Deserialize)]
pub struct Questions { pub struct Questions {
pub questions: Vec<Question>, pub questions: Vec<Question>,
#[serde(default, skip)]
pub wrong_questions: Vec<Question>,
#[serde(default, skip)]
pub count: usize,
} }
impl AddAssign for Questions { impl AddAssign for Questions {
@ -42,21 +27,10 @@ impl DerefMut for Questions {
} }
} }
#[derive(Debug, Default, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub enum QuestionState {
#[default]
None,
Correct,
Wrong,
}
#[derive(Debug, Default, Clone, PartialEq, Deserialize)]
pub struct Question { pub struct Question {
pub message: String, pub message: String,
pub answers: Vec<Answer>, pub answers: Vec<Answer>,
#[serde(default, skip)]
pub state: QuestionState,
} }
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]