✨ feat(dock/components): add AnimatedCircularProgressBar and AnimatedScale to dock components
This commit is contained in:
6 files changed
+83
-35
No files matched your search
@@ -10,6 +10,7 @@ from fabric.widgets.revealer import Revealer
|
||||
from gi.repository import GLib
|
||||
|
||||
import config.data as data
|
||||
from utils.animatedcircularprogressbar import AnimatedCircularProgressBar
|
||||
import utils.icons as icons
|
||||
|
||||
|
||||
@@ -155,7 +156,7 @@ class SingularMetric:
|
||||
self.icon_markup = icon
|
||||
|
||||
self.icon = Label(name="metrics-icon", markup=icon)
|
||||
self.circle = CircularProgressBar(
|
||||
self.circle = AnimatedCircularProgressBar(
|
||||
name="metrics-circle",
|
||||
value=0,
|
||||
size=28,
|
||||
|
||||
@@ -292,6 +292,7 @@ class MusicPlayer(Box):
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"[DEBUG] Error in get_playing_player: {e}")
|
||||
return None
|
||||
|
||||
def check_active_player(self):
|
||||
@@ -326,6 +327,7 @@ class MusicPlayer(Box):
|
||||
# If we can't safely compare, assume we should switch
|
||||
should_switch = True
|
||||
except Exception as e:
|
||||
print(f"[DEBUG] Error comparing players: {e}")
|
||||
should_switch = True
|
||||
|
||||
if should_switch:
|
||||
@@ -354,6 +356,7 @@ class MusicPlayer(Box):
|
||||
self.update_visibility()
|
||||
|
||||
except Exception as e:
|
||||
print(f"[DEBUG] Error in check_active_player: {e}")
|
||||
|
||||
# Return True to continue the timeout
|
||||
return True
|
||||
@@ -364,6 +367,7 @@ class MusicPlayer(Box):
|
||||
self.manager.init_all_players()
|
||||
self.update_visibility()
|
||||
except Exception as e:
|
||||
print(f"[DEBUG] Error in delayed music player init: {e}")
|
||||
return False # Don't repeat this timeout
|
||||
|
||||
def _try_switch_to_alternative_player(self, current_time):
|
||||
@@ -404,6 +408,7 @@ class MusicPlayer(Box):
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def set_current_player(self, player):
|
||||
"""Set the current active player"""
|
||||
@@ -709,6 +714,7 @@ class MusicPlayer(Box):
|
||||
):
|
||||
return True
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# Also check if player is currently playing (even without full metadata)
|
||||
if hasattr(player.props, "playback_status"):
|
||||
@@ -718,11 +724,13 @@ class MusicPlayer(Box):
|
||||
status.value_name == "PLAYERCTL_PLAYBACK_STATUS_PLAYING"):
|
||||
return True
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
continue
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -186,7 +186,6 @@ class Player(Box):
|
||||
|
||||
def on_seek(self, sender, ratio):
|
||||
pos = ratio * self.duration # duration in seconds
|
||||
print(f"Seeking to {pos:.2f}s")
|
||||
self._player.set_position(int(pos))
|
||||
|
||||
def on_metadata(self, sender, metadata, player):
|
||||
@@ -223,7 +222,7 @@ class Player(Box):
|
||||
f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg"
|
||||
)
|
||||
self.set_style(f"background-image:url('{thumbnail_url}')")
|
||||
print(f"Using YouTube thumbnail: {thumbnail_url}")
|
||||
|
||||
else:
|
||||
# Fallback to default wallpaper
|
||||
self.set_style(
|
||||
@@ -265,7 +264,6 @@ class Player(Box):
|
||||
self.play_pause_button.remove_style_class("pause-track")
|
||||
|
||||
def on_shuffle(self, sender, player, status):
|
||||
print("callback status", status)
|
||||
if status == False:
|
||||
self.shuffle_button.get_child().set_markup(icons.shuffle)
|
||||
self.shuffle_button.get_child().set_name("shuffle")
|
||||
@@ -278,10 +276,18 @@ class Player(Box):
|
||||
self.shuffle_button.get_child().set_style("color: white")
|
||||
|
||||
def handle_next(self, player):
|
||||
player.next()
|
||||
try:
|
||||
player.next()
|
||||
except Exception:
|
||||
# Next is not available for this player (common with browsers)
|
||||
pass
|
||||
|
||||
def handle_prev(self, player):
|
||||
player.previous()
|
||||
try:
|
||||
player.previous()
|
||||
except Exception:
|
||||
# Previous is not available for this player (common with browsers)
|
||||
pass
|
||||
|
||||
def handle_play_pause(self, player):
|
||||
is_playing = self.play_pause_button.get_child().get_name() == "play-label"
|
||||
@@ -312,13 +318,15 @@ class Player(Box):
|
||||
logger.warning("Failed to toggle playback:", e)
|
||||
|
||||
def handle_shuffle(self, shuffle_button, player):
|
||||
print("shuffle", player.props.shuffle)
|
||||
if player.props.shuffle == False:
|
||||
player.set_shuffle(True)
|
||||
print("setting to true", player.props.player_name)
|
||||
else:
|
||||
player.set_shuffle(False)
|
||||
shuffle_button.get_child().set_style("color: var(--outline)")
|
||||
try:
|
||||
if player.props.shuffle == False:
|
||||
player.set_shuffle(True)
|
||||
else:
|
||||
player.set_shuffle(False)
|
||||
shuffle_button.get_child().set_style("color: var(--outline)")
|
||||
except Exception:
|
||||
# Shuffle is not available for this player (common with browsers)
|
||||
pass
|
||||
|
||||
|
||||
class PlayerContainer(Box):
|
||||
@@ -367,15 +375,12 @@ class PlayerContainer(Box):
|
||||
self.manager.init_all_players()
|
||||
|
||||
def new_player(self, manager, player):
|
||||
print(player.props.player_name, "new player")
|
||||
print(player)
|
||||
new_player = Player(player=player)
|
||||
new_player.gtk_wrapper.queue_draw()
|
||||
new_player.set_name(player.props.player_name)
|
||||
self.player.append(new_player)
|
||||
# Store the player object
|
||||
self.player_objects[player.props.player_name] = player
|
||||
print("stacking player")
|
||||
self.stack.add_named(new_player, player.props.player_name)
|
||||
|
||||
self.player_switch_container.add_center(
|
||||
@@ -436,7 +441,6 @@ class PlayerContainer(Box):
|
||||
curr = self.stack.get_visible_child()
|
||||
if curr:
|
||||
for btn in self.player_switch_container.center_children:
|
||||
print(btn.get_name())
|
||||
if btn.get_name() == curr.get_name():
|
||||
btn.add_style_class("active")
|
||||
else:
|
||||
|
||||
@@ -35,7 +35,6 @@ class PlayerService(Service):
|
||||
self._player.connect("shuffle", self.on_shuffle)
|
||||
self._player.connect("metadata", self.on_metadata)
|
||||
self._player.connect("seeked", self.on_seeked)
|
||||
print(type(player))
|
||||
|
||||
self.status = self._player.props.playback_status
|
||||
self.pos_fabricator = Fabricator(
|
||||
@@ -58,12 +57,10 @@ class PlayerService(Service):
|
||||
self.pos_fabricator.start()
|
||||
|
||||
def set_position(self, pos: float):
|
||||
print("seeking in the service")
|
||||
self.pos_fabricator.stop()
|
||||
micro_pos = int(pos * 1_000_000)
|
||||
try:
|
||||
self._player.set_position(micro_pos)
|
||||
print(f"Set position to {micro_pos}")
|
||||
except GLib.Error as e:
|
||||
print(f"Failed to seek: {e}")
|
||||
|
||||
@@ -132,28 +129,19 @@ class PlayerService(Service):
|
||||
pass
|
||||
|
||||
def on_play(self, player, status):
|
||||
print("player is playing: {}".format(player.props.player_name))
|
||||
self.status = player.props.playback_status
|
||||
self.poll_progress()
|
||||
self.play()
|
||||
|
||||
def on_pause(self, player, status):
|
||||
print("player is paused: {}".format(player.props.player_name))
|
||||
self.status = player.props.playback_status
|
||||
self.poll_progress()
|
||||
self.pause()
|
||||
|
||||
def on_shuffle(self, player, status):
|
||||
print("suffle status changed for: {}".format(player.props.player_name))
|
||||
print(type(status), "here is the status type")
|
||||
self.shuffle_toggle(player, status)
|
||||
|
||||
def on_metadata(self, player, metadata):
|
||||
keys = metadata.keys()
|
||||
if "xesam:artist" in keys and "xesam:title" in keys:
|
||||
print(
|
||||
"{} - {}".format(metadata["xesam:artist"][0], metadata["xesam:title"])
|
||||
)
|
||||
self.meta_change(metadata, player)
|
||||
|
||||
|
||||
@@ -171,7 +159,6 @@ class PlayerManager(Service):
|
||||
self._manager.connect(
|
||||
"player-vanished", self._on_player_vanished, self._manager
|
||||
)
|
||||
print("playerctl init done")
|
||||
|
||||
self._players = {}
|
||||
|
||||
@@ -179,7 +166,6 @@ class PlayerManager(Service):
|
||||
# invoked in the UI
|
||||
for player_obj in self._manager.props.player_names:
|
||||
name_str = player_obj.name
|
||||
print(f"{name_str} appeared")
|
||||
if name_str in ALLOWED_PLAYERS:
|
||||
player = Playerctl.Player.new_from_name(player_obj)
|
||||
self._manager.manage_player(player)
|
||||
@@ -187,13 +173,10 @@ class PlayerManager(Service):
|
||||
|
||||
def _on_name_appeared(self, sender, name, manager):
|
||||
name_str = name.name
|
||||
print(f"{name_str} appeared")
|
||||
if name_str in ALLOWED_PLAYERS:
|
||||
player = Playerctl.Player.new_from_name(name)
|
||||
self._manager.manage_player(player)
|
||||
self.new_player(player)
|
||||
|
||||
def _on_player_vanished(self, sender, player, manager):
|
||||
print("player has exited: {}".format(player.props.player_name))
|
||||
print(type(player))
|
||||
self.player_vanish(player)
|
||||
@@ -0,0 +1,26 @@
|
||||
from fabric.widgets.circularprogressbar import CircularProgressBar
|
||||
from utils.animator import Animator
|
||||
|
||||
class AnimatedCircularProgressBar(CircularProgressBar):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.animator = (
|
||||
Animator(
|
||||
bezier_curve=(0.15, 0.88, 0.68, 0.95),
|
||||
duration=0.8,
|
||||
min_value=self.min_value,
|
||||
max_value=self.value,
|
||||
tick_widget=self,
|
||||
notify_value=lambda p, *_: self.set_value(p.value),
|
||||
)
|
||||
.build()
|
||||
.play()
|
||||
.unwrap()
|
||||
)
|
||||
|
||||
def animate_value(self, value: float):
|
||||
self.animator.pause()
|
||||
self.animator.min_value = self.value
|
||||
self.animator.max_value = value
|
||||
self.animator.play()
|
||||
return
|
||||
@@ -0,0 +1,26 @@
|
||||
from fabric.widgets.scale import Scale
|
||||
from utils.animator import Animator
|
||||
|
||||
class AnimatedScale(Scale):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.animator = (
|
||||
Animator(
|
||||
bezier_curve=(0.15, 0.88, 0.68, 0.95),
|
||||
duration=0.3,
|
||||
min_value=self.min_value,
|
||||
max_value=self.value,
|
||||
tick_widget=self,
|
||||
notify_value=lambda p, *_: self.set_value(p.value),
|
||||
)
|
||||
.build()
|
||||
.play()
|
||||
.unwrap()
|
||||
)
|
||||
|
||||
def animate_value(self, value: float):
|
||||
self.animator.pause()
|
||||
self.animator.min_value = self.value
|
||||
self.animator.max_value = value
|
||||
self.animator.play()
|
||||
return
|
||||
Reference in new issue
Block a user