mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-07-01 10:41:03 +02:00
feat(music): support for using images in name_map
, additional icon options
This commit is contained in:
parent
b054c17d14
commit
96141d4990
3 changed files with 158 additions and 79 deletions
|
@ -8,12 +8,34 @@ pub struct Icons {
|
|||
/// Icon to display when playing.
|
||||
#[serde(default = "default_icon_play")]
|
||||
pub(crate) play: String,
|
||||
|
||||
/// Icon to display when paused.
|
||||
#[serde(default = "default_icon_pause")]
|
||||
pub(crate) pause: String,
|
||||
|
||||
/// Icon to display for previous button.
|
||||
#[serde(default = "default_icon_prev")]
|
||||
pub(crate) prev: String,
|
||||
|
||||
/// Icon to display for next button.
|
||||
#[serde(default = "default_icon_next")]
|
||||
pub(crate) next: String,
|
||||
|
||||
/// Icon to display under volume slider
|
||||
#[serde(default = "default_icon_volume")]
|
||||
pub(crate) volume: String,
|
||||
|
||||
/// Icon to display nex to track title
|
||||
#[serde(default = "default_icon_track")]
|
||||
pub(crate) track: String,
|
||||
|
||||
/// Icon to display nex to album name
|
||||
#[serde(default = "default_icon_album")]
|
||||
pub(crate) album: String,
|
||||
|
||||
/// Icon to display nex to artist name
|
||||
#[serde(default = "default_icon_artist")]
|
||||
pub(crate) artist: String,
|
||||
}
|
||||
|
||||
impl Default for Icons {
|
||||
|
@ -21,7 +43,12 @@ impl Default for Icons {
|
|||
Self {
|
||||
pause: default_icon_pause(),
|
||||
play: default_icon_play(),
|
||||
prev: default_icon_prev(),
|
||||
next: default_icon_next(),
|
||||
volume: default_icon_volume(),
|
||||
track: default_icon_track(),
|
||||
album: default_icon_album(),
|
||||
artist: default_icon_artist(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +100,7 @@ fn default_socket() -> String {
|
|||
}
|
||||
|
||||
fn default_format() -> String {
|
||||
String::from("{icon} {title} / {artist}")
|
||||
String::from("{title} / {artist}")
|
||||
}
|
||||
|
||||
fn default_icon_play() -> String {
|
||||
|
@ -84,10 +111,30 @@ fn default_icon_pause() -> String {
|
|||
String::from("")
|
||||
}
|
||||
|
||||
fn default_icon_prev() -> String {
|
||||
String::from("\u{f9ad}")
|
||||
}
|
||||
|
||||
fn default_icon_next() -> String {
|
||||
String::from("\u{f9ac}")
|
||||
}
|
||||
|
||||
fn default_icon_volume() -> String {
|
||||
String::from("墳")
|
||||
}
|
||||
|
||||
fn default_icon_track() -> String {
|
||||
String::from("\u{f886}")
|
||||
}
|
||||
|
||||
fn default_icon_album() -> String {
|
||||
String::from("\u{f524}")
|
||||
}
|
||||
|
||||
fn default_icon_artist() -> String {
|
||||
String::from("\u{fd01}")
|
||||
}
|
||||
|
||||
fn default_music_dir() -> PathBuf {
|
||||
audio_dir().unwrap_or_else(|| home_dir().map(|dir| dir.join("Music")).unwrap_or_default())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod config;
|
||||
|
||||
use crate::clients::music::{self, MusicClient, PlayerState, PlayerUpdate, Status, Track};
|
||||
use crate::image::ImageProvider;
|
||||
use crate::image::{new_icon_button, new_icon_label, ImageProvider};
|
||||
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
||||
use crate::popup::Popup;
|
||||
use crate::{send_async, try_send};
|
||||
|
@ -18,7 +18,7 @@ use tokio::sync::mpsc::{Receiver, Sender};
|
|||
use tracing::error;
|
||||
|
||||
pub use self::config::MusicModule;
|
||||
use self::config::{Icons, PlayerType};
|
||||
use self::config::PlayerType;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PlayerCommand {
|
||||
|
@ -80,7 +80,6 @@ impl Module<Button> for MusicModule {
|
|||
mut rx: Receiver<Self::ReceiveMessage>,
|
||||
) -> Result<()> {
|
||||
let format = self.format.clone();
|
||||
let icons = self.icons.clone();
|
||||
|
||||
let re = Regex::new(r"\{([\w-]+)}")?;
|
||||
let tokens = get_tokens(&re, self.format.as_str());
|
||||
|
@ -102,13 +101,8 @@ impl Module<Button> for MusicModule {
|
|||
match update {
|
||||
PlayerUpdate::Update(track, status) => match *track {
|
||||
Some(track) => {
|
||||
let display_string = replace_tokens(
|
||||
format.as_str(),
|
||||
&tokens,
|
||||
&track,
|
||||
&status,
|
||||
&icons,
|
||||
);
|
||||
let display_string =
|
||||
replace_tokens(format.as_str(), &tokens, &track, &status);
|
||||
|
||||
let update = SongUpdate {
|
||||
song: track,
|
||||
|
@ -160,15 +154,22 @@ impl Module<Button> for MusicModule {
|
|||
info: &ModuleInfo,
|
||||
) -> Result<ModuleWidget<Button>> {
|
||||
let button = Button::new();
|
||||
let button_contents = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
button.add(&button_contents);
|
||||
|
||||
let icon_play = new_icon_label(&self.icons.play, info.icon_theme, 24);
|
||||
let icon_pause = new_icon_label(&self.icons.pause, info.icon_theme, 24);
|
||||
let label = Label::new(None);
|
||||
|
||||
label.set_angle(info.bar_position.get_angle());
|
||||
|
||||
if let Some(truncate) = self.truncate {
|
||||
truncate.truncate_label(&label);
|
||||
}
|
||||
|
||||
button.add(&label);
|
||||
button_contents.add(&icon_pause);
|
||||
button_contents.add(&icon_play);
|
||||
button_contents.add(&label);
|
||||
|
||||
let orientation = info.bar_position.get_orientation();
|
||||
|
||||
|
@ -190,6 +191,21 @@ impl Module<Button> for MusicModule {
|
|||
context.widget_rx.attach(None, move |mut event| {
|
||||
if let Some(event) = event.take() {
|
||||
label.set_label(&event.display_string);
|
||||
|
||||
match event.status.state {
|
||||
PlayerState::Playing => {
|
||||
icon_play.show();
|
||||
icon_pause.hide();
|
||||
}
|
||||
PlayerState::Paused => {
|
||||
icon_pause.show();
|
||||
icon_play.hide();
|
||||
}
|
||||
PlayerState::Stopped => {
|
||||
button.hide();
|
||||
}
|
||||
}
|
||||
|
||||
button.show();
|
||||
} else {
|
||||
button.hide();
|
||||
|
@ -212,9 +228,9 @@ impl Module<Button> for MusicModule {
|
|||
self,
|
||||
tx: Sender<Self::ReceiveMessage>,
|
||||
rx: glib::Receiver<Self::SendMessage>,
|
||||
_info: &ModuleInfo,
|
||||
info: &ModuleInfo,
|
||||
) -> Option<gtk::Box> {
|
||||
let icon_theme = IconTheme::new();
|
||||
let icon_theme = info.icon_theme;
|
||||
|
||||
let container = gtk::Box::builder()
|
||||
.orientation(Orientation::Horizontal)
|
||||
|
@ -228,10 +244,12 @@ impl Module<Button> for MusicModule {
|
|||
.name("album-art")
|
||||
.build();
|
||||
|
||||
let icons = self.icons;
|
||||
|
||||
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);
|
||||
let title_label = IconLabel::new(&icons.track, None, icon_theme);
|
||||
let album_label = IconLabel::new(&icons.album, None, icon_theme);
|
||||
let artist_label = IconLabel::new(&icons.artist, None, icon_theme);
|
||||
|
||||
title_label.container.set_widget_name("title");
|
||||
album_label.container.set_widget_name("album");
|
||||
|
@ -242,12 +260,22 @@ impl Module<Button> for MusicModule {
|
|||
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();
|
||||
|
||||
let btn_prev = new_icon_button(&icons.prev, icon_theme, 24);
|
||||
btn_prev.set_widget_name("btn-prev");
|
||||
|
||||
let btn_play = new_icon_button(&icons.play, icon_theme, 24);
|
||||
btn_play.set_widget_name("btn-play");
|
||||
|
||||
let btn_pause = new_icon_button(&icons.pause, icon_theme, 24);
|
||||
btn_pause.set_widget_name("btn-pause");
|
||||
|
||||
let btn_next = new_icon_button(&icons.next, icon_theme, 24);
|
||||
btn_next.set_widget_name("btn-next");
|
||||
|
||||
controls_box.add(&btn_prev);
|
||||
controls_box.add(&btn_play_pause);
|
||||
controls_box.add(&btn_play);
|
||||
controls_box.add(&btn_pause);
|
||||
controls_box.add(&btn_next);
|
||||
|
||||
info_box.add(&controls_box);
|
||||
|
@ -262,7 +290,7 @@ impl Module<Button> for MusicModule {
|
|||
volume_slider.set_inverted(true);
|
||||
volume_slider.set_widget_name("slider");
|
||||
|
||||
let volume_icon = Label::new(Some(&self.icons.volume));
|
||||
let volume_icon = new_icon_label(&icons.volume, icon_theme, 24);
|
||||
volume_icon.style_context().add_class("icon");
|
||||
|
||||
volume_box.pack_start(&volume_slider, true, true, 0);
|
||||
|
@ -277,13 +305,14 @@ impl Module<Button> for MusicModule {
|
|||
try_send!(tx_prev, PlayerCommand::Previous);
|
||||
});
|
||||
|
||||
let tx_toggle = tx.clone();
|
||||
btn_play_pause.connect_clicked(move |button| {
|
||||
if button.style_context().has_class("playing") {
|
||||
try_send!(tx_toggle, PlayerCommand::Pause);
|
||||
} else {
|
||||
try_send!(tx_toggle, PlayerCommand::Play);
|
||||
}
|
||||
let tx_play = tx.clone();
|
||||
btn_play.connect_clicked(move |_| {
|
||||
try_send!(tx_play, PlayerCommand::Play);
|
||||
});
|
||||
|
||||
let tx_pause = tx.clone();
|
||||
btn_pause.connect_clicked(move |_| {
|
||||
try_send!(tx_pause, PlayerCommand::Pause);
|
||||
});
|
||||
|
||||
let tx_next = tx.clone();
|
||||
|
@ -300,6 +329,8 @@ impl Module<Button> for MusicModule {
|
|||
container.show_all();
|
||||
|
||||
{
|
||||
let icon_theme = icon_theme.clone();
|
||||
|
||||
let mut prev_cover = None;
|
||||
rx.attach(None, move |update| {
|
||||
if let Some(update) = update {
|
||||
|
@ -308,7 +339,7 @@ impl Module<Button> for MusicModule {
|
|||
if prev_cover != new_cover {
|
||||
prev_cover = new_cover.clone();
|
||||
let res = match new_cover
|
||||
.map(|cover_path| ImageProvider::parse(cover_path, &icon_theme, 128))
|
||||
.map(|cover_path| ImageProvider::parse(&cover_path, &icon_theme, 128))
|
||||
{
|
||||
Some(Ok(image)) => image.load_into_image(album_image.clone()),
|
||||
Some(Err(err)) => {
|
||||
|
@ -337,23 +368,23 @@ impl Module<Button> for MusicModule {
|
|||
|
||||
match update.status.state {
|
||||
PlayerState::Stopped => {
|
||||
btn_play_pause.set_sensitive(false);
|
||||
btn_pause.hide();
|
||||
btn_play.show();
|
||||
btn_play.set_sensitive(false);
|
||||
}
|
||||
PlayerState::Playing => {
|
||||
btn_play_pause.set_sensitive(true);
|
||||
btn_play_pause.set_label(&self.icons.pause);
|
||||
btn_play.set_sensitive(false);
|
||||
btn_play.hide();
|
||||
|
||||
let style_context = btn_play_pause.style_context();
|
||||
style_context.add_class("playing");
|
||||
style_context.remove_class("paused");
|
||||
btn_pause.set_sensitive(true);
|
||||
btn_pause.show();
|
||||
}
|
||||
PlayerState::Paused => {
|
||||
btn_play_pause.set_sensitive(true);
|
||||
btn_play_pause.set_label(&self.icons.play);
|
||||
btn_pause.set_sensitive(false);
|
||||
btn_pause.hide();
|
||||
|
||||
let style_context = btn_play_pause.style_context();
|
||||
style_context.add_class("paused");
|
||||
style_context.remove_class("playing");
|
||||
btn_play.set_sensitive(true);
|
||||
btn_play.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,11 +414,10 @@ fn replace_tokens(
|
|||
tokens: &Vec<String>,
|
||||
song: &Track,
|
||||
status: &Status,
|
||||
icons: &Icons,
|
||||
) -> String {
|
||||
let mut compiled_string = format_string.to_string();
|
||||
for token in tokens {
|
||||
let value = get_token_value(song, status, icons, token);
|
||||
let value = get_token_value(song, status, token);
|
||||
compiled_string = compiled_string.replace(format!("{{{token}}}").as_str(), value.as_str());
|
||||
}
|
||||
compiled_string
|
||||
|
@ -395,14 +425,8 @@ fn replace_tokens(
|
|||
|
||||
/// Converts a string format token value
|
||||
/// into its respective value.
|
||||
fn get_token_value(song: &Track, status: &Status, icons: &Icons, token: &str) -> String {
|
||||
fn get_token_value(song: &Track, status: &Status, token: &str) -> String {
|
||||
match token {
|
||||
"icon" => match status.state {
|
||||
PlayerState::Stopped => None,
|
||||
PlayerState::Playing => Some(&icons.play),
|
||||
PlayerState::Paused => Some(&icons.pause),
|
||||
}
|
||||
.map(std::string::ToString::to_string),
|
||||
"title" => song.title.clone(),
|
||||
"album" => song.album.clone(),
|
||||
"artist" => song.artist.clone(),
|
||||
|
@ -417,17 +441,17 @@ fn get_token_value(song: &Track, status: &Status, icons: &Icons, token: &str) ->
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct IconLabel {
|
||||
label: Label,
|
||||
container: gtk::Box,
|
||||
}
|
||||
|
||||
impl IconLabel {
|
||||
fn new(icon: &str, label: Option<&str>) -> Self {
|
||||
fn new(icon_input: &str, label: Option<&str>, icon_theme: &IconTheme) -> Self {
|
||||
let container = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
|
||||
let icon = Label::new(Some(icon));
|
||||
let icon = new_icon_label(icon_input, icon_theme, 32);
|
||||
let label = Label::new(label);
|
||||
|
||||
icon.style_context().add_class("icon");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue