From f925f33348928ff450ceffa9e8141a57dade8e3d Mon Sep 17 00:00:00 2001 From: Marto Date: Sat, 1 Feb 2025 15:57:06 +0100 Subject: [PATCH] refacatoring --- Cargo.toml | 2 +- src/def.rs | 30 +++++++ src/main.rs | 219 +--------------------------------------------------- src/todo.rs | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 216 deletions(-) create mode 100644 src/def.rs create mode 100644 src/todo.rs diff --git a/Cargo.toml b/Cargo.toml index 426c635..58642c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -iced = { version = "0.13.1", features = ["advanced"] } \ No newline at end of file +iced = { version = "0.13.1"} \ No newline at end of file diff --git a/src/def.rs b/src/def.rs new file mode 100644 index 0000000..025d5c9 --- /dev/null +++ b/src/def.rs @@ -0,0 +1,30 @@ +use iced::Event; + +pub struct TaskData { + pub(crate) checked: bool, + pub(crate) value: String, + pub(crate) edit: bool, + pub(crate) can_update: bool, + pub(crate) can_delete: bool, +} + +pub struct Todo { + pub(crate) new_task: String, + pub(crate) updated_task: String, + pub(crate) tasks: Vec, + pub(crate) completed_tasks: usize, + pub(crate) local_storage: bool, +} + +#[derive(Debug, Clone)] +pub enum Message { + AddTask, + CheckTask(bool, usize), + EditTask(usize), + DeleteTask(usize), + DeleteAll, + ContentUpdated(bool, String), + Event(Event), + TaskPush(Option), + StorageToggle(bool), +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 424541f..30ebe65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,9 @@ -use iced::keyboard::key; -use iced::widget::{button, center, checkbox, column, row, scrollable, text_input, Space, Text}; use iced::window::Settings; -use iced::{event, keyboard, widget, Center, Element, Event, Length, Size, Subscription, Task, Theme}; +use iced::Size; +use def::Todo; -struct TaskData { - checked: bool, - value: String, - edit: bool, - can_update: bool, - can_delete: bool, -} +mod todo; +mod def; fn main() -> iced::Result { let settings = Settings { @@ -23,209 +17,4 @@ fn main() -> iced::Result { .theme(Todo::theme) .window(settings) .run() -} - -#[derive(Default)] -struct Todo { - new_task: String, - updated_task: String, - tasks: Vec, - completed_tasks: usize, - local_storage: bool, -} - -#[derive(Debug, Clone)] -enum Message { - AddTask, - CheckTask(bool, usize), - EditTask(usize), - DeleteTask(usize), - DeleteAll, - ContentUpdated(bool, String), - Event(Event), - TaskPush(Option), -} - -impl Todo { - fn update(&mut self, message: Message) -> Task { - match message { - Message::ContentUpdated(new, value) => { - if new { - self.new_task = value - } else { - self.updated_task = value - } - - Task::none() - } - Message::AddTask => { - if self.new_task.is_empty() { return Task::none(); } - - let data = TaskData { - checked: false, - value: self.new_task.to_string(), - edit: false, - can_update: true, - can_delete: true, - }; - - self.tasks.push(data); - self.new_task = String::new(); - - Task::none() - }, - Message::DeleteTask(id) => { - if self.tasks[id].checked { - self.completed_tasks -= 1; - } - self.tasks.remove(id); - - Task::none() - }, - Message::CheckTask(choice, id) => { - self.completed_tasks = if choice { self.completed_tasks + 1 } else { self.completed_tasks - 1 }; - self.tasks[id].checked = choice; - - Task::none() - }, - Message::EditTask(id) => { - let set_update; - - if self.tasks[id].edit { - if self.updated_task.is_empty() { - return Task::none(); - } - - self.tasks[id].value = self.updated_task.clone(); - set_update = true; - self.updated_task = String::new(); - } else { - set_update = false; - } - - self.tasks[id].edit = !self.tasks[id].edit; - self.set_other_update(id, set_update); - - widget::focus_previous() - }, - Message::DeleteAll => { - self.new_task = String::from(""); - self.updated_task = String::from(""); - self.tasks.clear(); - self.completed_tasks = 0; - - Task::none() - }, - Message::Event(event) => match event { - Event::Keyboard(keyboard::Event::KeyPressed { - key: keyboard::Key::Named(key::Named::Tab), - modifiers, - .. - }) => { - if modifiers.shift() { - widget::focus_previous() - } else { - widget::focus_next() - } - } - Event::Keyboard(keyboard::Event::KeyPressed { - key: keyboard::Key::Named(key::Named::Delete), - modifiers, - .. - }) => { - if modifiers.control() { - Task::perform(async move { Message::DeleteAll }, |result| result) - } else { - Task::none() - } - } - _ => Task::none() - }, - Message::TaskPush(option_id) => { - match option_id { - Some(i) => Task::perform(async move { Message::EditTask(i) }, |result| result), - None => Task::perform(async { Message::AddTask }, |result| result), - } - }, - } - } - - fn view(&self) -> Element { - let input = text_input("Enter new task", &self.new_task) - .width(300) - .size(25) - .on_input(|str| Message::ContentUpdated(true, str)) - .on_submit(Message::TaskPush(None)); - - let add_btn = button( - Text::new("Add") - .size(19) - .center() - ) - .width(Length::Shrink) - .padding(10) - .on_press(Message::AddTask); - - let clear_btn = button( - Text::new("Clear") - .size(19) - .center() - ) - .width(Length::Shrink) - .padding(10) - .style(button::danger) - .on_press(Message::DeleteAll); - - let new_task = row![input, add_btn, clear_btn].spacing(10); - let mut saved_tasks = column![]; - - for (i, task) in self.tasks.iter().enumerate() { - let chk = checkbox("", task.checked).size(25).on_toggle(move |b| Message::CheckTask(b, i)); - let label = Text::new(&task.value).width(200); - let input = text_input("Enter new name", &self.updated_task) - .width(200) - .on_input(|str| Message::ContentUpdated(false, str)) - .on_submit(Message::TaskPush(Some(i))); - let mut edit = button(if task.edit { "save" } else { "edit" }).width(Length::Shrink); - if task.can_update { - edit = edit.on_press(Message::EditTask(i)); - } - let mut delete = button("delete").width(Length::Shrink); - if task.can_delete { - delete = delete.on_press(Message::DeleteTask(i)); - } - let mut task_line = row![chk]; - task_line = if task.edit { task_line.push(input) } else { task_line.push(label) }; - task_line = task_line.push(edit).push(delete).spacing(10).padding([5, 10]); - - saved_tasks = saved_tasks.push(task_line); - } - - let status = Text::new(format!("{} / {}", self.completed_tasks, self.tasks.len())); - let storage = checkbox("Local storage", true); - let footer = row![status, Space::with_width(Length::Fill), storage].padding(10); - - let mut output = column![new_task.padding(10)]; - output = if self.tasks.is_empty() { output.push(saved_tasks.height(Length::Fill)) } else { output.push(scrollable(saved_tasks).height(Length::Fill).spacing(10)) }; - output = output.align_x(Center).push(footer); - - center(output).into() - } - - fn theme(&self) -> Theme { - Theme::Dark - } - - fn subscription(&self) -> Subscription { - event::listen().map(Message::Event) - } - - fn set_other_update(&mut self, id: usize, enable: bool) { - for (i, task) in self.tasks.iter_mut().enumerate() { - if id != i { - task.can_update = enable; - } - task.can_delete = enable; - } - } } \ No newline at end of file diff --git a/src/todo.rs b/src/todo.rs new file mode 100644 index 0000000..584f207 --- /dev/null +++ b/src/todo.rs @@ -0,0 +1,215 @@ +use iced::{event, keyboard, widget, Center, Element, Event, Length, Subscription, Task, Theme}; +use iced::keyboard::key; +use iced::widget::{button, center, checkbox, column, row, scrollable, text_input, Space, Text}; +use crate::def::{Message, TaskData, Todo}; + +impl Default for Todo { + fn default() -> Self { + Todo::new() + // startup checks + } +} + +impl Todo { + fn new() -> Self { + Self { + new_task: String::new(), + updated_task: String::new(), + tasks: Vec::new(), + completed_tasks: 0, + local_storage: true, + } + } + pub(crate) fn update(&mut self, message: Message) -> Task { + match message { + Message::ContentUpdated(new, value) => { + if new { + self.new_task = value + } else { + self.updated_task = value + } + + Task::none() + } + Message::AddTask => { + if self.new_task.is_empty() { return Task::none(); } + + let data = TaskData { + checked: false, + value: self.new_task.to_string(), + edit: false, + can_update: true, + can_delete: true, + }; + + self.tasks.push(data); + self.new_task = String::new(); + + Task::none() + }, + Message::DeleteTask(id) => { + if self.tasks[id].checked { + self.completed_tasks -= 1; + } + self.tasks.remove(id); + + Task::none() + }, + Message::CheckTask(choice, id) => { + self.completed_tasks = if choice { self.completed_tasks + 1 } else { self.completed_tasks - 1 }; + self.tasks[id].checked = choice; + + Task::none() + }, + Message::EditTask(id) => { + let set_update; + + if self.tasks[id].edit { + if self.updated_task.is_empty() { + return Task::none(); + } + + self.tasks[id].value = self.updated_task.clone(); + set_update = true; + self.updated_task = String::new(); + } else { + set_update = false; + } + + self.tasks[id].edit = !self.tasks[id].edit; + self.set_other_update(id, set_update); + + widget::focus_previous() + }, + Message::DeleteAll => { + self.new_task = String::from(""); + self.updated_task = String::from(""); + self.tasks.clear(); + self.completed_tasks = 0; + + Task::none() + }, + Message::Event(event) => match event { + Event::Keyboard(keyboard::Event::KeyPressed { + key: keyboard::Key::Named(key::Named::Tab), + modifiers, + .. + }) => { + if modifiers.shift() { + widget::focus_previous() + } else { + widget::focus_next() + } + } + Event::Keyboard(keyboard::Event::KeyPressed { + key: keyboard::Key::Named(key::Named::Delete), + modifiers, + .. + }) => { + if modifiers.control() { + Task::perform(async move { Message::DeleteAll }, |result| result) + } else { + Task::none() + } + } + _ => Task::none() + }, + Message::TaskPush(option_id) => { + match option_id { + Some(i) => Task::perform(async move { Message::EditTask(i) }, |result| result), + None => Task::perform(async { Message::AddTask }, |result| result), + } + }, + Message::StorageToggle(toggle) => { + self.local_storage = toggle; + + /* + todo + here we only call for storage change not implement the whole system + as the system should be running since the program startup + */ + + Task::none() + }, + } + } + + pub(crate) fn view(&self) -> Element { + let input = text_input("Enter new task", &self.new_task) + .width(300) + .size(25) + .on_input(|str| Message::ContentUpdated(true, str)) + .on_submit(Message::TaskPush(None)); + + let add_btn = button( + Text::new("Add") + .size(19) + .center() + ) + .width(Length::Shrink) + .padding(10) + .on_press(Message::AddTask); + + let clear_btn = button( + Text::new("Clear") + .size(19) + .center() + ) + .width(Length::Shrink) + .padding(10) + .style(button::danger) + .on_press(Message::DeleteAll); + + let new_task = row![input, add_btn, clear_btn].spacing(10); + let mut saved_tasks = column![]; + + for (i, task) in self.tasks.iter().enumerate() { + let chk = checkbox("", task.checked).size(25).on_toggle(move |b| Message::CheckTask(b, i)); + let label = Text::new(&task.value).width(200); + let input = text_input("Enter new name", &self.updated_task) + .width(200) + .on_input(|str| Message::ContentUpdated(false, str)) + .on_submit(Message::TaskPush(Some(i))); + let mut edit = button(if task.edit { "save" } else { "edit" }).width(Length::Shrink); + if task.can_update { + edit = edit.on_press(Message::EditTask(i)); + } + let mut delete = button("delete").width(Length::Shrink); + if task.can_delete { + delete = delete.on_press(Message::DeleteTask(i)); + } + let mut task_line = row![chk]; + task_line = if task.edit { task_line.push(input) } else { task_line.push(label) }; + task_line = task_line.push(edit).push(delete).spacing(10).padding([5, 10]); + + saved_tasks = saved_tasks.push(task_line); + } + + let status = Text::new(format!("{} / {}", self.completed_tasks, self.tasks.len())); + let storage = checkbox("Local storage", self.local_storage).on_toggle(Message::StorageToggle); + let footer = row![status, Space::with_width(Length::Fill), storage].padding(10); + + let mut output = column![new_task.padding(10)]; + output = if self.tasks.is_empty() { output.push(saved_tasks.height(Length::Fill)) } else { output.push(scrollable(saved_tasks).height(Length::Fill).spacing(10)) }; + output = output.align_x(Center).push(footer); + + center(output).into() + } + + pub(crate) fn theme(&self) -> Theme { + Theme::Dark + } + + pub(crate) fn subscription(&self) -> Subscription { + event::listen().map(Message::Event) + } + + fn set_other_update(&mut self, id: usize, enable: bool) { + for (i, task) in self.tasks.iter_mut().enumerate() { + if id != i { + task.can_update = enable; + } + task.can_delete = enable; + } + } +} \ No newline at end of file