use crate::app::AppState; use crate::data::entities::DeckSettings; use crate::data_provider::card_sets::{delete_set, update_deck}; use crate::data_provider::card_stats::{delete_stats, load_stats_of_deck}; use crate::navigation::Page::PreviousPage; use crate::navigation::{NavigatedPage, Page, RootMessage}; use crate::notification::MaybeError; use crate::pages::repetition_settings::RepetitionSettingsMessage::*; use crate::styling::*; use crate::{push_error, push_error_task}; use iced::widget::button::danger; use iced::widget::text_input::Catalog; use iced::widget::{button, column, row, scrollable, space, text, text_input}; use iced::{Element, Task}; use iced_core::Length::Fill; use iced_core::{Padding, Theme, color}; use parking_lot::Mutex; use std::sync::Arc; use std::time::Duration; pub struct RepetitionSettingsState { set: DeckSettings, index: usize, state: Arc>, real_delete: bool, correct_filter: bool, filter_changed: bool, } impl RepetitionSettingsState { pub(crate) fn new(index: usize, state: Arc>) -> RepetitionSettingsState { let set; { let local_state = state.lock(); set = local_state.decks[index].clone(); } let filter_state = set.check_filter(); RepetitionSettingsState { index, set, state, real_delete: false, correct_filter: filter_state, filter_changed: false, } } } impl NavigatedPage for RepetitionSettingsState { fn navigate(&mut self, message: &RepetitionSettingsMessage) -> Option { if let Back = message { Some(PreviousPage) } else { None } } fn navigated(&mut self) {} fn update(&mut self, message: RepetitionSettingsMessage) -> Task { match message { Back => {} Save => { let mut state = self.state.lock(); if let Err(e) = update_deck(&mut self.set, &state.connection) { return push_error_task!(e); } if self.filter_changed && let Err(e) = update_deck_stats(&self.set, &state) { return push_error_task!(e); } state.decks[self.index] = self.set.clone(); } SetName(new) => { self.set.name = new; } SetForward(new) => { self.set.forward = new; } SetBackward(backward) => { self.set.backward = backward; } SetFilter(new) => { self.set.filter = new; self.correct_filter = self.set.check_filter(); self.filter_changed = true; } TryFilter => { let state = self.state.lock(); let count = self.set.get_word_list(&state).len(); self.set.count = Some(count); } DeleteSet => { if !self.real_delete { self.real_delete = true; return Task::future(async { tokio::time::sleep(Duration::from_millis(3000)).await; RootMessage::RepetitionSettings(RevertDeleteSet) }); } let mut state = self.state.lock(); if let Err(e) = delete_set(&self.set, &state.connection) { return push_error_task!(e); } state.decks.remove(self.index); return Task::done(RootMessage::RepetitionSettings(Back)); } RevertDeleteSet => self.real_delete = false, } Task::none() } fn view(&self) -> Element<'_, RepetitionSettingsMessage> { back_overlay( iced::widget::column![ scrollable( column![ column![ text!("Название набора"), text_input("", &self.set.name).on_input(SetName), ] .spacing(QUARTER_SPACING), column![ text!("Передняя сторона"), text_input("", &self.set.forward).on_input(SetForward), ] .spacing(QUARTER_SPACING), column![ text!("Задняя сторона"), text_input("", &self.set.backward).on_input(SetBackward), ] .spacing(QUARTER_SPACING), column![ text!("Фильтр"), text_input("", &self.set.filter) .style(|x, status| { let mut primary = Theme::default()(x, status); if !self.correct_filter { primary.border.color = color!(255, 255, 0); } primary }) .on_input(SetFilter), button("Проверить фильтр") .style(jl_button) .on_press(TryFilter), self.count_view(&self.set), ] .spacing(QUARTER_SPACING), ] .spacing(DEFAULT_SPACING) .padding(Padding { top: 0.0, right: DEFAULT_SPACING, bottom: 0.0, left: 0.0, }) ) .height(Fill), row![ button("Сохранить").style(jl_button).on_press(Save), button(if self.real_delete { "Вы уверены?" } else { "Удалить" }) .style(danger) .on_press(DeleteSet), space().width(Fill), ] .spacing(DEFAULT_SPACING), ] .spacing(DEFAULT_SPACING) .into(), Back, ) } } fn update_deck_stats(deck: &DeckSettings, state: &AppState) -> MaybeError { let mut db_stats = load_stats_of_deck(deck, &state.connection).expect("Wrong db operation"); let filtered_words = deck.get_word_list(state); filtered_words.iter().for_each(|word| { let word_id = state.dictionary[*word].id; if let Some(index) = db_stats.iter().position(|stat| stat.word_id == word_id) { db_stats.remove(index); } }); delete_stats(db_stats.as_slice(), &state.connection)?; Ok(()) } impl RepetitionSettingsState { fn count_view(&self, set: &DeckSettings) -> Element<'_, RepetitionSettingsMessage> { if let Some(count) = set.count { return text!("Количество слов: {}", count).into(); } space().into() } } #[derive(Clone)] pub enum RepetitionSettingsMessage { Back, Save, SetName(String), SetForward(String), SetBackward(String), SetFilter(String), TryFilter, DeleteSet, RevertDeleteSet, }