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 rmp::TrackChangeOptions;
|
||||
use rmp::{QueuePlaylist, TrackChangeOptions};
|
||||
|
||||
use crate::playback::Playback;
|
||||
|
||||
pub struct AppOptions {
|
||||
pub title: String,
|
||||
pub enhanced_graphics: bool,
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
pub options: AppOptions,
|
||||
pub should_quit: bool,
|
||||
pub playback: Playback,
|
||||
pub track_change_options: TrackChangeOptions,
|
||||
}
|
||||
|
||||
pub struct AppOptions {
|
||||
pub title: String,
|
||||
pub enhanced_graphics: bool,
|
||||
pub queue_playlist: QueuePlaylist,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
|
@ -24,6 +25,7 @@ impl App {
|
|||
playback: Playback::new(),
|
||||
// TODO: Maybe read from some configuration (args, file, etc...)
|
||||
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_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) {
|
||||
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) {}
|
||||
|
|
|
|||
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)]
|
||||
pub struct ServerState {
|
||||
pub track_change_options: TrackChangeOptions,
|
||||
pub player: Option<PlayerState>,
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ListState {
|
||||
offset: usize,
|
||||
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)]
|
||||
pub struct PlayerState {
|
||||
pub track: PlaylistElement,
|
||||
pub is_paused: bool,
|
||||
pub duration: Option<f32>,
|
||||
pub current_position: Option<f32>,
|
||||
pub struct StatefulList<T> {
|
||||
pub state: ListState,
|
||||
pub items: Vec<T>,
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -21,23 +106,32 @@ pub enum PlaylistType {
|
|||
Queue,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Playlist {
|
||||
pub items: Vec<PlaylistElement>,
|
||||
pub current: Option<usize>,
|
||||
}
|
||||
|
||||
impl Playlist {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirectoryPlaylist {
|
||||
pub directory: PathBuf,
|
||||
pub playlist: Playlist,
|
||||
pub playlist: StatefulList<PlaylistElement>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
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)]
|
||||
|
|
@ -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 {
|
||||
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 CLEAR_CONTRAST: Color = Color::Rgb(100, 100, 100);
|
||||
|
||||
fn draw_playlist<B: Backend>(f: &mut Frame<B>, _app: &App, area: Rect) {
|
||||
let playlist = List::new(vec![])
|
||||
fn draw_playlist<B: Backend>(f: &mut Frame<B>, app: &App, area: Rect) {
|
||||
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::default()
|
||||
.borders(Borders::ALL)
|
||||
|
|
|
|||
Loading…
Reference in New Issue