koan_core/player/commands.rs
1use std::path::PathBuf;
2
3use crossbeam_channel::{Receiver, Sender, bounded};
4
5use super::state::{PlaylistItem, QueueItemId};
6
7/// Commands from the UI layer to the audio engine.
8#[derive(Debug)]
9pub enum PlayerCommand {
10 /// Set cursor + start playback. Replaces Play/SkipTo/SkipBack/PlayInterrupt.
11 Play(QueueItemId),
12 Pause,
13 Resume,
14 Stop,
15 Seek(u64), // position in ms
16 NextTrack,
17 PrevTrack,
18 AddToPlaylist(Vec<PlaylistItem>),
19 RemoveFromPlaylist(QueueItemId),
20 /// Batch remove: delete multiple items as a single undoable operation.
21 RemoveFromPlaylistBatch(Vec<QueueItemId>),
22 MoveInPlaylist {
23 id: QueueItemId,
24 target: QueueItemId,
25 after: bool,
26 },
27 /// Batch move: extract `ids` and reinsert them at `target` position.
28 MoveItemsInPlaylist {
29 ids: Vec<QueueItemId>,
30 target: QueueItemId,
31 after: bool,
32 },
33 /// Update file paths for playlist items after an organize operation.
34 /// On Unix, rename() doesn't invalidate open FDs so playback continues.
35 UpdatePaths(Vec<(QueueItemId, PathBuf)>),
36 /// Insert items after a specific queue item (for drag/drop at cursor position).
37 InsertInPlaylist {
38 items: Vec<PlaylistItem>,
39 after: QueueItemId,
40 },
41 /// Clear the entire playlist (stop + remove all items).
42 ClearPlaylist,
43 /// Download complete — check if cursor is waiting on this item.
44 TrackReady(QueueItemId),
45 /// Enough data buffered for streaming playback — check if cursor is waiting.
46 TrackStreamReady(QueueItemId),
47 /// Decode thread exhausted the playlist — auto-advance or stop.
48 DecodeFinished,
49 /// Undo the last reversible playlist operation.
50 Undo,
51 /// Redo the last undone operation.
52 Redo,
53 /// Begin collecting undo entries into a single batch (e.g. drag operations).
54 BeginUndoBatch,
55 /// End the batch — collapse collected entries into one undo step.
56 EndUndoBatch,
57 /// Switch output audio device by name. Restarts engine on current track.
58 SetOutputDevice(String),
59 /// Clear the configured output device, reverting to system default.
60 ClearOutputDevice,
61}
62
63/// Bounded SPSC command channel.
64///
65/// Small capacity — we don't want commands queuing up. If the engine is busy,
66/// the UI should know about it, not silently buffer 50 seeks.
67pub struct CommandChannel {
68 pub tx: Sender<PlayerCommand>,
69 pub rx: Receiver<PlayerCommand>,
70}
71
72impl Default for CommandChannel {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl CommandChannel {
79 pub fn new() -> Self {
80 let (tx, rx) = bounded(16);
81 Self { tx, rx }
82 }
83}