From 3f7944485208f774264fd7cb4e8a49a1cbb4e3f7 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 6 Aug 2026 11:31:11 +0300 Subject: [PATCH] Settings on new page --- src/repetition_settings.rs | 146 +++++++++++++++++++++++++++++++++++-- src/repetitions.rs | 138 +++++++++++++++++++---------------- 2 files changed, 214 insertions(+), 70 deletions(-) diff --git a/src/repetition_settings.rs b/src/repetition_settings.rs index 0dd9106..bb7de55 100644 --- a/src/repetition_settings.rs +++ b/src/repetition_settings.rs @@ -1,11 +1,41 @@ +use crate::AppState; +use crate::data_provider::card_sets::{delete_set, update_card_set}; use crate::navigation::Page::PreviousPage; use crate::navigation::{NavigatedPage, Page, RootMessage}; use crate::repetition_settings::RepetitionSettingsMessage::*; -use crate::styling::back_overlay; -use iced::widget::row; +use crate::repetitions::{CardSetSettings, RepetitionsMessage}; +use crate::styling::*; +use iced::widget::button::danger; +use iced::widget::{button, column, row, scrollable, space, text, text_input}; use iced::{Element, Task}; +use iced_core::Length::Fill; +use iced_core::{Length, Padding}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +pub struct RepetitionSettingsState { + set: CardSetSettings, + index: usize, + state: Arc>, + real_delete: bool, +} + +impl RepetitionSettingsState { + pub(crate) fn new(index: usize, p1: Arc>) -> RepetitionSettingsState { + let set; + { + let local_state = p1.lock().unwrap(); + set = local_state.card_sets[index].clone(); + } + RepetitionSettingsState { + index, + set, + state: p1, + real_delete: false, + } + } +} -pub struct RepetitionSettingsState {} impl NavigatedPage for RepetitionSettingsState { fn navigate(&self, message: &RepetitionSettingsMessage) -> Option { if let Back = message { @@ -20,19 +50,121 @@ impl RepetitionSettingsState { pub fn update(&mut self, message: RepetitionSettingsMessage) -> Task { match message { Back => {} + Save => { + let mut state = self.state.lock().unwrap(); + update_card_set(&mut self.set, &state.connection); + state.card_sets[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; + } + TryFilter => { + let state = self.state.lock().unwrap(); + let count = self.set.get_word_list(&state).len(); + self.set.count = Some(count); + } + DeleteSet => { + if self.real_delete == false { + self.real_delete = true; + return Task::future(async { + tokio::time::sleep(Duration::from_millis(3000)).await; + return RootMessage::RepetitionSettings(RevertDeleteSet); + }); + } + let mut state = self.state.lock().unwrap(); + delete_set(&self.set, &state.connection); + state.card_sets.remove(self.index); + return Task::done(RootMessage::RepetitionSettings(Back)); + }, + RevertDeleteSet => self.real_delete = false, } Task::none() } pub fn view(&self) -> Element<'_, RepetitionSettingsMessage> { back_overlay( - row![].into(), + 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).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 count_view(&self, set: &CardSetSettings) -> Element<'_, RepetitionSettingsMessage> { + if let Some(count) = set.count { + return text!("Количество слов: {}", count).into(); + } + space().into() + } } #[derive(Clone)] -pub enum RepetitionSettingsMessage { - Back -} \ No newline at end of file +pub enum RepetitionSettingsMessage { + Back, + Save, + SetName(String), + SetForward(String), + SetBackward(String), + SetFilter(String), + TryFilter, + DeleteSet, + RevertDeleteSet, +} diff --git a/src/repetitions.rs b/src/repetitions.rs index b87eb6e..d56e99d 100644 --- a/src/repetitions.rs +++ b/src/repetitions.rs @@ -5,27 +5,24 @@ use crate::lang::{SetOrderMode, WordData}; use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings}; use crate::navigation::{NavigatedPage, Page}; use crate::repetition::RepetitionState; -use crate::styling::*; -use crate::{AppState, RootMessage}; -pub use iced::widget::button::{Catalog, Style}; -use iced::widget::button::{Status, danger}; -use iced::widget::container::bordered_box; -use iced::widget::{ - Column, button, column, container, radio, row, scrollable, space, svg, text, text_input, -}; -use iced::{Background, Border, Center, Color, Element, Fill, Length, Shadow, Task, Theme}; -use iced_core::Padding; -use iced_core::svg::Handle; -use rhai::{Engine, Scope}; -use std::sync::{Arc, Mutex}; use crate::repetition_settings::RepetitionSettingsState; use crate::repetitions::RepetitionsMessage::*; +use crate::styling::*; +use crate::{AppState, RootMessage}; +use iced::widget::button::{danger, Status}; +pub use iced::widget::button::{Catalog, Style}; +use iced::widget::container::bordered_box; +use iced::widget::{button, column, container, radio, row, scrollable, space, svg, text, text_input, Column}; +use iced::{Background, Border, Center, Color, Element, Fill, Length, Shadow, Task, Theme}; +use iced_core::svg::Handle; +use iced_core::Padding; +use rhai::{Engine, Scope}; +use std::sync::{Arc, Mutex}; #[derive(Clone)] pub struct RepetitionsState { selected_set: Option, correct_filters: Vec, - pub state: Arc>, } @@ -46,11 +43,12 @@ impl NavigatedPage for RepetitionsState { card_set = self.state.lock().unwrap().card_sets[self.selected_set.unwrap()].clone(); } Some(Repetition(RepetitionState::new(card_set, clone))) - } - else if let GoToSettings = message { - Some(RepetitionSettings(RepetitionSettingsState {})) - } - else { + } else if let GoToSettings = message { + Some(RepetitionSettings(RepetitionSettingsState::new( + self.selected_set.unwrap(), + self.state.clone(), + ))) + } else { None } } @@ -103,11 +101,11 @@ impl RepetitionsState { self.correct_filters[i] = state.card_sets[i].check_filter(); } - let word = &mut state.card_sets[self.selected_set.unwrap()].clone(); + let set = &mut state.card_sets[self.selected_set.unwrap()].clone(); - update_card_set(word, &state.connection); + update_card_set(set, &state.connection); - state.card_sets[self.selected_set.unwrap()] = word.clone(); + state.card_sets[self.selected_set.unwrap()] = set.clone(); } SetForward(new) => { state.card_sets[self.selected_set.unwrap()].forward = new; @@ -129,7 +127,7 @@ impl RepetitionsState { .get_mut(self.selected_set.unwrap()) .unwrap() .open_mode = mode; - }, + } } Task::none() } @@ -157,23 +155,30 @@ impl RepetitionsState { ) } - fn launch_button(&self) -> Element<'_, RepetitionsMessage> { - if let Some(set) = self.selected_set - && self.state.lock().unwrap().card_sets[set].id != 0 + fn launch_delete_button(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { + if set.id != 0 { - return button(text!("Начать повторение").width(200).center()) - .style(cta_button) - .on_press(GoToRepetition) - .into(); + return row![ + space().width(Fill), + button(text!("Начать повторение").width(200).center()) + .style(cta_button) + .on_press(GoToRepetition) + ] + .into(); } - space().into() + button("Удалить").style(danger).on_press(DeleteSet).into() } fn selected_set_view(&self) -> Element<'_, RepetitionsMessage> { if let Some(index) = self.selected_set { let set; { - set = self.state.lock().unwrap().card_sets[index].clone(); + + let state = self.state.lock().unwrap(); + if state.card_sets.len() <= index { + return space().width(Length::FillPortion(3)).into() + } + set = state.card_sets[index].clone(); } return column![ scrollable( @@ -182,30 +187,41 @@ impl RepetitionsState { text!("Название набора"), row![ text_input("", &set.name).on_input(SetName), - button(svg(Handle::from_memory(SETTINGS_ICON))).width(43).on_press(GoToSettings), + button(svg(Handle::from_memory(SETTINGS_ICON))) + .width(43) + .on_press(GoToSettings), ] .spacing(HALF_SPACING) ] .spacing(QUARTER_SPACING), - column![ - text!("Передняя сторона"), - text_input("", &set.forward).on_input(SetForward), - ] - .spacing(QUARTER_SPACING), - column![ - text!("Задняя сторона"), - text_input("", &set.backward).on_input(SetBackward), - ] - .spacing(QUARTER_SPACING), - column![ - text!("Фильтр"), - text_input("", &set.filter).on_input(SetFilter), - button("Проверить фильтр") - .style(jl_button) - .on_press(TryFilter), - self.count_view(&set), - ] - .spacing(QUARTER_SPACING), + { + if set.id == 0 { + column![ + column![ + text!("Передняя сторона"), + text_input("", &set.forward).on_input(SetForward), + ] + .spacing(QUARTER_SPACING), + column![ + text!("Задняя сторона"), + text_input("", &set.backward).on_input(SetBackward), + ] + .spacing(QUARTER_SPACING), + column![ + text!("Фильтр"), + text_input("", &set.filter).on_input(SetFilter), + button("Проверить фильтр") + .style(jl_button) + .on_press(TryFilter), + self.count_view(&set), + ] + .spacing(QUARTER_SPACING), + ] + .spacing(DEFAULT_SPACING) + } else { + self.filled_set_data_view(&set) + } + }, radio( "Обычный режим", SetOrderMode::Default, @@ -213,9 +229,7 @@ impl RepetitionsState { SetOpenMode ), self.words_words_view(&set), - button("История") - .style(jl_button) - .on_press(GoToHistory), + button("История").style(jl_button).on_press(GoToHistory), ] .spacing(DEFAULT_SPACING) .padding(Padding { @@ -227,14 +241,8 @@ impl RepetitionsState { ) .height(Fill), row![ - button("Сохранить") - .style(jl_button) - .on_press(Save), - button("Удалить") - .style(danger) - .on_press(DeleteSet), - space().width(Fill), - self.launch_button() + button("Сохранить").style(jl_button).on_press(Save), + self.launch_delete_button(&set) ] .spacing(DEFAULT_SPACING), ] @@ -245,6 +253,10 @@ impl RepetitionsState { space().width(Length::FillPortion(3)).into() } + fn filled_set_data_view(&self, set: &CardSetSettings) -> Column<'_, RepetitionsMessage> { + column![].spacing(DEFAULT_SPACING).into() + } + fn words_words_view(&self, set: &CardSetSettings) -> Element<'_, RepetitionsMessage> { column![ text!("Худшие слова"),