summaryrefslogtreecommitdiff
path: root/src-tauri/src/storage.rs
diff options
context:
space:
mode:
authorSolstice <solstice@local>2026-06-09 01:10:46 -0700
committerSolstice <solstice@local>2026-06-09 01:10:46 -0700
commit887c0bc6f968f80ac90220f24bb578438e05708a (patch)
tree563925e9bc82ae0eee582dc9128ea753d0082ab0 /src-tauri/src/storage.rs
parent4e2d978eb5fc9457d5b913bc10faf1266e6dcda4 (diff)
fix: resolve final release blockers
Diffstat (limited to 'src-tauri/src/storage.rs')
-rw-r--r--src-tauri/src/storage.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/src-tauri/src/storage.rs b/src-tauri/src/storage.rs
index 8e2f148..2e726a3 100644
--- a/src-tauri/src/storage.rs
+++ b/src-tauri/src/storage.rs
@@ -2,6 +2,8 @@ use std::fs;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
+use crate::state::TimerPhase;
+
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Settings {
pub work_duration_secs: u64,
@@ -32,10 +34,22 @@ pub struct Task {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TimerSnapshot {
+ pub phase: TimerPhase,
+ pub remaining_secs: u64,
+ pub total_secs: u64,
+ pub running: bool,
+ pub session_count: u32,
+ pub current_task_id: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppData {
pub settings: Settings,
pub tasks: Vec<Task>,
pub current_task_id: Option<String>,
+ #[serde(default)]
+ pub timer_snapshot: Option<TimerSnapshot>,
}
impl Default for AppData {
@@ -44,6 +58,7 @@ impl Default for AppData {
settings: Settings::default(),
tasks: Vec::new(),
current_task_id: None,
+ timer_snapshot: None,
}
}
}
@@ -77,7 +92,100 @@ pub fn save(app_data_dir: &PathBuf, data: &AppData) -> Result<(), String> {
let tmp_path = app_data_dir.join("data.json.tmp");
fs::write(&tmp_path, contents)
.map_err(|e| format!("Failed to write temp data file: {}", e))?;
+
+ if cfg!(windows) {
+ if path.exists() {
+ fs::remove_file(&path)
+ .map_err(|e| format!("Failed to remove existing data file: {}", e))?;
+ }
+ }
+
fs::rename(&tmp_path, &path)
.map_err(|e| format!("Failed to finalize data file: {}", e))?;
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use super::{load, save, AppData, Settings, Task, TimerSnapshot};
+ use crate::state::TimerPhase;
+ use std::fs;
+ use std::time::{SystemTime, UNIX_EPOCH};
+
+ fn temp_dir(label: &str) -> std::path::PathBuf {
+ let unique = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_nanos();
+ std::env::temp_dir().join(format!("solstice-storage-{label}-{unique}"))
+ }
+
+ #[test]
+ fn load_preserves_persisted_timer_snapshot() {
+ let dir = temp_dir("load-timer-snapshot");
+ fs::create_dir_all(&dir).unwrap();
+
+ let json = serde_json::json!({
+ "settings": {
+ "work_duration_secs": 1500,
+ "short_break_secs": 300,
+ "long_break_secs": 900,
+ "sessions_before_long_break": 4
+ },
+ "tasks": [],
+ "current_task_id": "task-1",
+ "timer_snapshot": {
+ "phase": "short_break",
+ "remaining_secs": 120,
+ "total_secs": 300,
+ "running": false,
+ "session_count": 2,
+ "current_task_id": "task-1"
+ }
+ })
+ .to_string();
+ fs::write(dir.join("data.json"), json).unwrap();
+
+ let data = load(&dir);
+
+ let snapshot = data.timer_snapshot.expect("expected timer snapshot");
+ assert_eq!(snapshot.phase, TimerPhase::ShortBreak);
+ assert_eq!(snapshot.remaining_secs, 120);
+ assert_eq!(snapshot.total_secs, 300);
+ assert_eq!(snapshot.session_count, 2);
+ assert_eq!(snapshot.current_task_id.as_deref(), Some("task-1"));
+ }
+
+ #[test]
+ fn save_persists_timer_snapshot() {
+ let dir = temp_dir("save-timer-snapshot");
+ let data = AppData {
+ settings: Settings::default(),
+ tasks: vec![Task {
+ id: "task-1".to_string(),
+ name: "Deep work".to_string(),
+ total_sessions: 4,
+ remaining_sessions: 3,
+ completed: false,
+ created_at: "2026-06-09T00:00:00Z".to_string(),
+ }],
+ current_task_id: Some("task-1".to_string()),
+ timer_snapshot: Some(TimerSnapshot {
+ phase: TimerPhase::Work,
+ remaining_secs: 600,
+ total_secs: 1500,
+ running: true,
+ session_count: 1,
+ current_task_id: Some("task-1".to_string()),
+ }),
+ };
+
+ save(&dir, &data).unwrap();
+ let reloaded = load(&dir);
+
+ let snapshot = reloaded.timer_snapshot.expect("expected timer snapshot");
+ assert!(snapshot.running);
+ assert_eq!(snapshot.remaining_secs, 600);
+ assert_eq!(snapshot.total_secs, 1500);
+ }
+}