From 76c2a1b540989e41756ccfc7fac2623ded3de92f Mon Sep 17 00:00:00 2001 From: Jamie Murphy Date: Thu, 16 Feb 2023 07:54:42 -0800 Subject: task_list: Implement basic task list Currently, only adding and removing tasks from the list is supported --- src/engine/lib.rs | 1 + src/engine/task_list.rs | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 src/engine/task_list.rs diff --git a/src/engine/lib.rs b/src/engine/lib.rs index f8400b74..8ee729f4 100644 --- a/src/engine/lib.rs +++ b/src/engine/lib.rs @@ -4,4 +4,5 @@ pub mod provider; pub mod providers; pub mod schema; pub mod task; +pub mod task_list; pub mod utils; diff --git a/src/engine/task_list.rs b/src/engine/task_list.rs new file mode 100644 index 00000000..2d17870d --- /dev/null +++ b/src/engine/task_list.rs @@ -0,0 +1,151 @@ +use gtk::{ + gio::ListModel, + glib::{self, Object}, + prelude::*, + subclass::prelude::*, +}; +use indexmap::IndexMap; + +use crate::task::Task; + +mod imp { + use std::cell::{Cell, RefCell}; + + use gtk::glib::{subclass::Signal, ParamSpec, Properties, Value}; + use once_cell::sync::Lazy; + + use super::*; + + #[derive(Properties, Default)] + #[properties(wrapper_type = super::TaskList)] + pub struct TaskList { + #[property(get, set)] + pub name: RefCell, + #[property(get, set)] + pub archived: Cell, + // Can a TaskList be deleted or removed in any way? + // This should normally be True, except for global lists + // (like All Tasks or Inbox) + #[property(get, set, construct_only)] + pub removable: Cell, + + // INTERNAL PROPERTIES + pub tasks: RefCell>, + } + + #[glib::object_subclass] + impl ObjectSubclass for TaskList { + const NAME: &'static str = "GtdTaskList"; + type Type = super::TaskList; + type ParentType = glib::Object; + } + + impl ObjectImpl for TaskList { + fn properties() -> &'static [ParamSpec] { + Self::derived_properties() + } + + fn signals() -> &'static [Signal] { + static SIGNALS: Lazy> = Lazy::new(|| { + vec![ + Signal::builder("task-added") + .param_types([Task::static_type()]) + .build(), + Signal::builder("task-removed") + .param_types([Task::static_type()]) + .build(), + ] + }); + SIGNALS.as_ref() + } + + fn set_property(&self, id: usize, value: &Value, pspec: &ParamSpec) { + Self::derived_set_property(self, id, value, pspec) + } + + fn property(&self, id: usize, pspec: &ParamSpec) -> Value { + Self::derived_property(self, id, pspec) + } + } + + impl ListModelImpl for TaskList { + fn item_type(&self) -> glib::Type { + Task::static_type() + } + + fn n_items(&self) -> u32 { + self.tasks + .borrow() + .len() + .try_into() + .expect("Expected a u32") + } + + fn item(&self, position: u32) -> Option { + self.tasks + .borrow() + .get_index(position.try_into().expect("Expected a u32")) + .map(|(_, v)| v.clone().upcast::()) + } + } +} + +glib::wrapper! { + pub struct TaskList(ObjectSubclass) + @implements ListModel; +} + +impl Default for TaskList { + /// Create a new TaskList + fn default() -> Self { + Object::new() + } +} + +impl TaskList { + /// Create a new TaskList with values from a database + pub fn new(name: String, archived: bool, removable: bool) -> Self { + Object::builder() + .property("name", name) + .property("archived", archived) + .property("removable", removable) + .build() + } + + /// Add a GtdTask into this TaskList. + pub fn add_task(&self, task: &Task) { + let _self = self.clone(); + let mut list = _self.imp().tasks.borrow_mut(); + + if !list.contains_key(&task.id()) { + let (index, _) = list.insert_full(task.id(), task.clone()); + + self.clone().upcast::().items_changed( + index.try_into().expect("Expected a u32"), + 0, + 1, + ); + + self.emit_by_name::<()>("task-added", &[task]); + } + } + + // Removes a GtdTask from this TaskList + pub fn remove_task(&self, task: &Task) { + let _self = self.clone(); + let mut list = _self.imp().tasks.borrow_mut(); + + if list.contains_key(&task.id()) { + let index = list.get_index_of(&task.id()).unwrap_or_default(); + list.remove(&task.id()); + + self.clone().upcast::().items_changed( + index.try_into().expect("Expected a u32"), + 1, + 0, + ); + + self.emit_by_name::<()>("task-removed", &[task]); + } + } +} -- cgit v1.2.1