Files
ncspot/src/ui/statusbar.rs
2020-07-17 23:48:33 +02:00

230 lines
6.9 KiB
Rust

use std::sync::Arc;
use cursive::align::HAlign;
use cursive::event::{Event, EventResult, MouseButton, MouseEvent};
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
use cursive::traits::View;
use cursive::vec::Vec2;
use cursive::Printer;
use unicode_width::UnicodeWidthStr;
use crate::library::Library;
use crate::queue::{Queue, RepeatSetting};
use crate::spotify::{PlayerEvent, Spotify};
pub struct StatusBar {
queue: Arc<Queue>,
spotify: Arc<Spotify>,
library: Arc<Library>,
last_size: Vec2,
use_nerdfont: bool,
}
impl StatusBar {
pub fn new(queue: Arc<Queue>, library: Arc<Library>, use_nerdfont: bool) -> StatusBar {
let spotify = queue.get_spotify();
StatusBar {
queue,
spotify,
library,
last_size: Vec2::new(0, 0),
use_nerdfont,
}
}
}
impl View for StatusBar {
fn draw(&self, printer: &Printer<'_, '_>) {
if printer.size.x == 0 {
return;
}
let style_bar = ColorStyle::new(
ColorType::Color(*printer.theme.palette.custom("statusbar_progress").unwrap()),
ColorType::Palette(PaletteColor::Background),
);
let style_bar_bg = ColorStyle::new(
ColorType::Color(
*printer
.theme
.palette
.custom("statusbar_progress_bg")
.unwrap(),
),
ColorType::Palette(PaletteColor::Background),
);
let style = ColorStyle::new(
ColorType::Color(*printer.theme.palette.custom("statusbar").unwrap()),
ColorType::Color(*printer.theme.palette.custom("statusbar_bg").unwrap()),
);
printer.print(
(0, 0),
&vec![' '; printer.size.x].into_iter().collect::<String>(),
);
printer.with_color(style, |printer| {
printer.print(
(0, 1),
&vec![' '; printer.size.x].into_iter().collect::<String>(),
);
});
let state_icon = if self.use_nerdfont {
match self.spotify.get_current_status() {
PlayerEvent::Playing => "\u{f909} ",
PlayerEvent::Paused => "\u{f8e3} ",
PlayerEvent::Stopped | PlayerEvent::FinishedTrack => "\u{f9da} ",
}
} else {
match self.spotify.get_current_status() {
PlayerEvent::Playing => "",
PlayerEvent::Paused => "▮▮",
PlayerEvent::Stopped | PlayerEvent::FinishedTrack => "",
}
}
.to_string();
printer.with_color(style, |printer| {
printer.print((1, 1), &state_icon);
});
let updating = if !*self.library.is_done.read().unwrap() {
if self.use_nerdfont {
"\u{f9e5} "
} else {
"[U] "
}
} else {
""
};
let repeat = if self.use_nerdfont {
match self.queue.get_repeat() {
RepeatSetting::None => "",
RepeatSetting::RepeatPlaylist => "\u{f955} ",
RepeatSetting::RepeatTrack => "\u{f957} ",
}
} else {
match self.queue.get_repeat() {
RepeatSetting::None => "",
RepeatSetting::RepeatPlaylist => "[R] ",
RepeatSetting::RepeatTrack => "[R1] ",
}
};
let shuffle = if self.queue.get_shuffle() {
if self.use_nerdfont {
"\u{f99c} "
} else {
"[Z] "
}
} else {
""
};
let volume = format!(
" [{}%]",
(self.spotify.volume() as f64 / 65535_f64 * 100.0) as u16
);
printer.with_color(style_bar_bg, |printer| {
printer.print((0, 0), &"".repeat(printer.size.x));
});
let elapsed = self.spotify.get_current_progress();
let elapsed_ms = elapsed.as_millis() as u32;
let formatted_elapsed = format!(
"{:02}:{:02}",
elapsed.as_secs() / 60,
elapsed.as_secs() % 60
);
let playback_duration_status = match self.queue.get_current() {
Some(ref t) => format!("{} / {}", formatted_elapsed, t.duration_str()),
None => "".to_string(),
};
let right = updating.to_string()
+ repeat
+ shuffle
// + saved
+ &playback_duration_status
+ &volume;
let offset = HAlign::Right.get_offset(right.width(), printer.size.x);
printer.with_color(style, |printer| {
if let Some(ref t) = self.queue.get_current() {
printer.print((4, 1), &t.to_string());
}
printer.print((offset, 1), &right);
});
if let Some(t) = self.queue.get_current() {
printer.with_color(style_bar, |printer| {
let duration_width =
(((printer.size.x as u32) * elapsed_ms) / t.duration()) as usize;
printer.print((0, 0), &"".repeat(duration_width + 1));
});
}
// if let Some(Playable::Track(ref t)) = self.queue.get_current() {
// let saved = if self.library.is_saved_track(&Playable::Track(t.clone())) {
// if self.use_nerdfont {
// "\u{f62b} "
// } else {
// "✓ "
// }
// } else {
// ""
// };
// }
}
fn layout(&mut self, size: Vec2) {
self.last_size = size;
}
fn required_size(&mut self, constraint: Vec2) -> Vec2 {
Vec2::new(constraint.x, 2)
}
fn on_event(&mut self, event: Event) -> EventResult {
if let Event::Mouse {
offset,
position,
event,
} = event
{
let position = position - offset;
if position.y == 0 {
if event == MouseEvent::WheelUp {
self.spotify.seek_relative(-500);
}
if event == MouseEvent::WheelDown {
self.spotify.seek_relative(500);
}
if event == MouseEvent::Press(MouseButton::Left)
|| event == MouseEvent::Hold(MouseButton::Left)
{
if let Some(playable) = self.queue.get_current() {
let f: f32 = position.x as f32 / self.last_size.x as f32;
let new = playable.duration() as f32 * f;
self.spotify.seek(new as u32);
}
}
} else if event == MouseEvent::Press(MouseButton::Left) {
self.queue.toggleplayback();
}
EventResult::Consumed(None)
} else {
EventResult::Ignored
}
}
}