Pretify queue widget
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -37,6 +37,7 @@ dependencies = [
|
||||
"dotenv",
|
||||
"figment",
|
||||
"futures",
|
||||
"humantime",
|
||||
"itertools 0.14.0",
|
||||
"md5",
|
||||
"rand",
|
||||
@@ -780,6 +781,12 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.6.0"
|
||||
|
||||
@@ -23,6 +23,7 @@ directories = "6"
|
||||
|
||||
ratatui = "0.29"
|
||||
crossterm = { version = "0.28.1", features = ["event-stream", "serde"] }
|
||||
humantime = "2.2"
|
||||
|
||||
tokio = { version = "1.43", features = ["macros", "rt"] }
|
||||
tokio-stream = "0.1"
|
||||
|
||||
@@ -160,7 +160,11 @@ impl App {
|
||||
Action::Init => self.tx.send(Action::RandomQueue)?,
|
||||
Action::TryPlaySong(id) => self.player.try_play(id, self.client.clone())?,
|
||||
Action::AddToSink(id) => {
|
||||
self.player.add_to_sink(id)?;
|
||||
let res = self.player.add_to_sink(id);
|
||||
if res.is_err(){
|
||||
self.tx.send(Action::TrackEnded)?;
|
||||
}
|
||||
res?
|
||||
}
|
||||
Action::ScrollUp => {
|
||||
if self.mode == Mode::Queue {
|
||||
|
||||
@@ -84,6 +84,10 @@ impl Player {
|
||||
|
||||
/// Add the song specified by the index to the sink
|
||||
pub fn add_to_sink(&mut self, index: usize) -> Result<()> {
|
||||
if self.sink.empty() {
|
||||
// set only if is first to be added to sink
|
||||
self.current_playing = index;
|
||||
}
|
||||
// Retrieve file from index
|
||||
let id = self.songs_list.lock().unwrap()[index].id.clone();
|
||||
let mut path = config::temp_dir();
|
||||
@@ -94,11 +98,6 @@ impl Player {
|
||||
// This help having a constant volume
|
||||
let agc_source = decoder.automatic_gain_control(1.0, 4.0, 0.005, 5.0);
|
||||
|
||||
if self.sink.empty() {
|
||||
// set only if is first to be added to sink
|
||||
self.current_playing = index;
|
||||
}
|
||||
|
||||
self.sink.append(agc_source);
|
||||
debug!("{id} added to sink");
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use humantime::format_duration;
|
||||
use itertools::Itertools;
|
||||
use ratatui::{layout::Constraint::*, prelude::*, widgets::*};
|
||||
use ratatui::{
|
||||
@@ -5,6 +6,7 @@ use ratatui::{
|
||||
widgets::{StatefulWidget, Table, TableState},
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use style::Styled;
|
||||
|
||||
use subsonic_types::response::Child;
|
||||
@@ -29,13 +31,10 @@ impl StatefulWidget for &Queue {
|
||||
type State = TableState;
|
||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||
if !self.songs_list.lock().unwrap().is_empty() {
|
||||
let vertical_pad = |line| Text::from(vec!["".into(), line, "".into()]);
|
||||
let header_cells = ["#", "Title", "Artist", "Duration"]
|
||||
.map(|h| h.bold().into())
|
||||
.map(vertical_pad);
|
||||
let header = Row::new(header_cells).height(3);
|
||||
let header_cells = ["#", "Title", "Artist", "Duration"].map(|h| h.bold());
|
||||
let header = Row::new(header_cells).height(2);
|
||||
|
||||
let column_widths = [Max(4), Max(20), Max(20), Max(6)];
|
||||
let column_widths = [Max(4), Min(20), Min(20), Max(8)];
|
||||
|
||||
let list = self.songs_list.lock().unwrap();
|
||||
let rows = list
|
||||
@@ -50,14 +49,36 @@ impl StatefulWidget for &Queue {
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let queue_duration = list.iter().fold(Duration::ZERO, |mut acc, song| {
|
||||
acc += song
|
||||
.duration
|
||||
.map(|sec| sec.to_duration())
|
||||
.unwrap_or(Duration::ZERO);
|
||||
acc
|
||||
});
|
||||
|
||||
let block = Block::new()
|
||||
.border_type(BorderType::Rounded)
|
||||
.borders(Borders::all())
|
||||
.border_style(Style::default().fg(Color::White))
|
||||
.padding(Padding::right(1))
|
||||
.title("Queue")
|
||||
.title(
|
||||
Line::from(format!(
|
||||
"| Total {} songs | {} |",
|
||||
list.len(),
|
||||
format_duration(queue_duration)
|
||||
))
|
||||
.left_aligned(),
|
||||
);
|
||||
|
||||
let table = Table::new(rows, column_widths)
|
||||
.header(header)
|
||||
.column_spacing(3)
|
||||
.column_spacing(2)
|
||||
.highlight_spacing(HighlightSpacing::Always)
|
||||
.row_highlight_style(Style::new().reversed())
|
||||
.column_highlight_style(Style::new().red())
|
||||
.cell_highlight_style(Style::new().blue())
|
||||
.highlight_symbol(">>");
|
||||
.row_highlight_style(Style::new().fg(Color::Magenta))
|
||||
.highlight_symbol(">>")
|
||||
.block(block);
|
||||
|
||||
StatefulWidget::render(table, area, buf, state);
|
||||
} else {
|
||||
@@ -72,6 +93,7 @@ fn row_from_song(index: usize, song: &Child) -> Row {
|
||||
Text::from(index.to_string()),
|
||||
Text::from(song.title.clone()),
|
||||
Text::from(song.artist.clone().unwrap()),
|
||||
Text::from(format!("{:0>2}:{:0>2}", duration / 60, duration % 60)),
|
||||
Text::from(format!("{:0>2}:{:0>2}", duration / 60, duration % 60))
|
||||
.alignment(Alignment::Right),
|
||||
])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user