feat: native desktop notifications (experimental) (#59)

* desktop notification by entering `Mode::DONE` for `countdown` and `pomodoro`

* remove redundant `on_done_called` check

* remove build warning (release only)

* log notification errors

* cli arg to enable desktop notifications

* persistant notification settings

* ctrl shortcut

* update changelog

* max timer notification
This commit is contained in:
Jens Krause
2025-01-28 19:28:34 +01:00
committed by GitHub
parent 97787f718d
commit d3c436da0b
14 changed files with 957 additions and 221 deletions

View File

@@ -9,7 +9,9 @@ use crate::{
edit_time::EditTimeState,
},
};
use crossterm::event::KeyModifiers;
use notify_rust::Notification;
use ratatui::{
buffer::Buffer,
crossterm::event::KeyCode,
@@ -17,6 +19,7 @@ use ratatui::{
text::Line,
widgets::{StatefulWidget, Widget},
};
use tracing::{debug, error};
use std::ops::Sub;
use std::{cmp::max, time::Duration};
@@ -24,8 +27,16 @@ use time::OffsetDateTime;
use super::edit_time::{EditTimeStateArgs, EditTimeWidget};
pub struct CountdownStateArgs {
pub initial_value: Duration,
pub current_value: Duration,
pub elapsed_value: Duration,
pub app_time: AppTime,
pub with_decis: bool,
pub with_notification: bool,
}
/// State for Countdown Widget
#[derive(Debug, Clone)]
pub struct CountdownState {
/// clock to count down
clock: ClockState<clock::Countdown>,
@@ -37,13 +48,32 @@ pub struct CountdownState {
}
impl CountdownState {
pub fn new(
clock: ClockState<clock::Countdown>,
elapsed_value: Duration,
app_time: AppTime,
) -> Self {
pub fn new(args: CountdownStateArgs) -> Self {
let CountdownStateArgs {
initial_value,
current_value,
elapsed_value,
with_notification,
with_decis,
app_time,
} = args;
Self {
clock,
clock: ClockState::<clock::Countdown>::new(ClockStateArgs {
initial_value,
current_value,
tick_value: Duration::from_millis(TICK_VALUE_MS),
with_decis,
})
.with_on_done_by_condition(with_notification, || {
debug!("on_done COUNTDOWN");
let result = Notification::new()
.summary(&"Countdown done!".to_uppercase())
.show();
if let Err(err) = result {
error!("on_done COUNTDOWN error: {err}");
}
}),
elapsed_clock: ClockState::<clock::Timer>::new(ClockStateArgs {
initial_value: Duration::ZERO,
current_value: elapsed_value,