Files
jap_learn/src/main.rs
T

215 lines
5.7 KiB
Rust
Raw Normal View History

2026-02-10 17:25:39 +03:00
#![windows_subsystem = "windows"]
2026-04-09 22:45:31 +03:00
mod dictionary;
mod dictionary_test;
2026-02-10 11:28:12 +03:00
mod lang;
2026-02-10 12:12:16 +03:00
mod quiz;
2026-04-09 22:45:31 +03:00
mod randomizer;
mod repetition;
mod repetitions;
2026-02-10 12:12:16 +03:00
mod selector;
2026-02-10 17:04:48 +03:00
mod writing;
2026-04-13 22:25:58 +03:00
mod data_provider;
2026-04-17 12:38:05 +03:00
mod word;
2026-04-13 22:25:58 +03:00
use crate::data_provider::card_sets::load_sets;
use crate::data_provider::words::{create_db, load_words};
use crate::dictionary::{app_data_dir, DictionaryMessage, DictionaryState};
2026-04-09 22:45:31 +03:00
use crate::dictionary_test::{DictionaryQuizMessage, DictionaryQuizState};
2026-04-13 22:25:58 +03:00
use crate::lang::DictionaryElement;
2026-02-10 12:12:16 +03:00
use crate::quiz::*;
2026-04-09 22:45:31 +03:00
use crate::randomizer::randomizer::{RandomizerMessage, RandomizerState};
use crate::repetition::{RepetitionMessage, RepetitionState};
2026-04-13 22:25:58 +03:00
use crate::repetitions::{CardSetSettings, RepetitionsMessage, RepetitionsState};
2026-02-10 12:12:16 +03:00
use crate::selector::*;
2026-04-17 12:38:05 +03:00
use crate::word::{WordMessage, WordState};
2026-02-10 17:30:43 +03:00
use crate::writing::{WritingMessage, WritingState};
2026-04-09 22:45:31 +03:00
use crate::Page::{
2026-04-17 12:38:05 +03:00
Dictionary, DictionaryQuiz, Quiz, Randomizer, Repetition, Repetitions, Selector, Word, Writing
2026-04-09 22:45:31 +03:00
};
2026-04-17 12:38:05 +03:00
use crate::RootMessage::Keyboard;
use iced::keyboard::Event;
2026-02-10 12:12:16 +03:00
use iced::widget::text;
2026-04-15 07:55:03 +03:00
use iced::{keyboard, Element, Subscription};
2026-04-09 22:45:31 +03:00
use iced::{Font, Task};
2026-04-13 22:25:58 +03:00
use rusqlite::Connection;
2026-04-09 22:45:31 +03:00
use std::sync::{Arc, Mutex};
2026-02-10 11:28:12 +03:00
2026-04-16 09:56:57 +03:00
const DEFAULT_SPACING: f32 = 10.0;
2026-02-10 11:28:12 +03:00
fn main() -> iced::Result {
2026-04-14 15:19:46 +03:00
iced::application(ScreenState::boot, ScreenState::update, ScreenState::view).subscription(subscription)
2026-04-09 22:45:31 +03:00
.title("Kana learn app")
.font(include_bytes!("../noto.ttf"))
.default_font(Font::with_name("Noto Sans JP"))
2026-04-13 22:25:58 +03:00
.
run()
2026-02-10 11:28:12 +03:00
}
2026-04-14 15:19:46 +03:00
fn subscription(_state: &ScreenState) -> Subscription<RootMessage> {
keyboard::listen().map(|e| Keyboard(e))
}
#[derive(Clone)]
2026-02-10 11:28:12 +03:00
pub enum RootMessage {
Selector(SelectorMessage),
Quiz(QuizMessage),
2026-02-10 17:04:48 +03:00
Writing(WritingMessage),
2026-02-22 11:07:57 +03:00
Dictionary(DictionaryMessage),
DictionaryQuiz(DictionaryQuizMessage),
2026-04-09 22:45:31 +03:00
Randomizer(RandomizerMessage),
Repetitions(RepetitionsMessage),
Repetition(RepetitionMessage),
2026-04-17 12:38:05 +03:00
Word(WordMessage),
Keyboard(Event),
2026-02-10 11:28:12 +03:00
}
enum Page {
Selector(SelectorState),
Quiz(QuizState),
2026-02-10 17:04:48 +03:00
Writing(WritingState),
2026-02-22 11:07:57 +03:00
Dictionary(DictionaryState),
DictionaryQuiz(DictionaryQuizState),
Randomizer(RandomizerState),
2026-04-09 22:45:31 +03:00
Repetitions(RepetitionsState),
Repetition(RepetitionState),
2026-04-17 12:38:05 +03:00
Word(WordState),
2026-02-11 16:19:23 +03:00
PreviousPage,
2026-02-10 11:28:12 +03:00
}
pub struct ScreenState {
stack: Vec<Page>,
}
2026-04-09 22:45:31 +03:00
pub struct AppState {
pub dictionary: Vec<DictionaryElement>,
2026-04-13 22:25:58 +03:00
pub card_sets: Vec<CardSetSettings>,
pub connection: Connection
2026-04-09 22:45:31 +03:00
}
2026-02-10 11:28:12 +03:00
impl Default for ScreenState {
fn default() -> Self {
2026-04-13 22:25:58 +03:00
let path = app_data_dir();
let db_file = path.join("data.db");
let connection = Connection::open(db_file).unwrap();
2026-04-14 16:24:45 +03:00
connection.execute("PRAGMA foreign_keys = ON;", []).unwrap();
2026-04-13 22:25:58 +03:00
let list: Vec<DictionaryElement> = load_words(&connection);
let sets: Vec<CardSetSettings> = load_sets(&connection);
let state = Arc::new(Mutex::new(AppState { dictionary: list, card_sets: sets, connection }));
2026-02-10 11:28:12 +03:00
ScreenState {
2026-04-09 22:45:31 +03:00
stack: vec![Selector(SelectorState::new(state.clone()))],
2026-02-10 11:28:12 +03:00
}
}
}
impl ScreenState {
2026-04-09 22:45:31 +03:00
pub fn boot() -> (ScreenState, Task<RootMessage>) {
2026-04-13 22:25:58 +03:00
create_db();
2026-02-11 15:53:53 +03:00
(ScreenState::default(), Task::none())
}
2026-04-09 22:45:31 +03:00
pub fn update(&mut self, message: RootMessage) -> Task<RootMessage> {
2026-04-14 15:19:46 +03:00
if let Keyboard(e) = message {
return self.handle_keyboard(e);
}
2026-04-09 22:45:31 +03:00
state_update!(
message,
self.stack,
Selector,
Quiz,
Writing,
Dictionary,
DictionaryQuiz,
Randomizer,
Repetitions,
2026-04-17 12:38:05 +03:00
Repetition,
Word
2026-04-09 22:45:31 +03:00
);
2026-02-22 11:07:57 +03:00
Task::none()
2026-02-10 11:28:12 +03:00
}
pub fn view(&self) -> Element<'_, RootMessage> {
2026-04-09 22:45:31 +03:00
view_navigation!(
self.stack,
Quiz,
Selector,
Writing,
Dictionary,
DictionaryQuiz,
Randomizer,
Repetitions,
2026-04-17 12:38:05 +03:00
Repetition,
Word
2026-04-09 22:45:31 +03:00
)
2026-02-10 11:28:12 +03:00
}
2026-04-14 15:19:46 +03:00
fn handle_keyboard(&mut self, message: Event) -> Task<RootMessage> {
let page = self.stack.last_mut().unwrap();
2026-04-20 10:13:39 +03:00
return match page {
2026-04-14 15:19:46 +03:00
Repetition(page) => page.press(&message),
2026-04-20 10:13:39 +03:00
_ => Task::none(),
2026-04-14 15:19:46 +03:00
}
}
2026-02-10 11:28:12 +03:00
}
2026-04-14 15:19:46 +03:00
2026-02-10 12:12:16 +03:00
#[macro_export]
macro_rules! view_navigation {
($stack:expr, $($e:ident), *) => {
match &$stack.last().unwrap() {
$(
$e(s) => s.view().map(RootMessage::$e),
)*
_ => text!("").into(),
2026-02-10 11:28:12 +03:00
}
}
}
2026-02-10 12:12:16 +03:00
#[macro_export]
macro_rules! state_update {
($message:expr, $stack:expr, $($e:ident), *) => {
match $message {
$(
RootMessage::$e(msg) => {
if let $e(s) = $stack.last_mut().unwrap() {
message_navigation!(msg, $stack, s)
2026-02-10 11:28:12 +03:00
}
}
2026-02-10 12:12:16 +03:00
)*
2026-04-14 15:19:46 +03:00
_ => {}
2026-02-10 11:28:12 +03:00
}
}
}
2026-02-10 12:12:16 +03:00
#[macro_export]
macro_rules! message_navigation {
($msg:expr, $stack:expr, $state:expr) => {
if let Some(new_page) = $state.navigate(&$msg) {
2026-02-11 16:19:23 +03:00
if let Page::PreviousPage = new_page {
2026-02-10 12:12:16 +03:00
$stack.pop();
2026-02-22 11:07:57 +03:00
return Task::none();
2026-02-10 11:28:12 +03:00
}
2026-02-10 12:12:16 +03:00
$stack.push(new_page);
} else {
2026-02-22 11:07:57 +03:00
return $state.update($msg);
2026-02-10 11:28:12 +03:00
}
2026-02-10 12:12:16 +03:00
};
}
2026-02-10 11:28:12 +03:00
2026-02-10 12:12:16 +03:00
trait NavigatedPage<T> {
fn navigate(&self, message: &T) -> Option<Page>;
2026-04-09 22:45:31 +03:00
}
2026-04-14 15:19:46 +03:00
pub trait KeyPressedPage {
2026-04-20 10:13:39 +03:00
fn press(&mut self, message: &keyboard::Event) -> Task<RootMessage>;
2026-04-17 12:38:05 +03:00
}
/*pub fn danger_button(x: &Theme, status: Status) -> Style{
Style {
background: Some(Color(x.palette().danger)),
text_color: x.palette().text,
border: Border::default().rounded(2),
shadow: Default::default(),
snap: false,
}
}*/