Splitting kana set
This commit is contained in:
1 parent
36e5693564
commit
c74a0eb311
25 files changed
+368
-333
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
pub mod kana_set;
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct KanaSet {
|
||||||
|
name: String,
|
||||||
|
pub(crate) chars_type: KanaType,
|
||||||
|
pub(crate) dictionary: Vec<Vec<(String, String)>>,
|
||||||
|
pub(crate) include_map: [bool; 10],
|
||||||
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum KanaType {
|
||||||
|
Hiragana,
|
||||||
|
Katakana,
|
||||||
|
}
|
||||||
|
impl KanaSet {
|
||||||
|
pub fn hiragana() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "Хирагана".to_string(),
|
||||||
|
chars_type: KanaType::Hiragana,
|
||||||
|
dictionary: vec![
|
||||||
|
vec![
|
||||||
|
(String::from("ぁ"), String::from("a")),
|
||||||
|
(String::from("ぃ"), String::from("i")),
|
||||||
|
(String::from("ぅ"), String::from("u")),
|
||||||
|
(String::from("ぇ"), String::from("e")),
|
||||||
|
(String::from("ぉ"), String::from("o")),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("さ"), String::from("sa")),
|
||||||
|
(String::from("し"), String::from("shi")),
|
||||||
|
(String::from("す"), String::from("su")),
|
||||||
|
(String::from("せ"), String::from("se")),
|
||||||
|
(String::from("そ"), String::from("so")),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("か"), String::from("ka")),
|
||||||
|
(String::from("き"), String::from("ki")),
|
||||||
|
(String::from("く"), String::from("ku")),
|
||||||
|
(String::from("け"), String::from("ke")),
|
||||||
|
(String::from("こ"), String::from("ko")),
|
||||||
|
],
|
||||||
|
// Ряд «та» (たちつてと)
|
||||||
|
vec![
|
||||||
|
(String::from("た"), String::from("ta")),
|
||||||
|
(String::from("ち"), String::from("chi")),
|
||||||
|
(String::from("つ"), String::from("tsu")),
|
||||||
|
(String::from("て"), String::from("te")),
|
||||||
|
(String::from("と"), String::from("to")),
|
||||||
|
],
|
||||||
|
// Ряд «на» (なにぬねの)
|
||||||
|
vec![
|
||||||
|
(String::from("な"), String::from("na")),
|
||||||
|
(String::from("に"), String::from("ni")),
|
||||||
|
(String::from("ぬ"), String::from("nu")),
|
||||||
|
(String::from("ね"), String::from("ne")),
|
||||||
|
(String::from("の"), String::from("no")),
|
||||||
|
],
|
||||||
|
// Ряд «ха» (はひふへほ)
|
||||||
|
vec![
|
||||||
|
(String::from("は"), String::from("ha")),
|
||||||
|
(String::from("ひ"), String::from("hi")),
|
||||||
|
(String::from("ふ"), String::from("fu")),
|
||||||
|
(String::from("へ"), String::from("he")),
|
||||||
|
(String::from("ほ"), String::from("ho")),
|
||||||
|
],
|
||||||
|
// Ряд «ма» (まみむめも)
|
||||||
|
vec![
|
||||||
|
(String::from("ま"), String::from("ma")),
|
||||||
|
(String::from("み"), String::from("mi")),
|
||||||
|
(String::from("む"), String::from("mu")),
|
||||||
|
(String::from("め"), String::from("me")),
|
||||||
|
(String::from("も"), String::from("mo")),
|
||||||
|
],
|
||||||
|
// Ряд «я» (やゆよ) — только 3 символа
|
||||||
|
vec![
|
||||||
|
(String::from("や"), String::from("ya")),
|
||||||
|
(String::from("ゆ"), String::from("yu")),
|
||||||
|
(String::from("よ"), String::from("yo")),
|
||||||
|
],
|
||||||
|
// Ряд «ра» (らりるれろ)
|
||||||
|
vec![
|
||||||
|
(String::from("ら"), String::from("ra")),
|
||||||
|
(String::from("り"), String::from("ri")),
|
||||||
|
(String::from("る"), String::from("ru")),
|
||||||
|
(String::from("れ"), String::from("re")),
|
||||||
|
(String::from("ろ"), String::from("ro")),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("わ"), String::from("wa")),
|
||||||
|
(String::from("を"), String::from("wo")),
|
||||||
|
(String::from("ん"), String::from("n")),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
include_map: [true; 10],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn katakana() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "Катакана".to_string(),
|
||||||
|
chars_type: KanaType::Katakana,
|
||||||
|
dictionary: vec![
|
||||||
|
vec![
|
||||||
|
(String::from("ァ"), String::from("a")),
|
||||||
|
(String::from("ィ"), String::from("i")),
|
||||||
|
(String::from("ゥ"), String::from("u")),
|
||||||
|
(String::from("ェ"), String::from("e")),
|
||||||
|
(String::from("ォ"), String::from("o")),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("サ"), String::from("sa")),
|
||||||
|
(String::from("シ"), String::from("shi")),
|
||||||
|
(String::from("ス"), String::from("su")),
|
||||||
|
(String::from("セ"), String::from("se")),
|
||||||
|
(String::from("ソ"), String::from("so")),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("カ"), String::from("ka")),
|
||||||
|
(String::from("キ"), String::from("ki")),
|
||||||
|
(String::from("ク"), String::from("ku")),
|
||||||
|
(String::from("ケ"), String::from("ke")),
|
||||||
|
(String::from("コ"), String::from("ko")),
|
||||||
|
],
|
||||||
|
// Ряд «та» (タチツテト)
|
||||||
|
vec![
|
||||||
|
(String::from("タ"), String::from("ta")),
|
||||||
|
(String::from("チ"), String::from("chi")),
|
||||||
|
(String::from("ツ"), String::from("tsu")),
|
||||||
|
(String::from("テ"), String::from("te")),
|
||||||
|
(String::from("ト"), String::from("to")),
|
||||||
|
],
|
||||||
|
// Ряд «на» (ナニヌネノ)
|
||||||
|
vec![
|
||||||
|
(String::from("ナ"), String::from("na")),
|
||||||
|
(String::from("ニ"), String::from("ni")),
|
||||||
|
(String::from("ヌ"), String::from("nu")),
|
||||||
|
(String::from("ネ"), String::from("ne")),
|
||||||
|
(String::from("ノ"), String::from("no")),
|
||||||
|
],
|
||||||
|
// Ряд «ха» (ハヒフヘホ)
|
||||||
|
vec![
|
||||||
|
(String::from("ハ"), String::from("ha")),
|
||||||
|
(String::from("ヒ"), String::from("hi")),
|
||||||
|
(String::from("フ"), String::from("fu")),
|
||||||
|
(String::from("ヘ"), String::from("he")),
|
||||||
|
(String::from("ホ"), String::from("ho")),
|
||||||
|
],
|
||||||
|
// Ряд «ма» (マミムメモ)
|
||||||
|
vec![
|
||||||
|
(String::from("マ"), String::from("ma")),
|
||||||
|
(String::from("ミ"), String::from("mi")),
|
||||||
|
(String::from("ム"), String::from("mu")),
|
||||||
|
(String::from("メ"), String::from("me")),
|
||||||
|
(String::from("モ"), String::from("mo")),
|
||||||
|
],
|
||||||
|
// Ряд «я» (ヤユヨ) — только 3 символа
|
||||||
|
vec![
|
||||||
|
(String::from("ヤ"), String::from("ya")),
|
||||||
|
(String::from("ユ"), String::from("yu")),
|
||||||
|
(String::from("ヨ"), String::from("yo")),
|
||||||
|
],
|
||||||
|
// Ряд «ра» (ラリルレロ)
|
||||||
|
vec![
|
||||||
|
(String::from("ラ"), String::from("ra")),
|
||||||
|
(String::from("リ"), String::from("ri")),
|
||||||
|
(String::from("ル"), String::from("ru")),
|
||||||
|
(String::from("レ"), String::from("re")),
|
||||||
|
(String::from("ロ"), String::from("ro")),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
(String::from("ワ"), String::from("wa")),
|
||||||
|
(String::from("ヲ"), String::from("wo")),
|
||||||
|
(String::from("ン"), String::from("n")),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
include_map: [true; 10],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list(&self) -> Vec<(String, String)> {
|
||||||
|
let mut current_set: Vec<(String, String)> = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..10 {
|
||||||
|
if self.include_map[i] {
|
||||||
|
self.dictionary[i].iter().for_each(|v| {
|
||||||
|
current_set.push(v.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for KanaSet {
|
||||||
|
fn default() -> Self {
|
||||||
|
KanaSet::hiragana()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialEq<Self> for KanaSet {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name == other.name
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
use crate::dictionary::app_data_dir;
|
use crate::fs::*;
|
||||||
use crate::lang::{Id, WordOpenMode};
|
use crate::lang::{Id, WordOpenMode};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::fs;
|
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use crate::notification::NotificationData;
|
||||||
|
use crate::notification::NotificationData::PermissionDenied;
|
||||||
|
|
||||||
pub fn get_history_of_set(id: Id) -> Vec<HistoryItem> {
|
pub fn get_history_of_set(id: Id) -> Result<Vec<HistoryItem>, NotificationData> {
|
||||||
let app_dir = history_dir();
|
let app_dir = history_dir()?;
|
||||||
let head = app_dir.clone().join(format!("set_{}_history.csv", id));
|
let head = app_dir.clone().join(format!("set_{}_history.csv", id));
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
append_lines_if_exists(head, &mut lines);
|
append_lines_if_exists(head, &mut lines);
|
||||||
lines.reverse();
|
lines.reverse();
|
||||||
parse_history_items(lines)
|
Ok(parse_history_items(lines))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_lines_if_exists(path: PathBuf, lines: &mut Vec<String>) {
|
fn append_lines_if_exists(path: PathBuf, lines: &mut Vec<String>) {
|
||||||
@@ -56,15 +57,15 @@ fn parse_history_items(strings: Vec<String>) -> Vec<HistoryItem> {
|
|||||||
items
|
items
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_note(set_id: Id, item: HistoryItem) {
|
pub fn push_note(set_id: Id, item: HistoryItem) -> Result<(), NotificationData> {
|
||||||
let app_dir = history_dir();
|
let app_dir = history_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()
|
let mut file = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.append(true)
|
.append(true)
|
||||||
.open(path)
|
.open(path)
|
||||||
.unwrap();
|
.map_err(|_| PermissionDenied)?;
|
||||||
let line_str = format!(
|
let line_str = format!(
|
||||||
"{};{};{};{};{}",
|
"{};{};{};{};{}",
|
||||||
item.timestamp.timestamp(),
|
item.timestamp.timestamp(),
|
||||||
@@ -78,15 +79,8 @@ pub fn push_note(set_id: Id, item: HistoryItem) {
|
|||||||
item.before,
|
item.before,
|
||||||
item.after
|
item.after
|
||||||
);
|
);
|
||||||
writeln!(&mut file, "{}", line_str).unwrap();
|
writeln!(&mut file, "{}", line_str).map_err(|_| PermissionDenied)?;
|
||||||
}
|
Ok(())
|
||||||
|
|
||||||
pub fn history_dir() -> PathBuf {
|
|
||||||
let directory = app_data_dir().join("history");
|
|
||||||
if !directory.exists() {
|
|
||||||
fs::create_dir(directory.clone()).unwrap();
|
|
||||||
}
|
|
||||||
directory
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use crate::dictionary::app_data_dir;
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
use crate::fs::*;
|
||||||
|
|
||||||
pub fn create_db() {
|
pub fn create_db() {
|
||||||
let path = app_data_dir();
|
let db_file = db_path();
|
||||||
let db_file = path.join("data.db");
|
|
||||||
if !db_file.exists() {
|
if !db_file.exists() {
|
||||||
std::fs::File::create(&db_file).unwrap();
|
std::fs::File::create(&db_file).unwrap();
|
||||||
let connection = Connection::open(&db_file).unwrap();
|
let connection = Connection::open(&db_file).unwrap();
|
||||||
@@ -51,8 +50,7 @@ fn make_card_stats(conn: &Connection) -> Result<(), rusqlite::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_connection() -> Connection {
|
pub fn default_connection() -> Connection {
|
||||||
let path = app_data_dir();
|
let db_file = db_path();
|
||||||
let db_file = path.join("data.db");
|
|
||||||
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();
|
||||||
connection
|
connection
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
use crate::dictionary::app_data_dir;
|
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
use crate::fs::*;
|
||||||
use crate::notification::NotificationData;
|
use crate::notification::NotificationData;
|
||||||
use crate::notification::NotificationData::*;
|
use crate::notification::NotificationData::*;
|
||||||
|
|
||||||
pub async fn get_voice(text: &str) -> Result<BufReader<File>, NotificationData> {
|
pub async fn get_voice(text: &str) -> Result<BufReader<File>, NotificationData> {
|
||||||
let mut path = app_data_dir();
|
let mut path = voice_dir()?;
|
||||||
path.push("voice");
|
|
||||||
if !path.exists() {
|
|
||||||
std::fs::create_dir(path.clone()).map_err(|_| PermissionDenied)?;
|
|
||||||
}
|
|
||||||
let hash = format!("{}.wav", hex::encode(Sha256::digest(text.as_bytes())));
|
let hash = format!("{}.wav", hex::encode(Sha256::digest(text.as_bytes())));
|
||||||
path.push(hash);
|
path.push(hash);
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::dictionary::app_data_dir;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use log::info;
|
use log::info;
|
||||||
use tokio::fs::{File, OpenOptions};
|
use tokio::fs::{File, OpenOptions};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use zstd::{DEFAULT_COMPRESSION_LEVEL, Decoder, Encoder};
|
use zstd::{DEFAULT_COMPRESSION_LEVEL, Decoder, Encoder};
|
||||||
|
use crate::fs::*;
|
||||||
use crate::notification::NotificationData;
|
use crate::notification::NotificationData;
|
||||||
use crate::notification::NotificationData::{PermissionDenied, WebApiUnavailable};
|
use crate::notification::NotificationData::{PermissionDenied, WebApiUnavailable};
|
||||||
|
|
||||||
@@ -11,8 +11,7 @@ use crate::notification::NotificationData::{PermissionDenied, WebApiUnavailable}
|
|||||||
const API_URL: &str = "https://learning.micialware.ru/";
|
const API_URL: &str = "https://learning.micialware.ru/";
|
||||||
|
|
||||||
pub async fn send_data(id: String) -> Result<(), NotificationData> {
|
pub async fn send_data(id: String) -> Result<(), NotificationData> {
|
||||||
let path = app_data_dir();
|
let db_file = db_path();
|
||||||
let db_file = path.join("data.db");
|
|
||||||
let data = tokio::fs::read(db_file).await.map_err(|_| WebApiUnavailable)?;
|
let data = tokio::fs::read(db_file).await.map_err(|_| WebApiUnavailable)?;
|
||||||
let data = compress(data);
|
let data = compress(data);
|
||||||
|
|
||||||
@@ -102,7 +101,7 @@ pub async fn get_web_version(key: &str) -> Result<u32, NotificationData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_local_version() -> u32 {
|
pub async fn get_local_version() -> u32 {
|
||||||
let file = app_data_dir().join("data.meta");
|
let file = db_meta_path();
|
||||||
if file.exists() {
|
if file.exists() {
|
||||||
let mut data = String::new();
|
let mut data = String::new();
|
||||||
File::open(file.clone())
|
File::open(file.clone())
|
||||||
@@ -126,7 +125,7 @@ pub async fn get_local_version() -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_local_version(version: u32) {
|
pub async fn set_local_version(version: u32) {
|
||||||
let file_path = app_data_dir().join("data.meta");
|
let file_path = db_meta_path();
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use crate::notification::NotificationData;
|
||||||
|
use crate::notification::NotificationData::PermissionDenied;
|
||||||
|
|
||||||
|
pub fn app_data_dir() -> PathBuf {
|
||||||
|
let mut dir = dirs::data_dir().unwrap();
|
||||||
|
dir.push("jap_learn");
|
||||||
|
if !dir.exists() {
|
||||||
|
fs::create_dir_all(dir.clone()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
dir
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn db_path() -> PathBuf {
|
||||||
|
app_data_dir().join("data.db")
|
||||||
|
}
|
||||||
|
pub fn temp_db_path() -> PathBuf {
|
||||||
|
app_data_dir().join("data.db.tmp")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn temp_import_path() -> PathBuf {
|
||||||
|
app_data_dir().join("import")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn db_meta_path() -> PathBuf {
|
||||||
|
app_data_dir().join("data.meta")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn history_dir() -> Result<PathBuf, NotificationData> {
|
||||||
|
let directory = app_data_dir().join("history");
|
||||||
|
if !directory.exists() {
|
||||||
|
fs::create_dir_all(directory.clone()).map_err(|_| PermissionDenied)?;
|
||||||
|
}
|
||||||
|
Ok(directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn voice_dir() -> Result<PathBuf, NotificationData> {
|
||||||
|
let directory = app_data_dir().join("voice");
|
||||||
|
if !directory.exists() {
|
||||||
|
fs::create_dir_all(directory.clone()).map_err(|_| PermissionDenied)?;
|
||||||
|
}
|
||||||
|
Ok(directory)
|
||||||
|
}
|
||||||
+2
-202
@@ -83,207 +83,7 @@ impl Id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct KanaSet {
|
|
||||||
name: String,
|
|
||||||
pub(crate) chars_type: KanaType,
|
|
||||||
pub(crate) dictionary: Vec<Vec<(String, String)>>,
|
|
||||||
pub(crate) include_map: [bool; 10],
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum KanaType {
|
|
||||||
Hiragana,
|
|
||||||
Katakana,
|
|
||||||
}
|
|
||||||
impl KanaSet {
|
|
||||||
pub fn hiragana() -> Self {
|
|
||||||
Self {
|
|
||||||
name: "Хирагана".to_string(),
|
|
||||||
chars_type: KanaType::Hiragana,
|
|
||||||
dictionary: vec![
|
|
||||||
vec![
|
|
||||||
(String::from("ぁ"), String::from("a")),
|
|
||||||
(String::from("ぃ"), String::from("i")),
|
|
||||||
(String::from("ぅ"), String::from("u")),
|
|
||||||
(String::from("ぇ"), String::from("e")),
|
|
||||||
(String::from("ぉ"), String::from("o")),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
(String::from("さ"), String::from("sa")),
|
|
||||||
(String::from("し"), String::from("shi")),
|
|
||||||
(String::from("す"), String::from("su")),
|
|
||||||
(String::from("せ"), String::from("se")),
|
|
||||||
(String::from("そ"), String::from("so")),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
(String::from("か"), String::from("ka")),
|
|
||||||
(String::from("き"), String::from("ki")),
|
|
||||||
(String::from("く"), String::from("ku")),
|
|
||||||
(String::from("け"), String::from("ke")),
|
|
||||||
(String::from("こ"), String::from("ko")),
|
|
||||||
],
|
|
||||||
// Ряд «та» (たちつてと)
|
|
||||||
vec![
|
|
||||||
(String::from("た"), String::from("ta")),
|
|
||||||
(String::from("ち"), String::from("chi")),
|
|
||||||
(String::from("つ"), String::from("tsu")),
|
|
||||||
(String::from("て"), String::from("te")),
|
|
||||||
(String::from("と"), String::from("to")),
|
|
||||||
],
|
|
||||||
// Ряд «на» (なにぬねの)
|
|
||||||
vec![
|
|
||||||
(String::from("な"), String::from("na")),
|
|
||||||
(String::from("に"), String::from("ni")),
|
|
||||||
(String::from("ぬ"), String::from("nu")),
|
|
||||||
(String::from("ね"), String::from("ne")),
|
|
||||||
(String::from("の"), String::from("no")),
|
|
||||||
],
|
|
||||||
// Ряд «ха» (はひふへほ)
|
|
||||||
vec![
|
|
||||||
(String::from("は"), String::from("ha")),
|
|
||||||
(String::from("ひ"), String::from("hi")),
|
|
||||||
(String::from("ふ"), String::from("fu")),
|
|
||||||
(String::from("へ"), String::from("he")),
|
|
||||||
(String::from("ほ"), String::from("ho")),
|
|
||||||
],
|
|
||||||
// Ряд «ма» (まみむめも)
|
|
||||||
vec![
|
|
||||||
(String::from("ま"), String::from("ma")),
|
|
||||||
(String::from("み"), String::from("mi")),
|
|
||||||
(String::from("む"), String::from("mu")),
|
|
||||||
(String::from("め"), String::from("me")),
|
|
||||||
(String::from("も"), String::from("mo")),
|
|
||||||
],
|
|
||||||
// Ряд «я» (やゆよ) — только 3 символа
|
|
||||||
vec![
|
|
||||||
(String::from("や"), String::from("ya")),
|
|
||||||
(String::from("ゆ"), String::from("yu")),
|
|
||||||
(String::from("よ"), String::from("yo")),
|
|
||||||
],
|
|
||||||
// Ряд «ра» (らりるれろ)
|
|
||||||
vec![
|
|
||||||
(String::from("ら"), String::from("ra")),
|
|
||||||
(String::from("り"), String::from("ri")),
|
|
||||||
(String::from("る"), String::from("ru")),
|
|
||||||
(String::from("れ"), String::from("re")),
|
|
||||||
(String::from("ろ"), String::from("ro")),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
(String::from("わ"), String::from("wa")),
|
|
||||||
(String::from("を"), String::from("wo")),
|
|
||||||
(String::from("ん"), String::from("n")),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
include_map: [true; 10],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn katakana() -> Self {
|
|
||||||
Self {
|
|
||||||
name: "Катакана".to_string(),
|
|
||||||
chars_type: KanaType::Katakana,
|
|
||||||
dictionary: vec![
|
|
||||||
vec![
|
|
||||||
(String::from("ァ"), String::from("a")),
|
|
||||||
(String::from("ィ"), String::from("i")),
|
|
||||||
(String::from("ゥ"), String::from("u")),
|
|
||||||
(String::from("ェ"), String::from("e")),
|
|
||||||
(String::from("ォ"), String::from("o")),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
(String::from("サ"), String::from("sa")),
|
|
||||||
(String::from("シ"), String::from("shi")),
|
|
||||||
(String::from("ス"), String::from("su")),
|
|
||||||
(String::from("セ"), String::from("se")),
|
|
||||||
(String::from("ソ"), String::from("so")),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
(String::from("カ"), String::from("ka")),
|
|
||||||
(String::from("キ"), String::from("ki")),
|
|
||||||
(String::from("ク"), String::from("ku")),
|
|
||||||
(String::from("ケ"), String::from("ke")),
|
|
||||||
(String::from("コ"), String::from("ko")),
|
|
||||||
],
|
|
||||||
// Ряд «та» (タチツテト)
|
|
||||||
vec![
|
|
||||||
(String::from("タ"), String::from("ta")),
|
|
||||||
(String::from("チ"), String::from("chi")),
|
|
||||||
(String::from("ツ"), String::from("tsu")),
|
|
||||||
(String::from("テ"), String::from("te")),
|
|
||||||
(String::from("ト"), String::from("to")),
|
|
||||||
],
|
|
||||||
// Ряд «на» (ナニヌネノ)
|
|
||||||
vec![
|
|
||||||
(String::from("ナ"), String::from("na")),
|
|
||||||
(String::from("ニ"), String::from("ni")),
|
|
||||||
(String::from("ヌ"), String::from("nu")),
|
|
||||||
(String::from("ネ"), String::from("ne")),
|
|
||||||
(String::from("ノ"), String::from("no")),
|
|
||||||
],
|
|
||||||
// Ряд «ха» (ハヒフヘホ)
|
|
||||||
vec![
|
|
||||||
(String::from("ハ"), String::from("ha")),
|
|
||||||
(String::from("ヒ"), String::from("hi")),
|
|
||||||
(String::from("フ"), String::from("fu")),
|
|
||||||
(String::from("ヘ"), String::from("he")),
|
|
||||||
(String::from("ホ"), String::from("ho")),
|
|
||||||
],
|
|
||||||
// Ряд «ма» (マミムメモ)
|
|
||||||
vec![
|
|
||||||
(String::from("マ"), String::from("ma")),
|
|
||||||
(String::from("ミ"), String::from("mi")),
|
|
||||||
(String::from("ム"), String::from("mu")),
|
|
||||||
(String::from("メ"), String::from("me")),
|
|
||||||
(String::from("モ"), String::from("mo")),
|
|
||||||
],
|
|
||||||
// Ряд «я» (ヤユヨ) — только 3 символа
|
|
||||||
vec![
|
|
||||||
(String::from("ヤ"), String::from("ya")),
|
|
||||||
(String::from("ユ"), String::from("yu")),
|
|
||||||
(String::from("ヨ"), String::from("yo")),
|
|
||||||
],
|
|
||||||
// Ряд «ра» (ラリルレロ)
|
|
||||||
vec![
|
|
||||||
(String::from("ラ"), String::from("ra")),
|
|
||||||
(String::from("リ"), String::from("ri")),
|
|
||||||
(String::from("ル"), String::from("ru")),
|
|
||||||
(String::from("レ"), String::from("re")),
|
|
||||||
(String::from("ロ"), String::from("ro")),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
(String::from("ワ"), String::from("wa")),
|
|
||||||
(String::from("ヲ"), String::from("wo")),
|
|
||||||
(String::from("ン"), String::from("n")),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
include_map: [true; 10],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list(&self) -> Vec<(String, String)> {
|
|
||||||
let mut current_set: Vec<(String, String)> = Vec::new();
|
|
||||||
|
|
||||||
for i in 0..10 {
|
|
||||||
if self.include_map[i] {
|
|
||||||
self.dictionary[i].iter().for_each(|v| {
|
|
||||||
current_set.push(v.clone());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_set
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for KanaSet {
|
|
||||||
fn default() -> Self {
|
|
||||||
KanaSet::hiragana()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl PartialEq<Self> for KanaSet {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.name == other.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WordData {
|
pub struct WordData {
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
@@ -448,7 +248,7 @@ impl DeckData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_stat_score(word, &self.state.lock().connection);
|
update_stat_score(word, &self.state.lock().connection);
|
||||||
push_note(
|
let _ = push_note(
|
||||||
self.settings.id,
|
self.settings.id,
|
||||||
HistoryItem {
|
HistoryItem {
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
@@ -457,7 +257,7 @@ impl DeckData {
|
|||||||
before: old_score,
|
before: old_score,
|
||||||
after: new_score,
|
after: new_score,
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.set.len()
|
self.set.len()
|
||||||
|
|||||||
+6
-18
@@ -1,26 +1,14 @@
|
|||||||
#![windows_subsystem = "windows"]
|
#![windows_subsystem = "windows"]
|
||||||
mod data_provider;
|
mod data_provider;
|
||||||
mod dictionary;
|
|
||||||
mod dictionary_quiz;
|
|
||||||
mod history;
|
|
||||||
pub mod import;
|
|
||||||
mod lang;
|
|
||||||
pub mod navigation;
|
|
||||||
mod quiz;
|
|
||||||
mod randomizer;
|
|
||||||
mod repetition;
|
|
||||||
mod repetition_settings;
|
|
||||||
mod repetitions;
|
|
||||||
mod selector;
|
|
||||||
pub mod styling;
|
|
||||||
mod sync;
|
|
||||||
mod word;
|
|
||||||
mod writing;
|
|
||||||
pub mod notification;
|
pub mod notification;
|
||||||
pub mod app;
|
pub mod app;
|
||||||
|
mod lang;
|
||||||
|
mod styling;
|
||||||
|
mod pages;
|
||||||
|
mod navigation;
|
||||||
|
mod fs;
|
||||||
|
mod core;
|
||||||
use crate::app::start;
|
use crate::app::start;
|
||||||
use crate::navigation::RootMessage;
|
|
||||||
use mimalloc::MiMalloc;
|
use mimalloc::MiMalloc;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
|
|||||||
+42
-35
@@ -1,39 +1,46 @@
|
|||||||
use crate::app::{fill_state, AppState};
|
use crate::app::{fill_state, AppState};
|
||||||
use crate::data_provider::history::{get_history_of_set, history_dir};
|
use crate::data_provider::history::get_history_of_set;
|
||||||
use crate::data_provider::sqlite::{create_db, default_connection};
|
use crate::data_provider::sqlite::{create_db, default_connection};
|
||||||
use crate::data_provider::web_api::{get_local_version, get_web_version, load_data, set_local_version};
|
use crate::data_provider::web_api::{
|
||||||
use crate::dictionary::{app_data_dir, DictionaryMessage, DictionaryState};
|
get_local_version, get_web_version, load_data, set_local_version,
|
||||||
use crate::dictionary_quiz::{DictionaryQuizMessage, DictionaryQuizState};
|
};
|
||||||
use crate::history::{HistoryMessage, HistoryState};
|
use crate::fs::*;
|
||||||
use crate::import::{ImportMessage, ImportState};
|
|
||||||
use crate::lang::Id;
|
use crate::lang::Id;
|
||||||
use crate::message_navigation;
|
use crate::message_navigation;
|
||||||
use crate::navigation::Page::*;
|
use crate::navigation::Page::*;
|
||||||
use crate::navigation::RootMessage::{DataLoaded, Keyboard, Notification, PushNotification, UpdateData};
|
use crate::navigation::RootMessage::{
|
||||||
use crate::notification::{NotificationData, NotificationManager, NotificationMessage, NotificationRequest};
|
DataLoaded, Keyboard, Notification, PushNotification, UpdateData,
|
||||||
use crate::quiz::{QuizMessage, QuizState};
|
};
|
||||||
use crate::randomizer::{RandomizerMessage, RandomizerState};
|
use crate::notification::{
|
||||||
use crate::repetition::{RepetitionMessage, RepetitionState};
|
NotificationData, NotificationManager, NotificationMessage, NotificationRequest,
|
||||||
use crate::repetition_settings::{RepetitionSettingsMessage, RepetitionSettingsState};
|
};
|
||||||
use crate::repetitions::{RepetitionsMessage, RepetitionsState};
|
use crate::pages::dictionary::{DictionaryMessage, DictionaryState};
|
||||||
use crate::selector::{SelectorMessage, SelectorState};
|
use crate::pages::dictionary_quiz::{DictionaryQuizMessage, DictionaryQuizState};
|
||||||
|
use crate::pages::history::{HistoryMessage, HistoryState};
|
||||||
|
use crate::pages::import::{ImportMessage, ImportState};
|
||||||
|
use crate::pages::quiz::{QuizMessage, QuizState};
|
||||||
|
use crate::pages::randomizer::{RandomizerMessage, RandomizerState};
|
||||||
|
use crate::pages::repetition::{RepetitionMessage, RepetitionState};
|
||||||
|
use crate::pages::repetition_settings::{RepetitionSettingsMessage, RepetitionSettingsState};
|
||||||
|
use crate::pages::repetitions::{RepetitionsMessage, RepetitionsState};
|
||||||
|
use crate::pages::selector::{SelectorMessage, SelectorState};
|
||||||
|
use crate::pages::sync::{SyncMessage, SyncState};
|
||||||
|
use crate::pages::word::{WordMessage, WordState};
|
||||||
|
use crate::pages::writing::{WritingMessage, WritingState};
|
||||||
use crate::state_navigate_handle;
|
use crate::state_navigate_handle;
|
||||||
use crate::state_update;
|
use crate::state_update;
|
||||||
use crate::sync::{SyncMessage, SyncState};
|
|
||||||
use crate::view_navigation;
|
use crate::view_navigation;
|
||||||
use crate::word::{WordMessage, WordState};
|
|
||||||
use crate::writing::{WritingMessage, WritingState};
|
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use iced::keyboard::Event;
|
use iced::keyboard::Event;
|
||||||
use iced::widget::stack;
|
use iced::widget::stack;
|
||||||
use iced::{Element, Task};
|
use iced::{Element, Task};
|
||||||
use iced_core::Length::Fill;
|
use iced_core::Length::Fill;
|
||||||
|
use log::info;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use log::info;
|
|
||||||
|
|
||||||
impl Default for ScreenState {
|
impl Default for ScreenState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@@ -91,7 +98,7 @@ pub enum Page {
|
|||||||
pub struct ScreenState {
|
pub struct ScreenState {
|
||||||
stack: Vec<Page>,
|
stack: Vec<Page>,
|
||||||
app_state: Arc<Mutex<AppState>>,
|
app_state: Arc<Mutex<AppState>>,
|
||||||
notification_manager: NotificationManager
|
notification_manager: NotificationManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenState {
|
impl ScreenState {
|
||||||
@@ -108,21 +115,16 @@ impl ScreenState {
|
|||||||
let key = state_guard.sync_data.key.clone().unwrap();
|
let key = state_guard.sync_data.key.clone().unwrap();
|
||||||
final_task = Task::batch([
|
final_task = Task::batch([
|
||||||
reading_additional_task,
|
reading_additional_task,
|
||||||
Task::perform(
|
Task::perform(Self::load_web_backup(key), |result| match result {
|
||||||
Self::load_web_backup(key),
|
|
||||||
|result| {
|
|
||||||
match result {
|
|
||||||
Ok(update) => {
|
Ok(update) => {
|
||||||
if update {
|
if update {
|
||||||
UpdateData
|
UpdateData
|
||||||
}else {
|
} else {
|
||||||
RootMessage::None
|
RootMessage::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => PushNotification(NotificationRequest::Warning(err))
|
Err(err) => PushNotification(NotificationRequest::Warning(err)),
|
||||||
}
|
}),
|
||||||
}
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
final_task = reading_additional_task;
|
final_task = reading_additional_task;
|
||||||
@@ -135,6 +137,7 @@ impl ScreenState {
|
|||||||
|
|
||||||
async fn load_additional_data() -> RootMessage {
|
async fn load_additional_data() -> RootMessage {
|
||||||
let directory = history_dir();
|
let directory = history_dir();
|
||||||
|
if let Ok(directory) = directory {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for file in directory.read_dir().unwrap().flatten() {
|
for file in directory.read_dir().unwrap().flatten() {
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
@@ -148,6 +151,7 @@ impl ScreenState {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let history = get_history_of_set(id);
|
let history = get_history_of_set(id);
|
||||||
|
if let Ok(history) = history {
|
||||||
let by_date = history.chunk_by(|x, x1| {
|
let by_date = history.chunk_by(|x, x1| {
|
||||||
x.timestamp.naive_local().date() == x1.timestamp.naive_local().date()
|
x.timestamp.naive_local().date() == x1.timestamp.naive_local().date()
|
||||||
});
|
});
|
||||||
@@ -155,8 +159,13 @@ impl ScreenState {
|
|||||||
vec.push((group[0].timestamp.naive_local().date(), group.len() as u32));
|
vec.push((group[0].timestamp.naive_local().date(), group.len() as u32));
|
||||||
}
|
}
|
||||||
map.insert(id, vec);
|
map.insert(id, vec);
|
||||||
|
} else {
|
||||||
|
return PushNotification(NotificationRequest::Warning(history.err().unwrap()));
|
||||||
}
|
}
|
||||||
DataLoaded(map)
|
}
|
||||||
|
return DataLoaded(map);
|
||||||
|
}
|
||||||
|
PushNotification(NotificationRequest::Warning(directory.err().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_web_backup(string: String) -> Result<bool, NotificationData> {
|
async fn load_web_backup(string: String) -> Result<bool, NotificationData> {
|
||||||
@@ -191,9 +200,8 @@ impl ScreenState {
|
|||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
state.connection = Connection::open_in_memory().unwrap();
|
state.connection = Connection::open_in_memory().unwrap();
|
||||||
}
|
}
|
||||||
let path = app_data_dir();
|
let db_file = db_path();
|
||||||
let db_file = path.join("data.db");
|
let temp_db_file = temp_db_path();
|
||||||
let temp_db_file = path.join("data.db.tmp");
|
|
||||||
std::fs::rename(temp_db_file, &db_file).unwrap();
|
std::fs::rename(temp_db_file, &db_file).unwrap();
|
||||||
|
|
||||||
state.connection = default_connection();
|
state.connection = default_connection();
|
||||||
@@ -206,7 +214,7 @@ impl ScreenState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let PushNotification(notification) = &message {
|
if let PushNotification(notification) = &message {
|
||||||
return self.notification_manager.push(notification.clone())
|
return self.notification_manager.push(notification.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let task: (Task<RootMessage>, bool) = self.navigate_or_update(message);
|
let task: (Task<RootMessage>, bool) = self.navigate_or_update(message);
|
||||||
@@ -255,7 +263,6 @@ impl ScreenState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Element<'_, RootMessage> {
|
pub fn view(&self) -> Element<'_, RootMessage> {
|
||||||
|
|
||||||
info!("View update");
|
info!("View update");
|
||||||
let time = Instant::now();
|
let time = Instant::now();
|
||||||
let view = view_navigation!(
|
let view = view_navigation!(
|
||||||
@@ -275,7 +282,7 @@ impl ScreenState {
|
|||||||
Import
|
Import
|
||||||
);
|
);
|
||||||
|
|
||||||
let notifications = self.notification_manager.draw().map(RootMessage::Notification);
|
let notifications = self.notification_manager.draw().map(Notification);
|
||||||
|
|
||||||
info!("View took {:?}", time.elapsed());
|
info!("View took {:?}", time.elapsed());
|
||||||
stack![view, notifications].width(Fill).height(Fill).into()
|
stack![view, notifications].width(Fill).height(Fill).into()
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
pub mod dictionary;
|
||||||
|
pub mod dictionary_quiz;
|
||||||
|
pub mod history;
|
||||||
|
pub mod import;
|
||||||
|
pub mod quiz;
|
||||||
|
pub mod randomizer;
|
||||||
|
pub mod repetition;
|
||||||
|
pub mod repetition_settings;
|
||||||
|
pub mod repetitions;
|
||||||
|
pub mod selector;
|
||||||
|
pub mod sync;
|
||||||
|
pub mod word;
|
||||||
|
pub mod writing;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::data_provider::words::{delete_group, delete_word, update_group, update_word};
|
use crate::data_provider::words::{delete_group, delete_word, update_group, update_word};
|
||||||
use crate::dictionary::DictionaryMessage::*;
|
use crate::pages::dictionary::DictionaryMessage::*;
|
||||||
use crate::dictionary_quiz::DictionaryQuizState;
|
use crate::pages::dictionary_quiz::DictionaryQuizState;
|
||||||
use crate::import::ImportState;
|
use crate::pages::import::ImportState;
|
||||||
use crate::lang::{WordData, WordGroup};
|
use crate::lang::{WordData, WordGroup};
|
||||||
use crate::navigation::Page::{Import, Word};
|
use crate::navigation::Page::{Import, Word};
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use crate::word::WordState;
|
use crate::pages::word::WordState;
|
||||||
use chrono::{DateTime, TimeDelta, Utc};
|
use chrono::{DateTime, TimeDelta, Utc};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use iced::alignment::Vertical::Center;
|
use iced::alignment::Vertical::Center;
|
||||||
@@ -619,15 +619,7 @@ pub fn split_with_coma(ts: &str) -> Vec<String> {
|
|||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app_data_dir() -> PathBuf {
|
|
||||||
let mut dir = dirs::data_dir().unwrap();
|
|
||||||
dir.push("jap_learn");
|
|
||||||
if !dir.exists() {
|
|
||||||
fs::create_dir_all(dir.clone()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
dir
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq)]
|
#[derive(Hash, PartialEq, Eq)]
|
||||||
struct WordLineState {
|
struct WordLineState {
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::RootMessage;
|
use crate::navigation::RootMessage;
|
||||||
use crate::dictionary::split_with_coma;
|
use crate::pages::dictionary::split_with_coma;
|
||||||
use crate::dictionary_quiz::DictionaryQuizMessage::*;
|
use crate::pages::dictionary_quiz::DictionaryQuizMessage::*;
|
||||||
use crate::lang::WordData;
|
use crate::lang::WordData;
|
||||||
use crate::navigation::Page::PreviousPage;
|
use crate::navigation::Page::PreviousPage;
|
||||||
use crate::navigation::*;
|
use crate::navigation::*;
|
||||||
use crate::quiz::Score;
|
use crate::pages::quiz::Score;
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use iced::Background::Color;
|
use iced::Background::Color;
|
||||||
use iced::border::Radius;
|
use iced::border::Radius;
|
||||||
@@ -49,7 +49,7 @@ impl NavigatedPage<HistoryMessage> for HistoryState {
|
|||||||
impl HistoryState {
|
impl HistoryState {
|
||||||
pub fn new(id: crate::lang::Id, state: Arc<Mutex<AppState>>) -> Self {
|
pub fn new(id: crate::lang::Id, state: Arc<Mutex<AppState>>) -> Self {
|
||||||
let state = state.lock();
|
let state = state.lock();
|
||||||
let history = get_history_of_set(id);
|
let history = get_history_of_set(id).unwrap_or_default();
|
||||||
let words = history
|
let words = history
|
||||||
.iter()
|
.iter()
|
||||||
.map(
|
.map(
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::data_provider::import::{ImportData, ImportGroup, get_words_of_group, load_groups};
|
use crate::data_provider::import::{ImportData, ImportGroup, get_words_of_group, load_groups};
|
||||||
use crate::data_provider::words::{add_group, add_words};
|
use crate::data_provider::words::{add_group, add_words};
|
||||||
use crate::dictionary::app_data_dir;
|
use crate::pages::import::ImportMessage::*;
|
||||||
use crate::import::ImportMessage::*;
|
|
||||||
use crate::lang::{WordData, WordGroup};
|
use crate::lang::{WordData, WordGroup};
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::notification::NotificationData::OpenFileError;
|
use crate::notification::NotificationData::OpenFileError;
|
||||||
@@ -28,6 +27,7 @@ use log::info;
|
|||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
use zip::ZipArchive;
|
use zip::ZipArchive;
|
||||||
use crate::app::AppState;
|
use crate::app::AppState;
|
||||||
|
use crate::fs::*;
|
||||||
|
|
||||||
const DEFAULT_FIELDS: [&str; 6] = ["key", "value", "tags", "reading", "context", "description"];
|
const DEFAULT_FIELDS: [&str; 6] = ["key", "value", "tags", "reading", "context", "description"];
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ impl ImportState {
|
|||||||
let file = File::open(path).map_err(|_| OpenFileError)?;
|
let file = File::open(path).map_err(|_| OpenFileError)?;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
let mut archive = ZipArchive::new(reader).map_err(|_| OpenFileError)?;
|
let mut archive = ZipArchive::new(reader).map_err(|_| OpenFileError)?;
|
||||||
let temp_file_path = app_data_dir().join("import");
|
let temp_file_path = temp_import_path();
|
||||||
let mut temp_file = OpenOptions::new()
|
let mut temp_file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
@@ -394,7 +394,7 @@ impl ImportState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_import_file() -> Result<ImportData, NotificationData> {
|
fn read_import_file() -> Result<ImportData, NotificationData> {
|
||||||
let temp_file_path = app_data_dir().join("import");
|
let temp_file_path = temp_import_path();
|
||||||
let connection = Connection::open(&temp_file_path).map_err(|_| OpenFileError)?;
|
let connection = Connection::open(&temp_file_path).map_err(|_| OpenFileError)?;
|
||||||
let data = load_groups(&connection)?;
|
let data = load_groups(&connection)?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
@@ -431,7 +431,7 @@ impl ImportState {
|
|||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
let temp_file_path = app_data_dir().join("import");
|
let temp_file_path = temp_import_path();
|
||||||
let connection = Connection::open(&temp_file_path).map_err(|_| OpenFileError)?;
|
let connection = Connection::open(&temp_file_path).map_err(|_| OpenFileError)?;
|
||||||
let import_list = get_words_of_group(&connection, group.id)?;
|
let import_list = get_words_of_group(&connection, group.id)?;
|
||||||
let mut words_list = Vec::with_capacity(import_list.len());
|
let mut words_list = Vec::with_capacity(import_list.len());
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::lang::KanaSet;
|
|
||||||
use crate::navigation::Page::PreviousPage;
|
use crate::navigation::Page::PreviousPage;
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::quiz::QuizMessage::*;
|
use crate::pages::quiz::QuizMessage::*;
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use iced::widget::*;
|
use iced::widget::*;
|
||||||
use iced::{Element, Fill, Task, alignment};
|
use iced::{Element, Fill, Task, alignment};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use crate::app::USER_FONT;
|
use crate::app::USER_FONT;
|
||||||
|
use crate::core::kana_set::KanaSet;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct QuizState {
|
pub struct QuizState {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::RootMessage;
|
use crate::navigation::RootMessage;
|
||||||
use crate::navigation::{NavigatedPage, Page};
|
use crate::navigation::{NavigatedPage, Page};
|
||||||
use crate::randomizer::RandomizerMessage::{Back, Edit, Start};
|
use crate::pages::randomizer::RandomizerMessage::{Back, Edit, Start};
|
||||||
use crate::styling::{HALF_SPACING, back_overlay, jl_button};
|
use crate::styling::{HALF_SPACING, back_overlay, jl_button};
|
||||||
use iced::Task;
|
use iced::Task;
|
||||||
use iced::widget::{button, text_editor};
|
use iced::widget::{button, text_editor};
|
||||||
File renamed without changes.
@@ -4,7 +4,7 @@ use crate::data_provider::card_stats::{delete_stats, load_stats_of_deck};
|
|||||||
use crate::lang::DeckSettings;
|
use crate::lang::DeckSettings;
|
||||||
use crate::navigation::Page::PreviousPage;
|
use crate::navigation::Page::PreviousPage;
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::repetition_settings::RepetitionSettingsMessage::*;
|
use crate::pages::repetition_settings::RepetitionSettingsMessage::*;
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use iced::widget::button::danger;
|
use iced::widget::button::danger;
|
||||||
use iced::widget::text_input::Catalog;
|
use iced::widget::text_input::Catalog;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::data_provider::card_sets::update_deck;
|
use crate::data_provider::card_sets::update_deck;
|
||||||
use crate::data_provider::card_stats::{add_stat_list, load_stats_of_deck};
|
use crate::data_provider::card_stats::{add_stat_list, load_stats_of_deck};
|
||||||
use crate::history::HistoryState;
|
use crate::pages::history::HistoryState;
|
||||||
use crate::lang::{AppendMode, CardStatistics, DeckSettings, Id, OrderMode};
|
use crate::lang::{AppendMode, CardStatistics, DeckSettings, Id, OrderMode};
|
||||||
use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings};
|
use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings};
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::repetition::RepetitionState;
|
use crate::pages::repetition::RepetitionState;
|
||||||
use crate::repetition_settings::RepetitionSettingsState;
|
use crate::pages::repetition_settings::RepetitionSettingsState;
|
||||||
use crate::repetitions::RepetitionsMessage::*;
|
use crate::pages::repetitions::RepetitionsMessage::*;
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use chrono::{Days, Local, Utc};
|
use chrono::{Days, Local, Utc};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
use crate::dictionary::DictionaryState;
|
use crate::pages::dictionary::DictionaryState;
|
||||||
use crate::lang::{KanaSet, KanaType};
|
|
||||||
use crate::navigation::Page::*;
|
use crate::navigation::Page::*;
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::randomizer::RandomizerState;
|
use crate::pages::randomizer::RandomizerState;
|
||||||
use crate::repetitions::RepetitionsState;
|
use crate::pages::repetitions::RepetitionsState;
|
||||||
use crate::selector::SelectorMessage::ChangeMode;
|
use crate::pages::selector::SelectorMessage::ChangeMode;
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use crate::sync::SyncState;
|
use crate::pages::sync::SyncState;
|
||||||
use crate::writing::WritingState;
|
use crate::pages::writing::WritingState;
|
||||||
use iced::widget::button::{Status, Style};
|
use iced::widget::button::{Status, Style};
|
||||||
use iced::widget::*;
|
use iced::widget::*;
|
||||||
use iced::{Element, Task, alignment};
|
use iced::{Element, Task, alignment};
|
||||||
@@ -17,7 +16,8 @@ use iced_core::Color;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::app::AppState;
|
use crate::app::AppState;
|
||||||
use crate::quiz::QuizState;
|
use crate::core::kana_set::{KanaSet, KanaType};
|
||||||
|
use crate::pages::quiz::QuizState;
|
||||||
|
|
||||||
pub struct SelectorState {
|
pub struct SelectorState {
|
||||||
pub set: KanaSet,
|
pub set: KanaSet,
|
||||||
@@ -3,7 +3,7 @@ use crate::data_provider::web_api::*;
|
|||||||
use crate::navigation::Page::PreviousPage;
|
use crate::navigation::Page::PreviousPage;
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use crate::sync::SyncMessage::*;
|
use crate::pages::sync::SyncMessage::*;
|
||||||
use iced::widget::button::danger;
|
use iced::widget::button::danger;
|
||||||
use iced::widget::container::rounded_box;
|
use iced::widget::container::rounded_box;
|
||||||
use iced::widget::{button, column, container, progress_bar, row, space, text, toggler};
|
use iced::widget::{button, column, container, progress_bar, row, space, text, toggler};
|
||||||
@@ -3,7 +3,7 @@ use crate::lang::WordData;
|
|||||||
use crate::navigation::Page::PreviousPage;
|
use crate::navigation::Page::PreviousPage;
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use crate::word::WordMessage::*;
|
use crate::pages::word::WordMessage::*;
|
||||||
use iced::widget::button::danger;
|
use iced::widget::button::danger;
|
||||||
use iced::widget::{button, column, row, rule, scrollable, text, text_input};
|
use iced::widget::{button, column, row, rule, scrollable, text, text_input};
|
||||||
use iced::{Element, Fill, Task};
|
use iced::{Element, Fill, Task};
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::RootMessage;
|
|
||||||
use crate::lang::KanaSet;
|
|
||||||
use crate::navigation::Page::PreviousPage;
|
use crate::navigation::Page::PreviousPage;
|
||||||
use crate::navigation::{NavigatedPage, Page};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use iced::widget::*;
|
use iced::widget::*;
|
||||||
use iced::{Element, Fill, Task, alignment};
|
use iced::{Element, Fill, Task, alignment};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
use crate::core::kana_set::KanaSet;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WritingState {
|
pub struct WritingState {
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::repetitions::Style;
|
|
||||||
use iced::Element;
|
use iced::Element;
|
||||||
use iced::border::Radius;
|
use iced::border::Radius;
|
||||||
use iced::widget::button::*;
|
use iced::widget::button::*;
|
||||||
|
|||||||
Reference in new issue
Block a user