diff --git a/README.md b/README.md index cdf65f0..6d63390 100644 --- a/README.md +++ b/README.md @@ -40,24 +40,28 @@ $ cargo install pomodoro-cli Options for `start`: - `--duration` Set the duration for the timer (format: `1h 30m 15s`) +- `--add` Add more time to a running timer instead of starting a new timer (format: `1h 30m 15s`) +- `--resume` Resume a paused timer (default: disabled) - `--notify` Triggers system notification when the timer is finished (default: disabled) - `--silent` Do not play alarm sound when the timer is finished (default: enabled) - `--wait` Wait for the timer to finish (default: disabled) -- `--add` Add more time to a running timer instead of starting a new timer (default: disabled) -- `--resume` Resume a paused timer (default: disabled) ### Start/Stop the timer ```bash -# Start the timer with default configuration +# Start the timer with default configuration (25 min with alarm sound) $ pomodoro-cli start -# Start the timer with custom configuration -$ pomodoro-cli start --duration "1h 30m 15s" --silent --notify +# Start a 30 min timer wihout playing alarm sound, but triggering a system notification +$ pomodoro-cli start --duration "30m" --silent --notify # Stop the timer $ pomodoro-cli stop +``` +### Pause/Resume the timer + +```bash # Pause the Timer (calling this command again will resume the timer) $ pomodoro-cli pause @@ -69,7 +73,7 @@ $ pomodoro-cli start --resume ```bash # Add 10 minutes to the timer (instead of starting a new timer) -$ pomodoro-cli start -d 10 --add +$ pomodoro-cli start -add 10m ``` ### Query the timer status @@ -96,7 +100,7 @@ Add the following module to your waybar configuration: "format": "  {}", "exec": "pomodoro-cli status --format json", "return-type": "json", - "on-click": "pomodoro-cli start --duration 5m --add --notify", + "on-click": "pomodoro-cli start --add 5m --notify", "on-click-middle": "pomodoro-cli pause", "on-click-right": "pomodoro-cli stop", "interval": 1 @@ -127,7 +131,7 @@ If you want to signal Waybar to update the module immediately when you can add ` ```json "custom/pomo": { - "on-click": "pomodoro-cli start --duration 5m; pkill -SIGRTMIN+10 waybar", + "on-click": "pomodoro-cli start --add 5m; pkill -SIGRTMIN+10 waybar", "signal": 10, } ``` diff --git a/src/app.rs b/src/app.rs index a8c0b6f..7c596c0 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,6 @@ use crate::args::*; use crate::error::*; +use crate::timer_info::DEFAULT_TIMER_DURATION; use crate::timer_info::{TimerInfo, TimerState}; use crate::utils::*; use crossterm::cursor::{Hide, MoveToColumn, MoveToPreviousLine, Show}; @@ -22,9 +23,9 @@ pub fn run(args: &Cli) -> AppResult<()> { } => { start_timer( parse_duration(duration.clone()), + parse_duration(add.clone()), *silent, *notify, - *add, *resume, )?; if *wait { @@ -47,16 +48,18 @@ pub fn run(args: &Cli) -> AppResult<()> { /// Start the timer. If the timer is already running, the duration is added to the current duration. pub fn start_timer( - duration: i64, + duration: Option, + add: Option, silent: bool, notify: bool, - add: bool, resume: bool, ) -> AppResult<()> { let mut timer_info = TimerInfo::from_file_or_default()?; - if timer_info.is_running() && add { - timer_info.duration += duration; + if timer_info.is_running() && add.is_some() { + // Add more time to the timer + timer_info.duration += add.unwrap(); } else if timer_info.is_paused() && resume { + // Resume a paused timer let now = chrono::Utc::now().timestamp(); let elapsed = timer_info.pause_time - timer_info.start_time; timer_info.duration = timer_info.duration - elapsed; @@ -66,6 +69,8 @@ pub fn start_timer( timer_info.notify = timer_info.notify || notify; timer_info.state = TimerState::Running; } else { + // Start a new timer + let duration = duration.unwrap_or(add.unwrap_or(DEFAULT_TIMER_DURATION)); let now = chrono::Utc::now().timestamp() + 1; timer_info.duration = duration; timer_info.start_time = now; @@ -88,11 +93,11 @@ pub fn pause_timer() -> AppResult<()> { timer_info.write_to_file()?; } else { start_timer( - timer_info.duration, + Some(timer_info.duration), + None, timer_info.silent, timer_info.notify, false, - true, )?; } Ok(()) diff --git a/src/args.rs b/src/args.rs index 5496637..919d745 100644 --- a/src/args.rs +++ b/src/args.rs @@ -18,9 +18,22 @@ pub struct Cli { pub enum SubCommand { /// Start a new timer Start { - #[arg(short, long, help = "Duration of the timer in format 1h 30m 20s")] + #[arg( + short, + long, + conflicts_with_all = &["add", "resume"], + help = "Duration of the timer in format 1h 30m 20s" + )] duration: Option, + #[arg( + short, + long, + conflicts_with_all = &["resume"], + help = "Add more time to the timer" + )] + add: Option, + #[arg(long, default_value_t = false, help = "Enable system notification")] notify: bool, @@ -30,9 +43,6 @@ pub enum SubCommand { #[arg(long, default_value_t = false, help = "Wait for the timer to finish")] wait: bool, - #[arg(long, default_value_t = false, help = "Add more time to the timer")] - add: bool, - #[arg(long, default_value_t = false, help = "Resume paused timer")] resume: bool, }, diff --git a/src/utils.rs b/src/utils.rs index bc4e90b..0aaf00a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,3 @@ -use crate::timer_info::DEFAULT_TIMER_DURATION; use std::path::PathBuf; /// Return the path to the timer information file. This is the cache directory on Linux and @@ -38,10 +37,10 @@ pub fn get_custom_icon_file() -> Option { } /// The duration can be passed either as a number (as minutes) or as string in the format of "1h 30m 10s" -pub fn parse_duration(duration: Option) -> i64 { +pub fn parse_duration(duration: Option) -> Option { if let Some(duration) = duration { if let Ok(duration) = duration.parse::() { - return duration * 60; + return Some(duration * 60); } let mut duration = duration.to_lowercase(); @@ -72,9 +71,9 @@ pub fn parse_duration(duration: Option) -> i64 { let parts = duration.split("s").collect::>(); seconds = parts[0].parse().unwrap_or_default(); } - return hours * 60 * 60 + minutes * 60 + seconds; + return Some(hours * 60 * 60 + minutes * 60 + seconds); } - DEFAULT_TIMER_DURATION + None } /// Return the seconds in human-readable format (e.g. 1h 30m 10s) @@ -101,6 +100,9 @@ pub fn get_human_readable_time(seconds: i64) -> String { } time.push_str(&format!("{}s", seconds)); } + if time.is_empty() { + time.push_str("0s"); + } return time; } @@ -110,22 +112,25 @@ mod tests { #[test] fn test_parse_duration() { - assert_eq!(parse_duration(Some("1h 30m 10s".to_string())), 5410); - assert_eq!(parse_duration(Some("1H 30Min 10SeC".to_string())), 5410); - assert_eq!(parse_duration(Some("2h15m1s".to_string())), 8101); - assert_eq!(parse_duration(Some("1h 30m".to_string())), 5400); - assert_eq!(parse_duration(Some("1hour".to_string())), 3600); - assert_eq!(parse_duration(Some("30m 10s".to_string())), 1810); - assert_eq!(parse_duration(Some("30m".to_string())), 1800); - assert_eq!(parse_duration(Some("10s".to_string())), 10); - assert_eq!(parse_duration(Some("100".to_string())), 100 * 60); - assert_eq!(parse_duration(Some("Invalid string".to_string())), 0); + assert_eq!(parse_duration(Some("1h 30m 10s".to_string())), Some(5410)); + assert_eq!( + parse_duration(Some("1H 30Min 10SeC".to_string())), + Some(5410) + ); + assert_eq!(parse_duration(Some("2h15m1s".to_string())), Some(8101)); + assert_eq!(parse_duration(Some("1h 30m".to_string())), Some(5400)); + assert_eq!(parse_duration(Some("1hour".to_string())), Some(3600)); + assert_eq!(parse_duration(Some("30m 10s".to_string())), Some(1810)); + assert_eq!(parse_duration(Some("30m".to_string())), Some(1800)); + assert_eq!(parse_duration(Some("10s".to_string())), Some(10)); + assert_eq!(parse_duration(Some("100".to_string())), Some(100 * 60)); + assert_eq!(parse_duration(Some("Invalid string".to_string())), Some(0)); } #[test] fn test_get_human_readable_time() { assert_eq!(get_human_readable_time(5410), "1h 30m 10s"); - assert_eq!(get_human_readable_time(60), "1m 0s"); + assert_eq!(get_human_readable_time(60), "1m"); assert_eq!(get_human_readable_time(10), "10s"); assert_eq!(get_human_readable_time(0), "0s"); }