code cleanup

This commit is contained in:
2026-08-01 19:43:07 +03:00
parent 42d0488f23
commit 20cb50574c
21 changed files with 421 additions and 373 deletions
+19 -17
View File
@@ -1,21 +1,25 @@
use crate::lang::SetOrderMode;
use crate::repetitions::CardSetSettings; use crate::repetitions::CardSetSettings;
use rusqlite::Connection; use rusqlite::Connection;
use crate::lang::SetOrderMode;
pub fn load_sets(connection: &Connection) -> Vec<CardSetSettings> { pub fn load_sets(connection: &Connection) -> Vec<CardSetSettings> {
let mut stmt = connection.prepare("SELECT id, name, forward, backward, filter FROM card_set").unwrap(); let mut stmt = connection
let iter = stmt.query_map([], |row| { .prepare("SELECT id, name, forward, backward, filter FROM card_set")
Ok(CardSetSettings { .unwrap();
id: row.get(0)?, let iter = stmt
name: row.get(1)?, .query_map([], |row| {
forward: row.get(2)?, Ok(CardSetSettings {
backward: row.get(3)?, id: row.get(0)?,
filter: row.get(4)?, name: row.get(1)?,
count: None, forward: row.get(2)?,
worst_words_list: None, backward: row.get(3)?,
open_mode: SetOrderMode::Default, filter: row.get(4)?,
count: None,
worst_words_list: None,
open_mode: SetOrderMode::Default,
})
}) })
}).unwrap(); .unwrap();
let mut buffer = vec![]; let mut buffer = vec![];
for word in iter { for word in iter {
@@ -42,12 +46,10 @@ pub fn add_set(set: &mut CardSetSettings, connection: &Connection) {
set.id = index; set.id = index;
} }
pub fn update_card_set(set: &mut CardSetSettings, connection: &Connection){ pub fn update_card_set(set: &mut CardSetSettings, connection: &Connection) {
if set.id == 0 { if set.id == 0 {
add_set(set, &connection); add_set(set, &connection);
} } else {
else {
connection connection
.execute( .execute(
"UPDATE card_set SET name = ?1, forward = ?2, backward = ?3, filter = ?4 WHERE id = ?5", "UPDATE card_set SET name = ?1, forward = ?2, backward = ?3, filter = ?4 WHERE id = ?5",
+48 -33
View File
@@ -4,16 +4,20 @@ use rusqlite::Connection;
use std::time::Instant; use std::time::Instant;
pub fn load_stats_of_set(set: &CardSetSettings, connection: &Connection) -> Vec<CardStatistics> { pub fn load_stats_of_set(set: &CardSetSettings, connection: &Connection) -> Vec<CardStatistics> {
let mut stmt = connection.prepare("SELECT id, word_id, score, last_opened FROM card_stats WHERE set_id = ?1").unwrap(); let mut stmt = connection
let iter = stmt.query_map((set.id,), |row| { .prepare("SELECT id, word_id, score, last_opened FROM card_stats WHERE set_id = ?1")
Ok(CardStatistics { .unwrap();
id: row.get(0)?, let iter = stmt
word_id: row.get(1)?, .query_map((set.id,), |row| {
set_id: set.id, Ok(CardStatistics {
score: row.get(2)?, id: row.get(0)?,
last_open: row.get(3)?, word_id: row.get(1)?,
set_id: set.id,
score: row.get(2)?,
last_open: row.get(3)?,
})
}) })
}).unwrap(); .unwrap();
let mut buffer = vec![]; let mut buffer = vec![];
for word in iter { for word in iter {
@@ -23,23 +27,38 @@ pub fn load_stats_of_set(set: &CardSetSettings, connection: &Connection) -> Vec<
buffer buffer
} }
pub fn add_stat_list(stat: &mut Vec<CardStatistics>, connection: &Connection) { pub fn add_stat_list(stat: &mut Vec<CardStatistics>, connection: &Connection) {
let inserting = stat.iter().map(|stat| format!("({}, {}, {}, {})", stat.word_id.to_string(), stat.set_id.to_string(), stat.score.to_string(), stat.last_open.timestamp().to_string())).collect::<Vec<_>>().join(", "); let inserting = stat
let query = format!("INSERT INTO card_stats (word_id, set_id, score, last_opened) VALUES {}", inserting); .iter()
let count = connection .map(|stat| {
.execute( format!(
query.as_str(), "({}, {}, {}, {})",
( stat.word_id.to_string(),
), stat.set_id.to_string(),
); stat.score.to_string(),
stat.last_open.timestamp().to_string()
)
})
.collect::<Vec<_>>()
.join(", ");
let query = format!(
"INSERT INTO card_stats (word_id, set_id, score, last_opened) VALUES {}",
inserting
);
let count = connection.execute(query.as_str(), ());
if count.is_err() { if count.is_err() {
println!("{}", count.unwrap_err()); println!("{}", count.unwrap_err());
return; return;
} }
let last_index : u32 = connection.query_one("SELECT seq from sqlite_sequence WHERE name == ?1", ("card_stats".to_string(),), |row| row.get(0)).unwrap(); let last_index: u32 = connection
.query_one(
"SELECT seq from sqlite_sequence WHERE name == ?1",
("card_stats".to_string(),),
|row| row.get(0),
)
.unwrap();
let start_index = last_index - (count.unwrap() as u32) + 1; let start_index = last_index - (count.unwrap() as u32) + 1;
@@ -48,10 +67,8 @@ pub fn add_stat_list(stat: &mut Vec<CardStatistics>, connection: &Connection) {
stat[index].id = id as u32; stat[index].id = id as u32;
index += 1; index += 1;
} }
} }
pub fn add_stat(stat: &mut CardStatistics, connection: &Connection) { pub fn add_stat(stat: &mut CardStatistics, connection: &Connection) {
let time = Instant::now(); let time = Instant::now();
let index = connection let index = connection
@@ -71,21 +88,19 @@ pub fn add_stat(stat: &mut CardStatistics, connection: &Connection) {
println!("Added stat: {}", time.elapsed().as_millis()); println!("Added stat: {}", time.elapsed().as_millis());
} }
pub fn update_stat_score(stat: &CardStatistics, connection: &Connection){ pub fn update_stat_score(stat: &CardStatistics, connection: &Connection) {
let time = Instant::now(); let time = Instant::now();
connection connection
.execute( .execute(
"UPDATE card_stats SET score = ?1, last_opened = ?2 WHERE id = ?3", "UPDATE card_stats SET score = ?1, last_opened = ?2 WHERE id = ?3",
( (&stat.score, &stat.last_open.timestamp(), &stat.id),
&stat.score, )
&stat.last_open.timestamp(), .unwrap_or_else(|e| {
&stat.id println!("{}", e);
), 0
) });
.unwrap_or_else(|e| {println!("{}", e); 0});
println!("Updated stat: {}", time.elapsed().as_millis()); println!("Updated stat: {}", time.elapsed().as_millis());
} }
pub fn delete_stat(stat: &CardStatistics, connection: &Connection) { pub fn delete_stat(stat: &CardStatistics, connection: &Connection) {
+18 -10
View File
@@ -33,7 +33,6 @@ fn parse_history_items(strings: Vec<String>) -> Vec<HistoryItem> {
let mut items = Vec::with_capacity(strings.len()); let mut items = Vec::with_capacity(strings.len());
for string in strings { for string in strings {
if let [time, word, mode, before, after] = string.split(';').collect::<Vec<&str>>()[..] { if let [time, word, mode, before, after] = string.split(';').collect::<Vec<&str>>()[..] {
items.push(HistoryItem { items.push(HistoryItem {
timestamp: DateTime::from_timestamp(time.parse().unwrap(), 0).unwrap(), timestamp: DateTime::from_timestamp(time.parse().unwrap(), 0).unwrap(),
word_id: word.parse::<u32>().unwrap(), word_id: word.parse::<u32>().unwrap(),
@@ -56,15 +55,24 @@ pub fn push_note(set_id: u32, item: HistoryItem) {
let app_dir = app_data_dir(); let app_dir = app_data_dir();
let path = app_dir.clone().join(format!("set_{}_history.csv", set_id)); let path = app_dir.clone().join(format!("set_{}_history.csv", set_id));
let mut file = OpenOptions::new().create(true).append(true).open(path).unwrap(); let mut file = OpenOptions::new()
let line_str = format!("{};{};{};{};{}", item.timestamp.timestamp(), item.word_id, match item.mode { .create(true)
WordOpenMode::Easy => 4, .append(true)
WordOpenMode::Ok => 3, .open(path)
WordOpenMode::Hard => 2, .unwrap();
WordOpenMode::None => 1 let line_str = format!(
}, "{};{};{};{};{}",
item.before, item.timestamp.timestamp(),
item.after); item.word_id,
match item.mode {
WordOpenMode::Easy => 4,
WordOpenMode::Ok => 3,
WordOpenMode::Hard => 2,
WordOpenMode::None => 1,
},
item.before,
item.after
);
writeln!(&mut file, "{}", line_str.to_string()).unwrap(); writeln!(&mut file, "{}", line_str.to_string()).unwrap();
} }
+3 -4
View File
@@ -1,8 +1,7 @@
pub(crate) mod words;
pub(crate) mod card_sets; pub(crate) mod card_sets;
pub(crate) mod card_stats; pub(crate) mod card_stats;
pub(crate) mod voice; pub(crate) mod history;
pub(crate) mod settings; pub(crate) mod settings;
pub(crate) mod sqlite; pub(crate) mod sqlite;
pub(crate) mod history; pub(crate) mod voice;
pub(crate) mod words;
+9 -11
View File
@@ -1,10 +1,10 @@
use rusqlite::Connection; use rusqlite::Connection;
pub fn get_setting(key: String, connection: &Connection) -> Option<String> { pub fn get_setting(key: String, connection: &Connection) -> Option<String> {
let mut stmt = connection.prepare("SELECT value FROM settings WHERE id = ?1").unwrap(); let mut stmt = connection
let iter = stmt.query_map((key,), |row| { .prepare("SELECT value FROM settings WHERE id = ?1")
row.get(0) .unwrap();
}).unwrap(); let iter = stmt.query_map((key,), |row| row.get(0)).unwrap();
for row in iter { for row in iter {
if let Ok(value) = row { if let Ok(value) = row {
@@ -19,7 +19,7 @@ pub fn set_setting(key: String, value: String, connection: &Connection) {
let current = get_settings_list(connection); let current = get_settings_list(connection);
if current.contains(&key) { if current.contains(&key) {
update_settings(key, value, connection); update_settings(key, value, connection);
}else { } else {
create_settings(key, value, connection); create_settings(key, value, connection);
} }
} }
@@ -56,13 +56,11 @@ where id = ?1",
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
println!("{}", e); println!("{}", e);
0 0
});} });
}
fn get_settings_list(connection: &Connection) -> Vec<String> { fn get_settings_list(connection: &Connection) -> Vec<String> {
let mut stmt = connection.prepare("SELECT id FROM settings").unwrap(); let mut stmt = connection.prepare("SELECT id FROM settings").unwrap();
let iter = stmt.query_map((), |row| { let iter = stmt.query_map((), |row| row.get(0)).unwrap();
row.get(0) iter.map(|row| row.unwrap()).collect()
}).unwrap();
iter.map(|row| { row.unwrap() }).collect()
} }
+2 -4
View File
@@ -10,16 +10,14 @@ pub fn create_db() {
connection.execute("PRAGMA foreign_keys = ON;", []).unwrap(); connection.execute("PRAGMA foreign_keys = ON;", []).unwrap();
create_tables(&connection); create_tables(&connection);
}else { } else {
let connection = Connection::open(&db_file).unwrap(); let connection = Connection::open(&db_file).unwrap();
ensure_db_schema(&connection); ensure_db_schema(&connection);
} }
} }
fn ensure_db_schema(conn: &Connection) { fn ensure_db_schema(conn: &Connection) {}
}
fn create_tables(conn: &Connection) { fn create_tables(conn: &Connection) {
make_card_set(conn).unwrap(); make_card_set(conn).unwrap();
+4 -2
View File
@@ -27,9 +27,11 @@ pub async fn get_voice(text: &str) -> BufReader<File> {
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.body(query) .body(query)
.send() .send()
.await.unwrap() .await
.unwrap()
.bytes() .bytes()
.await.unwrap(); .await
.unwrap();
tokio::fs::write(&path, &audio).await.unwrap(); tokio::fs::write(&path, &audio).await.unwrap();
} }
-1
View File
@@ -2,7 +2,6 @@ use crate::lang::{WordData, WordGroup};
use rusqlite::Connection; use rusqlite::Connection;
use std::collections::HashMap; use std::collections::HashMap;
pub fn add_word(word: &mut WordData, connection: &Connection) { pub fn add_word(word: &mut WordData, connection: &Connection) {
let index = connection let index = connection
.query_row( .query_row(
+7 -19
View File
@@ -12,6 +12,7 @@ use iced::alignment::Vertical::Center;
use iced::widget::button::Style; use iced::widget::button::Style;
use iced::widget::button::{danger, text}; use iced::widget::button::{danger, text};
use iced::widget::space::horizontal; use iced::widget::space::horizontal;
use iced::widget::text_input::default;
use iced::widget::*; use iced::widget::*;
use iced::{Border, Color, Length, Shadow, Task}; use iced::{Border, Color, Length, Shadow, Task};
use rand::random_range; use rand::random_range;
@@ -21,8 +22,6 @@ use std::ops::Add;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use iced::widget::text_input::default;
use DictionaryMessage::Back;
#[derive(Clone)] #[derive(Clone)]
pub struct DictionaryState { pub struct DictionaryState {
@@ -295,12 +294,10 @@ impl DictionaryState {
iced::widget::column![ iced::widget::column![
self.groups_panel(), self.groups_panel(),
self.words_list(), self.words_list(),
button("Добавить слово") button("Добавить слово").style(jl_button).on_press(NewWord),
.style(jl_button) ]
.on_press(NewWord), .spacing(5),
].spacing(5),
self.filters(), self.filters(),
] ]
.spacing(5) .spacing(5)
.into(), .into(),
@@ -340,10 +337,7 @@ impl DictionaryState {
let mut line = Row::new().width(Length::Fill).align_y(Center); let mut line = Row::new().width(Length::Fill).align_y(Center);
line = line line = line
.push( .push(checkbox(self.include_map[i]).on_toggle(move |b| Include(i, b)))
checkbox(self.include_map[i])
.on_toggle(move |b| Include(i, b)),
)
.push(space().width(10)); .push(space().width(10));
line = line.push( line = line.push(
@@ -396,9 +390,7 @@ impl DictionaryState {
}); });
} }
button("") button("").on_press(WordAction(i)).width(15)
.on_press(WordAction(i))
.width(15)
}; };
line = line.push(line_button()).push(space().width(10)); line = line.push(line_button()).push(space().width(10));
@@ -524,11 +516,7 @@ impl DictionaryState {
fn groups_panel(&self) -> iced::Element<'_, DictionaryMessage> { fn groups_panel(&self) -> iced::Element<'_, DictionaryMessage> {
let mut row = Row::new(); let mut row = Row::new();
row = row.push( row = row.push(button("+").style(text).on_press(CreateGroup));
button("+")
.style(text)
.on_press(CreateGroup),
);
let state = &self.state.lock().unwrap(); let state = &self.state.lock().unwrap();
let groups = &state.word_groups; let groups = &state.word_groups;
+13 -17
View File
@@ -1,17 +1,17 @@
use crate::dictionary::{split_with_coma}; use crate::dictionary::split_with_coma;
use crate::dictionary_test::DictionaryQuizMessage::*;
use crate::lang::WordData;
use crate::navigation::Page::PreviousPage;
use crate::navigation::*;
use crate::quiz::Score; use crate::quiz::Score;
use crate::{RootMessage}; use crate::styling::*;
use crate::RootMessage;
use iced::border::Radius; use iced::border::Radius;
use iced::widget::container::Style; use iced::widget::container::Style;
use iced::widget::{button, container, row, space, text, text_input, Row}; use iced::widget::{button, container, row, space, text, text_input, Row};
use iced::Background::Color; use iced::Background::Color;
use iced::{alignment, Border, Element, Fill, Task, Theme}; use iced::{alignment, Border, Element, Fill, Task, Theme};
use rand::prelude::SliceRandom; use rand::prelude::SliceRandom;
use crate::dictionary_test::DictionaryQuizMessage::*;
use crate::lang::WordData;
use crate::navigation::{NavigatedPage, Page};
use crate::navigation::Page::PreviousPage;
use crate::styling::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DictionaryQuizState { pub struct DictionaryQuizState {
@@ -44,11 +44,7 @@ impl NavigatedPage<DictionaryQuizMessage> for DictionaryQuizState {
} }
impl DictionaryQuizState { impl DictionaryQuizState {
pub fn new( pub fn new(words: Vec<WordData>, reverse: bool, no_typing: bool) -> DictionaryQuizState {
words: Vec<WordData>,
reverse: bool,
no_typing: bool,
) -> DictionaryQuizState {
DictionaryQuizState { DictionaryQuizState {
words, words,
current_set: Vec::new(), current_set: Vec::new(),
@@ -86,7 +82,9 @@ impl DictionaryQuizState {
} else { } else {
String::new() String::new()
} }
).size(ACCENT_FONT_SIZE).align_y(alignment::Vertical::Center), )
.size(ACCENT_FONT_SIZE)
.align_y(alignment::Vertical::Center),
] ]
.align_x(alignment::Horizontal::Center) .align_x(alignment::Horizontal::Center)
.spacing(5), .spacing(5),
@@ -136,7 +134,7 @@ impl DictionaryQuizState {
self.is_help = false; self.is_help = false;
self.score.total += 1; self.score.total += 1;
self.show_next() self.show_next()
}else { } else {
self.is_help = true; self.is_help = true;
} }
} }
@@ -206,9 +204,7 @@ impl DictionaryQuizState {
fn appeal_button(&self) -> Element<'_, DictionaryQuizMessage> { fn appeal_button(&self) -> Element<'_, DictionaryQuizMessage> {
if self.is_help && self.no_typing == false { if self.is_help && self.no_typing == false {
return button("Апелляция").style(jl_button) return button("Апелляция").style(jl_button).on_press(Appeal).into();
.on_press(Appeal)
.into();
} }
space().into() space().into()
} }
+13 -20
View File
@@ -51,26 +51,19 @@ impl HistoryState {
} }
pub fn view(&self) -> Element<'_, HistoryMessage> { pub fn view(&self) -> Element<'_, HistoryMessage> {
back_overlay(iced::widget::row![ back_overlay(
horizontal().width(FillPortion(1)), iced::widget::row![
scrollable(self.history_lines().padding(DEFAULT_SPACING)) horizontal().width(FillPortion(1)),
.height(Fill) scrollable(self.history_lines().padding(DEFAULT_SPACING))
.width(FillPortion(5)), .height(Fill)
horizontal().width(FillPortion(1)) .width(FillPortion(5)),
] horizontal().width(FillPortion(1))
.height(Fill) ]
.width(Fill).into(), Back) .height(Fill)
// container( .width(Fill)
// iced::widget::column![ .into(),
// button("Назад").style(jl_button).on_press(Back), Back,
// )
// ]
// .align_x(Left)
// .width(Fill),
// )
// .center_x(Fill)
// .padding(10)
// .into()
} }
fn history_lines(&self) -> Column<'_, HistoryMessage> { fn history_lines(&self) -> Column<'_, HistoryMessage> {
+24 -18
View File
@@ -1,12 +1,12 @@
use crate::AppState;
use crate::data_provider::card_stats::{ use crate::data_provider::card_stats::{
add_stat_list, delete_stat, load_stats_of_set, update_stat_score, add_stat_list, delete_stat, load_stats_of_set, update_stat_score,
}; };
use crate::data_provider::history::{HistoryItem, push_note}; use crate::data_provider::history::{push_note, HistoryItem};
use crate::repetitions::CardSetSettings; use crate::repetitions::CardSetSettings;
use crate::AppState;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use rand::distr::Distribution;
use rand::distr::weighted::WeightedIndex; use rand::distr::weighted::WeightedIndex;
use rand::distr::Distribution;
use rand::prelude::SliceRandom; use rand::prelude::SliceRandom;
use rand::rng; use rand::rng;
use rand::rngs::ThreadRng; use rand::rngs::ThreadRng;
@@ -399,13 +399,13 @@ impl CardSet {
index index
} }
OrderModule::WorstWordsSRS(mut module) => { OrderModule::WorstWordsSRS(mut module) => {
if module.initialized == false { if module.initialized == false {
module.init(self) module.init(self)
} }
let index = module.next(self); let index = module.next(self);
self.order_module = OrderModule::WorstWordsSRS(module); self.order_module = OrderModule::WorstWordsSRS(module);
index index
} }
}; };
self.current_word_index = Some(index); self.current_word_index = Some(index);
@@ -433,9 +433,9 @@ impl CardSet {
self.order_module = OrderModule::RandomSRS(module); self.order_module = OrderModule::RandomSRS(module);
} }
OrderModule::WorstWordsSRS(mut module) => { OrderModule::WorstWordsSRS(mut module) => {
module.open(status, index, word.clone()); module.open(status, index, word.clone());
self.order_module = OrderModule::WorstWordsSRS(module); self.order_module = OrderModule::WorstWordsSRS(module);
} }
} }
update_stat_score(word, &self.state.lock().unwrap().connection); update_stat_score(word, &self.state.lock().unwrap().connection);
push_note( push_note(
@@ -596,9 +596,7 @@ impl SRSModule for WorstWordsSRSModule {
self.queue.pop().unwrap() self.queue.pop().unwrap()
} }
fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {}
fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {
}
fn init(&mut self, _: &mut CardSet) { fn init(&mut self, _: &mut CardSet) {
self.initialized = true; self.initialized = true;
@@ -618,9 +616,17 @@ impl WorstWordsSRSModule {
} }
fn fill_pool(&mut self, set: &CardSet) { fn fill_pool(&mut self, set: &CardSet) {
let mut sorted = set.set.clone().into_iter().zip(0..set.set.len()).collect::<Vec<_>>(); let mut sorted = set
.set
.clone()
.into_iter()
.zip(0..set.set.len())
.collect::<Vec<_>>();
sorted.sort_by_key(|c| c.0.score); sorted.sort_by_key(|c| c.0.score);
let mut worst = sorted[0..self.pool_size].iter().map(|(_, index)| *index).collect::<Vec<usize>>(); let mut worst = sorted[0..self.pool_size]
.iter()
.map(|(_, index)| *index)
.collect::<Vec<usize>>();
worst.shuffle(&mut rand::rng()); worst.shuffle(&mut rand::rng());
self.pool = worst; self.pool = worst;
} }
+5 -12
View File
@@ -2,18 +2,18 @@
mod data_provider; mod data_provider;
mod dictionary; mod dictionary;
mod dictionary_test; mod dictionary_test;
mod history;
mod lang; mod lang;
pub mod navigation;
mod quiz; mod quiz;
mod randomizer; mod randomizer;
mod repetition; mod repetition;
mod repetitions; mod repetitions;
mod selector; mod selector;
pub mod styling;
mod sync; mod sync;
mod word; mod word;
mod writing; mod writing;
mod history;
pub mod navigation;
pub mod styling;
use crate::data_provider::card_sets::load_sets; use crate::data_provider::card_sets::load_sets;
use crate::data_provider::settings::get_setting; use crate::data_provider::settings::get_setting;
@@ -28,15 +28,13 @@ use iced::Font;
use iced::{keyboard, Program, Subscription, Theme}; use iced::{keyboard, Program, Subscription, Theme};
use rusqlite::Connection; use rusqlite::Connection;
const USER_FONT: Font = Font::with_name("Noto Sans JP"); const USER_FONT: Font = Font::with_name("Noto Sans JP");
fn main() -> iced::Result { fn main() -> iced::Result {
iced::application(ScreenState::boot, ScreenState::update, ScreenState::view) iced::application(ScreenState::boot, ScreenState::update, ScreenState::view)
.subscription(subscription) .subscription(subscription)
.title("Kana learn app") .title("Kana learn app")
.settings(iced::Settings{ .settings(iced::Settings {
default_text_size: iced::Pixels(18.0), default_text_size: iced::Pixels(18.0),
..iced::Settings::default() ..iced::Settings::default()
}) })
@@ -50,8 +48,6 @@ fn subscription(_state: &ScreenState) -> Subscription<RootMessage> {
keyboard::listen().map(|e| Keyboard(e)) keyboard::listen().map(|e| Keyboard(e))
} }
pub struct AppState { pub struct AppState {
pub dictionary: Vec<WordData>, pub dictionary: Vec<WordData>,
pub card_sets: Vec<CardSetSettings>, pub card_sets: Vec<CardSetSettings>,
@@ -67,7 +63,7 @@ impl AppState {
let connection = Connection::open(db_file).unwrap(); let connection = Connection::open(db_file).unwrap();
connection.execute("PRAGMA foreign_keys = ON;", []).unwrap(); connection.execute("PRAGMA foreign_keys = ON;", []).unwrap();
Self{ Self {
dictionary: vec![], dictionary: vec![],
card_sets: vec![], card_sets: vec![],
word_groups: vec![], word_groups: vec![],
@@ -77,8 +73,6 @@ impl AppState {
} }
} }
fn fill_state(state: &mut AppState) { fn fill_state(state: &mut AppState) {
let list = load_words(&state.connection); let list = load_words(&state.connection);
let sets = load_sets(&state.connection); let sets = load_sets(&state.connection);
@@ -95,4 +89,3 @@ fn load_settings(connection: &Connection) -> AppSettings {
let key = get_setting("SYNC_KEY".to_string(), connection); let key = get_setting("SYNC_KEY".to_string(), connection);
AppSettings { key } AppSettings { key }
} }
+8 -12
View File
@@ -1,25 +1,24 @@
use crate::message_navigation;
use crate::state_update;
use crate::view_navigation;
use std::sync::{Arc, Mutex};
use iced::{Element, Task};
use iced::keyboard::Event;
use crate::{fill_state, AppState };
use crate::data_provider::sqlite::create_db; use crate::data_provider::sqlite::create_db;
use crate::dictionary::{DictionaryMessage, DictionaryState}; use crate::dictionary::{DictionaryMessage, DictionaryState};
use crate::dictionary_test::{DictionaryQuizMessage, DictionaryQuizState}; use crate::dictionary_test::{DictionaryQuizMessage, DictionaryQuizState};
use crate::history::{HistoryMessage, HistoryState}; use crate::history::{HistoryMessage, HistoryState};
use crate::message_navigation;
use crate::navigation::Page::*; use crate::navigation::Page::*;
use crate::navigation::RootMessage::Keyboard; use crate::navigation::RootMessage::Keyboard;
use crate::quiz::{QuizMessage, QuizState}; use crate::quiz::{QuizMessage, QuizState};
use crate::randomizer::randomizer::{RandomizerMessage, RandomizerState}; use crate::randomizer::{RandomizerMessage, RandomizerState};
use crate::repetition::{RepetitionMessage, RepetitionState}; use crate::repetition::{RepetitionMessage, RepetitionState};
use crate::repetitions::{RepetitionsMessage, RepetitionsState}; use crate::repetitions::{RepetitionsMessage, RepetitionsState};
use crate::selector::{SelectorMessage, SelectorState}; use crate::selector::{SelectorMessage, SelectorState};
use crate::state_update;
use crate::sync::{SyncMessage, SyncState}; use crate::sync::{SyncMessage, SyncState};
use crate::view_navigation;
use crate::word::{WordMessage, WordState}; use crate::word::{WordMessage, WordState};
use crate::writing::{WritingMessage, WritingState}; use crate::writing::{WritingMessage, WritingState};
use crate::{fill_state, AppState};
use iced::keyboard::Event;
use iced::{Element, Task};
use std::sync::{Arc, Mutex};
impl Default for ScreenState { impl Default for ScreenState {
fn default() -> Self { fn default() -> Self {
@@ -63,9 +62,6 @@ pub enum Page {
PreviousPage, PreviousPage,
} }
pub struct ScreenState { pub struct ScreenState {
stack: Vec<Page>, stack: Vec<Page>,
} }
+8 -6
View File
@@ -1,12 +1,12 @@
use crate::lang::KanaSet; use crate::lang::KanaSet;
use crate::{ RootMessage, USER_FONT}; use crate::navigation::Page::PreviousPage;
use crate::navigation::{NavigatedPage, Page};
use crate::quiz::QuizMessage::*;
use crate::styling::*;
use crate::{RootMessage, USER_FONT};
use iced::widget::*; use iced::widget::*;
use iced::{alignment, Element, Fill, Task}; use iced::{alignment, Element, Fill, Task};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use crate::navigation::{NavigatedPage, Page};
use crate::navigation::Page::PreviousPage;
use crate::quiz::QuizMessage::*;
use crate::styling::*;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct QuizState { pub struct QuizState {
@@ -104,7 +104,9 @@ impl QuizState {
container( container(
iced::widget::column![ iced::widget::column![
row![ row![
text!("{}", self.kana.to_uppercase()).size(54).font(USER_FONT), text!("{}", self.kana.to_uppercase())
.size(54)
.font(USER_FONT),
text!( text!(
"{}", "{}",
if self.is_help { if self.is_help {
+74 -76
View File
@@ -1,82 +1,80 @@
pub mod randomizer { use crate::navigation::{NavigatedPage, Page};
use crate::navigation::{NavigatedPage, Page}; use crate::randomizer::RandomizerMessage::{Back, Edit, Start};
use crate::randomizer::randomizer::RandomizerMessage::{Back, Edit, Start}; use crate::styling::{back_overlay, jl_button};
use crate::styling::{back_overlay, jl_button}; use crate::RootMessage;
use crate::RootMessage; use iced::widget::{button, text_editor};
use iced::widget::{button, text_editor}; use iced::Task;
use iced::Task; use rand::prelude::SliceRandom;
use rand::prelude::SliceRandom;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RandomizerState { pub struct RandomizerState {
text: text_editor::Content, text: text_editor::Content,
list: Vec<String>, list: Vec<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum RandomizerMessage { pub enum RandomizerMessage {
Back, Back,
Start, Start,
Edit(text_editor::Action), Edit(text_editor::Action),
} }
impl NavigatedPage<RandomizerMessage> for RandomizerState { impl NavigatedPage<RandomizerMessage> for RandomizerState {
fn navigate(&self, message: &RandomizerMessage) -> Option<Page> { fn navigate(&self, message: &RandomizerMessage) -> Option<Page> {
if let Back = message { if let Back = message {
return Some(Page::PreviousPage); return Some(Page::PreviousPage);
}
None
}
}
impl Default for RandomizerState {
fn default() -> Self {
Self::new()
}
}
impl RandomizerState {
pub fn new() -> RandomizerState {
RandomizerState {
text: Default::default(),
list: vec![],
}
}
pub fn update(&mut self, message: RandomizerMessage) -> Task<RootMessage> {
match message {
Edit(action) => {
self.text.perform(action);
self.list = self
.text
.text()
.split("\n")
.map(|s| s.to_string())
.collect();
}
Start => {
self.list.shuffle(&mut rand::rng());
self.text = text_editor::Content::with_text(self.list.join("\n").as_str());
}
_ => {}
}
Task::none()
}
pub fn view(&self) -> iced::Element<'_, RandomizerMessage> {
back_overlay(
iced::widget::column![
text_editor(&self.text)
.on_action(Edit)
.width(400)
.height(400)
.placeholder("Каждый элемент с новой строки"),
button("Перемешать").style(jl_button).on_press(Start),
]
.spacing(5)
.into(),
Back,
)
} }
None
}
}
impl Default for RandomizerState {
fn default() -> Self {
Self::new()
}
}
impl RandomizerState {
pub fn new() -> RandomizerState {
RandomizerState {
text: Default::default(),
list: vec![],
}
}
pub fn update(&mut self, message: RandomizerMessage) -> Task<RootMessage> {
match message {
Edit(action) => {
self.text.perform(action);
self.list = self
.text
.text()
.split("\n")
.map(|s| s.to_string())
.collect();
}
Start => {
self.list.shuffle(&mut rand::rng());
self.text = text_editor::Content::with_text(self.list.join("\n").as_str());
}
_ => {}
}
Task::none()
}
pub fn view(&self) -> iced::Element<'_, RandomizerMessage> {
back_overlay(
iced::widget::column![
text_editor(&self.text)
.on_action(Edit)
.width(400)
.height(400)
.placeholder("Каждый элемент с новой строки"),
button("Перемешать").style(jl_button).on_press(Start),
]
.spacing(5)
.into(),
Back,
)
} }
} }
+27 -24
View File
@@ -113,31 +113,34 @@ impl RepetitionState {
} }
pub fn view(&self) -> Element<'_, RepetitionMessage> { pub fn view(&self) -> Element<'_, RepetitionMessage> {
back_overlay(column![ back_overlay(
container(self.draw_forward()) column![
.width(Fill) container(self.draw_forward())
.height(Fill) .width(Fill)
.align_x(Center) .height(Fill)
.align_y(alignment::Vertical::Center), .align_x(Center)
rule::horizontal(2), .align_y(alignment::Vertical::Center),
container(self.draw_backward()) rule::horizontal(2),
.width(Fill) container(self.draw_backward())
.height(Fill) .width(Fill)
.align_x(Center) .height(Fill)
.align_y(alignment::Vertical::Center), .align_x(Center)
container(self.answer_bar()) .align_y(alignment::Vertical::Center),
.width(Fill) container(self.answer_bar())
.align_x(Center) .width(Fill)
.height(80), .align_x(Center)
text!( .height(80),
"Затронуто слов {}, {}%", text!(
self.opened.len(), "Затронуто слов {}, {}%",
(self.opened.len() as f32 / self.set.len() as f32 * 10000.0).round() self.opened.len(),
/ 100.0 (self.opened.len() as f32 / self.set.len() as f32 * 10000.0).round() / 100.0
) )
] ]
.height(Fill) .height(Fill)
.width(Fill).into(), RepetitionMessage::Back) .width(Fill)
.into(),
RepetitionMessage::Back,
)
} }
fn draw_forward(&self) -> Element<'_, RepetitionMessage> { fn draw_forward(&self) -> Element<'_, RepetitionMessage> {
+70 -35
View File
@@ -10,7 +10,9 @@ use crate::{AppState, RootMessage};
use iced::widget::button::{danger, Status}; use iced::widget::button::{danger, Status};
pub use iced::widget::button::{Catalog, Style}; pub use iced::widget::button::{Catalog, Style};
use iced::widget::container::bordered_box; use iced::widget::container::bordered_box;
use iced::widget::{button, column, container, radio, row, scrollable, space, text, text_input, Column}; use iced::widget::{
button, column, container, radio, row, scrollable, space, text, text_input, Column,
};
use iced::{Background, Border, Center, Color, Element, Fill, Length, Shadow, Task, Theme}; use iced::{Background, Border, Center, Color, Element, Fill, Length, Shadow, Task, Theme};
use rhai::{Engine, Scope}; use rhai::{Engine, Scope};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -111,36 +113,48 @@ impl RepetitionsState {
let set = state.card_sets.get(self.selected_set.unwrap()).unwrap(); let set = state.card_sets.get(self.selected_set.unwrap()).unwrap();
let count = set.get_word_list(&state).len(); let count = set.get_word_list(&state).len();
state.card_sets[self.selected_set.unwrap()].count = Some(count); state.card_sets[self.selected_set.unwrap()].count = Some(count);
}, }
RepetitionsMessage::SetOpenMode(mode) => { RepetitionsMessage::SetOpenMode(mode) => {
state.card_sets.get_mut(self.selected_set.unwrap()).unwrap().open_mode = mode; state
.card_sets
.get_mut(self.selected_set.unwrap())
.unwrap()
.open_mode = mode;
} }
} }
Task::none() Task::none()
} }
pub fn view(&self) -> Element<'_, RepetitionsMessage> { pub fn view(&self) -> Element<'_, RepetitionsMessage> {
back_overlay(row![ back_overlay(
column![ row![
scrollable(self.sets_list()).height(Fill), column![
button("Добавить").style(jl_button) scrollable(self.sets_list()).height(Fill),
.width(Fill) button("Добавить")
.on_press(RepetitionsMessage::CreateSet), .style(jl_button)
] .width(Fill)
.spacing(DEFAULT_SPACING) .on_press(RepetitionsMessage::CreateSet),
.width(Length::FillPortion(1)),
self.selected_set_view(),
self.launch_button()
] ]
.spacing(DEFAULT_SPACING)
.width(Length::FillPortion(1)),
self.selected_set_view(),
self.launch_button()
]
.align_y(Center) .align_y(Center)
.spacing(DEFAULT_SPACING) .spacing(DEFAULT_SPACING)
.width(Fill) .width(Fill)
.height(Fill).into(), RepetitionsMessage::Back) .height(Fill)
.into(),
RepetitionsMessage::Back,
)
} }
fn launch_button(&self) -> Element<'_, RepetitionsMessage> { fn launch_button(&self) -> Element<'_, RepetitionsMessage> {
if let Some(set) = self.selected_set && self.state.lock().unwrap().card_sets[set].id != 0 { if let Some(set) = self.selected_set
return button(text!("").height(Fill).center()).style(jl_button) && self.state.lock().unwrap().card_sets[set].id != 0
{
return button(text!("").height(Fill).center())
.style(jl_button)
.height(200) .height(200)
.on_press(RepetitionsMessage::GoToRepetition) .on_press(RepetitionsMessage::GoToRepetition)
.into(); .into();
@@ -165,17 +179,28 @@ impl RepetitionsState {
.on_input(RepetitionsMessage::SetBackward), .on_input(RepetitionsMessage::SetBackward),
text!("Фильтр"), text!("Фильтр"),
text_input("", &set.filter).on_input(RepetitionsMessage::SetFilter), text_input("", &set.filter).on_input(RepetitionsMessage::SetFilter),
button("Проверить фильтр").style(jl_button).on_press(RepetitionsMessage::TryFilter), button("Проверить фильтр")
.style(jl_button)
.on_press(RepetitionsMessage::TryFilter),
self.count_view(&set), self.count_view(&set),
radio("Обычный режим", SetOrderMode::Default, Some(set.open_mode), RepetitionsMessage::SetOpenMode), radio(
"Обычный режим",
SetOrderMode::Default,
Some(set.open_mode),
RepetitionsMessage::SetOpenMode
),
self.words_words_view(&set), self.words_words_view(&set),
button("История").style(jl_button).on_press(RepetitionsMessage::GoToHistory), button("История")
.style(jl_button)
.on_press(RepetitionsMessage::GoToHistory),
] ]
.spacing(DEFAULT_SPACING) .spacing(DEFAULT_SPACING)
) )
.height(Fill), .height(Fill),
row![ row![
button("Сохранить").style(jl_button).on_press(RepetitionsMessage::Save), button("Сохранить")
.style(jl_button)
.on_press(RepetitionsMessage::Save),
button("Удалить") button("Удалить")
.style(danger) .style(danger)
.on_press(RepetitionsMessage::DeleteSet) .on_press(RepetitionsMessage::DeleteSet)
@@ -193,16 +218,24 @@ impl RepetitionsState {
column![ column![
text!("Худшие слова"), text!("Худшие слова"),
container(scrollable(self.worst_words_list(&set)).height(200)).style(bordered_box), container(scrollable(self.worst_words_list(&set)).height(200)).style(bordered_box),
radio("Начать с плохих слов", SetOrderMode::TrainWorstFirst, Some(set.open_mode), RepetitionsMessage::SetOpenMode), radio(
radio("Полностью случайно", SetOrderMode::FullRandom, Some(set.open_mode), RepetitionsMessage::SetOpenMode) "Начать с плохих слов",
SetOrderMode::TrainWorstFirst,
Some(set.open_mode),
RepetitionsMessage::SetOpenMode
),
radio(
"Полностью случайно",
SetOrderMode::FullRandom,
Some(set.open_mode),
RepetitionsMessage::SetOpenMode
)
] ]
.spacing(DEFAULT_SPACING) .spacing(DEFAULT_SPACING)
.into() .into()
} }
fn worst_words_list(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { fn worst_words_list(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> {
let mut column = Column::new(); let mut column = Column::new();
for word in set.worst_words_list.clone().unwrap() { for word in set.worst_words_list.clone().unwrap() {
@@ -226,14 +259,18 @@ impl RepetitionsState {
column = column.push( column = column.push(
button(text!("{}", set.name.clone())) button(text!("{}", set.name.clone()))
.on_press_with(move || RepetitionsMessage::SelectSet(i.clone())) .on_press_with(move || RepetitionsMessage::SelectSet(i.clone()))
.style(move |_x: &Theme, status : Status| Style { .style(move |_x: &Theme, status: Status| Style {
background: if status == Status::Hovered {Some(Background::Color(Color::WHITE.scale_alpha(0.1)))} else { None }, background: if status == Status::Hovered {
Some(Background::Color(Color::WHITE.scale_alpha(0.1)))
} else {
None
},
text_color: if self.correct_filters[i.clone()] { text_color: if self.correct_filters[i.clone()] {
_x.palette().primary _x.palette().primary
} else { } else {
_x.palette().warning _x.palette().warning
}, },
border: Border{ border: Border {
color: Default::default(), color: Default::default(),
width: 0.0, width: 0.0,
radius: 8.0.into(), radius: 8.0.into(),
@@ -247,7 +284,6 @@ impl RepetitionsState {
column column
} }
} }
#[derive(Clone)] #[derive(Clone)]
@@ -277,7 +313,7 @@ pub struct CardSetSettings {
pub filter: String, pub filter: String,
pub count: Option<usize>, pub count: Option<usize>,
pub worst_words_list: Option<Vec<WordData>>, pub worst_words_list: Option<Vec<WordData>>,
pub open_mode: SetOrderMode pub open_mode: SetOrderMode,
} }
impl CardSetSettings { impl CardSetSettings {
@@ -346,7 +382,7 @@ impl CardSetSettings {
self.forward == "speech" || self.backward == "speech" self.forward == "speech" || self.backward == "speech"
} }
fn update_worst_words(&mut self, state: &AppState){ fn update_worst_words(&mut self, state: &AppState) {
if let Some(_) = self.worst_words_list { if let Some(_) = self.worst_words_list {
return; return;
} }
@@ -360,15 +396,14 @@ impl CardSetSettings {
.iter() .iter()
.take_while(|word| word.calculated_score() < avg) .take_while(|word| word.calculated_score() < avg)
.map(|stat| { .map(|stat| {
state.dictionary[ state state.dictionary[state
.dictionary .dictionary
.binary_search_by_key(&stat.word_id, |x| x.id) .binary_search_by_key(&stat.word_id, |x| x.id)
.unwrap()].clone() .unwrap()]
.clone()
}) })
.collect(); .collect();
self.worst_words_list = Some(bad.clone()); self.worst_words_list = Some(bad.clone());
} }
} }
+26 -14
View File
@@ -1,22 +1,22 @@
use std::sync::{Arc, Mutex};
use crate::dictionary::DictionaryState; use crate::dictionary::DictionaryState;
use crate::lang::{KanaSet, KanaType}; use crate::lang::{KanaSet, KanaType};
use crate::randomizer::randomizer::RandomizerState; use crate::navigation::Page::*;
use crate::navigation::{NavigatedPage, Page};
use crate::randomizer::RandomizerState;
use crate::repetitions::RepetitionsState; use crate::repetitions::RepetitionsState;
use crate::selector::SelectorMessage::ChangeMode; use crate::selector::SelectorMessage::ChangeMode;
use crate::styling::*;
use crate::sync::SyncState;
use crate::writing::WritingState; use crate::writing::WritingState;
use crate::{AppState, QuizState, RootMessage}; use crate::{AppState, QuizState, RootMessage};
use iced::widget::*; use iced::widget::*;
use iced::{alignment, Element, Task}; use iced::{alignment, Element, Task};
use crate::navigation::{NavigatedPage, Page}; use std::sync::{Arc, Mutex};
use crate::navigation::Page::*;
use crate::styling::*;
use crate::sync::SyncState;
pub struct SelectorState { pub struct SelectorState {
pub set: KanaSet, pub set: KanaSet,
is_writing: bool, is_writing: bool,
state: Arc<Mutex<AppState>> state: Arc<Mutex<AppState>>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -61,7 +61,7 @@ impl NavigatedPage<SelectorMessage> for SelectorState {
impl SelectorState { impl SelectorState {
pub fn new(state: Arc<Mutex<AppState>>) -> Self { pub fn new(state: Arc<Mutex<AppState>>) -> Self {
Self{ Self {
set: Default::default(), set: Default::default(),
is_writing: false, is_writing: false,
state, state,
@@ -84,18 +84,30 @@ impl SelectorState {
container( container(
iced::widget::column![ iced::widget::column![
row![ row![
button("あ ↔ ア").on_press(SelectorMessage::Change).style(jl_button), button("あ ↔ ア")
button("Словарь").on_press(SelectorMessage::ToDictionary).style(button::text), .on_press(SelectorMessage::Change)
button("Рандомайзер").on_press(SelectorMessage::ToRandomize).style(button::text), .style(jl_button),
button("Повторение").on_press(SelectorMessage::ToRepetitions).style(button::text), button("Словарь")
button("Синхронизация").on_press(SelectorMessage::ToSync).style(button::text) .on_press(SelectorMessage::ToDictionary)
.style(button::text),
button("Рандомайзер")
.on_press(SelectorMessage::ToRandomize)
.style(button::text),
button("Повторение")
.on_press(SelectorMessage::ToRepetitions)
.style(button::text),
button("Синхронизация")
.on_press(SelectorMessage::ToSync)
.style(button::text)
] ]
.spacing(DEFAULT_SPACING), .spacing(DEFAULT_SPACING),
self.rows_selector(), self.rows_selector(),
toggler(self.is_writing) toggler(self.is_writing)
.label("Режим письма") .label("Режим письма")
.on_toggle(ChangeMode), .on_toggle(ChangeMode),
button("К тесту").on_press(SelectorMessage::Goto).style(jl_button), button("К тесту")
.on_press(SelectorMessage::Goto)
.style(jl_button),
] ]
.spacing(DEFAULT_SPACING), .spacing(DEFAULT_SPACING),
) )
+28 -24
View File
@@ -15,7 +15,6 @@ use std::time::Duration;
use zstd::{Decoder, Encoder, DEFAULT_COMPRESSION_LEVEL}; use zstd::{Decoder, Encoder, DEFAULT_COMPRESSION_LEVEL};
const API_URL: &str = "https://learning.micialware.ru/"; const API_URL: &str = "https://learning.micialware.ru/";
/*const API_URL: &str = "http://localhost:8089/";*/
#[derive(Clone)] #[derive(Clone)]
pub enum SyncMessage { pub enum SyncMessage {
@@ -70,14 +69,11 @@ impl SyncState {
.map(|_val: String| RootMessage::Sync(KeyCopied)); .map(|_val: String| RootMessage::Sync(KeyCopied));
} }
InitSync => { InitSync => {
return Task::perform(first_sync(), |id| { return Task::perform(first_sync(), |id| RootMessage::Sync(IdReceived(id)));
RootMessage::Sync(IdReceived(id))
});
} }
GetKey => { GetKey => {
return iced::clipboard::read().map(|key| { return iced::clipboard::read()
RootMessage::Sync(IdReceived(key.unwrap_or_else(String::new))) .map(|key| RootMessage::Sync(IdReceived(key.unwrap_or_else(String::new))));
});
} }
KeyCopied => {} KeyCopied => {}
IdReceived(new_id) => { IdReceived(new_id) => {
@@ -97,9 +93,7 @@ impl SyncState {
async { tokio::time::sleep(Duration::from_millis(200)).await }, async { tokio::time::sleep(Duration::from_millis(200)).await },
|_| RootMessage::Sync(NextAnimation), |_| RootMessage::Sync(NextAnimation),
), ),
Task::perform(send_data(id), |_| { Task::perform(send_data(id), |_| RootMessage::Sync(NetworkFinished)),
RootMessage::Sync(NetworkFinished)
}),
]); ]);
return tasks; return tasks;
@@ -111,9 +105,7 @@ impl SyncState {
async { tokio::time::sleep(Duration::from_millis(200)).await }, async { tokio::time::sleep(Duration::from_millis(200)).await },
|_| RootMessage::Sync(NextAnimation), |_| RootMessage::Sync(NextAnimation),
), ),
Task::perform(load_data(id), |_| { Task::perform(load_data(id), |_| RootMessage::Sync(NetworkFinished)),
RootMessage::Sync(NetworkFinished)
}),
]); ]);
return tasks; return tasks;
@@ -141,7 +133,6 @@ impl SyncState {
state.card_sets = updated_state.card_sets; state.card_sets = updated_state.card_sets;
state.dictionary = updated_state.dictionary; state.dictionary = updated_state.dictionary;
state.word_groups = updated_state.word_groups; state.word_groups = updated_state.word_groups;
} }
Disable => {} Disable => {}
DisableSync => { DisableSync => {
@@ -155,9 +146,13 @@ impl SyncState {
} }
pub fn view(&self) -> Element<'_, SyncMessage> { pub fn view(&self) -> Element<'_, SyncMessage> {
back_overlay(row![space().width(Fill), self.sync_column(), space().width(Fill)] back_overlay(
.spacing(DEFAULT_SPACING) row![space().width(Fill), self.sync_column(), space().width(Fill)]
.width(Fill).into(), Back) .spacing(DEFAULT_SPACING)
.width(Fill)
.into(),
Back,
)
} }
fn sync_column(&self) -> Element<'_, SyncMessage> { fn sync_column(&self) -> Element<'_, SyncMessage> {
@@ -171,11 +166,16 @@ impl SyncState {
column![ column![
text!("Ваш ключ синхронизации"), text!("Ваш ключ синхронизации"),
container( container(
container(text!("{}", key).size(ACCENT_FONT_SIZE).font(Font::MONOSPACE)).padding(3) container(
text!("{}", key)
.size(ACCENT_FONT_SIZE)
.font(Font::MONOSPACE)
)
.padding(3)
) )
.style(rounded_box), .style(rounded_box),
button("Скопировать в буфер обмена").style(jl_button) button("Скопировать в буфер обмена")
.style(jl_button)
.on_press(CopyKey) .on_press(CopyKey)
.width(Fill), .width(Fill),
row![ row![
@@ -191,18 +191,22 @@ impl SyncState {
] ]
} else { } else {
column![ column![
button("Создать сохранение").style(jl_button).on_press(InitSync), button("Создать сохранение")
button("Вставить ключ из буфера").style(jl_button).on_press(GetKey), .style(jl_button)
.on_press(InitSync),
button("Вставить ключ из буфера")
.style(jl_button)
.on_press(GetKey),
] ]
} }
} }
.spacing(DEFAULT_SPACING) .spacing(DEFAULT_SPACING)
.align_x(Center) .align_x(Center)
.width(Length::Shrink) .width(Length::Shrink)
.into() .into()
} }
/* fn app_updater(&self) -> Element<'_, SyncMessage> { /* fn app_updater(&self) -> Element<'_, SyncMessage> {
column![].width(Fill).into() column![].width(Fill).into()
}*/ }*/
+12 -11
View File
@@ -1,11 +1,11 @@
use crate::lang::KanaSet; use crate::lang::KanaSet;
use crate::{ RootMessage}; use crate::navigation::Page::PreviousPage;
use crate::navigation::{NavigatedPage, Page};
use crate::styling::*;
use crate::RootMessage;
use iced::widget::*; use iced::widget::*;
use iced::{alignment, Element, Fill, Task}; use iced::{alignment, Element, Fill, Task};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use crate::navigation::{NavigatedPage, Page};
use crate::navigation::Page::PreviousPage;
use crate::styling::*;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WritingState { pub struct WritingState {
@@ -45,7 +45,7 @@ impl WritingState {
} }
impl WritingState { impl WritingState {
pub fn update(&mut self, message: WritingMessage) -> Task<RootMessage> { pub fn update(&mut self, message: WritingMessage) -> Task<RootMessage> {
match message { match message {
WritingMessage::Back => todo!(), WritingMessage::Back => todo!(),
WritingMessage::Next => self.next(), WritingMessage::Next => self.next(),
@@ -66,7 +66,6 @@ impl WritingState {
} }
if self.show_all { if self.show_all {
if self.set.is_empty() == false && self.kana_total.is_empty() == false { if self.set.is_empty() == false && self.kana_total.is_empty() == false {
self.set.clear(); self.set.clear();
} }
@@ -75,8 +74,6 @@ impl WritingState {
self.roman_total += &*format!("{} ", &pair.1.clone()).to_string(); self.roman_total += &*format!("{} ", &pair.1.clone()).to_string();
self.kana_total += &*format!("{} ", &pair.0).to_string(); self.kana_total += &*format!("{} ", &pair.0).to_string();
} }
} else { } else {
let current = self.set.pop().unwrap(); let current = self.set.pop().unwrap();
self.kana_total += &*format!("{} ", &current.0).to_string(); self.kana_total += &*format!("{} ", &current.0).to_string();
@@ -95,8 +92,12 @@ impl WritingState {
text!("{}", self.kana).size(48), text!("{}", self.kana).size(48),
self.answers(), self.answers(),
row![ row![
button(text!("{}", self.next_text)).style(jl_button).on_press(WritingMessage::Next), button(text!("{}", self.next_text))
button("Закончить").style(jl_button).on_press(WritingMessage::Back), .style(jl_button)
.on_press(WritingMessage::Next),
button("Закончить")
.style(jl_button)
.on_press(WritingMessage::Back),
] ]
.spacing(DEFAULT_SPACING) .spacing(DEFAULT_SPACING)
] ]
@@ -110,7 +111,7 @@ impl WritingState {
} }
fn answers(&self) -> Element<'_, WritingMessage> { fn answers(&self) -> Element<'_, WritingMessage> {
if self.set.is_empty() { if self.set.is_empty() {
text!("{}", self.kana_total).size(36).into() text!("{}", self.kana_total).size(36).into()
} else { } else {
space().height(36).into() space().height(36).into()