176 lines
5.0 KiB
Rust
176 lines
5.0 KiB
Rust
pub use crate::popup::Popup;
|
|
use gtk::gdk_pixbuf::Pixbuf;
|
|
use gtk::prelude::*;
|
|
use gtk::{Button, Image, Label, Orientation};
|
|
use mpd_client::responses::{PlayState, Song, Status};
|
|
use std::path::Path;
|
|
use tokio::sync::mpsc;
|
|
|
|
#[derive(Clone)]
|
|
struct IconLabel {
|
|
label: Label,
|
|
container: gtk::Box,
|
|
}
|
|
|
|
impl IconLabel {
|
|
fn new(icon: &str, label: Option<&str>) -> Self {
|
|
let container = gtk::Box::new(Orientation::Horizontal, 5);
|
|
|
|
let icon = Label::new(Some(icon));
|
|
let label = Label::new(label);
|
|
|
|
icon.style_context().add_class("icon");
|
|
label.style_context().add_class("label");
|
|
|
|
container.add(&icon);
|
|
container.add(&label);
|
|
|
|
Self { label, container }
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct MpdPopup {
|
|
pub popup: Popup,
|
|
|
|
cover: Image,
|
|
|
|
title: IconLabel,
|
|
album: IconLabel,
|
|
artist: IconLabel,
|
|
|
|
btn_prev: Button,
|
|
btn_play_pause: Button,
|
|
btn_next: Button,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum PopupEvent {
|
|
Previous,
|
|
Toggle,
|
|
Next,
|
|
}
|
|
|
|
impl MpdPopup {
|
|
pub fn new(popup: Popup, tx: mpsc::Sender<PopupEvent>) -> Self {
|
|
let album_image = Image::builder()
|
|
.width_request(128)
|
|
.height_request(128)
|
|
.name("album-art")
|
|
.build();
|
|
|
|
let info_box = gtk::Box::new(Orientation::Vertical, 10);
|
|
|
|
let title_label = IconLabel::new("\u{f886}", None);
|
|
let album_label = IconLabel::new("\u{f524}", None);
|
|
let artist_label = IconLabel::new("\u{fd01}", None);
|
|
|
|
title_label.container.set_widget_name("title");
|
|
album_label.container.set_widget_name("album");
|
|
artist_label.container.set_widget_name("label");
|
|
|
|
info_box.add(&title_label.container);
|
|
info_box.add(&album_label.container);
|
|
info_box.add(&artist_label.container);
|
|
|
|
let controls_box = gtk::Box::builder().name("controls").build();
|
|
|
|
let btn_prev = Button::builder().label("\u{f9ad}").name("btn-prev").build();
|
|
let btn_play_pause = Button::builder().label("").name("btn-play-pause").build();
|
|
let btn_next = Button::builder().label("\u{f9ac}").name("btn-next").build();
|
|
|
|
controls_box.add(&btn_prev);
|
|
controls_box.add(&btn_play_pause);
|
|
controls_box.add(&btn_next);
|
|
|
|
info_box.add(&controls_box);
|
|
|
|
popup.container.add(&album_image);
|
|
popup.container.add(&info_box);
|
|
|
|
let tx_prev = tx.clone();
|
|
btn_prev.connect_clicked(move |_| {
|
|
tx_prev
|
|
.try_send(PopupEvent::Previous)
|
|
.expect("Failed to send prev track message");
|
|
});
|
|
|
|
let tx_toggle = tx.clone();
|
|
btn_play_pause.connect_clicked(move |_| {
|
|
tx_toggle
|
|
.try_send(PopupEvent::Toggle)
|
|
.expect("Failed to send play/pause track message");
|
|
});
|
|
|
|
let tx_next = tx;
|
|
btn_next.connect_clicked(move |_| {
|
|
tx_next
|
|
.try_send(PopupEvent::Next)
|
|
.expect("Failed to send next track message");
|
|
});
|
|
|
|
Self {
|
|
popup,
|
|
cover: album_image,
|
|
artist: artist_label,
|
|
album: album_label,
|
|
title: title_label,
|
|
btn_prev,
|
|
btn_play_pause,
|
|
btn_next,
|
|
}
|
|
}
|
|
|
|
pub fn update(&self, song: &Song, status: &Status, path: &Path) {
|
|
let prev_album = self.album.label.text();
|
|
let curr_album = song.album().unwrap_or_default();
|
|
|
|
// only update art when album changes
|
|
if prev_album != curr_album {
|
|
let cover_path = path.join(
|
|
song.file_path()
|
|
.parent()
|
|
.expect("Song path should not be root")
|
|
.join("cover.jpg"),
|
|
);
|
|
|
|
if let Ok(pixbuf) = Pixbuf::from_file_at_scale(cover_path, 128, 128, true) {
|
|
self.cover.set_from_pixbuf(Some(&pixbuf));
|
|
}
|
|
}
|
|
|
|
self.title.label.set_text(song.title().unwrap_or_default());
|
|
self.album.label.set_text(song.album().unwrap_or_default());
|
|
self.artist
|
|
.label
|
|
.set_text(song.artists().first().unwrap_or(&String::new()));
|
|
|
|
match status.state {
|
|
PlayState::Stopped => {
|
|
self.btn_play_pause.set_sensitive(false);
|
|
}
|
|
PlayState::Playing => {
|
|
self.btn_play_pause.set_sensitive(true);
|
|
self.btn_play_pause.set_label("");
|
|
}
|
|
PlayState::Paused => {
|
|
self.btn_play_pause.set_sensitive(true);
|
|
self.btn_play_pause.set_label("");
|
|
}
|
|
}
|
|
|
|
let enable_prev = match status.current_song {
|
|
Some((pos, _)) => pos.0 > 0,
|
|
None => false,
|
|
};
|
|
|
|
let enable_next = match status.current_song {
|
|
Some((pos, _)) => pos.0 < status.playlist_length,
|
|
None => false,
|
|
};
|
|
|
|
self.btn_prev.set_sensitive(enable_prev);
|
|
self.btn_next.set_sensitive(enable_next);
|
|
}
|
|
}
|