1use std::time::Duration;
2pub const DEFAULT_WORK_DUR: Duration = Duration::from_secs(45 * 60);
3pub const DEFAULT_WORK_IDLE_TO_PAUSE: Duration = Duration::from_secs(2 * 60);
4pub const DEFAULT_REST_DUR: Duration = Duration::from_secs(15 * 60);
5
6#[cfg(feature = "config")]
7pub mod config {
8 use super::*;
9 use toml;
10 use std::path::Path;
11 use serde::{Serialize, Deserialize};
12 use std::time::Duration;
13 use std::error::Error;
14 use std::fs;
15
16 #[derive(Serialize, Deserialize, Default, Debug)]
17 pub struct Config {
18 #[serde(default)]
19 pub work_time: WorkTime,
20
21 #[serde(default)]
22 pub rest_time: RestTime,
23 }
24
25 impl Config {
26 pub fn from_file<T: AsRef<Path>>(path: T) -> Result<Self, Box<dyn Error>> {
27 let file_data = fs::read_to_string(path)?;
28 Ok(toml::from_str(&file_data)?)
29 }
30
31 pub fn apply_from_file<T: AsRef<Path>>(path: T) -> Self {
32 match Self::from_file(path) {
33 Ok(config) => config,
34 Err(_) => Self::default(),
35 }
36 }
37 }
38
39 #[derive(Serialize, Deserialize, Debug)]
40 pub struct WorkTime {
41 #[serde(with = "humantime_serde")]
42 #[serde(default = "WorkTime::default_duration")]
43 pub duration: Duration,
44
45 #[serde(with = "humantime_serde")]
46 #[serde(default = "WorkTime::default_idle_to_pause")]
47 pub idle_to_pause: Duration,
48 }
49
50 impl WorkTime {
51 fn default_duration() -> Duration {
52 DEFAULT_WORK_DUR
53 }
54
55 fn default_idle_to_pause() -> Duration {
56 DEFAULT_WORK_IDLE_TO_PAUSE
57 }
58 }
59
60 impl Default for WorkTime {
61 fn default() -> Self {
62 Self {
63 duration: Self::default_duration(),
64 idle_to_pause: Self::default_idle_to_pause(),
65 }
66 }
67 }
68
69 #[derive(Serialize, Deserialize, Debug)]
70 pub struct RestTime {
71 #[serde(with = "humantime_serde")]
72 #[serde(default = "RestTime::default_duration")]
73 pub duration: Duration,
74 }
75
76 impl RestTime {
77 fn default_duration() -> Duration {
78 DEFAULT_REST_DUR
79 }
80 }
81
82 impl Default for RestTime {
83 fn default() -> Self {
84 Self {
85 duration: Self::default_duration(),
86 }
87 }
88 }
89}
90
91pub mod counter {
92 #[cfg(feature = "notify")]
93 use notify_rust::{Notification, Timeout};
94 use user_idle::UserIdle;
95 use std::time::Duration;
96 use std::thread;
97
98 pub struct Work {
100 work_dur: Duration,
102
103 idle_dur: Duration,
105 }
106
107 impl Work {
108 pub fn new(work_dur: Duration,
110 idle_dur: Duration) -> Self {
111 Self {
112 work_dur,
113 idle_dur,
114 }
115 }
116
117 pub fn count(&self) {
119 let mut ctr = 0;
120 let idle_dur = self.idle_dur.as_secs();
121 let work_dur = self.work_dur.as_secs();
122
123 self.trigger();
124 while ctr < work_dur {
125 if idle_time() < idle_dur {
126 wait(1);
127 ctr += 1;
128 } else {
129 if (ctr as i32 - idle_dur as i32) <= 0 {
130 ctr = 0;
131 } else {
132 ctr -= idle_dur;
133 }
134
135 self.idle_trigger();
136 loop {
137 if idle_time() == 0 {
138 self.work_resumed_trigger();
139 break;
140 }
141 }
142 }
143 }
144 }
145
146 fn trigger(&self) {
148 println!("It's time to work.");
149 #[cfg(feature = "notify")]
150 Notification::new()
151 .summary("Take a breath: Work")
152 .body("It's time to work.")
153 .timeout(Timeout::Milliseconds(5000))
154 .show()
155 .unwrap();
156 }
157
158 fn idle_trigger(&self) {
160 println!("Idle while work counter started.");
161 #[cfg(feature = "notify")]
162 Notification::new()
163 .summary("Take a breath: Work Idle")
164 .body("Idle while work counter started.")
165 .timeout(Timeout::Milliseconds(5000))
166 .show()
167 .unwrap();
168 }
169
170 fn work_resumed_trigger(&self) {
172 println!("Work has been resumed.");
173 #[cfg(feature = "notify")]
174 Notification::new()
175 .summary("Take a breath: Work Resumed")
176 .body("Work has been resumed.")
177 .timeout(Timeout::Milliseconds(5000))
178 .show()
179 .unwrap();
180 }
181 }
182
183 pub struct Rest {
185 rest_dur: Duration,
187 }
188
189 impl Rest {
190 pub fn new(rest_dur: Duration) -> Self {
192 Self {
193 rest_dur,
194 }
195 }
196
197 pub fn count(&self) {
199 let mut ctr = 0;
200 let rest_dur = self.rest_dur.as_secs();
201
202 self.trigger();
203 while ctr < rest_dur {
204 wait(1);
205 if idle_time() > 0 {
206 ctr += 1;
207 } else {
208 self.short_rest_trigger(Duration::from_secs(ctr));
209 loop {
210 if idle_time() > 0 {
211 self.rest_resumed_trigger();
212 break;
213 }
214 }
215 }
216 }
217 }
218
219 fn trigger(&self) {
221 println!("It's time ti take a breath.");
222 #[cfg(feature = "notify")]
223 Notification::new()
224 .summary("Take a breath")
225 .body("It's time to take a breath.")
226 .timeout(Timeout::Milliseconds(5000))
227 .show()
228 .unwrap();
229 }
230
231 fn short_rest_trigger(&self, ctr: Duration) {
233 let left = (self.rest_dur - ctr).as_secs() as f32 / 60.0;
234 println!("You had too little rest! {:.2} minutes left.", left);
235 #[cfg(feature = "notify")]
236 Notification::new()
237 .summary("Take a breath")
238 .body(&format!("You had too little rest!\n{:.2} minutes left.", left))
239 .timeout(Timeout::Milliseconds(10000))
240 .show()
241 .unwrap();
242 }
243
244 fn rest_resumed_trigger(&self) {
246 println!("Rest has been resumed.");
247 #[cfg(feature = "notify")]
248 Notification::new()
249 .summary("Take a breath")
250 .body("Rest has been resumed.")
251 .timeout(Timeout::Milliseconds(5000))
252 .show()
253 .unwrap();
254 }
255 }
256
257 fn wait(secs: u64) {
259 thread::sleep(Duration::from_secs(secs));
260 }
261
262 fn idle_time() -> u64 {
264 UserIdle::get_time().unwrap().as_seconds()
265 }
266}