diff --git a/src/tui/app.rs b/src/tui/app.rs index 1343918..d5bee29 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -11,7 +11,7 @@ use tracing::{debug, info, trace}; use crate::{ config::Config, tui::{Event, Tui, components::Viewport}, - types::{KastenHandle, ZettelId}, + types::{KastenHandle, TodoTree, ZettelId}, }; pub use crate::tui::components::TodoRegion; @@ -243,6 +243,12 @@ impl App { self.page = page; } + Signal::Refresh => { + let mut kt = self.kh.write().await; + // fuck it we just fully rebuild the tree, how computationally expensive could it even be + kt.todo_tree = TodoTree::construct(&kt.db).await.expect("Must not error"); + } + Signal::Suspend => self.should_suspend = true, Signal::Resume => self.should_suspend = false, diff --git a/src/tui/components/todo/inspector/mod.rs b/src/tui/components/todo/inspector/mod.rs index a7fa093..0c4abd9 100644 --- a/src/tui/components/todo/inspector/mod.rs +++ b/src/tui/components/todo/inspector/mod.rs @@ -15,7 +15,7 @@ use crate::{ Signal, components::{Component, DEFAULT_NAME}, }, - types::{Group, KastenHandle, Task, TodoNode, TodoNodeKind}, + types::{Group, KastenHandle, Priority, Task, TodoNode, TodoNodeKind}, }; mod rootview; @@ -134,6 +134,20 @@ impl Inspector<'_> { } } } + + async fn refresh(&mut self) { + // cheaper to clone this than the node + let kh = self.kh.clone(); + let kt = kh.read().await; + + let Some(ref inspecting) = self.inspecting else { + return; + }; + let node = kt.todo_tree.get_node_by_nano_id(inspecting).data(); + self.inspect(node); + + drop(kt); + } } pub enum RenderData<'text> { @@ -194,16 +208,23 @@ impl Component for Inspector<'_> { priority.set_cursor_style(Style::default().reversed()); priority.set_cursor_line_style(Style::default().underlined()); + priority.move_cursor(CursorMove::WordBack); + priority.delete_line_by_end(); self.editing = Some(Edit::Priority); return Ok(Some(Signal::EnterRawText)); } + Signal::Refresh => { + self.refresh().await; + } + _ => {} } Ok(None) } + #[expect(clippy::too_many_lines)] async fn handle_key_event(&mut self, key: KeyEvent) -> color_eyre::Result> { let signal_tx = self .signal_tx @@ -262,24 +283,69 @@ impl Component for Inspector<'_> { RenderData::Group { widget } => &mut widget.priority, }; - if key.code == KeyCode::Enter { - priority.set_cursor_style(Style::reset()); - priority.set_cursor_line_style(Style::reset()); + // we dont want them entering into this + if key.code != KeyCode::Enter { + priority.input_without_shortcuts(key); + } + let priority_str = priority.lines()[0].as_str(); + + if let Ok(prio) = Priority::try_from(priority_str) { priority.set_block( priority .block() .cloned() .expect("All of them should have blocks") - .border_style(Style::default().fg(Color::Reset)), + .border_style(Style::default().fg(Color::Green)), ); - self.editing = None; - Ok(Some(Signal::ExitRawText)) + if key.code == KeyCode::Enter { + self.editing = None; + signal_tx.send(Signal::ExitRawText)?; + + priority.set_cursor_style(Style::reset()); + priority.set_cursor_line_style(Style::reset()); + + priority.set_block( + priority + .block() + .cloned() + .expect("All of them should have blocks") + .border_style(Style::default().fg(Color::Reset)), + ); + + let id = self + .inspecting + .clone() + .expect("Invariant Broken, this must be some id"); + + let kt = self.kh.read().await; + + match &self.render_data { + RenderData::Task { .. } => { + Task::alter_priority(id.clone(), prio, &kt).await?; + } + RenderData::Group { .. } => { + Group::alter_priority(id.clone(), prio, &kt).await?; + } + RenderData::Root { .. } => unreachable!("Already returned above"), + } + + drop(kt); + + return Ok(Some(Signal::Refresh)); + } } else { - priority.input_without_shortcuts(key); - Ok(None) + priority.set_block( + priority + .block() + .cloned() + .expect("All of them should have blocks") + .border_style(Style::default().fg(Color::Red)), + ); } + + Ok(None) } None => return Ok(None), diff --git a/src/tui/components/todo/mod.rs b/src/tui/components/todo/mod.rs index 02334c3..a8a35bf 100644 --- a/src/tui/components/todo/mod.rs +++ b/src/tui/components/todo/mod.rs @@ -13,7 +13,7 @@ use tracing::debug; use crate::{ tui::{Page, Signal, components::Component}, - types::{Group, KastenHandle, Priority, Task, TodoTree}, + types::{Group, KastenHandle, Priority, Task}, }; mod explorer; @@ -83,10 +83,7 @@ impl Todo<'_> { .selected() .and_then(|idx| task_list.id_list.get(idx)); - let mut kt = self.kh.write().await; - - // fuck it we just fully rebuild the tree, how computationally expensive could it even be - kt.todo_tree = TodoTree::construct(&kt.db).await.expect("Must not error"); + let kt = self.kh.read().await; let tree = &kt.todo_tree; @@ -131,7 +128,6 @@ impl Todo<'_> { self.explorer = Some(explorer); self.task_list = Some(task_list); - self.update_inspector_from_selection().await; } async fn update_inspector_from_selection(&mut self) { diff --git a/src/types/group.rs b/src/types/group.rs index 859d6d6..f8eee09 100644 --- a/src/types/group.rs +++ b/src/types/group.rs @@ -28,49 +28,6 @@ pub struct Group { } impl Group { - pub fn created_at(&self) -> String { - self.created_at - .format(frontmatter::DATE_FMT_STR) - .to_string() - } - pub fn modified_at(&self) -> String { - self.modified_at - .format(frontmatter::DATE_FMT_STR) - .to_string() - } - - pub async fn alter_name( - id: NanoId, - new_name: impl Into, - kt: &mut Kasten, - ) -> Result<()> { - let new_name = new_name.into(); - - let g = GroupEntity::load() - .filter_by_nano_id(id.clone()) - .with(TagEntity) - .with((ZettelEntity, TagEntity)) - .one(&kt.db) - .await? - .expect("Invariant Broken: Must exist"); - - let tag_id = g.tag.as_ref().expect("Must be loaded").nano_id.clone(); - - let zettel_id = g.zettel_id.clone(); - - let _ = g - .into_active_model() - .set_name(new_name.as_str()) - .update(&kt.db) - .await?; - - Tag::alter_name(tag_id, &new_name, kt).await?; - - Zettel::alter_name(zettel_id.into(), &new_name, kt).await?; - - Ok(()) - } - pub async fn new( name: impl Into, parent_id: Option, @@ -125,6 +82,63 @@ impl Group { kt.todo_tree.insert_group(&group); Ok(group) } + + pub async fn alter_name( + id: NanoId, + new_name: impl Into, + kt: &mut Kasten, + ) -> Result<()> { + let new_name = new_name.into(); + + let g = GroupEntity::load() + .filter_by_nano_id(id.clone()) + .with(TagEntity) + .with((ZettelEntity, TagEntity)) + .one(&kt.db) + .await? + .expect("Invariant Broken: Must exist"); + + let tag_id = g.tag.as_ref().expect("Must be loaded").nano_id.clone(); + + let zettel_id = g.zettel_id.clone(); + + let _ = g + .into_active_model() + .set_name(new_name.as_str()) + .update(&kt.db) + .await?; + + Tag::alter_name(tag_id, &new_name, kt).await?; + + Zettel::alter_name(zettel_id.into(), &new_name, kt).await?; + + Ok(()) + } + + pub async fn alter_priority(id: NanoId, new_prio: Priority, kt: &Kasten) -> Result<()> { + GroupEntity::load() + .filter_by_nano_id(id) + .one(&kt.db) + .await? + .expect("Must exist") + .into_active_model() + .set_priority(new_prio) + .update(&kt.db) + .await?; + + Ok(()) + } + + pub fn created_at(&self) -> String { + self.created_at + .format(frontmatter::DATE_FMT_STR) + .to_string() + } + pub fn modified_at(&self) -> String { + self.modified_at + .format(frontmatter::DATE_FMT_STR) + .to_string() + } } impl From for Group { diff --git a/src/types/priority.rs b/src/types/priority.rs index 10f0644..a53bc49 100644 --- a/src/types/priority.rs +++ b/src/types/priority.rs @@ -1,5 +1,6 @@ use std::fmt::Display; +use color_eyre::eyre::eyre; use dto::PriorityDTO; /// An Enum for the various `Priority` levels @@ -26,3 +27,28 @@ impl Display for Priority { write!(f, "{}", self.field1) } } + +impl TryFrom<&str> for Priority { + type Error = color_eyre::Report; + + fn try_from(value: &str) -> Result { + match value.to_ascii_lowercase().chars().next() { + Some('a') => Ok(Self { + field1: PriorityDTO::Asap, + }), + Some('h') => Ok(Self { + field1: PriorityDTO::High, + }), + Some('m') => Ok(Self { + field1: PriorityDTO::Medium, + }), + Some('l') => Ok(Self { + field1: PriorityDTO::Low, + }), + Some('f') => Ok(Self { + field1: PriorityDTO::Far, + }), + _ => Err(eyre!("Invalid Priority!")), + } + } +} diff --git a/src/types/task.rs b/src/types/task.rs index 51de7db..dc1f93f 100644 --- a/src/types/task.rs +++ b/src/types/task.rs @@ -115,6 +115,20 @@ impl Task { Ok(()) } + pub async fn alter_priority(id: NanoId, new_prio: Priority, kt: &Kasten) -> Result<()> { + TaskEntity::load() + .filter_by_nano_id(id) + .one(&kt.db) + .await? + .expect("Must exist") + .into_active_model() + .set_priority(new_prio) + .update(&kt.db) + .await?; + + Ok(()) + } + pub fn due(&self) -> Option { self.due .map(|due| due.format(frontmatter::DATE_FMT_STR).to_string())