feat: implement task stopping shortcut
This commit is contained in:
parent
06bfe8e18a
commit
9fbe3e27cb
|
@ -104,12 +104,15 @@ To stop time-tracking completely, simply move to the root of all tasks.
|
|||
|
||||
Dots and slashes can be repeated to move to parent tasks.
|
||||
|
||||
- `:[IND][COL]` - add property column COL at IND or end, if it already exists remove property column COL or IND (1-indexed)
|
||||
- `*[TIME]` - add timetracking with the specified offset (empty: list tracked times)
|
||||
- `:[IND][PROP]` - add property column PROP at IND or end, if it already exists remove property column PROP or IND (1-indexed)
|
||||
- `::[PROP]` - Sort by property PROP
|
||||
- `([TIME]` - insert timetracking with the specified offset in minutes (empty: list tracked times)
|
||||
- `)[TIME]` - stop timetracking with the specified offset in minutes - convenience helper to move to root (empty: stop now)
|
||||
- `>[TEXT]` - complete active task and move to parent, with optional state description
|
||||
- `<[TEXT]` - close active task and move to parent, with optional state description
|
||||
- `!TEXT` - set state for current task from text
|
||||
- `,TEXT` - add text note (comment / description)
|
||||
- TBI: `*[INT]` - set priority - can also be used in task, with any digit
|
||||
- `@` - undoes last action (moving in place or upwards or waiting a minute confirms pending actions)
|
||||
- `wss://...` - switch or subscribe to relay (prefix with space to forcibly add a new one)
|
||||
|
||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -378,22 +378,27 @@ async fn main() {
|
|||
None => tasks.clear_filter()
|
||||
}
|
||||
|
||||
Some('*') =>
|
||||
Some('(') =>
|
||||
match arg {
|
||||
Some(arg) => {
|
||||
if let Ok(num) = arg.parse::<i64>() {
|
||||
tasks.track_at(Timestamp::from(Timestamp::now().as_u64().saturating_add_signed(num)));
|
||||
} else if let Ok(date) = DateTime::parse_from_rfc3339(arg) {
|
||||
tasks.track_at(Timestamp::from(date.to_utc().timestamp() as u64));
|
||||
} else {
|
||||
warn!("Cannot parse {arg}");
|
||||
Some(arg) =>
|
||||
if !tasks.track_from(arg) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
println!("{}", tasks.times_tracked());
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some(')') => {
|
||||
tasks.move_to(None);
|
||||
if let Some(arg) = arg {
|
||||
if !tasks.track_from(arg) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some('.') => {
|
||||
let mut dots = 1;
|
||||
|
|
31
src/tasks.rs
31
src/tasks.rs
|
@ -7,7 +7,7 @@ use std::str::FromStr;
|
|||
use std::sync::mpsc::Sender;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::{Local, TimeZone};
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use chrono::LocalResult::Single;
|
||||
use colored::Colorize;
|
||||
use itertools::Itertools;
|
||||
|
@ -633,10 +633,25 @@ impl Tasks {
|
|||
self.tasks.get(id).map_or(id.to_string(), |t| t.get_title())
|
||||
}
|
||||
|
||||
/// Parse string and set tracking
|
||||
/// Returns false if parsing failed
|
||||
pub(crate) fn track_from(&mut self, str: &str) -> bool {
|
||||
if let Ok(num) = str.parse::<i64>() {
|
||||
self.track_at(Timestamp::from(Timestamp::now().as_u64().saturating_add_signed(num * 60)));
|
||||
} else if let Ok(date) = DateTime::parse_from_rfc3339(str) {
|
||||
self.track_at(Timestamp::from(date.to_utc().timestamp() as u64));
|
||||
} else {
|
||||
warn!("Cannot parse {str}");
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn track_at(&mut self, time: Timestamp) -> EventId {
|
||||
info!("Tracking \"{:?}\" from {}", self.position.map(|id| self.get_task_title(&id)), time.to_human_datetime());
|
||||
info!("{} from {}", self.position.map_or(String::from("Stopping time-tracking"), |id| format!("Tracking \"{}\"", self.get_task_title(&id))), time.to_human_datetime()); // TODO omit seconds
|
||||
let pos = self.get_position();
|
||||
let tracking = build_tracking(pos);
|
||||
// TODO this can lead to funny deletions
|
||||
self.get_own_history().map(|events| {
|
||||
if let Some(event) = events.pop_last() {
|
||||
if event.kind.as_u16() == TRACKING_KIND &&
|
||||
|
@ -914,6 +929,18 @@ mod tasks_test {
|
|||
// TODO test received events
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_timestamps() {
|
||||
let mut tasks = stub_tasks();
|
||||
let zero = EventId::all_zeros();
|
||||
tasks.move_to(Some(zero));
|
||||
tasks.track_at(Timestamp::from(Timestamp::now().as_u64() + 100));
|
||||
assert_eq!(timestamps(tasks.history.values().nth(0).unwrap().into_iter(), &vec![zero]).collect_vec().len(), 2)
|
||||
// TODO Does not show both future and current tracking properly, need to split by now
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_depth() {
|
||||
let mut tasks = stub_tasks();
|
||||
|
|
Loading…
Reference in New Issue