code cleanup
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
|
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")
|
||||||
|
.unwrap();
|
||||||
|
let iter = stmt
|
||||||
|
.query_map([], |row| {
|
||||||
Ok(CardSetSettings {
|
Ok(CardSetSettings {
|
||||||
id: row.get(0)?,
|
id: row.get(0)?,
|
||||||
name: row.get(1)?,
|
name: row.get(1)?,
|
||||||
@@ -15,7 +18,8 @@ pub fn load_sets(connection: &Connection) -> Vec<CardSetSettings> {
|
|||||||
worst_words_list: None,
|
worst_words_list: None,
|
||||||
open_mode: SetOrderMode::Default,
|
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",
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ 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")
|
||||||
|
.unwrap();
|
||||||
|
let iter = stmt
|
||||||
|
.query_map((set.id,), |row| {
|
||||||
Ok(CardStatistics {
|
Ok(CardStatistics {
|
||||||
id: row.get(0)?,
|
id: row.get(0)?,
|
||||||
word_id: row.get(1)?,
|
word_id: row.get(1)?,
|
||||||
@@ -13,7 +16,8 @@ pub fn load_stats_of_set(set: &CardSetSettings, connection: &Connection) -> Vec<
|
|||||||
score: row.get(2)?,
|
score: row.get(2)?,
|
||||||
last_open: row.get(3)?,
|
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(),
|
|
||||||
&stat.id
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|e| {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) {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
.append(true)
|
||||||
|
.open(path)
|
||||||
|
.unwrap();
|
||||||
|
let line_str = format!(
|
||||||
|
"{};{};{};{};{}",
|
||||||
|
item.timestamp.timestamp(),
|
||||||
|
item.word_id,
|
||||||
|
match item.mode {
|
||||||
WordOpenMode::Easy => 4,
|
WordOpenMode::Easy => 4,
|
||||||
WordOpenMode::Ok => 3,
|
WordOpenMode::Ok => 3,
|
||||||
WordOpenMode::Hard => 2,
|
WordOpenMode::Hard => 2,
|
||||||
WordOpenMode::None => 1
|
WordOpenMode::None => 1,
|
||||||
},
|
},
|
||||||
item.before,
|
item.before,
|
||||||
item.after);
|
item.after
|
||||||
|
);
|
||||||
writeln!(&mut file, "{}", line_str.to_string()).unwrap();
|
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_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;
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-13
@@ -51,7 +51,8 @@ impl HistoryState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Element<'_, HistoryMessage> {
|
pub fn view(&self) -> Element<'_, HistoryMessage> {
|
||||||
back_overlay(iced::widget::row![
|
back_overlay(
|
||||||
|
iced::widget::row![
|
||||||
horizontal().width(FillPortion(1)),
|
horizontal().width(FillPortion(1)),
|
||||||
scrollable(self.history_lines().padding(DEFAULT_SPACING))
|
scrollable(self.history_lines().padding(DEFAULT_SPACING))
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
@@ -59,18 +60,10 @@ impl HistoryState {
|
|||||||
horizontal().width(FillPortion(1))
|
horizontal().width(FillPortion(1))
|
||||||
]
|
]
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
.width(Fill).into(), Back)
|
.width(Fill)
|
||||||
// container(
|
.into(),
|
||||||
// iced::widget::column![
|
Back,
|
||||||
// button("Назад").style(jl_button).on_press(Back),
|
)
|
||||||
//
|
|
||||||
// ]
|
|
||||||
// .align_x(Left)
|
|
||||||
// .width(Fill),
|
|
||||||
// )
|
|
||||||
// .center_x(Fill)
|
|
||||||
// .padding(10)
|
|
||||||
// .into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn history_lines(&self) -> Column<'_, HistoryMessage> {
|
fn history_lines(&self) -> Column<'_, HistoryMessage> {
|
||||||
|
|||||||
+14
-8
@@ -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;
|
||||||
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||||
|
|||||||
+18
-20
@@ -1,41 +1,40 @@
|
|||||||
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
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RandomizerState {
|
impl Default for RandomizerState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RandomizerState {
|
impl RandomizerState {
|
||||||
pub fn new() -> RandomizerState {
|
pub fn new() -> RandomizerState {
|
||||||
RandomizerState {
|
RandomizerState {
|
||||||
text: Default::default(),
|
text: Default::default(),
|
||||||
@@ -78,5 +77,4 @@ pub mod randomizer {
|
|||||||
Back,
|
Back,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-4
@@ -113,7 +113,8 @@ impl RepetitionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Element<'_, RepetitionMessage> {
|
pub fn view(&self) -> Element<'_, RepetitionMessage> {
|
||||||
back_overlay(column![
|
back_overlay(
|
||||||
|
column![
|
||||||
container(self.draw_forward())
|
container(self.draw_forward())
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
@@ -132,12 +133,14 @@ impl RepetitionState {
|
|||||||
text!(
|
text!(
|
||||||
"Затронуто слов {}, {}%",
|
"Затронуто слов {}, {}%",
|
||||||
self.opened.len(),
|
self.opened.len(),
|
||||||
(self.opened.len() as f32 / self.set.len() as f32 * 10000.0).round()
|
(self.opened.len() as f32 / self.set.len() as f32 * 10000.0).round() / 100.0
|
||||||
/ 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> {
|
||||||
|
|||||||
+61
-26
@@ -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,19 +113,25 @@ 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(
|
||||||
|
row![
|
||||||
column![
|
column![
|
||||||
scrollable(self.sets_list()).height(Fill),
|
scrollable(self.sets_list()).height(Fill),
|
||||||
button("Добавить").style(jl_button)
|
button("Добавить")
|
||||||
|
.style(jl_button)
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.on_press(RepetitionsMessage::CreateSet),
|
.on_press(RepetitionsMessage::CreateSet),
|
||||||
]
|
]
|
||||||
@@ -135,12 +143,18 @@ impl RepetitionsState {
|
|||||||
.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
@@ -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),
|
||||||
)
|
)
|
||||||
|
|||||||
+26
-22
@@ -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(
|
||||||
|
row![space().width(Fill), self.sync_column(), space().width(Fill)]
|
||||||
.spacing(DEFAULT_SPACING)
|
.spacing(DEFAULT_SPACING)
|
||||||
.width(Fill).into(), Back)
|
.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,8 +191,12 @@ 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),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +206,7 @@ impl SyncState {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fn app_updater(&self) -> Element<'_, SyncMessage> {
|
/* fn app_updater(&self) -> Element<'_, SyncMessage> {
|
||||||
column![].width(Fill).into()
|
column![].width(Fill).into()
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|||||||
+10
-9
@@ -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 {
|
||||||
@@ -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!("{} ", ¤t.0).to_string();
|
self.kana_total += &*format!("{} ", ¤t.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)
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user