feat: add pausing of timers

man-page
Moritz Böhme 2023-07-30 22:22:34 +02:00
parent 8bbb6c9113
commit bd91ea9d90
Signed by: moritz
GPG Key ID: 970C6E89EB0547A9
4 changed files with 60 additions and 3 deletions

View File

@ -40,6 +40,12 @@ pub enum Command {
/// List timers /// List timers
#[clap(visible_alias = "l")] #[clap(visible_alias = "l")]
List, List,
/// Toggle timer
#[clap(visible_alias = "t")]
Toggle {
/// name of the timer to toggle
name: String
},
/// Remove a timer /// Remove a timer
#[clap(visible_alias = "r")] #[clap(visible_alias = "r")]
Remove { Remove {
@ -83,6 +89,9 @@ pub enum PomodoroCommand {
/// List the pomodoro settings and remaining duration /// List the pomodoro settings and remaining duration
#[clap(visible_alias = "l")] #[clap(visible_alias = "l")]
List, List,
/// Toggle pomodoro
#[clap(visible_alias = "t")]
Toggle
} }
fn get_stream(socket_path: &String) -> Result<UnixStream> { fn get_stream(socket_path: &String) -> Result<UnixStream> {

View File

@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::{ use std::{
io::Write, io::Write,
os::unix::net::{UnixListener, UnixStream}, os::unix::net::{UnixListener, UnixStream},
@ -18,6 +18,7 @@ use std::{
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum Command { pub enum Command {
Add(Box<str>, Duration), Add(Box<str>, Duration),
Toggle(Box<str>),
Remove(Box<str>), Remove(Box<str>),
List, List,
PomodoroStart { PomodoroStart {
@ -28,6 +29,7 @@ pub enum Command {
}, },
PomodoroRemove, PomodoroRemove,
PomodoroList, PomodoroList,
PomodoroToggle,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -64,6 +66,8 @@ pub enum AnswerErr {
TimerAlreadyExist(Box<str>), TimerAlreadyExist(Box<str>),
#[error("No timer with the name '{}' exists", .0)] #[error("No timer with the name '{}' exists", .0)]
NoSuchTimer(Box<str>), NoSuchTimer(Box<str>),
#[error("No pomodoro running")]
NoPomodoro,
} }
pub struct Daemon { pub struct Daemon {
@ -110,7 +114,11 @@ impl Daemon {
} }
fn has_timer(&mut self, name: &str) -> bool { fn has_timer(&mut self, name: &str) -> bool {
self.timers.iter().any(|other| other.name.as_ref() == name) self.get_timer(name).is_some()
}
fn get_timer(&mut self, name: &str) -> Option<&mut Timer> {
self.timers.iter_mut().find(|t| t.name.as_ref() == name)
} }
fn handle_command(&mut self, command: Command) -> Result<Answer, AnswerErr> { fn handle_command(&mut self, command: Command) -> Result<Answer, AnswerErr> {
@ -137,6 +145,13 @@ impl Daemon {
self.timers.push(timer); self.timers.push(timer);
Ok(Answer::Ok) Ok(Answer::Ok)
} }
Command::Toggle(name) => match self.get_timer(&name) {
Some(timer) => {
timer.toggle();
Ok(Answer::Ok)
}
None => Err(AnswerErr::NoSuchTimer(name)),
},
Command::Remove(name) => { Command::Remove(name) => {
if !self.has_timer(&name) { if !self.has_timer(&name) {
return Err(AnswerErr::NoSuchTimer(name)); return Err(AnswerErr::NoSuchTimer(name));
@ -160,6 +175,14 @@ impl Daemon {
Ok(Answer::Ok) Ok(Answer::Ok)
} }
Command::PomodoroList => Ok(Answer::Pomodoro(self.pomodoro.clone())), Command::PomodoroList => Ok(Answer::Pomodoro(self.pomodoro.clone())),
Command::PomodoroToggle => match &mut self.pomodoro {
Some(ref mut pomodoro) => {
pomodoro.timer.toggle();
Ok(Answer::Ok)
},
None => Err(AnswerErr::NoPomodoro),
}
} }
} }
@ -204,7 +227,7 @@ impl Daemon {
} }
self.check_timers(); self.check_timers();
sleep(Duration::from_millis(100)); sleep(Duration::from_millis(100));
}; }
Ok(()) Ok(())
} }
} }

View File

@ -22,6 +22,7 @@ fn main() -> Result<(), anyhow::Error> {
} }
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::Toggle { name } => DaemonCommand::Toggle(name.into_boxed_str()),
CliCommand::Pomodoro(pomodoro) => match pomodoro { CliCommand::Pomodoro(pomodoro) => match pomodoro {
PomodoroCommand::Start { PomodoroCommand::Start {
work, work,
@ -36,6 +37,7 @@ fn main() -> Result<(), anyhow::Error> {
}, },
PomodoroCommand::Remove => DaemonCommand::PomodoroRemove, PomodoroCommand::Remove => DaemonCommand::PomodoroRemove,
PomodoroCommand::List => DaemonCommand::PomodoroList, PomodoroCommand::List => DaemonCommand::PomodoroList,
PomodoroCommand::Toggle => DaemonCommand::PomodoroToggle,
}, },
}; };
let answer = send_command(&args.socket, daemon_command)?; let answer = send_command(&args.socket, daemon_command)?;

View File

@ -38,6 +38,13 @@ pub struct Timer {
#[serde(with = "approx_instant")] #[serde(with = "approx_instant")]
start: Instant, start: Instant,
duration: Duration, duration: Duration,
state: State,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub enum State {
Running,
Paused,
} }
impl Display for Timer { impl Display for Timer {
@ -57,6 +64,7 @@ impl Timer {
name, name,
start: Instant::now(), start: Instant::now(),
duration, duration,
state: State::Running,
} }
} }
@ -66,10 +74,14 @@ impl Timer {
/// Returns the remaining duration rounded to seconds of this [`Timer`]. /// Returns the remaining duration rounded to seconds of this [`Timer`].
pub fn remaining(&self) -> Duration { pub fn remaining(&self) -> Duration {
if self.state == State::Paused {
return self.duration;
};
let exact = self.duration - (Instant::now() - self.start); let exact = self.duration - (Instant::now() - self.start);
Duration::from_secs(exact.as_secs()) Duration::from_secs(exact.as_secs())
} }
/// Logs or notifies timer expiration
pub fn handle_expiration(&self, notify: bool) { pub fn handle_expiration(&self, notify: bool) {
let msg = format!("Timer {} has expired!", self.name); let msg = format!("Timer {} has expired!", self.name);
println!("{}", &msg); println!("{}", &msg);
@ -77,4 +89,15 @@ impl Timer {
send_notifictation(msg.as_str()); send_notifictation(msg.as_str());
} }
} }
/// Toggles the timers state
pub fn toggle(&mut self) {
if self.state != State::Paused {
self.duration = self.remaining();
self.state = State::Paused;
} else {
self.start = Instant::now();
self.state = State::Running;
}
}
} }