summaryrefslogtreecommitdiff
path: root/src-tauri/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src-tauri/src/lib.rs')
-rw-r--r--src-tauri/src/lib.rs66
1 files changed, 51 insertions, 15 deletions
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index c298fdf..aff41cc 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -23,6 +23,17 @@ fn app_data_dir(app: &AppHandle) -> std::path::PathBuf {
app.path().app_data_dir().expect("Failed to resolve app data dir")
}
+fn persist_timer_snapshot(
+ timer: &TimerState,
+ data: &State<'_, AppDataWrapper>,
+ app: &AppHandle,
+) -> Result<(), String> {
+ let mut app_data = data.data.lock().unwrap();
+ app_data.current_task_id = timer.current_task_id.clone();
+ app_data.timer_snapshot = Some(timer.snapshot());
+ storage::save(&app_data_dir(app), &app_data)
+}
+
fn sync_audio_ducking(audio: &AudioState, phase: TimerPhase) {
if let Some(engine) = audio.0.lock().unwrap().as_mut() {
if audio::should_duck_for_phase(phase) {
@@ -49,19 +60,33 @@ fn get_timer_status(timer: State<'_, TimerStateWrapper>) -> serde_json::Value {
}
#[tauri::command]
-fn start_timer(timer: State<'_, TimerStateWrapper>) {
+fn start_timer(
+ timer: State<'_, TimerStateWrapper>,
+ data: State<'_, AppDataWrapper>,
+ app: AppHandle,
+) -> Result<(), String> {
let mut ts = timer.0.lock().unwrap();
ts.running = true;
+ persist_timer_snapshot(&ts, &data, &app)
}
#[tauri::command]
-fn pause_timer(timer: State<'_, TimerStateWrapper>) {
+fn pause_timer(
+ timer: State<'_, TimerStateWrapper>,
+ data: State<'_, AppDataWrapper>,
+ app: AppHandle,
+) -> Result<(), String> {
let mut ts = timer.0.lock().unwrap();
ts.running = false;
+ persist_timer_snapshot(&ts, &data, &app)
}
#[tauri::command]
-fn reset_timer(timer: State<'_, TimerStateWrapper>, data: State<'_, AppDataWrapper>) {
+fn reset_timer(
+ timer: State<'_, TimerStateWrapper>,
+ data: State<'_, AppDataWrapper>,
+ app: AppHandle,
+) -> Result<(), String> {
let mut ts = timer.0.lock().unwrap();
let total = {
let app_data = data.data.lock().unwrap();
@@ -74,6 +99,7 @@ fn reset_timer(timer: State<'_, TimerStateWrapper>, data: State<'_, AppDataWrapp
ts.remaining_secs = total;
ts.total_secs = total;
ts.running = false;
+ persist_timer_snapshot(&ts, &data, &app)
}
#[tauri::command]
@@ -82,7 +108,7 @@ fn skip_phase(
data: State<'_, AppDataWrapper>,
audio: State<'_, AudioState>,
app: AppHandle,
-) {
+) -> Result<(), String> {
use tauri::Emitter;
let mut ts = timer.0.lock().unwrap();
let app_data = data.data.lock().unwrap();
@@ -111,6 +137,7 @@ fn skip_phase(
ts.running = false;
let phase = ts.phase;
let session_count = ts.session_count;
+ persist_timer_snapshot(&ts, &data, &app)?;
drop(ts);
sync_audio_ducking(&audio, phase);
@@ -122,6 +149,8 @@ fn skip_phase(
session_count,
},
);
+
+ Ok(())
}
#[tauri::command]
@@ -132,19 +161,17 @@ fn set_current_task(
app: AppHandle,
) -> Result<(), String> {
{
- let mut app_data = data.data.lock().unwrap();
- // Validate task exists if Some
+ let app_data = data.data.lock().unwrap();
if let Some(ref tid) = task_id {
if !app_data.tasks.iter().any(|t| &t.id == tid) {
return Err(format!("Task {} not found", tid));
}
}
- app_data.current_task_id = task_id.clone();
- storage::save(&app_data_dir(&app), &app_data)?;
}
{
let mut ts = timer.0.lock().unwrap();
ts.current_task_id = task_id;
+ persist_timer_snapshot(&ts, &data, &app)?;
}
Ok(())
}
@@ -170,7 +197,6 @@ fn update_settings(
{
let mut app_data = data.data.lock().unwrap();
app_data.settings = settings.clone();
- storage::save(&app_data_dir(&app), &app_data)?;
}
// Restart timer at new work duration
{
@@ -180,6 +206,7 @@ fn update_settings(
ts.remaining_secs = settings.work_duration_secs;
ts.running = false;
ts.session_count = 0;
+ persist_timer_snapshot(&ts, &data, &app)?;
}
sync_audio_ducking(&audio, TimerPhase::Work);
Ok(())
@@ -199,6 +226,14 @@ fn add_task(
data: State<'_, AppDataWrapper>,
app: AppHandle,
) -> Result<Task, String> {
+ let name = name.trim().to_string();
+ if name.is_empty() {
+ return Err("Task name cannot be empty".to_string());
+ }
+ if total_sessions == 0 {
+ return Err("total_sessions must be at least 1".to_string());
+ }
+
let task = Task {
id: Uuid::new_v4().to_string(),
name,
@@ -268,6 +303,7 @@ fn delete_task(
let mut ts = timer.0.lock().unwrap();
if ts.current_task_id.as_deref() == Some(&id) {
ts.current_task_id = None;
+ persist_timer_snapshot(&ts, &data, &app)?;
}
}
Ok(())
@@ -363,14 +399,14 @@ pub fn run() {
// Load persisted data
let app_data = storage::load(&data_dir);
let work_secs = app_data.settings.work_duration_secs;
- let current_task_id = app_data.current_task_id.clone();
+ let timer_snapshot = app_data.timer_snapshot.clone();
let data_arc = Arc::new(Mutex::new(app_data));
- let timer_arc = Arc::new(Mutex::new({
- let mut ts = TimerState::new(work_secs);
- ts.current_task_id = current_task_id;
- ts
- }));
+ let timer_arc = Arc::new(Mutex::new(
+ timer_snapshot
+ .map(TimerState::from_snapshot)
+ .unwrap_or_else(|| TimerState::new(work_secs))
+ ));
// Register managed state
app.manage(TimerStateWrapper(Arc::clone(&timer_arc)));