add metadata in queue list
This commit is contained in:
parent
c61b0503c7
commit
bf531facb0
|
|
@ -38,6 +38,6 @@ A MPD client in Rust
|
|||
- [x] add to playlists
|
||||
- [x] search for songs
|
||||
- [x] Humantime format
|
||||
- [x] metadata based tree view
|
||||
- [ ] view playlist
|
||||
- [ ] change playlist name
|
||||
- [ ] metadata based tree view
|
||||
|
|
|
|||
|
|
@ -98,24 +98,27 @@ impl FileBrowser {
|
|||
|
||||
// Go to next item in filetree
|
||||
pub fn next(&mut self) {
|
||||
// if self.selected < self.filetree.len() - 1 {
|
||||
// self.selected += 1;
|
||||
// }
|
||||
|
||||
if self.selected == self.filetree.len() - 1 {
|
||||
self.selected = 0;
|
||||
} else {
|
||||
if self.selected < self.filetree.len() - 1 {
|
||||
self.selected += 1;
|
||||
}
|
||||
|
||||
// if self.selected == self.filetree.len() - 1 {
|
||||
// self.selected = 0;
|
||||
// } else {
|
||||
// self.selected += 1;
|
||||
// }
|
||||
}
|
||||
|
||||
/// Go to previous item in filetree
|
||||
pub fn prev(&mut self) {
|
||||
if self.selected == 0 {
|
||||
self.selected = self.filetree.len() - 1;
|
||||
} else {
|
||||
if self.selected != 0 {
|
||||
self.selected -= 1;
|
||||
}
|
||||
// if self.selected == 0 {
|
||||
// self.selected = self.filetree.len() - 1;
|
||||
// } else {
|
||||
// self.selected -= 1;
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn handle_go_back(&mut self, conn: &mut Connection) -> AppResult<()> {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
match key_event.code {
|
||||
|
|
@ -200,7 +199,6 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
app.conn
|
||||
.load_playlist(app.pl_list.list.get(app.pl_list.index).unwrap())?;
|
||||
}
|
||||
|
||||
}
|
||||
app.conn.update_status();
|
||||
}
|
||||
|
|
@ -279,6 +277,7 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
KeyCode::Char('>') => {
|
||||
if !app.queue_list.list.is_empty() {
|
||||
app.conn.conn.next()?;
|
||||
app.update_queue();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -286,6 +285,7 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
|||
KeyCode::Char('<') => {
|
||||
if !app.queue_list.list.is_empty() {
|
||||
app.conn.conn.prev()?;
|
||||
app.update_queue();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
32
src/list.rs
32
src/list.rs
|
|
@ -14,30 +14,36 @@ impl<T> ContentList<T> {
|
|||
|
||||
// Go to next item in list
|
||||
pub fn next(&mut self) {
|
||||
// if self.index < self.list.len() - 1 {
|
||||
// self.index += 1;
|
||||
// }
|
||||
|
||||
let len = self.list.len();
|
||||
if len != 0 {
|
||||
if self.index == self.list.len() - 1 {
|
||||
self.index = 0;
|
||||
} else {
|
||||
if self.index < len - 1 {
|
||||
self.index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// let len = self.list.len();
|
||||
// if len != 0 {
|
||||
// if self.index == self.list.len() - 1 {
|
||||
// self.index = 0;
|
||||
// } else {
|
||||
// self.index += 1;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/// Go to previous item in list
|
||||
pub fn prev(&mut self) {
|
||||
if self.index == 0 {
|
||||
let len = self.list.len();
|
||||
if len != 0 {
|
||||
self.index = len - 1;
|
||||
}
|
||||
} else {
|
||||
if self.index != 0 {
|
||||
self.index -= 1;
|
||||
}
|
||||
// if self.index == 0 {
|
||||
// let len = self.list.len();
|
||||
// if len != 0 {
|
||||
// self.index = len - 1;
|
||||
// }
|
||||
// } else {
|
||||
// self.index -= 1;
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn reset_index(&mut self) {
|
||||
|
|
|
|||
181
src/ui.rs
181
src/ui.rs
|
|
@ -1,6 +1,7 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::app::{App, SelectedTab};
|
||||
use mpd::Song;
|
||||
use ratatui::{
|
||||
prelude::*,
|
||||
widgets::{block::Title, *},
|
||||
|
|
@ -32,8 +33,7 @@ pub fn render(app: &mut App, frame: &mut Frame) {
|
|||
match app.selected_tab {
|
||||
SelectedTab::Queue => draw_queue(frame, app, layout[0]),
|
||||
SelectedTab::Playlists => draw_playlists(frame, app, layout[0]),
|
||||
SelectedTab::DirectoryBrowser => draw_song_browser(frame, app, layout[0]),
|
||||
// SelectedTab::SongBrowser => draw_song_browser(frame, app, layout[0]),
|
||||
SelectedTab::DirectoryBrowser => draw_directory_browser(frame, app, layout[0]),
|
||||
}
|
||||
|
||||
match app.inputmode {
|
||||
|
|
@ -50,63 +50,8 @@ pub fn render(app: &mut App, frame: &mut Frame) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Draws the file tree browser
|
||||
/// Draws the directory
|
||||
fn draw_directory_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let mut song_state = ListState::default();
|
||||
let total_songs = app.conn.conn.stats().unwrap().songs.to_string();
|
||||
let mut list: Vec<ListItem> = vec![];
|
||||
for (t, s) in app.browser.filetree.iter() {
|
||||
if t == "file" {
|
||||
let mut status: bool = false;
|
||||
for sn in app.queue_list.list.iter() {
|
||||
if sn.contains(s) {
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
if status {
|
||||
list.push(ListItem::new(s.clone().magenta().bold()));
|
||||
} else {
|
||||
// list.push(ListItem::new(s.clone()));
|
||||
list.push(ListItem::new(s.clone()));
|
||||
}
|
||||
} else {
|
||||
list.push(ListItem::new(Line::styled(
|
||||
format!("[{}]", *s),
|
||||
Style::default(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
let list = List::new(list)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(format!("Directory Browser: {}", app.browser.path.clone()).bold())
|
||||
.title(
|
||||
Title::from(format!("Total Songs: {}", total_songs).bold().green())
|
||||
.alignment(Alignment::Center),
|
||||
)
|
||||
.title(
|
||||
Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
|
||||
.alignment(Alignment::Right),
|
||||
)
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.highlight_style(
|
||||
Style::new()
|
||||
.fg(Color::Cyan)
|
||||
.bg(Color::Black)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
.add_modifier(Modifier::REVERSED),
|
||||
)
|
||||
.highlight_symbol(">>")
|
||||
.repeat_highlight_symbol(true)
|
||||
.scroll_padding(20);
|
||||
|
||||
song_state.select(Some(app.browser.selected));
|
||||
frame.render_stateful_widget(list, size, &mut song_state);
|
||||
}
|
||||
|
||||
/// Draws the song browser
|
||||
fn draw_song_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let total_songs = app.conn.conn.stats().unwrap().songs.to_string();
|
||||
|
||||
let rows = app.browser.filetree.iter().enumerate().map(|(i, (t, s))| {
|
||||
|
|
@ -149,7 +94,7 @@ fn draw_song_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
Cell::from(track.green()),
|
||||
Cell::from(title),
|
||||
Cell::from(album),
|
||||
Cell::from(time.to_string().red()),
|
||||
Cell::from(time.to_string().magenta()),
|
||||
]);
|
||||
row.magenta().bold()
|
||||
} else {
|
||||
|
|
@ -158,7 +103,7 @@ fn draw_song_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
Cell::from(track.green()),
|
||||
Cell::from(title),
|
||||
Cell::from(album),
|
||||
Cell::from(time.to_string().red()),
|
||||
Cell::from(time.to_string().magenta()),
|
||||
]);
|
||||
row
|
||||
}
|
||||
|
|
@ -178,9 +123,9 @@ fn draw_song_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
let table = Table::new(
|
||||
rows,
|
||||
[
|
||||
Constraint::Percentage(33),
|
||||
Constraint::Percentage(20),
|
||||
Constraint::Percentage(3),
|
||||
Constraint::Percentage(30),
|
||||
Constraint::Min(30),
|
||||
Constraint::Percentage(30),
|
||||
Constraint::Percentage(3),
|
||||
],
|
||||
|
|
@ -205,7 +150,8 @@ fn draw_song_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
.bg(Color::Black),
|
||||
)
|
||||
.highlight_symbol(">>")
|
||||
.header(header);
|
||||
.header(header)
|
||||
.flex(layout::Flex::Legacy);
|
||||
|
||||
state.select(Some(app.browser.selected));
|
||||
frame.render_stateful_widget(table, size, &mut state);
|
||||
|
|
@ -213,8 +159,79 @@ fn draw_song_browser(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
|
||||
/// draws playing queue
|
||||
fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
|
||||
let mut queue_state = ListState::default();
|
||||
let title = Block::default()
|
||||
let rows = app.queue_list.list.iter().map(|s| {
|
||||
// metadata
|
||||
let song = app
|
||||
.conn
|
||||
.conn
|
||||
.lsinfo(&Song {
|
||||
file: app.conn.get_full_path(&s).unwrap_or_default(),
|
||||
..Default::default()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let song = song.get(0).unwrap();
|
||||
let title = song.clone().title.unwrap_or_else(|| song.clone().file);
|
||||
let artist = song.clone().artist.unwrap_or_default().cyan();
|
||||
let album = song
|
||||
.tags
|
||||
.iter()
|
||||
.filter(|(x, _)| x == "Album")
|
||||
.map(|(_, l)| l.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
|
||||
let track = song
|
||||
.tags
|
||||
.iter()
|
||||
.filter(|(x, _)| x == "Track")
|
||||
.map(|(_, l)| l.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
|
||||
let time = humantime::format_duration(
|
||||
song.clone().duration.unwrap_or_else(|| Duration::new(0, 0)),
|
||||
);
|
||||
|
||||
if s.contains(&app.conn.current_song.file) {
|
||||
let row = Row::new(vec![
|
||||
Cell::from(artist),
|
||||
Cell::from(track.green()),
|
||||
Cell::from(title),
|
||||
Cell::from(album),
|
||||
Cell::from(time.to_string().magenta()),
|
||||
]);
|
||||
row.magenta().bold()
|
||||
} else {
|
||||
let row = Row::new(vec![
|
||||
Cell::from(artist),
|
||||
Cell::from(track.green()),
|
||||
Cell::from(title),
|
||||
Cell::from(album),
|
||||
Cell::from(time.to_string().magenta()),
|
||||
]);
|
||||
row
|
||||
}
|
||||
});
|
||||
|
||||
let mut state = TableState::new();
|
||||
let header = ["Artist", "Track", "Title", "Album", "Time"]
|
||||
.into_iter()
|
||||
.map(Cell::from)
|
||||
.collect::<Row>()
|
||||
.bold()
|
||||
.height(1);
|
||||
let table = Table::new(
|
||||
rows,
|
||||
[
|
||||
Constraint::Percentage(20),
|
||||
Constraint::Percentage(3),
|
||||
Constraint::Min(30),
|
||||
Constraint::Percentage(30),
|
||||
Constraint::Percentage(3),
|
||||
],
|
||||
)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Title::from("Play Queue".green().bold()))
|
||||
.title(Title::from(
|
||||
format!("({} items)", app.queue_list.list.len()).bold(),
|
||||
|
|
@ -222,29 +239,21 @@ fn draw_queue(frame: &mut Frame, app: &mut App, size: Rect) {
|
|||
.title(
|
||||
Title::from(format!("Volume: {}%", app.conn.volume).bold().green())
|
||||
.alignment(Alignment::Right),
|
||||
);
|
||||
|
||||
let mut items: Vec<ListItem> = vec![];
|
||||
for item in app.queue_list.list.iter() {
|
||||
if item.contains(&app.conn.current_song.file) {
|
||||
items.push(ListItem::new(item.clone().magenta().bold()))
|
||||
} else {
|
||||
items.push(ListItem::new(item.clone()));
|
||||
}
|
||||
}
|
||||
let list = List::new(items)
|
||||
.block(title.borders(Borders::ALL))
|
||||
.highlight_style(
|
||||
Style::new()
|
||||
.fg(Color::Cyan)
|
||||
.bg(Color::Black)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
.add_modifier(Modifier::REVERSED),
|
||||
)
|
||||
.highlight_symbol(">>");
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.highlight_style(
|
||||
Style::default()
|
||||
.add_modifier(Modifier::REVERSED)
|
||||
.fg(Color::Cyan)
|
||||
.bg(Color::Black),
|
||||
)
|
||||
.highlight_symbol(">>")
|
||||
.header(header)
|
||||
.flex(layout::Flex::Legacy);
|
||||
|
||||
queue_state.select(Some(app.queue_list.index));
|
||||
frame.render_stateful_widget(list, size, &mut queue_state);
|
||||
state.select(Some(app.queue_list.index));
|
||||
frame.render_stateful_widget(table, size, &mut state);
|
||||
}
|
||||
|
||||
/// draws all playlists
|
||||
|
|
|
|||
Reference in New Issue