use crate::app::AppState; use crate::core::deck::DeckData; use crate::data::entities::{DeckSettings, EntityHandle}; use crate::data::repositories::{BatchedRepository, Repository}; use crate::jl_button; 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::space::horizontal; 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 std::sync::Arc; use std::time::Duration; pub struct RepetitionSettingsState { settings_handle: EntityHandle, settings_data: DeckSettings, state: AppState, real_delete: bool, real_delete_states: bool, correct_filter: bool, filter_changed: bool, filtered_words: Option, } impl RepetitionSettingsState { pub(crate) fn new( settings: EntityHandle, state: AppState, ) -> RepetitionSettingsState { let data = state.decks.read().get_static(settings).unwrap(); RepetitionSettingsState { settings_data: data, settings_handle: settings, state, real_delete: false, real_delete_states: false, correct_filter: true, filter_changed: false, filtered_words: None, } } } 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 decks = self.state.decks.write(); decks.set(&mut self.settings_handle, self.settings_data.clone()); if let Err(e) = decks.save(&mut self.settings_handle) { return push_error_task!(e); } drop(decks); if self.filter_changed && let Err(e) = update_deck_stats(&self.settings_data, &self.state) { return push_error_task!(e); } } SetName(new) => { self.settings_data.name = new; } SetForward(new) => { self.settings_data.forward = new; } SetBackward(backward) => { self.settings_data.backward = backward; } SetFilter(new) => { self.settings_data.filter = new; self.correct_filter = self.settings_data.check_filter(); self.filter_changed = true; } TryFilter => { let list = DeckData::list(&self.settings_data, &self.state); self.filtered_words = Some(list.len() as u32); } 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 decks = self.state.decks.write(); if let Err(e) = decks.delete(self.settings_handle) { return push_error_task!(e); } return Task::done(RootMessage::RepetitionSettings(Back)); } RevertDeleteSet => { self.real_delete = false; self.real_delete_states = true; } DeleteStates => { if !self.real_delete_states { self.real_delete_states = true; return Task::future(async { tokio::time::sleep(Duration::from_millis(3000)).await; RootMessage::RepetitionSettings(RevertDeleteSet) }); } let mut states = self.state.card_states.write(); let deck_id = self.settings_handle.id; let mut query = states .query(Arc::new(move |state| state.deck_id == deck_id)) .handles() .collect::>(); if let Err(e) = states.delete_many(query.as_mut_slice()) { return push_error_task!(e); } self.real_delete_states = false; } } Task::none() } fn view(&self) -> Element<'_, RepetitionSettingsMessage> { back_overlay( iced::widget::column![ scrollable( column![ column![ text!("Название набора"), text_input("", &self.settings_data.name).on_input(SetName), ] .spacing(QUARTER_SPACING), column![ text!("Передняя сторона"), text_input("", &self.settings_data.forward).on_input(SetForward), ] .spacing(QUARTER_SPACING), column![ text!("Задняя сторона"), text_input("", &self.settings_data.backward).on_input(SetBackward), ] .spacing(QUARTER_SPACING), column![ text!("Фильтр"), text_input("", &self.settings_data.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), jl_button!("Проверить фильтр").on_press(TryFilter), self.count_view(), ] .spacing(QUARTER_SPACING), ] .spacing(DEFAULT_SPACING) .padding(Padding { top: 0.0, right: DEFAULT_SPACING, bottom: 0.0, left: 0.0, }) ) .height(Fill), row![ jl_button!("Сохранить").on_press(Save), horizontal(), button(if self.real_delete_states { "Вы уверены?" } else { "Удалить прогресс?" }) .style(danger) .on_press(DeleteStates), button(if self.real_delete { "Вы уверены?" } else { "Удалить" }) .style(danger) .on_press(DeleteSet), ] .spacing(DEFAULT_SPACING), ] .spacing(DEFAULT_SPACING) .into(), Back, ) } } fn update_deck_stats(deck: &DeckSettings, state: &AppState) -> MaybeError { let states_repo = &mut state.card_states.write(); let deck_id = deck.id; let mut db_stats = states_repo .query_par(Arc::new(move |s| s.deck_id == deck_id)) .iter(states_repo) .collect::>(); let filtered_words = DeckData::list(deck, state) .iter() .map(|w| w.id) .collect::>(); filtered_words.iter().for_each(|word_id| { if let Some(index) = db_stats.iter().position(|stat_id| stat_id.id == *word_id) { db_stats.remove(index); } }); let mut delete_operation = db_stats .iter() .map(|state| EntityHandle::new(state.id, state.id.0 as usize, true)) .collect::>(); states_repo.delete_many(delete_operation.as_mut_slice())?; Ok(()) } impl RepetitionSettingsState { fn count_view(&self) -> Element<'_, RepetitionSettingsMessage> { if let Some(count) = self.filtered_words { return text!("Количество слов: {}", count).into(); } space().into() } } #[derive(Clone)] pub enum RepetitionSettingsMessage { Back, Save, SetName(String), SetForward(String), SetBackward(String), SetFilter(String), TryFilter, DeleteSet, DeleteStates, RevertDeleteSet, }