2026-07-05 01:52:19 +03:00
|
|
|
use crate::dictionary::app_data_dir;
|
|
|
|
|
use crate::lang::{WordData, WordOpenMode};
|
2026-07-05 01:22:19 +03:00
|
|
|
use crate::{AppState, NavigatedPage, Page, RootMessage};
|
2026-07-05 01:52:19 +03:00
|
|
|
use chrono::{DateTime, Utc};
|
2026-07-05 01:22:19 +03:00
|
|
|
use iced::widget::*;
|
|
|
|
|
use iced::{Element, Fill, Left, Task};
|
2026-07-05 01:52:19 +03:00
|
|
|
use std::fs::File;
|
|
|
|
|
use std::io::{BufRead, BufReader};
|
2026-07-05 01:22:19 +03:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
use HistoryMessage::Back;
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct HistoryState {
|
|
|
|
|
set_id: u32,
|
2026-07-05 01:52:19 +03:00
|
|
|
list: Vec<HistoryItem>,
|
2026-07-05 01:22:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl NavigatedPage<HistoryMessage> for HistoryState {
|
|
|
|
|
fn navigate(&self, message: &HistoryMessage) -> Option<Page> {
|
|
|
|
|
match message {
|
|
|
|
|
Back => Some(Page::PreviousPage),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl HistoryState {
|
|
|
|
|
pub fn new(id: u32, state: Arc<Mutex<AppState>>) -> Self {
|
2026-07-05 01:52:19 +03:00
|
|
|
Self {
|
|
|
|
|
set_id: id,
|
|
|
|
|
list: get_history_of_set(id, &state.lock().unwrap().dictionary),
|
|
|
|
|
}
|
2026-07-05 01:22:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn update(&mut self, message: HistoryMessage) -> Task<RootMessage> {
|
|
|
|
|
Task::none()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn view(&self) -> Element<'_, HistoryMessage> {
|
|
|
|
|
container(
|
|
|
|
|
iced::widget::column![
|
|
|
|
|
button("Назад").on_press(HistoryMessage::Back),
|
|
|
|
|
// column![
|
|
|
|
|
//
|
|
|
|
|
// ]
|
|
|
|
|
// .height(Fill)
|
|
|
|
|
// .width(Fill)
|
|
|
|
|
]
|
|
|
|
|
.align_x(Left)
|
|
|
|
|
.width(Fill),
|
|
|
|
|
)
|
|
|
|
|
.center_x(Fill)
|
|
|
|
|
.padding(10)
|
|
|
|
|
.into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 01:52:19 +03:00
|
|
|
fn get_history_of_set(id: u32, words: &Vec<WordData>) -> Vec<HistoryItem> {
|
|
|
|
|
let app_dir = app_data_dir();
|
|
|
|
|
let head = app_dir.clone().join(format!("set_{}_history.csv", id));
|
|
|
|
|
let tail = app_dir.clone().join(format!("set_{}_history.csv", id));
|
|
|
|
|
let mut lines = Vec::new();
|
|
|
|
|
if tail.exists() {
|
|
|
|
|
let reader = BufReader::new(File::open(tail).unwrap());
|
|
|
|
|
for line in reader.lines() {
|
|
|
|
|
lines.push(line.unwrap());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if head.exists() {
|
|
|
|
|
let reader = BufReader::new(File::open(head).unwrap());
|
|
|
|
|
for line in reader.lines() {
|
|
|
|
|
lines.push(line.unwrap());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse_history_items(lines, words)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_history_items(strings: Vec<String>, words: &Vec<WordData>) -> Vec<HistoryItem> {
|
|
|
|
|
let mut items = Vec::with_capacity(strings.len());
|
|
|
|
|
for string in strings {
|
|
|
|
|
if let [time, word, mode, before, after] = string.split(';').collect::<Vec<&str>>()[..] {
|
|
|
|
|
items.push(HistoryItem {
|
|
|
|
|
timestamp: DateTime::from_timestamp(time.parse().unwrap(), 0).unwrap(),
|
|
|
|
|
word: words
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|w| w.id == word.parse::<u32>().unwrap())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.clone(),
|
|
|
|
|
mode: match mode.parse::<u8>().unwrap() {
|
|
|
|
|
2 => WordOpenMode::Hard,
|
|
|
|
|
3 => WordOpenMode::Ok,
|
|
|
|
|
4 => WordOpenMode::Easy,
|
|
|
|
|
_ => WordOpenMode::None,
|
|
|
|
|
},
|
|
|
|
|
before: before.parse().unwrap(),
|
|
|
|
|
after: after.parse().unwrap(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
items
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 01:22:19 +03:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub enum HistoryMessage {
|
|
|
|
|
Back,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2026-07-05 01:52:19 +03:00
|
|
|
pub struct HistoryItem {
|
|
|
|
|
timestamp: DateTime<Utc>,
|
|
|
|
|
word: WordData,
|
|
|
|
|
mode: WordOpenMode,
|
|
|
|
|
before: u8,
|
|
|
|
|
after: u8,
|
|
|
|
|
}
|