diff --git a/Cargo.lock b/Cargo.lock
index 0554e89401..e68a54a10f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1256,6 +1256,7 @@ dependencies = [
"nix 0.28.0",
"nom",
"notmuch",
+ "num-traits",
"pipewire",
"regex",
"reqwest",
diff --git a/Cargo.toml b/Cargo.toml
index 86255703ab..a5e8d494f9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -57,6 +57,7 @@ neli-wifi = { version = "0.6", features = ["async"] }
nix = { version = "0.28", features = ["fs", "process"] }
nom = "7.1.2"
notmuch = { version = "0.8", optional = true }
+num-traits = "0.2"
pipewire = { version = "0.8", default-features = false, optional = true }
regex = "1.5"
reqwest = { version = "0.11", features = ["json"] }
diff --git a/src/blocks/pomodoro.rs b/src/blocks/pomodoro.rs
index ae0ea70692..1c8a24d0fa 100644
--- a/src/blocks/pomodoro.rs
+++ b/src/blocks/pomodoro.rs
@@ -15,16 +15,21 @@
//!
//! Key | Values | Default
//! ----|--------|--------
-//! `format` | A string to customise the output of this block. | \" $icon{ $message|} \"
+//! `format` | The format used when in idle, prompt, or notify states | \" $icon{ $message\|} \"
+//! `pomodoro_format` | The format used when the pomodoro is running or paused | \" $icon $status_icon{ $completed_pomodoros.tally()\|} $time_remaining.duration(hms:true) \"
+//! `break_format` |The format used when the pomodoro is during the break | \" $icon $status_icon Break: $time_remaining.duration(hms:true) \"
//! `message` | Message when timer expires | `"Pomodoro over! Take a break!"`
//! `break_message` | Message when break is over | `"Break over! Time to work!"`
//! `notify_cmd` | A shell command to run as a notifier. `{msg}` will be substituted with either `message` or `break_message`. | `None`
//! `blocking_cmd` | Is `notify_cmd` blocking? If it is, then pomodoro block will wait until the command finishes before proceeding. Otherwise, you will have to click on the block in order to proceed. | `false`
//!
-//! Placeholder | Value | Type
-//! ------------|-------------------------------------|------
-//! `icon` | A static icon | Icon
-//! `message` | Current message | Text
+//! Placeholder | Value | Type | Supported by
+//! ----------------------|-----------------------------------------------|----------|--------------
+//! `icon` | A static icon | Icon | All formats
+//! `status_icon` | An icon that reflects the pomodoro state | Icon | `pomodoro_format`, `break_format`
+//! `message` | Current message | Text | `format`
+//! `time_remaining` | How much time is left (minutes) | Duration | `pomodoro_format`, `break_format`
+//! `completed_pomodoros` | The number of completed pomodoros | Number | `pomodoro_format`
//!
//! # Example
//!
@@ -52,21 +57,25 @@
//! - `pomodoro_stopped`
//! - `pomodoro_paused`
//! - `pomodoro_break`
-//!
-//! # TODO
-//! - Use different icons.
-//! - Use format strings.
+use num_traits::{Num, NumAssignOps, SaturatingSub};
use tokio::sync::mpsc;
use super::prelude::*;
-use crate::subprocess::{spawn_shell, spawn_shell_sync};
+use crate::{
+ formatting::Format,
+ subprocess::{spawn_shell, spawn_shell_sync},
+};
use std::time::Instant;
+make_log_macro!(debug, "pomodoro");
+
#[derive(Deserialize, Debug, SmartDefault)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
pub format: FormatConfig,
+ pub pomodoro_format: FormatConfig,
+ pub break_format: FormatConfig,
#[default("Pomodoro over! Take a break!".into())]
pub message: String,
#[default("Break over! Time to work!".into())]
@@ -75,21 +84,70 @@ pub struct Config {
pub blocking_cmd: bool,
}
+enum PomodoroState {
+ Idle,
+ Prompt,
+ Notify,
+ Break,
+ PomodoroRunning,
+ PomodoroPaused,
+}
+
+impl PomodoroState {
+ fn get_block_state(&self) -> State {
+ use PomodoroState::*;
+ match self {
+ Idle | PomodoroPaused => State::Idle,
+ Prompt => State::Warning,
+ Notify => State::Good,
+ Break | PomodoroRunning => State::Info,
+ }
+ }
+
+ fn get_status_icon(&self) -> Option> {
+ use PomodoroState::*;
+ match self {
+ Idle => Some("pomodoro_stopped".into()),
+ Break => Some("pomodoro_break".into()),
+ PomodoroRunning => Some("pomodoro_started".into()),
+ PomodoroPaused => Some("pomodoro_paused".into()),
+ _ => None,
+ }
+ }
+}
+
struct Block<'a> {
widget: Widget,
actions: mpsc::UnboundedReceiver,
api: &'a CommonApi,
- block_config: &'a Config,
+ config: &'a Config,
+ state: PomodoroState,
+ format: Format,
+ pomodoro_format: Format,
+ break_format: Format,
}
impl Block<'_> {
- async fn set_text(&mut self, text: String) -> Result<()> {
- let mut values = map!(
+ async fn set_text(&mut self, additional_values: Values) -> Result<()> {
+ let mut values = map! {
"icon" => Value::icon("pomodoro"),
- );
- if !text.is_empty() {
- values.insert("message".into(), Value::text(text));
+ };
+ values.extend(additional_values);
+
+ if let Some(icon) = self.state.get_status_icon() {
+ values.insert("status_icon".into(), Value::icon(icon));
}
+ self.widget.set_format(match self.state {
+ PomodoroState::Idle | PomodoroState::Prompt | PomodoroState::Notify => {
+ self.format.clone()
+ }
+ PomodoroState::Break => self.break_format.clone(),
+ PomodoroState::PomodoroRunning | PomodoroState::PomodoroPaused => {
+ self.pomodoro_format.clone()
+ }
+ });
+ self.widget.state = self.state.get_block_state();
+ debug!("{:?}", values);
self.widget.set_values(values);
self.api.set_widget(self.widget.clone())
}
@@ -99,78 +157,118 @@ impl Block<'_> {
Ok(())
}
- async fn read_params(&mut self) -> Result<(Duration, Duration, u64)> {
- let task_len = self.read_u64(25, "Task length:").await?;
- let break_len = self.read_u64(5, "Break length:").await?;
- let pomodoros = self.read_u64(4, "Pomodoros:").await?;
- Ok((
+ async fn read_params(&mut self) -> Result