use std::cell::RefMut; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Duration; use color_eyre::Result; use glib::{markup_escape_text, Propagation, PropertySet}; use gtk::prelude::*; use gtk::{Button, IconTheme, Label, Orientation, Scale}; use regex::Regex; use tokio::sync::{broadcast, mpsc}; use tracing::error; use crate::clients::music::{ self, MusicClient, PlayerState, PlayerUpdate, ProgressTick, Status, Track, }; use crate::clients::Clients; use crate::gtk_helpers::{IronbarGtkExt, IronbarLabelExt}; use crate::image::{new_icon_button, new_icon_label, ImageProvider}; use crate::modules::PopupButton; use crate::modules::{ Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext, }; use crate::{glib_recv, module_impl, send_async, spawn, try_send}; pub use self::config::MusicModule; use self::config::PlayerType; mod config; #[derive(Debug)] pub enum PlayerCommand { Previous, Play, Pause, Next, Volume(u8), Seek(Duration), } /// Formats a duration given in seconds /// in hh:mm format fn format_time(duration: Duration) -> String { let time = duration.as_secs(); let minutes = (time / 60) % 60; let seconds = time % 60; format!("{minutes:0>2}:{seconds:0>2}") } /// Extracts the formatting tokens from a formatting string fn get_tokens(re: &Regex, format_string: &str) -> Vec { re.captures_iter(format_string) .map(|caps| caps[1].to_string()) .collect::>() } #[derive(Clone, Debug)] pub enum ControllerEvent { Update(Option), UpdateProgress(ProgressTick), } #[derive(Clone, Debug)] pub struct SongUpdate { song: Track, status: Status, display_string: String, } fn get_client( mut clients: RefMut<'_, Clients>, player_type: PlayerType, host: String, music_dir: PathBuf, ) -> Arc { let client_type = match player_type { PlayerType::Mpd => music::ClientType::Mpd { host, music_dir }, PlayerType::Mpris => music::ClientType::Mpris, }; clients.music(client_type) } impl Module