First working POC
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::media::MediaItem;
|
||||
|
||||
/// Tracks why playback ended to determine autoplay behavior
|
||||
///
|
||||
/// @req: UR-005 - Control media playback (autoplay logic)
|
||||
/// @req: DR-001 - Player state machine (end reason tracking)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum EndReason {
|
||||
/// Track played to completion (natural end) - trigger autoplay
|
||||
Finished,
|
||||
/// User pressed next/previous - already handled, don't autoplay
|
||||
UserSkip,
|
||||
/// User stopped playback - don't autoplay
|
||||
UserStop,
|
||||
/// Playback error - don't autoplay
|
||||
Error,
|
||||
/// User selected a different track - don't autoplay
|
||||
NewTrackLoaded,
|
||||
}
|
||||
|
||||
/// Player state machine (6 states: Idle, Loading, Playing, Paused, Seeking, Error)
|
||||
///
|
||||
/// @req: DR-001 - Player state machine (idle, loading, playing, paused, seeking, error)
|
||||
/// @req: UR-005 - Control media playback (state tracking)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum PlayerState {
|
||||
#[default]
|
||||
/// No media loaded
|
||||
Idle,
|
||||
/// Media is being loaded/buffered
|
||||
Loading { media: MediaItem },
|
||||
/// Media is playing
|
||||
Playing {
|
||||
media: MediaItem,
|
||||
/// Current position in seconds
|
||||
position: f64,
|
||||
/// Total duration in seconds
|
||||
duration: f64,
|
||||
},
|
||||
/// Media is paused
|
||||
Paused {
|
||||
media: MediaItem,
|
||||
/// Current position in seconds
|
||||
position: f64,
|
||||
/// Total duration in seconds
|
||||
duration: f64,
|
||||
},
|
||||
/// Seeking to a new position
|
||||
Seeking {
|
||||
media: MediaItem,
|
||||
/// Target position in seconds
|
||||
target: f64,
|
||||
},
|
||||
/// An error occurred
|
||||
Error {
|
||||
media: Option<MediaItem>,
|
||||
error: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl PlayerState {
|
||||
/// Get the current playback position if available
|
||||
pub fn position(&self) -> Option<f64> {
|
||||
match self {
|
||||
PlayerState::Playing { position, .. } => Some(*position),
|
||||
PlayerState::Paused { position, .. } => Some(*position),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the player is currently playing
|
||||
pub fn is_playing(&self) -> bool {
|
||||
matches!(self, PlayerState::Playing { .. })
|
||||
}
|
||||
|
||||
/// Check if the player is currently paused
|
||||
#[allow(dead_code)]
|
||||
pub fn is_paused(&self) -> bool {
|
||||
matches!(self, PlayerState::Paused { .. })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user