From 3b9fedd9a35bcba21121d50d8fdd52f78e19b0da Mon Sep 17 00:00:00 2001 From: xeruf <27jf@pm.me> Date: Mon, 19 Aug 2024 17:30:05 +0300 Subject: [PATCH] feat(tasks): display details on task without subtasks --- src/main.rs | 8 ++++---- src/tasks.rs | 35 ++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index ef091ad..9d1ac18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -456,12 +456,12 @@ async fn main() { Some('(') => { if let Some(arg) = arg { if tasks.track_from(arg) { - let (prefix, tracked) = tasks.times_tracked(); - println!("{}\n{}", prefix.bold(), tracked.rev().take(15).join("\n")); + let (label, times) = tasks.times_tracked(); + println!("{}\n{}", label.italic(), times.rev().take(15).join("\n")); } } else { - let (prefix, mut tracked) = tasks.times_tracked(); - println!("{}\n{}", prefix.bold(), tracked.join("\n")); + let (label, mut times) = tasks.times_tracked(); + println!("{}\n{}", label.italic(), times.join("\n")); } continue; } diff --git a/src/tasks.rs b/src/tasks.rs index e980ff3..e66a2f8 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -37,7 +37,6 @@ pub(crate) struct Tasks { /// A filtered view of the current tasks view: Vec, - /// Negative: Only Leaf nodes /// Zero: Only Active node /// Positive: Go down the respective level depth: i8, @@ -187,10 +186,11 @@ impl Tasks { .map(|str| EventId::from_str(str).ok().map_or(str.to_string(), |id| self.get_task_title(&id))) .join(" ")); if new.as_ref() != full.last() { + // TODO alternating color for days full.push(format!("{:>15} {}", relative_datetimestamp(&event.created_at), new.as_ref().unwrap_or(&"---".to_string()))); } } - ("Your Time Tracking History:".to_string(), Box::from(full.into_iter())) + ("Your Time-Tracking History:".to_string(), Box::from(full.into_iter())) } else { ("You have nothing tracked yet".to_string(), Box::from(empty())) } @@ -217,14 +217,14 @@ impl Tasks { vec.push(format!("{} started by {}", local_datetimestamp(stamp), key))); vec }).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people - (format!("Times tracked on {}", self.get_task_title(&id)), Box::from(history)) + (format!("Times Tracked on {:?}", self.get_task_title(&id)), Box::from(history)) } } } /// Total time in seconds tracked on this task by the current user. pub(crate) fn time_tracked(&self, id: EventId) -> u64 { - TimesTracked::from(self.history.get(&self.sender.pubkey()).into_iter().flatten(), &vec![&id]).sum::().as_secs() + Durations::from(self.history.get(&self.sender.pubkey()).into_iter().flatten(), &vec![&id]).sum::().as_secs() } @@ -234,7 +234,7 @@ impl Tasks { let children = self.get_task_tree(&id).get_all(); for user in self.history.values() { - total += TimesTracked::from(user, &children).into_iter().sum::().as_secs(); + total += Durations::from(user, &children).sum::().as_secs(); } total } @@ -381,7 +381,7 @@ impl Tasks { pub(crate) fn visible_tasks(&self) -> Vec<&Task> { if self.depth == 0 { - return self.get_current_task().into_iter().collect(); + return vec![]; } if self.view.len() > 0 { return self.resolve_tasks(self.view.iter()).collect(); @@ -413,11 +413,21 @@ impl Tasks { )?; writeln!(lock, "{}", t.descriptions().join("\n"))?; } + + let mut tasks = self.visible_tasks(); + if tasks.is_empty() { + let (label, times) = self.times_tracked(); + let mut times_recent = times.rev().take(6).collect_vec(); + times_recent.reverse(); + // TODO Add recent prefix + writeln!(lock, "{}\n{}", label.italic(), times_recent.join("\n"))?; + return Ok(()); + } + // TODO proper column alignment // TODO hide empty columns writeln!(lock, "{}", self.properties.join("\t").bold())?; let mut total_time = 0; - let mut tasks = self.visible_tasks(); let count = tasks.len(); tasks.sort_by_cached_key(|task| { self.sorting @@ -951,22 +961,21 @@ fn timestamps<'a>(events: impl Iterator, ids: &'a Vec<&'a EventI /// Iterates Events to accumulate times tracked /// Expects a sorted iterator -struct TimesTracked<'a> { +struct Durations<'a> { events: Box + 'a>, ids: &'a Vec<&'a EventId>, threshold: Option, } -impl TimesTracked<'_> { - fn from<'b>(events: impl IntoIterator + 'b, ids: &'b Vec<&EventId>) -> TimesTracked<'b> { - TimesTracked { +impl Durations<'_> { + fn from<'b>(events: impl IntoIterator + 'b, ids: &'b Vec<&EventId>) -> Durations<'b> { + Durations { events: Box::new(events.into_iter()), ids, threshold: Some(Timestamp::now()), } } } - -impl Iterator for TimesTracked<'_> { +impl Iterator for Durations<'_> { type Item = Duration; fn next(&mut self) -> Option {