Add session-owned Pomodoro cycles and controls
Add configurable work and break intervals, pause/resume, CLI and activity-popup controls, and silent completion alerts. Use CLOCK_BOOTTIME deadlines so running timers include suspend without consuming paused time. Refs #31
This commit is contained in:
1 parent
53ba599918
commit
2c9bb85f2c
18 files changed
+1209
-16
No files matched your search
@@ -24,6 +24,11 @@ pub enum Command {
|
||||
#[command(subcommand)]
|
||||
action: LauncherAction,
|
||||
},
|
||||
/// Control the session’s work and break timer.
|
||||
Pomodoro {
|
||||
#[command(subcommand)]
|
||||
action: crate::pomodoro::Action,
|
||||
},
|
||||
/// Publish bounded activity data owned by the invoking shell.
|
||||
Activity {
|
||||
#[command(subcommand)]
|
||||
@@ -248,7 +253,7 @@ pub enum LauncherAction {
|
||||
impl Command {
|
||||
pub fn ipc(&self) -> Option<(&'static str, Value)> {
|
||||
let (command, args) = match self {
|
||||
Self::Activity { .. } | Self::Run { .. } => return None,
|
||||
Self::Pomodoro { .. } | Self::Activity { .. } | Self::Run { .. } => return None,
|
||||
Self::Launcher {
|
||||
action: LauncherAction::Toggle,
|
||||
} => ("toggle-launcher", json!({})),
|
||||
|
||||
@@ -2,6 +2,7 @@ mod activities;
|
||||
mod autostart;
|
||||
mod cli;
|
||||
mod output;
|
||||
mod pomodoro;
|
||||
|
||||
use std::error::Error;
|
||||
use std::io::Write;
|
||||
@@ -55,6 +56,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
match &cli.command {
|
||||
Command::Theme { action } => theme_command(action, &socket, cli.json),
|
||||
Command::Activity { action } => activities::command(action, &socket, cli.json),
|
||||
Command::Pomodoro { action } => pomodoro::command(action, &socket, cli.json),
|
||||
Command::EventStream => event_stream(&socket),
|
||||
command => {
|
||||
let (command, args) = command.ipc().expect("IPC command");
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
use clap::Subcommand;
|
||||
use ferese_ipc::activities::{PomodoroAction, PomodoroRequest, VERSION};
|
||||
use std::{error::Error, os::unix::net::UnixStream, path::Path, time::Duration};
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum Action {
|
||||
/// Start a session using activities.pomodoro settings.
|
||||
Start,
|
||||
Pause,
|
||||
Resume,
|
||||
/// Skip the current interval, or start a phase that is ready.
|
||||
Next,
|
||||
/// Cancel and remove the session without a completion alert.
|
||||
Stop,
|
||||
/// Cancel and start a new session with current settings.
|
||||
Reset,
|
||||
Status,
|
||||
}
|
||||
pub fn command(action: &Action, socket: &Path, json: bool) -> Result<(), Box<dyn Error>> {
|
||||
let action = match action {
|
||||
Action::Start => PomodoroAction::Start,
|
||||
Action::Pause => PomodoroAction::Pause,
|
||||
Action::Resume => PomodoroAction::Resume,
|
||||
Action::Next => PomodoroAction::Next,
|
||||
Action::Stop => PomodoroAction::Stop,
|
||||
Action::Reset => PomodoroAction::Reset,
|
||||
Action::Status => PomodoroAction::Status,
|
||||
};
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.set_read_timeout(Some(Duration::from_secs(2)))?;
|
||||
stream.set_write_timeout(Some(Duration::from_secs(2)))?;
|
||||
let result = super::request(
|
||||
&mut stream,
|
||||
"pomodoro",
|
||||
serde_json::to_value(PomodoroRequest {
|
||||
version: VERSION,
|
||||
action,
|
||||
session: None,
|
||||
})?,
|
||||
)?;
|
||||
super::output::print(&result, json)
|
||||
}
|
||||
@@ -485,3 +485,26 @@ fn launcher_toggle_uses_the_shell_command() {
|
||||
);
|
||||
server.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pomodoro_commands_use_the_versioned_session_api() {
|
||||
for action in ["start", "pause", "resume", "next", "stop", "reset", "status"] {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let socket = directory.path().join("control.sock");
|
||||
let listener = UnixListener::bind(&socket).unwrap();
|
||||
let worker = thread::spawn(move || {
|
||||
let (mut stream, _) = listener.accept().unwrap();
|
||||
let request: Request = read_frame(&mut stream).unwrap();
|
||||
assert_eq!(request.command, "pomodoro");
|
||||
assert_eq!(request.args, json!({"version":1,"action":action,"session":null}));
|
||||
write_frame(&mut stream, &Response::success(request.id, json!({"phase":"work"}))).unwrap();
|
||||
});
|
||||
success(
|
||||
ctl(&["--socket", socket.to_str().unwrap(), "pomodoro", action])
|
||||
.output()
|
||||
.unwrap(),
|
||||
);
|
||||
worker.join().unwrap();
|
||||
}
|
||||
success(ctl(&["pomodoro", "--help"]).output().unwrap());
|
||||
}
|
||||
Reference in new issue
Block a user