diff --git a/config/assets/icons/player/Pause.svg b/config/assets/icons/player/Pause.svg new file mode 100644 index 0000000..e5a5c9a --- /dev/null +++ b/config/assets/icons/player/Pause.svg @@ -0,0 +1,3 @@ + + + diff --git a/config/assets/icons/player/Rewind.svg b/config/assets/icons/player/Rewind.svg new file mode 100644 index 0000000..e52bc1d --- /dev/null +++ b/config/assets/icons/player/Rewind.svg @@ -0,0 +1,3 @@ + + + diff --git a/config/assets/icons/player/audio-switcher.svg b/config/assets/icons/player/audio-switcher.svg new file mode 100644 index 0000000..d50264f --- /dev/null +++ b/config/assets/icons/player/audio-switcher.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/config/assets/icons/player/fwd.svg b/config/assets/icons/player/fwd.svg new file mode 100644 index 0000000..57f16c3 --- /dev/null +++ b/config/assets/icons/player/fwd.svg @@ -0,0 +1,3 @@ + + + diff --git a/config/assets/icons/player/play.svg b/config/assets/icons/player/play.svg new file mode 100644 index 0000000..d3356bf --- /dev/null +++ b/config/assets/icons/player/play.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/modules/controlcenter/expanded_player.py b/modules/controlcenter/expanded_player.py index f000a3f..52f48d4 100644 --- a/modules/controlcenter/expanded_player.py +++ b/modules/controlcenter/expanded_player.py @@ -14,6 +14,7 @@ from typing import List import threading from fabric.utils import bulk_connect, invoke_repeater, cooldown +from fabric.utils.helpers import get_relative_path from fabric.widgets.image import Image from fabric.widgets.overlay import Overlay from fabric.widgets.stack import Stack @@ -207,27 +208,11 @@ class PlayerBoxStack(Box): fallback_cover_path = f"{data.HOME_DIR}/.current.wall" # Album cover with fallback image using Image widget - album_cover_image = Image( - name="macos-album-cover-image", - pixbuf=None, - ) - - try: - from gi.repository import GdkPixbuf - - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( - fallback_cover_path, 70, 70, True - ) - album_cover_image.set_from_pixbuf(pixbuf) - album_cover_image.set_size_request(70, 70) - except Exception as e: - logger.warning(f"Failed to load fallback image in no-media box: {e}") album_cover = Box( name="macos-album-image", - children=[album_cover_image], ) - album_cover.set_size_request(70, 70) + album_cover.set_style(f"background-image:url('{fallback_cover_path}')") image_stack = Box(h_align="start", v_align="center", name="player-image-stack") image_stack.children = [album_cover] @@ -501,7 +486,6 @@ class PlayerBox(Box): self.player_stack = player_stack self.fallback_cover_path = f"{data.HOME_DIR}/.current.wall" - self.image_size = 70 # Medium album art size for expanded player self.icon_size = 15 # State @@ -515,10 +499,14 @@ class PlayerBox(Box): self._download_cancelled = False # Flag to cancel downloads self._signal_connections = [] # Track signal connections - self.album_cover = Box(style_classes="macos-album-image") + # Use same CSS background approach as small player for consistency + self.album_cover = Box( + name="macos-album-image", + ) self.album_cover.set_style( f"background-image:url('{self.fallback_cover_path}')" ) + self.album_cover.set_size_request(70, 70) self.image_stack = Box( h_align="start", v_align="center", name="player-image-stack" @@ -556,39 +544,6 @@ class PlayerBox(Box): visible=True, # Hide artist and album when no media ) - # Use Image widget instead of CSS background for more reliable image display - self.album_cover_image = Image( - name="macos-album-cover-image", - pixbuf=None, - ) - - # Set fallback image immediately with proper scaling - try: - from gi.repository import GdkPixbuf - - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( - self.fallback_cover_path, 70, 70, True - ) - self.album_cover_image.set_from_pixbuf(pixbuf) - self.album_cover_image.set_size_request(70, 70) - except Exception as e: - logger.warning(f"Failed to load fallback image: {e}") - - # Container box for styling with fixed size - self.album_cover = Box( - name="macos-album-image", - children=[self.album_cover_image], - ) - self.album_cover.set_size_request(70, 70) - - self.image_stack = Box( - h_align="start", - v_align="start", - h_expand=False, # Fixed width for album art - name="macos-player-image-stack", - ) - self.image_stack.children = [*self.image_stack.children, self.album_cover] - self.app_icon = Box( children=Image( icon_name=self.player.player_name, name="player-app-icon", icon_size=20 @@ -732,10 +687,20 @@ class PlayerBox(Box): ) self.stack_buttons_box.hide() # Initially hidden - self.skip_next_icon = Image(icon_name="player_fwd") - self.skip_prev_icon = Image(icon_name="player_rew") - self.shuffle_icon = Image(icon_name="shuffle") - self.play_pause_icon = Image(icon_name="player_pause") + # Create SVG icons from player directory + self.skip_next_icon = Image( + image_file=get_relative_path("../../config/assets/icons/player/fwd.svg"), + icon_size=16, + ) + self.skip_prev_icon = Image( + image_file=get_relative_path("../../config/assets/icons/player/Rewind.svg"), + icon_size=16, + ) + self.shuffle_icon = Image(icon_name="shuffle") # Keep existing shuffle icon + self.play_pause_icon = Image( + image_file=get_relative_path("../../config/assets/icons/player/Pause.svg"), + icon_size=20, + ) self.play_pause_button = Button( name="macos-play-button", @@ -959,39 +924,22 @@ class PlayerBox(Box): status = player.get_property("playback-status") if status == "paused": - self.play_pause_icon.set_from_icon_name("player_start") + self.play_pause_icon.set_from_file( + get_relative_path("../../config/assets/icons/player/play.svg") + ) if status == "playing": - self.play_pause_icon.set_from_icon_name("player_pause") + self.play_pause_icon.set_from_file( + get_relative_path("../../config/assets/icons/player/Pause.svg") + ) def _update_image(self, image_path): - try: - from gi.repository import GdkPixbuf - - if image_path and os.path.isfile(image_path): - # Create scaled pixbuf to ensure proper size - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( - image_path, 70, 70, True - ) - self.album_cover_image.set_from_pixbuf(pixbuf) - # Explicitly clear pixbuf reference to help GC - del pixbuf - else: - # Use fallback image with scaling - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( - self.fallback_cover_path, 70, 70, True - ) - self.album_cover_image.set_from_pixbuf(pixbuf) - # Explicitly clear pixbuf reference to help GC - del pixbuf - except Exception as e: - logger.warning(f"Failed to update album cover image: {e}") - # Try simple file setting as last resort - try: - self.album_cover_image.set_from_file(self.fallback_cover_path) - self.album_cover_image.set_size_request(70, 70) - except Exception as e2: - logger.error(f"Failed to set fallback image: {e2}") + if image_path and os.path.isfile(image_path): + self.album_cover.set_style(f"background-image:url('{image_path}')") + else: + self.album_cover.set_style( + f"background-image:url('{self.fallback_cover_path}')" + ) def _set_image(self, *_): art_url = self.player.arturl @@ -1022,6 +970,7 @@ class PlayerBox(Box): ) self.current_download_thread.start() else: + print(art_url) self._update_image(art_url) def _download_and_set_artwork(self, arturl): diff --git a/modules/controlcenter/player.py b/modules/controlcenter/player.py index 21f1bc4..0ee0b86 100644 --- a/modules/controlcenter/player.py +++ b/modules/controlcenter/player.py @@ -9,6 +9,7 @@ import threading from fabric.utils import ( bulk_connect, ) +from fabric.utils.helpers import get_relative_path from fabric.widgets.box import Box from fabric.widgets.button import Button from fabric.widgets.image import Image @@ -558,25 +559,36 @@ class PlayerBox(Box): ], ) - # Buttons + # Buttons with fixed sizing for layout stability self.button_box = Box( name="button-box-c", - # h_align="end", - # visible=False, h_expand=False, spacing=2, ) - self.skip_next_icon = Image(icon_name="player_fwd") - self.skip_prev_icon = Image(icon_name="media-skip-backward") - self.shuffle_icon = Image(icon_name="shuffle") - self.play_pause_icon = Image(icon_name="player_pause") + # Create SVG icons with consistent sizing + self.skip_next_icon = Image( + image_file=get_relative_path("../../config/assets/icons/player/fwd.svg"), + icon_size=16 + ) + self.skip_prev_icon = Image( + image_file=get_relative_path("../../config/assets/icons/player/Rewind.svg"), + icon_size=16 + ) + self.shuffle_icon = Image(icon_name="shuffle", icon_size=16) + self.play_pause_icon = Image( + image_file=get_relative_path("../../config/assets/icons/player/Pause.svg"), + icon_size=18 + ) + # Fixed size buttons to prevent layout shifts self.play_pause_button = Button( name="player-button", child=self.play_pause_icon, on_clicked=self.player.play_pause, ) + # Set consistent button size + self.play_pause_button.set_size_request(32, 32) self.player.bind_property("can_pause", self.play_pause_button, "sensitive") @@ -585,6 +597,8 @@ class PlayerBox(Box): child=self.skip_next_icon, on_clicked=self._on_player_next, ) + # Set consistent button size + self.next_button.set_size_request(32, 32) self.player.bind_property("can_go_next", self.next_button, "sensitive") self.prev_button = Button( @@ -592,11 +606,16 @@ class PlayerBox(Box): child=self.skip_prev_icon, on_clicked=self._on_prev_button_click, ) + # Set consistent button size + self.prev_button.set_size_request(32, 32) + self.shuffle_button = Button( style_classes=["player-button"], child=self.shuffle_icon, on_clicked=self.player.toggle_shuffle, ) + # Set consistent button size + self.shuffle_button.set_size_request(32, 32) self.player.bind_property("can_shuffle", self.shuffle_button, "sensitive") self.button_box.children = ( @@ -767,10 +786,14 @@ class PlayerBox(Box): status = player.get_property("playback-status") if status == "paused": - self.play_pause_icon.set_from_icon_name("player_play") + self.play_pause_icon.set_from_file( + get_relative_path("../../config/assets/icons/player/play.svg") + ) if status == "playing": - self.play_pause_icon.set_from_icon_name("player_pause") + self.play_pause_icon.set_from_file( + get_relative_path("../../config/assets/icons/player/Pause.svg") + ) # Notify the player stack that this player started playing if self.player_stack and hasattr( self.player_stack, "on_player_playback_changed" @@ -781,10 +804,14 @@ class PlayerBox(Box): status = player.get_property("playback-status") if status == "paused": - self.play_pause_icon.set_from_icon_name("player_play") + self.play_pause_icon.set_from_file( + get_relative_path("../../config/assets/icons/player/play.svg") + ) if status == "playing": - self.play_pause_icon.set_from_icon_name("player_pause") + self.play_pause_icon.set_from_file( + get_relative_path("../../config/assets/icons/player/Pause.svg") + ) # Notify the player stack that this player started playing if self.player_stack and hasattr( self.player_stack, "on_player_playback_changed" diff --git a/styles/controlcenter.css b/styles/controlcenter.css index a7714bb..465f584 100644 --- a/styles/controlcenter.css +++ b/styles/controlcenter.css @@ -557,11 +557,11 @@ /* macOS-style expanded player - more compact */ #macos-outer-player-box { - min-height: 110px; /* Reduced height */ - min-width: 420px; /* Slightly wider to accommodate expanded track info */ + min-height: 80px; /* Reduced height */ + min-width: 380px; /* Slightly wider to accommodate expanded track info */ border-radius: 12px; /* margin: 10px; */ - padding: 15px; /* Reduced padding */ + padding: 15px; background-color: alpha(#000, 0.4); box-shadow: 0 4px 16px alpha(#000, 0.25), @@ -572,17 +572,25 @@ margin-left: 5px; } +#macos-album-cover-image image { + min-width: 70px; + min-height: 70px; + border-radius: 9px; +} #macos-album-image { min-width: 70px; min-height: 70px; border-radius: 9px; + background-position: center; + background-size: cover; box-shadow: 0 2px 8px alpha(#000, 0.3); } -#macos-album-cover-image { +#macos-album-image image { min-width: 70px; min-height: 70px; border-radius: 9px; + box-shadow: 0 2px 8px alpha(#000, 0.3); } /* Track info container that expands to fill available space */