feat: better durations and allow stopping pomodoro
This commit is contained in:
parent
103c6d779e
commit
0c954962cc
7 changed files with 81 additions and 49 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -562,6 +562,12 @@ version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -1117,6 +1123,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"humantime",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.71"
|
anyhow = "1.0.71"
|
||||||
clap = { version = "4.3.4", features = ["derive"] }
|
clap = { version = "4.3.4", features = ["derive"] }
|
||||||
|
humantime = "2.1.0"
|
||||||
notify-rust = "4.8.0"
|
notify-rust = "4.8.0"
|
||||||
serde = { version = "1.0.164", features = ["derive"] }
|
serde = { version = "1.0.164", features = ["derive"] }
|
||||||
serde_cbor = "0.11.2"
|
serde_cbor = "0.11.2"
|
||||||
|
|
26
src/cli.rs
26
src/cli.rs
|
@ -3,6 +3,7 @@ use anyhow::{Context, Result};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use std::net::Shutdown;
|
use std::net::Shutdown;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(name = "timers")]
|
#[command(name = "timers")]
|
||||||
|
@ -24,22 +25,29 @@ pub enum Command {
|
||||||
},
|
},
|
||||||
Add {
|
Add {
|
||||||
name: String,
|
name: String,
|
||||||
duration_seconds: u64,
|
duration: humantime::Duration,
|
||||||
},
|
},
|
||||||
List,
|
List,
|
||||||
Remove {
|
Remove {
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
Pomodoro {
|
#[command(subcommand)]
|
||||||
#[clap(default_value_t = 25)]
|
Pomodoro(PomodoroCommand)
|
||||||
work_minutes: u64,
|
}
|
||||||
#[clap(default_value_t = 5)]
|
|
||||||
pause_minutes: u64,
|
#[derive(Debug, Subcommand)]
|
||||||
#[clap(default_value_t = 10)]
|
pub enum PomodoroCommand {
|
||||||
long_pause_minutes: u64,
|
Start {
|
||||||
|
#[clap(default_value_t = Duration::from_secs(25 * 60).into())]
|
||||||
|
work: humantime::Duration,
|
||||||
|
#[clap(default_value_t = Duration::from_secs(5 * 60).into())]
|
||||||
|
pause: humantime::Duration,
|
||||||
|
#[clap(default_value_t = Duration::from_secs(10 * 60).into())]
|
||||||
|
long_pause: humantime::Duration,
|
||||||
#[clap(default_value_t = 3)]
|
#[clap(default_value_t = 3)]
|
||||||
pauses_till_long: u64,
|
pauses_till_long: u64,
|
||||||
}
|
},
|
||||||
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_stream(socket_path: &String) -> Result<UnixStream> {
|
fn get_stream(socket_path: &String) -> Result<UnixStream> {
|
||||||
|
|
|
@ -16,12 +16,13 @@ pub enum Command {
|
||||||
Add(Box<str>, Duration),
|
Add(Box<str>, Duration),
|
||||||
Remove(Box<str>),
|
Remove(Box<str>),
|
||||||
List,
|
List,
|
||||||
Pomodoro {
|
PomodoroStart {
|
||||||
work: Duration,
|
work: Duration,
|
||||||
pause: Duration,
|
pause: Duration,
|
||||||
long_pause: Duration,
|
long_pause: Duration,
|
||||||
pauses_till_long: u64,
|
pauses_till_long: u64,
|
||||||
},
|
},
|
||||||
|
PomodoroStop
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -100,7 +101,14 @@ impl Daemon {
|
||||||
if self.notify {
|
if self.notify {
|
||||||
match Notification::new()
|
match Notification::new()
|
||||||
.summary(" Timers")
|
.summary(" Timers")
|
||||||
.body(format!("Started timer {} for {:?}", &name, duration).as_str())
|
.body(
|
||||||
|
format!(
|
||||||
|
"Started timer {} for {}",
|
||||||
|
&name,
|
||||||
|
humantime::format_duration(duration)
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
)
|
||||||
.show()
|
.show()
|
||||||
{
|
{
|
||||||
Ok(_) => println!("Sent notification sucessfully."),
|
Ok(_) => println!("Sent notification sucessfully."),
|
||||||
|
@ -120,7 +128,7 @@ impl Daemon {
|
||||||
.retain(|other| other.name.as_ref() != name.as_ref());
|
.retain(|other| other.name.as_ref() != name.as_ref());
|
||||||
Ok(Answer::Ok)
|
Ok(Answer::Ok)
|
||||||
}
|
}
|
||||||
Command::Pomodoro {
|
Command::PomodoroStart {
|
||||||
work,
|
work,
|
||||||
pause,
|
pause,
|
||||||
long_pause,
|
long_pause,
|
||||||
|
@ -137,6 +145,10 @@ impl Daemon {
|
||||||
self.pomodoro = Some(Pomodoro::new(work, pause, long_pause, pauses_till_long));
|
self.pomodoro = Some(Pomodoro::new(work, pause, long_pause, pauses_till_long));
|
||||||
Ok(Answer::Ok)
|
Ok(Answer::Ok)
|
||||||
}
|
}
|
||||||
|
Command::PomodoroStop => {
|
||||||
|
self.pomodoro = None;
|
||||||
|
Ok(Answer::Ok)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/main.rs
32
src/main.rs
|
@ -3,34 +3,34 @@ pub mod daemon;
|
||||||
pub mod pomodoro;
|
pub mod pomodoro;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use crate::cli::{send_command, Cli, Command as CliCommand};
|
use crate::cli::{send_command, Cli, Command as CliCommand};
|
||||||
use crate::daemon::{Command as DaemonCommand, Daemon};
|
use crate::daemon::{Command as DaemonCommand, Daemon};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use cli::PomodoroCommand;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
let daemon_command = match args.command {
|
let daemon_command = match args.command {
|
||||||
CliCommand::Daemon { notify } => return Daemon::new(args.socket, notify)?.run(),
|
CliCommand::Daemon { notify } => return Daemon::new(args.socket, notify)?.run(),
|
||||||
CliCommand::Add {
|
CliCommand::Add { name, duration } => {
|
||||||
name,
|
DaemonCommand::Add(name.into_boxed_str(), duration.into())
|
||||||
duration_seconds,
|
}
|
||||||
} => DaemonCommand::Add(name.into_boxed_str(), Duration::from_secs(duration_seconds)),
|
|
||||||
CliCommand::List => DaemonCommand::List,
|
CliCommand::List => DaemonCommand::List,
|
||||||
CliCommand::Remove { name } => DaemonCommand::Remove(name.into_boxed_str()),
|
CliCommand::Remove { name } => DaemonCommand::Remove(name.into_boxed_str()),
|
||||||
CliCommand::Pomodoro {
|
CliCommand::Pomodoro(pomodoro) => match pomodoro {
|
||||||
work_minutes,
|
PomodoroCommand::Start {
|
||||||
pause_minutes,
|
work,
|
||||||
long_pause_minutes,
|
pause,
|
||||||
|
long_pause,
|
||||||
pauses_till_long,
|
pauses_till_long,
|
||||||
|
} => DaemonCommand::PomodoroStart {
|
||||||
} => DaemonCommand::Pomodoro{
|
work: work.into(),
|
||||||
work: Duration::from_secs(work_minutes * 60),
|
pause: pause.into(),
|
||||||
pause: Duration::from_secs(pause_minutes * 60),
|
long_pause: long_pause.into(),
|
||||||
long_pause: Duration::from_secs(long_pause_minutes * 60),
|
pauses_till_long,
|
||||||
pauses_till_long
|
},
|
||||||
|
PomodoroCommand::Stop => DaemonCommand::PomodoroStop,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
send_command(&args.socket, daemon_command)
|
send_command(&args.socket, daemon_command)
|
||||||
|
|
|
@ -19,12 +19,12 @@ impl Display for Pomodoro {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Pomodoro ({:?}, {:?}, {:?}) currently {} with {:?} remaining.",
|
"Pomodoro ({}, {}, {}) currently {} with {} remaining.",
|
||||||
self.work,
|
humantime::format_duration(self.work),
|
||||||
self.pause,
|
humantime::format_duration(self.pause),
|
||||||
self.long_pause,
|
humantime::format_duration(self.long_pause),
|
||||||
self.status,
|
self.status,
|
||||||
self.timer.remaining()
|
humantime::format_duration(self.timer.remaining())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,15 @@ impl Display for Pomodoro {
|
||||||
enum Status {
|
enum Status {
|
||||||
Working,
|
Working,
|
||||||
Pausing,
|
Pausing,
|
||||||
|
LongPause,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Status {
|
impl Display for Status {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Status::Working => write!(f, "working"),
|
Status::Working => write!(f, "pomodoro work"),
|
||||||
Status::Pausing => write!(f, "pausing"),
|
Status::Pausing => write!(f, "pomodoro pause"),
|
||||||
|
Status::LongPause => write!(f, "pomodoro long pause"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +67,6 @@ impl Pomodoro {
|
||||||
pub fn handle_expiration(&mut self, notify: bool) {
|
pub fn handle_expiration(&mut self, notify: bool) {
|
||||||
self.timer.handle_expiration(notify);
|
self.timer.handle_expiration(notify);
|
||||||
let duration = match self.status {
|
let duration = match self.status {
|
||||||
Status::Pausing => self.work,
|
|
||||||
Status::Working => {
|
Status::Working => {
|
||||||
if self.pauses == self.pauses_till_long {
|
if self.pauses == self.pauses_till_long {
|
||||||
self.long_pause
|
self.long_pause
|
||||||
|
@ -73,13 +74,14 @@ impl Pomodoro {
|
||||||
self.pause
|
self.pause
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => self.work,
|
||||||
};
|
};
|
||||||
self.status = match self.status {
|
self.status = match self.status {
|
||||||
Status::Working => {
|
Status::Working => {
|
||||||
self.pauses += 1;
|
self.pauses += 1;
|
||||||
Status::Pausing
|
Status::Pausing
|
||||||
}
|
}
|
||||||
Status::Pausing => Status::Working,
|
_ => Status::Working,
|
||||||
};
|
};
|
||||||
self.timer = Timer::new(self.status.to_string().into_boxed_str(), duration);
|
self.timer = Timer::new(self.status.to_string().into_boxed_str(), duration);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,9 @@ impl Display for Timer {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{} has {}s remaining.",
|
"{} has {} remaining.",
|
||||||
self.name,
|
self.name,
|
||||||
self.remaining().as_secs()
|
humantime::format_duration(self.remaining())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,10 @@ impl Timer {
|
||||||
Instant::now() - self.start > self.duration
|
Instant::now() - self.start > self.duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the remaining duration rounded to seconds of this [`Timer`].
|
||||||
pub fn remaining(&self) -> Duration {
|
pub fn remaining(&self) -> Duration {
|
||||||
self.duration - (Instant::now() - self.start)
|
let exact = self.duration - (Instant::now() - self.start);
|
||||||
|
Duration::from_secs(exact.as_secs())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_expiration(&self, notify: bool) {
|
pub fn handle_expiration(&self, notify: bool) {
|
||||||
|
|
Loading…
Reference in a new issue