Show tracks + duration of album, playlist, queue
Stats are in the top right Fixes #475
This commit is contained in:
@@ -69,6 +69,7 @@ mod theme;
|
|||||||
mod track;
|
mod track;
|
||||||
mod traits;
|
mod traits;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
#[cfg(feature = "mpris")]
|
#[cfg(feature = "mpris")]
|
||||||
mod mpris;
|
mod mpris;
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ pub trait ViewExt: View {
|
|||||||
"".into()
|
"".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_sub(&self) -> String {
|
||||||
|
"".into()
|
||||||
|
}
|
||||||
|
|
||||||
fn on_leave(&self) {}
|
fn on_leave(&self) {}
|
||||||
|
|
||||||
fn on_command(&mut self, _s: &mut Cursive, _cmd: &Command) -> Result<CommandResult, String> {
|
fn on_command(&mut self, _s: &mut Cursive, _cmd: &Command) -> Result<CommandResult, String> {
|
||||||
@@ -67,6 +71,10 @@ impl<V: ViewExt> ViewExt for NamedView<V> {
|
|||||||
self.with_view(|v| v.title()).unwrap_or_default()
|
self.with_view(|v| v.title()).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_sub(&self) -> String {
|
||||||
|
self.with_view(|v| v.title_sub()).unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
fn on_leave(&self) {
|
fn on_leave(&self) {
|
||||||
self.with_view(|v| v.on_leave());
|
self.with_view(|v| v.on_leave());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,17 @@ impl ViewExt for AlbumView {
|
|||||||
format!("{} ({})", self.album.title, self.album.year)
|
format!("{} ({})", self.album.title, self.album.year)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_sub(&self) -> String {
|
||||||
|
if let Some(tracks) = &self.album.tracks {
|
||||||
|
let duration_secs: u64 = tracks.iter().map(|t| t.duration as u64 / 1000).sum();
|
||||||
|
let duration = std::time::Duration::from_secs(duration_secs);
|
||||||
|
let duration_str = crate::utils::format_duration(&duration);
|
||||||
|
format!("{} tracks, {}", tracks.len(), duration_str)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
||||||
self.tabs.on_command(s, cmd)
|
self.tabs.on_command(s, cmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,6 +219,11 @@ impl View for Layout {
|
|||||||
printer.print((offset, 0), &view.title());
|
printer.print((offset, 0), &view.title());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
printer.with_color(ColorStyle::secondary(), |printer| {
|
||||||
|
let offset = HAlign::Right.get_offset(view.title_sub().width(), printer.size.x);
|
||||||
|
printer.print((offset, 0), &view.title_sub());
|
||||||
|
});
|
||||||
|
|
||||||
// screen content
|
// screen content
|
||||||
let printer = &printer
|
let printer = &printer
|
||||||
.offset((0, 1))
|
.offset((0, 1))
|
||||||
|
|||||||
@@ -62,6 +62,20 @@ impl ViewExt for PlaylistView {
|
|||||||
self.playlist.name.clone()
|
self.playlist.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_sub(&self) -> String {
|
||||||
|
if let Some(tracks) = self.playlist.tracks.as_ref() {
|
||||||
|
let duration_secs = tracks.iter().map(|p| p.duration as u64 / 1000).sum();
|
||||||
|
let duration = std::time::Duration::from_secs(duration_secs);
|
||||||
|
format!(
|
||||||
|
"{} tracks, {}",
|
||||||
|
tracks.len(),
|
||||||
|
crate::utils::format_duration(&duration)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
||||||
if let Command::Delete = cmd {
|
if let Command::Delete = cmd {
|
||||||
let pos = self.list.get_selected_index();
|
let pos = self.list.get_selected_index();
|
||||||
|
|||||||
@@ -93,6 +93,29 @@ impl ViewExt for QueueView {
|
|||||||
"Queue".to_string()
|
"Queue".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_sub(&self) -> String {
|
||||||
|
let track_count = self.queue.len();
|
||||||
|
let duration_secs: u64 = self
|
||||||
|
.queue
|
||||||
|
.queue
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.duration() as u64 / 1000)
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
if duration_secs > 0 {
|
||||||
|
let duration = std::time::Duration::from_secs(duration_secs);
|
||||||
|
format!(
|
||||||
|
"{} tracks, {}",
|
||||||
|
track_count,
|
||||||
|
crate::utils::format_duration(&duration)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
||||||
match cmd {
|
match cmd {
|
||||||
Command::Play => {
|
Command::Play => {
|
||||||
|
|||||||
21
src/utils.rs
Normal file
21
src/utils.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/// Returns a human readable String of a Duration
|
||||||
|
///
|
||||||
|
/// Example: `3h 12m 53s`
|
||||||
|
pub fn format_duration(d: &std::time::Duration) -> String {
|
||||||
|
let mut s = String::new();
|
||||||
|
let mut append_unit = |value, unit| {
|
||||||
|
if value > 0 {
|
||||||
|
s.push_str(&format!("{}{}", value, unit));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let seconds = d.as_secs() % 60;
|
||||||
|
let minutes = (d.as_secs() / 60) % 60;
|
||||||
|
let hours = (d.as_secs() / 60) / 60;
|
||||||
|
|
||||||
|
append_unit(hours, "h ");
|
||||||
|
append_unit(minutes, "m ");
|
||||||
|
append_unit(seconds, "s ");
|
||||||
|
|
||||||
|
s.trim_end().to_string()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user