Readded StatefulList to handle playlists

monolith
hheik 2024-08-22 02:42:39 +03:00
parent 4f84ee9785
commit 3f15bad5f3
3 changed files with 172 additions and 51 deletions

View File

@ -1,19 +1,20 @@
use std::{path::PathBuf, time::Duration}; use std::{path::PathBuf, time::Duration};
use rmp::TrackChangeOptions; use rmp::{QueuePlaylist, TrackChangeOptions};
use crate::playback::Playback; use crate::playback::Playback;
pub struct AppOptions {
pub title: String,
pub enhanced_graphics: bool,
}
pub struct App { pub struct App {
pub options: AppOptions, pub options: AppOptions,
pub should_quit: bool, pub should_quit: bool,
pub playback: Playback, pub playback: Playback,
pub track_change_options: TrackChangeOptions, pub track_change_options: TrackChangeOptions,
} pub queue_playlist: QueuePlaylist,
pub struct AppOptions {
pub title: String,
pub enhanced_graphics: bool,
} }
impl App { impl App {
@ -24,6 +25,7 @@ impl App {
playback: Playback::new(), playback: Playback::new(),
// TODO: Maybe read from some configuration (args, file, etc...) // TODO: Maybe read from some configuration (args, file, etc...)
track_change_options: Default::default(), track_change_options: Default::default(),
queue_playlist: QueuePlaylist::generate_mock(),
} }
} }
@ -62,12 +64,21 @@ impl App {
pub fn on_right(&mut self) {} pub fn on_right(&mut self) {}
pub fn on_up(&mut self) {} pub fn on_up(&mut self) {
// TODO: Apply to selected playlist
self.queue_playlist.playlist.previous();
}
pub fn on_down(&mut self) {} pub fn on_down(&mut self) {
// TODO: Apply to selected playlist
self.queue_playlist.playlist.next();
}
pub fn on_enter(&mut self) { pub fn on_enter(&mut self) {
self.play("".into()); // TODO: Remove hardcoding // TODO: Apply to selected playlist
if let Some(current) = self.queue_playlist.playlist.current() {
self.play(current.into());
}
} }
pub fn on_tab(&mut self) {} pub fn on_tab(&mut self) {}

View File

@ -1,17 +1,102 @@
use std::{path::PathBuf, str::FromStr}; use std::{ops::Deref, path::PathBuf};
#[derive(Debug, Default)] #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct ServerState { pub struct ListState {
pub track_change_options: TrackChangeOptions, offset: usize,
pub player: Option<PlayerState>, selected: Option<usize>,
}
impl ListState {
pub fn offset(&self) -> usize {
self.offset
}
pub fn offset_mut(&mut self) -> &mut usize {
&mut self.offset
}
pub fn with_selected(mut self, selected: Option<usize>) -> Self {
self.selected = selected;
self
}
pub fn with_offset(mut self, offset: usize) -> Self {
self.offset = offset;
self
}
pub fn selected(&self) -> Option<usize> {
self.selected
}
pub fn select(&mut self, index: Option<usize>) {
self.selected = index;
if index.is_none() {
self.offset = 0;
}
}
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct PlayerState { pub struct StatefulList<T> {
pub track: PlaylistElement, pub state: ListState,
pub is_paused: bool, pub items: Vec<T>,
pub duration: Option<f32>, }
pub current_position: Option<f32>,
impl<T> StatefulList<T>
where
T: Deref + Eq,
{
pub fn with_items(items: Vec<T>) -> StatefulList<T> {
StatefulList {
state: ListState::default(),
items,
}
}
pub fn next(&mut self) {
let i = match self.state.selected() {
Some(i) => {
if i >= self.items.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn previous(&mut self) {
let i = match self.state.selected() {
Some(i) => {
if i == 0 {
self.items.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn index_of(&self, item: T) -> Option<usize> {
self.items.iter().position(|element| *element == item)
}
pub fn current(&self) -> Option<&T> {
self.state
.selected
.map_or(None, |index| self.items.get(index))
}
pub fn current_mut(&mut self) -> Option<&mut T> {
self.state
.selected
.map_or(None, |index| self.items.get_mut(index))
}
} }
pub type PlaylistElement = PathBuf; pub type PlaylistElement = PathBuf;
@ -21,23 +106,32 @@ pub enum PlaylistType {
Queue, Queue,
} }
#[derive(Debug, Default)]
pub struct Playlist {
pub items: Vec<PlaylistElement>,
pub current: Option<usize>,
}
impl Playlist {}
#[derive(Debug)] #[derive(Debug)]
pub struct DirectoryPlaylist { pub struct DirectoryPlaylist {
pub directory: PathBuf, pub directory: PathBuf,
pub playlist: Playlist, pub playlist: StatefulList<PlaylistElement>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct QueuePlaylist { pub struct QueuePlaylist {
pub playlist: Playlist, pub playlist: StatefulList<PlaylistElement>,
}
impl QueuePlaylist {
pub fn generate_mock() -> Self {
Self {
playlist: StatefulList::with_items(vec![
"/home/hheikkinen/Music/Mariya Takeuchi/Mariya Takeuchi (竹内 まりや) - September [Lyrics KanRomEng] [3wkxIBBP7Vg].opus",
"/home/hheikkinen/Music/Compilerbau - Le Jardin/LEJARDIN.OGG",
"/home/hheikkinen/Music/Casiopea - Mint Jams (1982) FULL ALBUM/001 Take Me.opus",
"/home/hheikkinen/Music/Casiopea - Mint Jams (1982) FULL ALBUM/002 Asayake.opus",
"/home/hheikkinen/Music/A Groovy Thing/01 - Flamingosis - A Groovy Intro.mp3",
"/home/hheikkinen/Music/Brian Ellis - Smocaine 3/Brian Ellis - Smocaine 3- An MDE Film OST - 01 Smocaine Theme (TV Edit).wav",
"/home/hheikkinen/Music/Jun Fukamachi - Starview HCT-5808/T-02.m4a",
"/home/hheikkinen/Music/noby/Fluidy [189046035].flac",
].iter().map(|val| val.into()).collect()),
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -57,26 +151,6 @@ impl Default for TrackChangeOptions {
} }
} }
#[derive(Clone, Copy, Debug, Default)]
pub enum LogLevel {
Quiet = 0,
Error = 1,
#[default]
All = 2,
}
impl FromStr for LogLevel {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"quiet" => Ok(Self::Quiet),
"error" => Ok(Self::Error),
"all" => Ok(Self::All),
_ => Err(()),
}
}
}
pub mod server { pub mod server {
use std::{fmt::Debug, path::PathBuf}; use std::{fmt::Debug, path::PathBuf};

View File

@ -19,8 +19,44 @@ static SECONDARY_COLOR: Color = Color::Rgb(200, 200, 200);
static PRIMARY_CONTRAST: Color = Color::Black; static PRIMARY_CONTRAST: Color = Color::Black;
static CLEAR_CONTRAST: Color = Color::Rgb(100, 100, 100); static CLEAR_CONTRAST: Color = Color::Rgb(100, 100, 100);
fn draw_playlist<B: Backend>(f: &mut Frame<B>, _app: &App, area: Rect) { fn draw_playlist<B: Backend>(f: &mut Frame<B>, app: &App, area: Rect) {
let playlist = List::new(vec![]) let tracks: Vec<_> = app
.queue_playlist
.playlist
.items
.iter()
.enumerate()
.map(|(index, path)| {
let selected = app
.queue_playlist
.playlist
.state
.selected()
.map_or(false, |selected| index == selected);
// let playing = app
// .player_state
// .currently_playing
// .clone()
// .map_or(false, |currently_playing| currently_playing == *path);
let playing = false;
let mut style = Style::default();
match (selected, playing) {
(true, false) => {
style.fg = Some(Color::Black);
style.bg = Some(PRIMARY_COLOR);
}
(false, true) => style.fg = Some(PRIMARY_COLOR),
(true, true) => {
style.fg = None;
style.bg = Some(PRIMARY_COLOR);
}
(_, _) => (),
}
let content = Span::from(path.to_string_lossy().to_string());
ListItem::new(content).set_style(style)
})
.collect();
let playlist = List::new(tracks)
.block( .block(
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)