1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
use std::{
sync::{Arc, Mutex},
time::{Duration, Instant},
};
use zbus::{dbus_interface, ConnectionBuilder, Result};
use notify_rust::Notification;
const WORK_DURATION_SECS: f32 = 15.0 * 60.0;
const SHORT_BREAK_DURATION_SECS: f32 = 5.0 * 60.0;
const LONG_BREAK_DURATION_SECS: f32 = 15.0 * 60.0;
const NUM_ITERATIONS: u8 = 4;
struct Pomd {
remaining: Duration,
iteration: u8,
running: bool,
on_break: bool,
last_instant: Instant,
}
#[derive(Default)]
struct PomdInterface {
data: Arc<Mutex<Pomd>>,
}
#[dbus_interface(name = "dev.exvacuum.pomd")]
impl PomdInterface {
async fn get_remaining(&self) -> Duration {
self.data.lock().unwrap().remaining
}
async fn get_iteration(&self) -> u8 {
self.data.lock().unwrap().iteration
}
async fn is_running(&self) -> bool {
self.data.lock().unwrap().running
}
async fn is_on_break(&self) -> bool {
self.data.lock().unwrap().on_break
}
async fn start(&self) {
self.data.lock().unwrap().running = true;
}
async fn pause(&self) {
self.data.lock().unwrap().running = false;
}
async fn stop(&self) {
*self.data.lock().unwrap() = Pomd::default();
}
async fn skip(&self) {
self.data.lock().unwrap().running = false;
self.data.lock().unwrap().setup_next_iteration();
}
}
impl Default for Pomd {
fn default() -> Self {
Self {
remaining: Duration::from_secs_f32(WORK_DURATION_SECS),
iteration: 0,
running: false,
on_break: false,
last_instant: Instant::now(),
}
}
}
impl Pomd {
fn update(&mut self) {
let elapsed = self.last_instant.elapsed();
self.last_instant = Instant::now();
if self.running {
if self.remaining > elapsed {
self.remaining -= elapsed;
} else {
self.running = false;
self.notify();
self.setup_next_iteration();
}
}
}
fn setup_next_iteration(&mut self) {
self.on_break ^= true;
self.remaining = if self.on_break {
if self.iteration == NUM_ITERATIONS-1 { Duration::from_secs_f32(LONG_BREAK_DURATION_SECS) } else { Duration::from_secs_f32(SHORT_BREAK_DURATION_SECS) }
} else {
self.iteration = (self.iteration + 1) % NUM_ITERATIONS;
Duration::from_secs_f32(WORK_DURATION_SECS)
}
}
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, NUM_ITERATIONS))
.body("Click to dismiss")
.show().unwrap();
}
}
}
#[async_std::main]
async fn main() -> Result<()> {
let pomd_interface = PomdInterface::default();
let pomd = pomd_interface.data.clone();
let _connection = ConnectionBuilder::session()?
.name("dev.exvacuum.pomd")?
.serve_at("/dev/exvacuum/pomd", pomd_interface)?
.build()
.await?;
loop {
pomd.lock().unwrap().update();
}
}
|