Readded StatefulList to handle playlists
parent
4f84ee9785
commit
3f15bad5f3
29
src/app.rs
29
src/app.rs
|
|
@ -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) {}
|
||||||
|
|
|
||||||
154
src/lib.rs
154
src/lib.rs
|
|
@ -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 Kan⧸Rom⧸Eng] [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};
|
||||||
|
|
||||||
|
|
|
||||||
40
src/ui.rs
40
src/ui.rs
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue