Writing test page

This commit is contained in:
2026-02-10 17:04:48 +03:00
parent fe75d7de23
commit 87a9fae91a
4 changed files with 143 additions and 12 deletions
+9 -3
View File
@@ -180,6 +180,14 @@ impl KanaSet {
} }
pub fn next(&mut self) -> (String, String) { pub fn next(&mut self) -> (String, String) {
let current_set = self.list();
let mut rand = rand::rng();
let index: u32 = rand.random();
current_set[index as usize % current_set.len()].clone()
}
pub fn list(&self) -> Vec<(String, String)> {
let mut current_set: Vec<(String, String)> = Vec::new(); let mut current_set: Vec<(String, String)> = Vec::new();
for i in 0..10 { for i in 0..10 {
@@ -190,9 +198,7 @@ impl KanaSet {
} }
} }
let mut rand = rand::rng(); current_set
let index: u32 = rand.random();
current_set[index as usize % current_set.len()].clone()
} }
} }
+7 -3
View File
@@ -1,12 +1,14 @@
mod lang; mod lang;
mod quiz; mod quiz;
mod selector; mod selector;
mod writing;
use crate::quiz::*; use crate::quiz::*;
use crate::selector::*; use crate::selector::*;
use crate::Page::{Quiz, Selector}; use crate::Page::{Quiz, Selector, Writing};
use iced::widget::text; use iced::widget::text;
use iced::Element; use iced::Element;
use crate::writing::{WritingMessage, WritingState};
fn main() -> iced::Result { fn main() -> iced::Result {
iced::application("A kana learn app", ScreenState::update, ScreenState::view).run() iced::application("A kana learn app", ScreenState::update, ScreenState::view).run()
@@ -16,11 +18,13 @@ fn main() -> iced::Result {
pub enum RootMessage { pub enum RootMessage {
Selector(SelectorMessage), Selector(SelectorMessage),
Quiz(QuizMessage), Quiz(QuizMessage),
Writing(WritingMessage),
} }
enum Page { enum Page {
Selector(SelectorState), Selector(SelectorState),
Quiz(QuizState), Quiz(QuizState),
Writing(WritingState),
Back, Back,
} }
@@ -44,11 +48,11 @@ impl Default for ScreenState {
impl ScreenState { impl ScreenState {
pub fn update(&mut self, message: RootMessage) { pub fn update(&mut self, message: RootMessage) {
state_update!(message, self.stack, Selector, Quiz); state_update!(message, self.stack, Selector, Quiz, Writing);
} }
pub fn view(&self) -> Element<'_, RootMessage> { pub fn view(&self) -> Element<'_, RootMessage> {
view_navigation!(self.stack, Quiz, Selector) view_navigation!(self.stack, Quiz, Selector, Writing)
} }
} }
+17 -3
View File
@@ -1,17 +1,21 @@
use crate::lang::{KanaSet, KanaType}; use crate::lang::{KanaSet, KanaType};
use crate::Page::Quiz; use crate::selector::SelectorMessage::ChangeMode;
use crate::writing::WritingState;
use crate::Page::{Quiz, Writing};
use crate::{NavigatedPage, Page, QuizState}; use crate::{NavigatedPage, Page, QuizState};
use iced::widget::{button, checkbox, container, text, Column, Row}; use iced::widget::*;
use iced::{alignment, Element, Font}; use iced::{alignment, Element, Font};
pub struct SelectorState { pub struct SelectorState {
pub set: KanaSet, pub set: KanaSet,
is_writing: bool,
} }
impl Default for SelectorState { impl Default for SelectorState {
fn default() -> Self { fn default() -> Self {
Self { Self {
set: KanaSet::hiragana(), set: KanaSet::hiragana(),
is_writing: false,
} }
} }
} }
@@ -21,14 +25,20 @@ pub enum SelectorMessage {
Change, Change,
Goto, Goto,
Check(usize, bool), Check(usize, bool),
ChangeMode(bool),
} }
impl NavigatedPage<SelectorMessage> for SelectorState { impl NavigatedPage<SelectorMessage> for SelectorState {
fn navigate(&self, message: &SelectorMessage) -> Option<Page> { fn navigate(&self, message: &SelectorMessage) -> Option<Page> {
if let SelectorMessage::Goto = message { if let SelectorMessage::Goto = message {
return if self.is_writing {
let writing = WritingState::new(&self.set);
Some(Writing(writing))
} else {
let mut quiz = QuizState::new(); let mut quiz = QuizState::new();
quiz.set = self.set.clone(); quiz.set = self.set.clone();
return Some(Quiz(quiz)); Some(Quiz(quiz))
};
} }
None None
} }
@@ -43,6 +53,7 @@ impl SelectorState {
}, },
SelectorMessage::Goto => {} SelectorMessage::Goto => {}
SelectorMessage::Check(i, b) => self.set.include_map[i] = b, SelectorMessage::Check(i, b) => self.set.include_map[i] = b,
ChangeMode(b) => self.is_writing = b,
} }
} }
@@ -51,6 +62,9 @@ impl SelectorState {
iced::widget::column![ iced::widget::column![
button("Переключить").on_press(SelectorMessage::Change), button("Переключить").on_press(SelectorMessage::Change),
self.rows_selector(), self.rows_selector(),
toggler(self.is_writing)
.label("Режим письма")
.on_toggle(ChangeMode),
button("К тесту").on_press(SelectorMessage::Goto), button("К тесту").on_press(SelectorMessage::Goto),
] ]
.spacing(10), .spacing(10),
+107
View File
@@ -0,0 +1,107 @@
use crate::lang::KanaSet;
use crate::Page::Back;
use crate::{NavigatedPage, Page};
use iced::widget::*;
use iced::{alignment, Element, Fill, Font};
use rand::seq::SliceRandom;
#[derive(Clone, Debug)]
pub struct WritingState {
kana: String,
set: Vec<(String, String)>,
original_set: Vec<(String, String)>,
kana_total: String,
roman_total: String,
is_help: bool,
next_text: String,
}
impl NavigatedPage<WritingMessage> for WritingState {
fn navigate(&self, message: &WritingMessage) -> Option<Page> {
if let WritingMessage::Back = message {
Some(Back)
} else {
None
}
}
}
impl WritingState {
pub(crate) fn new(set: &KanaSet) -> WritingState {
let mut list = set.list();
list.shuffle(&mut rand::rng());
WritingState {
kana: "".to_string(),
set: list.clone(),
original_set: list,
kana_total: "".to_string(),
roman_total: "".to_string(),
is_help: false,
next_text: "Дальше".to_string(),
}
}
}
impl WritingState {
pub fn update(&mut self, message: WritingMessage) {
match message {
WritingMessage::Back => todo!(),
WritingMessage::Next => self.next(),
}
}
fn next(&mut self) {
if self.set.is_empty() {
self.kana = "".to_string();
self.roman_total = "".to_string();
self.kana_total = "".to_string();
self.set = self.original_set.clone();
return;
}
let current = self.set.pop().unwrap();
self.kana_total += &*format!("{} ", &current.0).to_string();
self.roman_total += &*format!("{} ", &current.1.clone()).to_string();
self.kana = current.1;
}
pub fn view(&self) -> Element<'_, WritingMessage> {
container(
iced::widget::column![
text!("{}", self.roman_total).size(24),
text!("{}", self.kana).size(48),
self.answers(),
row![
button(text!("{}", self.next_text)).on_press(WritingMessage::Next),
button("Закончить").on_press(WritingMessage::Back),
]
.spacing(10)
]
.spacing(10)
.align_x(alignment::Horizontal::Center),
)
.center_x(Fill)
.into()
}
fn answers(&self) -> Element<'_, WritingMessage> {
if self.set.is_empty() {
text!("{}", self.kana_total).font(Font::with_name("AppleGothic")).size(36).into()
} else {
vertical_space().height(36).into()
}
}
}
#[derive(Debug, Clone)]
pub enum WritingMessage {
Next,
Back,
}
#[derive(Default, Debug, Clone)]
pub struct Score {
total: i32,
correct: i32,
fail: i32,
}