aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Silas Bartha <[email protected]>2024-01-04 22:49:55 -0500
committerLibravatar Silas Bartha <[email protected]>2024-01-04 22:49:55 -0500
commitad825d48308091927e57f35df0d7acfa1a7b7366 (patch)
tree8270270e4b791df802234c977bd0b34442e1c6e3
parent37c7a239b81102d2d1a75b9542a91468676cbd98 (diff)
Refactor + Document
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--LICENSE-APACHE13
-rw-r--r--src/config.rs28
-rw-r--r--src/interface.rs55
-rw-r--r--src/main.rs164
-rw-r--r--src/pomd.rs82
7 files changed, 179 insertions, 167 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 989a4b7..00c11a6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -959,7 +959,7 @@ dependencies = [
[[package]]
name = "pomd"
-version = "1.3.0"
+version = "1.4.0"
dependencies = [
"async-std",
"confy",
diff --git a/Cargo.toml b/Cargo.toml
index f15ab07..23ca1b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "pomd"
-version = "1.3.0"
+version = "1.4.0"
description = "A simple configurable pomodoro D-Bus daemon"
license = "MIT OR Apache-2.0"
edition = "2021"
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
index 261eeb9..faaaba8 100644
--- a/LICENSE-APACHE
+++ b/LICENSE-APACHE
@@ -175,18 +175,7 @@
END OF TERMS AND CONDITIONS
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2023 Silas Bartha
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..a14ff7c
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,28 @@
+use serde::{Serialize, Deserialize};
+
+/// Configuration for program
+#[derive(Serialize, Deserialize, Clone, Copy)]
+pub struct PomdConfig {
+ /// Length of work phases in seconds
+ pub work_duration: f32,
+ /// Length of short breaks in seconds
+ pub short_break_duration: f32,
+ /// Length of long breaks in seconds
+ pub long_break_duration: f32,
+ /// Number of iterations between long breaks
+ pub num_iterations: u8,
+ /// Whether to show system notifications
+ pub notify: bool,
+}
+
+impl Default for PomdConfig {
+ fn default() -> Self {
+ Self {
+ work_duration: 15.0 * 60.0,
+ short_break_duration: 5.0 * 60.0,
+ long_break_duration: 25.0 * 60.0,
+ num_iterations: 4,
+ notify: true,
+ }
+ }
+}
diff --git a/src/interface.rs b/src/interface.rs
new file mode 100644
index 0000000..870162c
--- /dev/null
+++ b/src/interface.rs
@@ -0,0 +1,55 @@
+use std::{sync::{Arc, Mutex}, time::Duration};
+use zbus::dbus_interface;
+
+use crate::pomd::Pomd;
+
+/// D-Bus interface for the program
+pub struct PomdInterface {
+ pub state: Arc<Mutex<Pomd>>,
+}
+
+impl PomdInterface {
+ /// Create a new instance of the interface with a reference to the program state
+ pub fn new(state: Arc<Mutex<Pomd>>) -> Self {
+ Self {
+ state
+ }
+ }
+}
+
+#[dbus_interface(name = "dev.exvacuum.pomd")]
+impl PomdInterface {
+ fn get_remaining(&self) -> Duration {
+ let data = self.state.lock().unwrap();
+ data.duration.checked_sub(data.start.elapsed(&data.clock)).unwrap_or_default()
+ }
+
+ fn get_iteration(&self) -> u8 {
+ self.state.lock().unwrap().iteration
+ }
+
+ fn is_running(&self) -> bool {
+ !self.state.lock().unwrap().clock.is_paused()
+ }
+
+ fn is_on_break(&self) -> bool {
+ self.state.lock().unwrap().on_break
+ }
+
+ fn start(&self) {
+ self.state.lock().unwrap().clock.resume();
+ }
+
+ fn pause(&self) {
+ self.state.lock().unwrap().clock.pause();
+ }
+
+ fn stop(&self) {
+ let mut data = self.state.lock().unwrap();
+ *data = Pomd::new(data.config);
+ }
+
+ fn skip(&self) {
+ self.state.lock().unwrap().setup_next_iteration();
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 992748c..3a8bcb0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,162 +1,20 @@
-use std::{
- sync::{Arc, Mutex},
- time::Duration, thread::sleep,
-};
+use std::sync::{Mutex, Arc};
+use std::{thread::sleep, time::Duration};
+use zbus::{ConnectionBuilder, Result};
-use pausable_clock::{PausableClock, PausableInstant};
-use serde::{Serialize, Deserialize};
-use zbus::{dbus_interface, ConnectionBuilder, Result};
+use crate::config::PomdConfig;
+use crate::interface::PomdInterface;
+use crate::pomd::Pomd;
-use notify_rust::Notification;
-
-#[derive(Serialize, Deserialize, Clone, Copy)]
-struct PomdConfig {
- work_duration: f32,
- short_break_duration: f32,
- long_break_duration: f32,
- num_iterations: u8,
- notify: bool,
-}
-
-impl Default for PomdConfig {
- fn default() -> Self {
- Self {
- work_duration: 15.0 * 60.0,
- short_break_duration: 5.0 * 60.0,
- long_break_duration: 25.0 * 60.0,
- num_iterations: 4,
- notify: true,
- }
- }
-}
-
-
-struct Pomd {
- config: PomdConfig,
- duration: Duration,
- iteration: u8,
- on_break: bool,
- clock: PausableClock,
- start: PausableInstant
-}
-
-struct PomdInterface {
- data: Arc<Mutex<Pomd>>,
- config: PomdConfig
-}
-
-impl PomdInterface {
- fn new(config: PomdConfig) -> Self {
- Self {
- data: Arc::new(Mutex::new(Pomd::new(config))),
- config,
- }
- }
-}
-
-#[dbus_interface(name = "dev.exvacuum.pomd")]
-impl PomdInterface {
- async fn get_remaining(&self) -> Duration {
- let data = self.data.lock().unwrap();
- data.duration.checked_sub(data.start.elapsed(&data.clock)).unwrap_or_default()
- }
-
- async fn get_iteration(&self) -> u8 {
- self.data.lock().unwrap().iteration
- }
-
- async fn is_running(&self) -> bool {
- !self.data.lock().unwrap().clock.is_paused()
- }
-
- async fn is_on_break(&self) -> bool {
- self.data.lock().unwrap().on_break
- }
-
- async fn start(&self) {
- self.data.lock().unwrap().clock.resume();
- }
-
- async fn pause(&self) {
- self.data.lock().unwrap().clock.pause();
- }
-
- async fn stop(&self) {
- *self.data.lock().unwrap() = Pomd::new(self.config);
- }
-
- async fn skip(&self) {
- self.data.lock().unwrap().setup_next_iteration();
- }
-}
-
-impl Pomd {
- fn new(config: PomdConfig) -> Self {
- let clock = PausableClock::new(Duration::ZERO, true);
- let start = clock.now();
- Self {
- config,
- duration: Duration::from_secs_f32(config.work_duration),
- iteration: 0,
- on_break: false,
- clock,
- start,
- }
- }
-}
-
-impl Pomd {
- fn update(&mut self) {
- if self.duration < self.start.elapsed(&self.clock) {
- if self.config.notify {
- self.notify();
- }
- self.setup_next_iteration();
- }
- }
-
- fn setup_next_iteration(&mut self) {
- self.clock.pause();
- self.start = self.clock.now();
- self.on_break ^= true;
- self.duration = if self.on_break {
- if self.iteration == self.config.num_iterations - 1 {
- Duration::from_secs_f32(self.config.long_break_duration)
- } else {
- Duration::from_secs_f32(self.config.short_break_duration)
- }
- } else {
- self.iteration = (self.iteration + 1) % self.config.num_iterations;
- Duration::from_secs_f32(self.config.work_duration)
- }
- }
-
- fn notify(&self) {
- if self.on_break {
- Notification::new()
- .summary("Break Complete")
- .body("Click to dismiss")
- .show()
- .unwrap();
- } else {
- Notification::new()
- .summary(&format!(
- "Pomodoro Complete ({}/{})",
- self.iteration + 1,
- self.config.num_iterations
- ))
- .body("Click to dismiss")
- .show()
- .unwrap();
- }
- }
-}
+mod config;
+mod interface;
+mod pomd;
#[async_std::main]
async fn main() -> Result<()> {
let config: PomdConfig = confy::load("pomd", "config").expect("Failed to load config!");
- let pomd_interface = PomdInterface::new(config);
- let pomd = pomd_interface.data.clone();
+ let pomd = Arc::new(Mutex::new(Pomd::new(config)));
+ let pomd_interface = PomdInterface::new(pomd.clone());
let _connection = ConnectionBuilder::session()?
.name("dev.exvacuum.pomd")?
.serve_at("/dev/exvacuum/pomd", pomd_interface)?
diff --git a/src/pomd.rs b/src/pomd.rs
new file mode 100644
index 0000000..5a6679f
--- /dev/null
+++ b/src/pomd.rs
@@ -0,0 +1,82 @@
+use std::time::Duration;
+
+use pausable_clock::{PausableClock, PausableInstant};
+
+use notify_rust::Notification;
+
+use crate::config::PomdConfig;
+
+/// Represents the current state of the program
+pub struct Pomd {
+ pub config: PomdConfig,
+ pub duration: Duration,
+ pub iteration: u8,
+ pub on_break: bool,
+ pub clock: PausableClock,
+ pub start: PausableInstant,
+}
+
+impl Pomd {
+ /// Creates a new instance of this struct with a given configuration
+ pub fn new(config: PomdConfig) -> Self {
+ let clock = PausableClock::new(Duration::ZERO, true);
+ let start = clock.now();
+ Self {
+ config,
+ duration: Duration::from_secs_f32(config.work_duration),
+ iteration: 0,
+ on_break: false,
+ clock,
+ start,
+ }
+ }
+
+ /// Check whether sufficient time has elapsed to enter next iteration of cycle
+ pub fn update(&mut self) {
+ if self.duration < self.start.elapsed(&self.clock) {
+ if self.config.notify {
+ self.notify();
+ }
+ self.setup_next_iteration();
+ }
+ }
+
+ /// Resets state for next iteration
+ pub fn setup_next_iteration(&mut self) {
+ // Stop clock until user restarts it
+ self.clock.pause();
+
+ self.start = self.clock.now();
+ self.on_break ^= true;
+ self.duration = if self.on_break {
+ // Long break on last iteration
+ if self.iteration == self.config.num_iterations - 1 {
+ Duration::from_secs_f32(self.config.long_break_duration)
+ } else {
+ Duration::from_secs_f32(self.config.short_break_duration)
+ }
+ } else {
+ self.iteration = (self.iteration + 1) % self.config.num_iterations;
+ Duration::from_secs_f32(self.config.work_duration)
+ }
+ }
+
+ /// Displays a system notification
+ pub fn notify(&self) {
+ Notification::new()
+ .summary(
+ &(if self.on_break {
+ "Break Complete".to_string()
+ } else {
+ format!(
+ "Pomodoro Complete ({}/{})",
+ self.iteration + 1,
+ self.config.num_iterations
+ )
+ }),
+ )
+ .body("Click to dismiss")
+ .show()
+ .unwrap();
+ }
+}