feat: mpris player widget
This commit is contained in:
@@ -4,7 +4,7 @@ from fabric.widgets.image import Image
|
|||||||
from fabric.widgets.overlay import Overlay
|
from fabric.widgets.overlay import Overlay
|
||||||
from fabric.widgets.datetime import DateTime
|
from fabric.widgets.datetime import DateTime
|
||||||
from fabric.widgets.centerbox import CenterBox
|
from fabric.widgets.centerbox import CenterBox
|
||||||
from sims.modules.player import Player
|
from sims.modules.player import Player, PlayerSmall
|
||||||
from sims.modules.battery import Battery
|
from sims.modules.battery import Battery
|
||||||
from sims.modules.control_center import ControlCenter
|
from sims.modules.control_center import ControlCenter
|
||||||
from sims.modules.notmuch import NotmuchWidget
|
from sims.modules.notmuch import NotmuchWidget
|
||||||
@@ -82,6 +82,7 @@ class StatusBar(Window):
|
|||||||
overlays=[self.cpu_progress_bar, self.progress_label],
|
overlays=[self.cpu_progress_bar, self.progress_label],
|
||||||
)
|
)
|
||||||
self.player = Player()
|
self.player = Player()
|
||||||
|
self.player_small = PlayerSmall()
|
||||||
|
|
||||||
self.battery = None
|
self.battery = None
|
||||||
if BATTERY["enable"]:
|
if BATTERY["enable"]:
|
||||||
@@ -132,6 +133,7 @@ class StatusBar(Window):
|
|||||||
children=[
|
children=[
|
||||||
Image(name="nixos-label", icon_name="nix-snowflake-white", icon_size=20),
|
Image(name="nixos-label", icon_name="nix-snowflake-white", icon_size=20),
|
||||||
self.workspaces,
|
self.workspaces,
|
||||||
|
self.player_small,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
center_children=Box(
|
center_children=Box(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from fabric.widgets.box import Box
|
|||||||
from fabric.widgets.centerbox import CenterBox
|
from fabric.widgets.centerbox import CenterBox
|
||||||
from fabric.widgets.label import Label
|
from fabric.widgets.label import Label
|
||||||
from fabric.widgets.button import Button
|
from fabric.widgets.button import Button
|
||||||
|
from fabric.widgets.image import Image
|
||||||
from fabric.widgets.circularprogressbar import CircularProgressBar
|
from fabric.widgets.circularprogressbar import CircularProgressBar
|
||||||
from fabric.widgets.overlay import Overlay
|
from fabric.widgets.overlay import Overlay
|
||||||
from fabric.widgets.stack import Stack
|
from fabric.widgets.stack import Stack
|
||||||
@@ -522,30 +523,52 @@ class Player(Box):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class PlayerSmall(CenterBox):
|
class PlayerSmall(Box):
|
||||||
|
PLAY_ICON = "media-playback-start-symbolic"
|
||||||
|
PAUSE_ICON = "media-playback-pause-symbolic"
|
||||||
|
PREV_ICON = "media-skip-backward-symbolic"
|
||||||
|
NEXT_ICON = "media-skip-forward-symbolic"
|
||||||
|
FALLBACK_ICON = "audio-x-generic-symbolic"
|
||||||
|
COVER_SIZE = 22
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
name="player-small", orientation="h", h_align="fill", v_align="center"
|
name="player-small", orientation="h", v_align="center"
|
||||||
)
|
)
|
||||||
self._show_artist = False # toggle flag
|
self._display_options = ["title", "artist"]
|
||||||
self._display_options = ["cavalcade", "title", "artist"]
|
|
||||||
self._display_index = 0
|
self._display_index = 0
|
||||||
self._current_display = "cavalcade"
|
self._current_display = "title"
|
||||||
|
self._spin_timer_id = None
|
||||||
|
self._spin_step = 2 # deg per tick → ~9s per rotation at 50ms
|
||||||
|
self._spin_interval_ms = 50
|
||||||
|
|
||||||
|
self.cover = CircleImage(
|
||||||
|
name="compact-mpris-cover",
|
||||||
|
size=self.COVER_SIZE,
|
||||||
|
h_align="center",
|
||||||
|
v_align="center",
|
||||||
|
)
|
||||||
|
self.fallback_icon = Image(
|
||||||
|
name="compact-mpris-fallback",
|
||||||
|
icon_name=self.FALLBACK_ICON,
|
||||||
|
icon_size=16,
|
||||||
|
)
|
||||||
|
self.cover_stack = Stack(
|
||||||
|
name="compact-mpris-cover-stack",
|
||||||
|
transition_type="crossfade",
|
||||||
|
transition_duration=200,
|
||||||
|
children=[self.fallback_icon, self.cover],
|
||||||
|
)
|
||||||
|
self.cover_stack.set_visible_child(self.fallback_icon)
|
||||||
|
|
||||||
self.mpris_icon = Button(
|
self.mpris_icon = Button(
|
||||||
name="compact-mpris-icon",
|
name="compact-mpris-icon",
|
||||||
h_align="center",
|
h_align="center",
|
||||||
v_align="center",
|
v_align="center",
|
||||||
child=Label(name="compact-mpris-icon-label", markup=icons.disc),
|
child=self.cover_stack,
|
||||||
)
|
)
|
||||||
# Remove scroll events; instead, add button press events.
|
|
||||||
self.mpris_icon.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
self.mpris_icon.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
||||||
self.mpris_icon.connect("button-press-event", self._on_icon_button_press)
|
self.mpris_icon.connect("button-press-event", self._on_icon_button_press)
|
||||||
# Prevent the child from propagating events.
|
|
||||||
child = self.mpris_icon.get_child()
|
|
||||||
child.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
|
||||||
child.connect("button-press-event", lambda widget, event: True)
|
|
||||||
# Add hover effect
|
|
||||||
add_hover_cursor(self.mpris_icon)
|
add_hover_cursor(self.mpris_icon)
|
||||||
|
|
||||||
self.mpris_label = Label(
|
self.mpris_label = Label(
|
||||||
@@ -555,36 +578,33 @@ class PlayerSmall(CenterBox):
|
|||||||
max_chars_width=26,
|
max_chars_width=26,
|
||||||
h_align="center",
|
h_align="center",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.play_image = Image(
|
||||||
|
name="compact-mpris-button-icon",
|
||||||
|
icon_name=self.PLAY_ICON,
|
||||||
|
icon_size=16,
|
||||||
|
)
|
||||||
self.mpris_button = Button(
|
self.mpris_button = Button(
|
||||||
name="compact-mpris-button",
|
name="compact-mpris-button",
|
||||||
h_align="center",
|
h_align="center",
|
||||||
v_align="center",
|
v_align="center",
|
||||||
child=Label(name="compact-mpris-button-label", markup=icons.play),
|
child=self.play_image,
|
||||||
)
|
)
|
||||||
self.mpris_button.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
self.mpris_button.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
|
||||||
self.mpris_button.connect(
|
self.mpris_button.connect(
|
||||||
"button-press-event", self._on_play_pause_button_press
|
"button-press-event", self._on_play_pause_button_press
|
||||||
)
|
)
|
||||||
# Add hover effect
|
|
||||||
add_hover_cursor(self.mpris_button)
|
add_hover_cursor(self.mpris_button)
|
||||||
|
|
||||||
# self.cavalcade = SpectrumRender()
|
|
||||||
# self.cavalcade_box = self.cavalcade.get_spectrum_box()
|
|
||||||
|
|
||||||
self.center_stack = Stack(
|
self.center_stack = Stack(
|
||||||
name="compact-mpris",
|
name="compact-mpris",
|
||||||
transition_type="crossfade",
|
transition_type="crossfade",
|
||||||
transition_duration=100,
|
transition_duration=100,
|
||||||
v_align="center",
|
v_align="center",
|
||||||
v_expand=False,
|
v_expand=False,
|
||||||
children=[
|
children=[self.mpris_label],
|
||||||
# self.cavalcade_box,
|
|
||||||
self.mpris_label,
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
# self.center_stack.set_visible_child(self.cavalcade_box) # default to cavalcade
|
|
||||||
|
|
||||||
# Create additional compact view.
|
|
||||||
self.mpris_small = CenterBox(
|
self.mpris_small = CenterBox(
|
||||||
name="compact-mpris",
|
name="compact-mpris",
|
||||||
orientation="h",
|
orientation="h",
|
||||||
@@ -593,7 +613,7 @@ class PlayerSmall(CenterBox):
|
|||||||
v_align="center",
|
v_align="center",
|
||||||
v_expand=False,
|
v_expand=False,
|
||||||
start_children=self.mpris_icon,
|
start_children=self.mpris_icon,
|
||||||
center_children=self.center_stack, # Changed to center_stack to handle stack switching
|
center_children=self.center_stack,
|
||||||
end_children=self.mpris_button,
|
end_children=self.mpris_button,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -601,157 +621,177 @@ class PlayerSmall(CenterBox):
|
|||||||
|
|
||||||
self.mpris_manager = MprisPlayerManager()
|
self.mpris_manager = MprisPlayerManager()
|
||||||
self.mpris_player = None
|
self.mpris_player = None
|
||||||
# Almacenar el índice del reproductor actual
|
|
||||||
self.current_index = 0
|
self.current_index = 0
|
||||||
|
|
||||||
players = self.mpris_manager.players
|
players = self.mpris_manager.players
|
||||||
if players:
|
if players:
|
||||||
mp = MprisPlayer(players[self.current_index])
|
mp = MprisPlayer(players[self.current_index])
|
||||||
self.mpris_player = mp
|
self.mpris_player = mp
|
||||||
self._apply_mpris_properties()
|
|
||||||
self.mpris_player.connect("changed", self._on_mpris_changed)
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
||||||
else:
|
|
||||||
self._apply_mpris_properties()
|
self._apply_mpris_properties()
|
||||||
|
|
||||||
self.mpris_manager.connect("player-appeared", self.on_player_appeared)
|
self.mpris_manager.connect("player-appeared", self.on_player_appeared)
|
||||||
self.mpris_manager.connect("player-vanished", self.on_player_vanished)
|
self.mpris_manager.connect("player-vanished", self.on_player_vanished)
|
||||||
self.mpris_button.connect("clicked", self._on_play_pause_clicked)
|
|
||||||
|
def _set_cover_from_path(self, image_path):
|
||||||
|
if image_path and os.path.isfile(image_path):
|
||||||
|
try:
|
||||||
|
self.cover.set_image_from_file(image_path)
|
||||||
|
self.cover_stack.set_visible_child(self.cover)
|
||||||
|
self._update_spin()
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.cover_stack.set_visible_child(self.fallback_icon)
|
||||||
|
self._update_spin()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _start_spin(self):
|
||||||
|
if self._spin_timer_id is None:
|
||||||
|
self._spin_timer_id = GLib.timeout_add(
|
||||||
|
self._spin_interval_ms, self._advance_spin
|
||||||
|
)
|
||||||
|
|
||||||
|
def _stop_spin(self):
|
||||||
|
if self._spin_timer_id is not None:
|
||||||
|
GLib.source_remove(self._spin_timer_id)
|
||||||
|
self._spin_timer_id = None
|
||||||
|
|
||||||
|
def _advance_spin(self):
|
||||||
|
self.cover.angle = (self.cover.angle + self._spin_step) % 360
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _update_spin(self):
|
||||||
|
showing_cover = self.cover_stack.get_visible_child() is self.cover
|
||||||
|
is_playing = (
|
||||||
|
self.mpris_player is not None
|
||||||
|
and self.mpris_player.playback_status == "playing"
|
||||||
|
)
|
||||||
|
if showing_cover and is_playing:
|
||||||
|
self._start_spin()
|
||||||
|
else:
|
||||||
|
self._stop_spin()
|
||||||
|
|
||||||
|
def _download_artwork(self, arturl):
|
||||||
|
try:
|
||||||
|
parsed = urllib.parse.urlparse(arturl)
|
||||||
|
suffix = os.path.splitext(parsed.path)[1] or ".png"
|
||||||
|
with urllib.request.urlopen(arturl) as response:
|
||||||
|
data = response.read()
|
||||||
|
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
|
||||||
|
tmp.write(data)
|
||||||
|
tmp.close()
|
||||||
|
local_path = tmp.name
|
||||||
|
except Exception:
|
||||||
|
local_path = None
|
||||||
|
GLib.idle_add(self._set_cover_from_path, local_path)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _update_cover(self, mp):
|
||||||
|
if not mp or not mp.arturl:
|
||||||
|
self.cover_stack.set_visible_child(self.fallback_icon)
|
||||||
|
return
|
||||||
|
parsed = urllib.parse.urlparse(mp.arturl)
|
||||||
|
if parsed.scheme == "file":
|
||||||
|
self._set_cover_from_path(urllib.parse.unquote(parsed.path))
|
||||||
|
elif parsed.scheme in ("http", "https"):
|
||||||
|
GLib.Thread.new("compact-artwork", self._download_artwork, mp.arturl)
|
||||||
|
else:
|
||||||
|
self._set_cover_from_path(mp.arturl)
|
||||||
|
|
||||||
def _apply_mpris_properties(self):
|
def _apply_mpris_properties(self):
|
||||||
if not self.mpris_player:
|
if not self.mpris_player:
|
||||||
self.mpris_label.set_text("Nothing Playing")
|
self.mpris_label.set_text("Nothing Playing")
|
||||||
self.mpris_button.get_child().set_markup(icons.stop)
|
self.play_image.set_property("icon-name", self.PLAY_ICON)
|
||||||
self.mpris_icon.get_child().set_markup(icons.disc)
|
self.cover_stack.set_visible_child(self.fallback_icon)
|
||||||
if self._current_display != "cavalcade":
|
self.center_stack.set_visible_child(self.mpris_label)
|
||||||
self.center_stack.set_visible_child(
|
self._update_spin()
|
||||||
self.mpris_label
|
|
||||||
) # if was title or artist, keep showing label
|
|
||||||
# else:
|
|
||||||
# self.center_stack.set_visible_child(
|
|
||||||
# self.cavalcade_box
|
|
||||||
# ) # default to cavalcade if no player
|
|
||||||
return
|
return
|
||||||
|
|
||||||
mp = self.mpris_player
|
mp = self.mpris_player
|
||||||
|
self._update_cover(mp)
|
||||||
# Choose icon based on player name.
|
|
||||||
player_name = (
|
|
||||||
mp.player_name.lower()
|
|
||||||
if hasattr(mp, "player_name") and mp.player_name
|
|
||||||
else ""
|
|
||||||
)
|
|
||||||
icon_markup = get_player_icon_markup_by_name(player_name)
|
|
||||||
self.mpris_icon.get_child().set_markup(icon_markup)
|
|
||||||
self.update_play_pause_icon()
|
self.update_play_pause_icon()
|
||||||
|
|
||||||
if self._current_display == "title":
|
if self._current_display == "title":
|
||||||
text = mp.title if mp.title and mp.title.strip() else "Nothing Playing"
|
text = mp.title if mp.title and mp.title.strip() else "Nothing Playing"
|
||||||
|
else: # "artist"
|
||||||
|
text = mp.artist if mp.artist and mp.artist.strip() else "Nothing Playing"
|
||||||
self.mpris_label.set_text(text)
|
self.mpris_label.set_text(text)
|
||||||
self.center_stack.set_visible_child(self.mpris_label)
|
self.center_stack.set_visible_child(self.mpris_label)
|
||||||
elif self._current_display == "artist":
|
|
||||||
text = mp.artist if mp.artist else "Nothing Playing"
|
|
||||||
self.mpris_label.set_text(text)
|
|
||||||
self.center_stack.set_visible_child(self.mpris_label)
|
|
||||||
# else: # default cavalcade
|
|
||||||
# self.center_stack.set_visible_child(self.cavalcade_box)
|
|
||||||
|
|
||||||
def _on_icon_button_press(self, widget, event):
|
def _on_icon_button_press(self, widget, event):
|
||||||
from gi.repository import Gdk
|
if event.type != Gdk.EventType.BUTTON_PRESS:
|
||||||
|
return True
|
||||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
||||||
players = self.mpris_manager.players
|
players = self.mpris_manager.players
|
||||||
if not players:
|
if not players:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if event.button == 2: # Middle-click: cycle display
|
if event.button == 2:
|
||||||
self._display_index = (self._display_index + 1) % len(
|
self._display_index = (self._display_index + 1) % len(self._display_options)
|
||||||
self._display_options
|
|
||||||
)
|
|
||||||
self._current_display = self._display_options[self._display_index]
|
self._current_display = self._display_options[self._display_index]
|
||||||
self._apply_mpris_properties() # Re-apply to update label/cavalcade
|
self._apply_mpris_properties()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Cambiar de reproductor según el botón presionado.
|
if event.button == 1:
|
||||||
if event.button == 1: # Left-click: next player
|
|
||||||
self.current_index = (self.current_index + 1) % len(players)
|
self.current_index = (self.current_index + 1) % len(players)
|
||||||
elif event.button == 3: # Right-click: previous player
|
elif event.button == 3:
|
||||||
self.current_index = (self.current_index - 1) % len(players)
|
self.current_index = (self.current_index - 1) % len(players)
|
||||||
if self.current_index < 0:
|
else:
|
||||||
self.current_index = len(players) - 1
|
return True
|
||||||
|
|
||||||
mp_new = MprisPlayer(players[self.current_index])
|
self.mpris_player = MprisPlayer(players[self.current_index])
|
||||||
self.mpris_player = mp_new
|
|
||||||
# Conectar el evento "changed" para que se actualice
|
|
||||||
self.mpris_player.connect("changed", self._on_mpris_changed)
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
||||||
self._apply_mpris_properties()
|
self._apply_mpris_properties()
|
||||||
return True # Se consume el evento
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _on_play_pause_button_press(self, widget, event):
|
def _on_play_pause_button_press(self, widget, event):
|
||||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
if event.type != Gdk.EventType.BUTTON_PRESS or not self.mpris_player:
|
||||||
if event.button == 1: # Click izquierdo -> track anterior
|
return True
|
||||||
if self.mpris_player:
|
if event.button == 1:
|
||||||
self.mpris_player.previous()
|
|
||||||
self.mpris_button.get_child().set_markup(icons.prev)
|
|
||||||
GLib.timeout_add(500, self._restore_play_pause_icon)
|
|
||||||
elif event.button == 3: # Click derecho -> siguiente track
|
|
||||||
if self.mpris_player:
|
|
||||||
self.mpris_player.next()
|
|
||||||
self.mpris_button.get_child().set_markup(icons.next)
|
|
||||||
GLib.timeout_add(500, self._restore_play_pause_icon)
|
|
||||||
elif event.button == 2: # Click medio -> play/pausa
|
|
||||||
if self.mpris_player:
|
|
||||||
self.mpris_player.play_pause()
|
self.mpris_player.play_pause()
|
||||||
self.update_play_pause_icon()
|
self.update_play_pause_icon()
|
||||||
return True
|
elif event.button == 3:
|
||||||
|
self.mpris_player.next()
|
||||||
|
self.play_image.set_property("icon-name", self.NEXT_ICON)
|
||||||
|
GLib.timeout_add(500, self._restore_play_pause_icon)
|
||||||
|
elif event.button == 2:
|
||||||
|
self.mpris_player.previous()
|
||||||
|
self.play_image.set_property("icon-name", self.PREV_ICON)
|
||||||
|
GLib.timeout_add(500, self._restore_play_pause_icon)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _restore_play_pause_icon(self):
|
def _restore_play_pause_icon(self):
|
||||||
self.update_play_pause_icon()
|
self.update_play_pause_icon()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _on_icon_clicked(
|
|
||||||
self, widget
|
|
||||||
): # No longer used, logic moved to _on_icon_button_press
|
|
||||||
pass
|
|
||||||
|
|
||||||
def update_play_pause_icon(self):
|
def update_play_pause_icon(self):
|
||||||
if self.mpris_player and self.mpris_player.playback_status == "playing":
|
playing = (
|
||||||
self.mpris_button.get_child().set_markup(icons.pause)
|
self.mpris_player
|
||||||
else:
|
and self.mpris_player.playback_status == "playing"
|
||||||
self.mpris_button.get_child().set_markup(icons.play)
|
)
|
||||||
|
self.play_image.set_property(
|
||||||
def _on_play_pause_clicked(self, button):
|
"icon-name", self.PAUSE_ICON if playing else self.PLAY_ICON
|
||||||
if self.mpris_player:
|
)
|
||||||
self.mpris_player.play_pause()
|
self._update_spin()
|
||||||
self.update_play_pause_icon()
|
|
||||||
|
|
||||||
def _on_mpris_changed(self, *args):
|
def _on_mpris_changed(self, *args):
|
||||||
# Update properties when the player's state changes.
|
|
||||||
self._apply_mpris_properties()
|
self._apply_mpris_properties()
|
||||||
|
|
||||||
def on_player_appeared(self, manager, player):
|
def on_player_appeared(self, manager, player):
|
||||||
# When a new player appears, use it if no player is active.
|
|
||||||
if not self.mpris_player:
|
if not self.mpris_player:
|
||||||
mp = MprisPlayer(player)
|
self.mpris_player = MprisPlayer(player)
|
||||||
self.mpris_player = mp
|
|
||||||
self._apply_mpris_properties()
|
|
||||||
self.mpris_player.connect("changed", self._on_mpris_changed)
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
||||||
|
self._apply_mpris_properties()
|
||||||
|
|
||||||
def on_player_vanished(self, manager, player_name):
|
def on_player_vanished(self, manager, player_name):
|
||||||
players = self.mpris_manager.players
|
players = self.mpris_manager.players
|
||||||
if (
|
if self.mpris_player and self.mpris_player.player_name == player_name:
|
||||||
players
|
if players:
|
||||||
and self.mpris_player
|
|
||||||
and self.mpris_player.player_name == player_name
|
|
||||||
):
|
|
||||||
if players: # Check if players is not empty after vanishing
|
|
||||||
self.current_index = self.current_index % len(players)
|
self.current_index = self.current_index % len(players)
|
||||||
new_player = MprisPlayer(players[self.current_index])
|
self.mpris_player = MprisPlayer(players[self.current_index])
|
||||||
self.mpris_player = new_player
|
|
||||||
self.mpris_player.connect("changed", self._on_mpris_changed)
|
self.mpris_player.connect("changed", self._on_mpris_changed)
|
||||||
else:
|
else:
|
||||||
self.mpris_player = None # No players left
|
self.mpris_player = None
|
||||||
elif not players:
|
elif not players:
|
||||||
self.mpris_player = None
|
self.mpris_player = None
|
||||||
self._apply_mpris_properties()
|
self._apply_mpris_properties()
|
||||||
|
|||||||
@@ -300,6 +300,43 @@ tooltip>* {{
|
|||||||
font-size: 0px;
|
font-size: 0px;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
/* Compact MPRIS player */
|
||||||
|
#player-small {{
|
||||||
|
background-color: #{colors["base01"]};
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 100px;
|
||||||
|
}}
|
||||||
|
|
||||||
|
#compact-mpris-icon,
|
||||||
|
#compact-mpris-button {{
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0 4px;
|
||||||
|
margin: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}}
|
||||||
|
|
||||||
|
#compact-mpris-button-icon,
|
||||||
|
#compact-mpris-fallback {{
|
||||||
|
color: #{colors["base05"]};
|
||||||
|
}}
|
||||||
|
|
||||||
|
#compact-mpris-button:hover #compact-mpris-button-icon {{
|
||||||
|
color: #{colors["base0D"]};
|
||||||
|
}}
|
||||||
|
|
||||||
|
#compact-mpris-fallback {{
|
||||||
|
opacity: 0.7;
|
||||||
|
}}
|
||||||
|
|
||||||
|
#compact-mpris-label {{
|
||||||
|
color: #{colors["base05"]};
|
||||||
|
font-size: {font_size}px;
|
||||||
|
margin: 0 6px;
|
||||||
|
}}
|
||||||
|
|
||||||
/* Quick Menu styling */
|
/* Quick Menu styling */
|
||||||
#quick-menu-container {{
|
#quick-menu-container {{
|
||||||
background-color: #{colors["base00"]};
|
background-color: #{colors["base00"]};
|
||||||
|
|||||||
@@ -265,7 +265,11 @@ class MprisPlayerManager(Service):
|
|||||||
|
|
||||||
def on_name_appeard(self, manager, player_name: Playerctl.PlayerName):
|
def on_name_appeard(self, manager, player_name: Playerctl.PlayerName):
|
||||||
logger.info(f"[MprisPlayer] {player_name.name} appeared")
|
logger.info(f"[MprisPlayer] {player_name.name} appeared")
|
||||||
|
try:
|
||||||
new_player = Playerctl.Player.new_from_name(player_name)
|
new_player = Playerctl.Player.new_from_name(player_name)
|
||||||
|
except GLib.Error as e:
|
||||||
|
logger.warning(f"[MprisPlayer] could not attach to {player_name.name}: {e}")
|
||||||
|
return
|
||||||
manager.manage_player(new_player)
|
manager.manage_player(new_player)
|
||||||
self.emit("player-appeared", new_player) # type: ignore
|
self.emit("player-appeared", new_player) # type: ignore
|
||||||
|
|
||||||
@@ -275,7 +279,10 @@ class MprisPlayerManager(Service):
|
|||||||
|
|
||||||
def add_players(self):
|
def add_players(self):
|
||||||
for player in self._manager.get_property("player-names"): # type: ignore
|
for player in self._manager.get_property("player-names"): # type: ignore
|
||||||
|
try:
|
||||||
self._manager.manage_player(Playerctl.Player.new_from_name(player)) # type: ignore
|
self._manager.manage_player(Playerctl.Player.new_from_name(player)) # type: ignore
|
||||||
|
except GLib.Error as e:
|
||||||
|
logger.warning(f"[MprisPlayer] could not attach to {getattr(player, 'name', player)}: {e}")
|
||||||
|
|
||||||
@Property(object, "readable")
|
@Property(object, "readable")
|
||||||
def players(self):
|
def players(self):
|
||||||
|
|||||||
@@ -62,6 +62,42 @@
|
|||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#player-small {
|
||||||
|
background-color: var(--module-bg);
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#compact-mpris-icon,
|
||||||
|
#compact-mpris-button {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0 4px;
|
||||||
|
margin: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#compact-mpris-button-icon {
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
#compact-mpris-button:hover #compact-mpris-button-icon {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#compact-mpris-fallback {
|
||||||
|
color: var(--foreground);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
#compact-mpris-label {
|
||||||
|
color: var(--foreground);
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
#nixos-label {
|
#nixos-label {
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user