summaryrefslogtreecommitdiff
path: root/src-tauri/src/lib.rs
diff options
context:
space:
mode:
authorSolstice <solstice@local>2026-06-09 00:52:52 -0700
committerSolstice <solstice@local>2026-06-09 00:52:52 -0700
commit3019f7ffda7d7c82cfd8b31ea7397b0ab528ec65 (patch)
treed10073c6223faf003212da50aa4c4c7b7e1d3082 /src-tauri/src/lib.rs
parentc973d48c41169240e3f53769804696fd0d352a09 (diff)
feat: ambient sound engine and volume controls
Diffstat (limited to 'src-tauri/src/lib.rs')
-rw-r--r--src-tauri/src/lib.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index c9ebbd9..d1864eb 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -1,12 +1,15 @@
+mod audio;
mod state;
mod storage;
mod timer;
use std::sync::{Arc, Mutex};
use chrono::Utc;
+use serde::Serialize;
use tauri::{AppHandle, Manager, State};
use uuid::Uuid;
+use audio::AudioState;
use state::{AppDataWrapper, TimerPhase, TimerState, TimerStateWrapper};
use storage::{Settings, Task};
@@ -252,6 +255,66 @@ fn delete_task(
Ok(())
}
+// ── Audio commands ──────────────────────────────────────────────────────────
+
+#[derive(Serialize)]
+struct AudioStatus {
+ available: bool,
+ playing: bool,
+ sound: Option<String>,
+ volume: f32,
+}
+
+#[tauri::command]
+fn play_ambient(sound: String, audio: State<'_, AudioState>) -> Result<(), String> {
+ let mut guard = audio.0.lock().unwrap();
+ match guard.as_mut() {
+ None => Err("Audio not available".to_string()),
+ Some(engine) => {
+ if sound == "none" {
+ engine.stop();
+ Ok(())
+ } else {
+ match audio::AmbientSound::from_str(&sound) {
+ Some(s) => engine.play(s),
+ None => Err(format!("Unknown sound: {sound}")),
+ }
+ }
+ }
+ }
+}
+
+#[tauri::command]
+fn stop_ambient(audio: State<'_, AudioState>) {
+ if let Some(ref mut engine) = *audio.0.lock().unwrap() {
+ engine.stop();
+ }
+}
+
+#[tauri::command]
+fn set_ambient_volume(volume: f32, audio: State<'_, AudioState>) -> Result<(), String> {
+ match audio.0.lock().unwrap().as_mut() {
+ None => Err("Audio not available".to_string()),
+ Some(engine) => {
+ engine.set_volume(volume);
+ Ok(())
+ }
+ }
+}
+
+#[tauri::command]
+fn get_audio_status(audio: State<'_, AudioState>) -> AudioStatus {
+ match audio.0.lock().unwrap().as_ref() {
+ None => AudioStatus { available: false, playing: false, sound: None, volume: 0.5 },
+ Some(engine) => AudioStatus {
+ available: true,
+ playing: engine.is_playing(),
+ sound: engine.current_sound().map(|s| s.name().to_string()),
+ volume: engine.volume(),
+ },
+ }
+}
+
// ── App entry point ─────────────────────────────────────────────────────────
#[cfg_attr(mobile, tauri::mobile_entry_point)]
@@ -281,11 +344,20 @@ pub fn run() {
data: Arc::clone(&data_arc),
});
+ // Initialise audio engine (graceful if no device)
+ let audio_dir = app.handle().path().resource_dir()
+ .unwrap_or_else(|_| std::path::PathBuf::from("."))
+ .join("audio");
+ let audio_state = audio::init_audio(audio_dir);
+ let audio_arc = Arc::clone(&audio_state.0);
+ app.manage(audio_state);
+
// Spawn background timer thread
timer::spawn_timer_thread(
app.handle().clone(),
Arc::clone(&timer_arc),
Arc::clone(&data_arc),
+ audio_arc,
data_dir,
);
@@ -304,6 +376,10 @@ pub fn run() {
add_task,
update_task,
delete_task,
+ play_ambient,
+ stop_ambient,
+ set_ambient_volume,
+ get_audio_status,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");