Skip to content

Commit 9ac1620

Browse files
committed
feat: switch to callback timer with system time
1 parent 8feb6cc commit 9ac1620

File tree

9 files changed

+93
-65
lines changed

9 files changed

+93
-65
lines changed

src-tauri/Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ tauri = { version = "1.4.1", features = [ "shell-open", "test", "global-shortcut
2020
window-vibrancy = "0.3.2"
2121
tauri-plugin-autostart = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
2222
ts-rs = "6.2.1"
23-
ticking-timer = { git = "https://github.com/G07cha/ticking-timer", version = "0.1.1" }
23+
ticking-timer = { git = "https://github.com/g07cha/ticking-timer", branch = "main" }
2424
anyhow = "1.0.71"
2525

2626
[dev-dependencies]

src-tauri/src/commands/timer.rs

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,67 @@
11
use tauri::{command, State, Window};
22

3-
use crate::{PomodoroState, SettingsState, TimerState, TimerStatePayload};
3+
use crate::{
4+
state::{Pomodoro, TimerMode},
5+
PomodoroState, SettingsState, TimerState, TimerStatePayload,
6+
};
7+
8+
fn update_pomodoro_state(state: &Pomodoro) -> Pomodoro {
9+
match state.mode {
10+
TimerMode::Relax => Pomodoro {
11+
mode: TimerMode::Work,
12+
cycles: state.cycles + 1,
13+
},
14+
TimerMode::Work => Pomodoro {
15+
mode: TimerMode::Relax,
16+
cycles: state.cycles,
17+
},
18+
}
19+
}
420

521
#[command]
6-
pub fn toggle_timer(window: Window, timer: State<'_, TimerState>) {
7-
timer.toggle();
22+
pub fn toggle_timer(window: Window, timer: State<'_, TimerState>) -> Result<(), String> {
23+
timer
24+
.toggle()
25+
.map_err(|_| "Failed to toggle timer".to_string())?;
26+
27+
window
28+
.emit("timer-running-change", *timer.is_running())
29+
.map_err(|_| "Failed to communicate running state".to_string())
30+
}
31+
32+
#[command]
33+
pub fn reset_timer(
34+
window: Window,
35+
timer: State<'_, TimerState>,
36+
pomodoro_state: State<'_, PomodoroState>,
37+
settings: State<'_, SettingsState>,
38+
) -> Result<(), String> {
39+
let mut pomodoro_state = pomodoro_state.lock().unwrap();
40+
41+
*pomodoro_state = update_pomodoro_state(&pomodoro_state);
42+
let new_duration = pomodoro_state.duration(&settings.read().unwrap());
43+
timer
44+
.reset(new_duration)
45+
.map_err(|_| "Failed to reset timer".to_string())?;
46+
timer
47+
.resume()
48+
.map_err(|_| "Failed to resume timer".to_string())?;
49+
50+
window
51+
.emit::<TimerStatePayload>(
52+
"timer-state",
53+
TimerStatePayload {
54+
mode: pomodoro_state.mode,
55+
cycle: pomodoro_state.cycles,
56+
is_ended: false,
57+
duration_secs: new_duration.as_secs() as u32,
58+
},
59+
)
60+
.map_err(|_| "Failed to communicate new state".to_string())?;
861

962
window
10-
.emit("timer-running-change", timer.is_running())
11-
.unwrap()
63+
.emit("timer-running-change", *timer.is_running())
64+
.map_err(|_| "Failed to communicate running state".to_string())
1265
}
1366

1467
#[command]

src-tauri/src/helpers/shortcuts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ pub fn register_toggle_shortcut<R: Runtime>(
2929
let app_handle = app_handle.clone();
3030
move || {
3131
let timer = app_handle.state::<TimerState>();
32-
timer.toggle();
32+
timer.toggle().expect("Failed to toggle timer");
3333
app_handle
3434
.get_window(MAIN_WINDOW_LABEL)
3535
.expect("Failed to find main window")
36-
.emit("timer-running-change", timer.is_running())
36+
.emit("timer-running-change", *timer.is_running())
3737
.unwrap();
3838
}
3939
})?

src-tauri/src/helpers/timer.rs

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,14 @@
1-
use tauri::{AppHandle, Manager};
1+
use std::time::Duration;
22

3-
use crate::{
4-
state::{Pomodoro, TimerMode},
5-
PomodoroState, SettingsState, TimerState, TimerStatePayload, MAIN_WINDOW_LABEL,
6-
};
3+
use tauri::{AppHandle, Manager};
74

8-
fn update_pomodoro_state(state: &Pomodoro) -> Pomodoro {
9-
match state.mode {
10-
TimerMode::Relax => Pomodoro {
11-
mode: TimerMode::Work,
12-
cycles: state.cycles + 1,
13-
},
14-
TimerMode::Work => Pomodoro {
15-
mode: TimerMode::Relax,
16-
cycles: state.cycles,
17-
},
18-
}
19-
}
5+
use crate::{PomodoroState, TimerStatePayload, MAIN_WINDOW_LABEL};
206

21-
pub fn setup_timer_listener(app_handle: &AppHandle) -> impl Fn() {
22-
let window = app_handle
23-
.get_window(MAIN_WINDOW_LABEL)
24-
.expect("Unable to retrieve main window");
25-
let update_receiver = app_handle.state::<TimerState>().update_receiver.clone();
7+
pub fn create_timer_listener(app_handle: &AppHandle) -> impl Fn(Duration) {
268
let app_handle = app_handle.clone();
9+
let main_window = app_handle.get_window(MAIN_WINDOW_LABEL).unwrap();
2710

28-
move || loop {
29-
let remaining = update_receiver
30-
.recv()
31-
.expect("Failed to receive timer tick");
11+
move |remaining: Duration| {
3212
let remaining_secs = remaining.as_secs();
3313

3414
#[cfg(target_os = "macos")]
@@ -47,25 +27,17 @@ pub fn setup_timer_listener(app_handle: &AppHandle) -> impl Fn() {
4727
app_handle.emit_all("timer-tick", &remaining_secs).unwrap();
4828

4929
if remaining.is_zero() {
50-
let settings = app_handle.state::<SettingsState>();
5130
let pomodoro_state = app_handle.state::<PomodoroState>();
52-
let mut pomodoro_state = pomodoro_state.lock().unwrap();
53-
54-
*pomodoro_state = update_pomodoro_state(&pomodoro_state);
55-
let new_duration = pomodoro_state.duration(&settings.read().unwrap());
56-
app_handle
57-
.state::<TimerState>()
58-
.reset(new_duration)
59-
.unwrap();
31+
let pomodoro_state = pomodoro_state.lock().unwrap();
6032

61-
window
33+
main_window
6234
.emit::<TimerStatePayload>(
6335
"timer-state",
6436
TimerStatePayload {
6537
mode: pomodoro_state.mode,
6638
cycle: pomodoro_state.cycles,
6739
is_ended: true,
68-
duration_secs: new_duration.as_secs() as u32,
40+
duration_secs: remaining.as_secs() as u32,
6941
},
7042
)
7143
.unwrap();

src-tauri/src/main.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
)]
55

66
use std::sync::{Arc, Mutex, RwLock};
7-
use std::thread;
87
use std::time::Duration;
98

109
use commands::settings::*;
1110
use commands::timer::*;
1211
use helpers::fs::load_settings;
1312
use helpers::shortcuts::setup_shortcuts;
14-
use helpers::timer::setup_timer_listener;
13+
use helpers::timer::create_timer_listener;
1514
use serde::Serialize;
1615
use state::{Pomodoro, Settings};
1716
use tauri::{Manager, RunEvent};
@@ -48,14 +47,25 @@ pub type PomodoroState = Mutex<Pomodoro>;
4847
fn main() {
4948
tauri::Builder::default()
5049
.menu(tauri::Menu::new())
51-
.manage::<TimerState>(Arc::new(Timer::new(Duration::from_millis(100))))
5250
.manage::<SettingsState>(RwLock::new(Settings::default()))
5351
.manage::<PomodoroState>(Mutex::new(Pomodoro {
5452
cycles: 0,
5553
mode: state::TimerMode::Work,
5654
}))
5755
.setup(|app| {
5856
let app_handle = app.handle();
57+
let main_window = setup_main_window(&app_handle).unwrap();
58+
decorate_window(&main_window);
59+
60+
#[cfg(debug_assertions)]
61+
main_window.open_devtools();
62+
63+
let timer = Timer::new(
64+
Duration::from_millis(100),
65+
create_timer_listener(&app_handle),
66+
);
67+
68+
app_handle.manage::<TimerState>(Arc::new(timer));
5969

6070
{
6171
match load_settings(&app_handle) {
@@ -70,20 +80,8 @@ fn main() {
7080
}
7181
}
7282

73-
{
74-
let main_window = setup_main_window(&app_handle).unwrap();
75-
decorate_window(&main_window);
76-
77-
#[cfg(debug_assertions)]
78-
main_window.open_devtools();
79-
}
80-
8183
setup_tray(app);
8284

83-
thread::Builder::new()
84-
.name("Timer listener".into())
85-
.spawn(setup_timer_listener(&app_handle))?;
86-
8785
Ok(())
8886
})
8987
.plugin(tauri_plugin_autostart::init(
@@ -92,6 +90,7 @@ fn main() {
9290
))
9391
.invoke_handler(tauri::generate_handler![
9492
toggle_timer,
93+
reset_timer,
9594
get_timer_state,
9695
get_settings,
9796
set_settings

src-tauri/src/state.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
use std::time::Duration;
22

3+
use serde::{Deserialize, Serialize};
34
use ts_rs::TS;
45

56
use crate::commands::settings::SettingsPayload;
67

7-
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, Debug, TS)]
8+
#[derive(Clone, Copy, Serialize, Deserialize, Debug, TS)]
89
#[ts(export)]
910
pub enum TimerMode {
1011
Work,
1112
Relax,
1213
}
1314

14-
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
15+
#[derive(Clone, Serialize, Deserialize, Debug)]
1516
pub struct Settings {
1617
pub work_duration: Duration,
1718
pub relax_duration: Duration,

src-ui/pages/main/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ timerService.onEnd(() => {
3838
timerUI.showIcon(TimerIcon.Play);
3939
timerUI.setText('');
4040
timerUI.setCycle(0);
41-
message('Timer is done', { type: 'info' }).then(() => timerService.toggle());
41+
message('Timer is done', { type: 'info' }).then(() => timerService.reset());
4242
});
4343

4444
timerService.onPause(() => {

src-ui/pages/main/timer.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export class TimerService {
6262

6363
toggle = () => invoke('toggle_timer');
6464

65+
reset = () => invoke('reset_timer');
66+
6567
get duration() {
6668
return this._duration;
6769
}

0 commit comments

Comments
 (0)