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