✨ feat(dock/components): add AnimatedCircularProgressBar and AnimatedScale to dock components

This commit is contained in:
sankalp committed 2025-07-11 01:32:04 +05:45
1 parent 6cc77cda73
commit 53f0800c59
6 files changed
+83 -35

No files matched your search

+2 -1
View File
@@ -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,
+9 -1
View File
@@ -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
+20 -16
View File
@@ -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:
-17
View File
@@ -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)
+26
View File
@@ -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
+26
View File
@@ -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