refactor: extract shared mixins, fix cpu waste, resolve browser icons
- Extract CloseButtonRevealerMixin, PullToRefreshMixin, BasePlayerBoxStack - Replace mpris.py 2s+5s D-Bus polling with Seeked signal subscription - Remove redundant desktop/main.py os.listdir() poll (FileMonitor covers) - Remove switcher/main.py 200ms capture timer, chain from frame-ready - Resolve browser MPRIS icons via desktop file lookup, fallback to app name - Fix CodeQL py/clear-text-storage by rounding lat/lon and stripping from cache
This commit is contained in:
14 files changed
+515
-740
No files matched your search
@@ -1,6 +1,6 @@
|
||||
from enum import Enum, auto
|
||||
|
||||
from fabric.utils import Gdk, GLib, Gtk, idle_add, logger
|
||||
from fabric.utils import GLib, Gtk, idle_add, logger
|
||||
from fabric.widgets.box import Box
|
||||
from fabric.widgets.button import Button
|
||||
from fabric.widgets.centerbox import CenterBox
|
||||
@@ -9,6 +9,7 @@ from fabric.widgets.label import Label
|
||||
from fabric.widgets.separator import Separator
|
||||
|
||||
from services.bluetooth import BluetoothClient, BluetoothDevice
|
||||
from shared.widgets.pull_to_refresh import PullToRefreshMixin
|
||||
from shared.widgets.smooth_switch import SmoothSwitch
|
||||
from shared.window.animated_scrollwindow import AnimatedScrollable
|
||||
from utils.functions import spawn_detached
|
||||
@@ -304,7 +305,7 @@ class BluetoothDeviceSlot(Box):
|
||||
logger.warning(f"[Bluetooth] Failed to remove device: {e}")
|
||||
|
||||
|
||||
class BluetoothConnections(Box):
|
||||
class BluetoothConnections(PullToRefreshMixin, Box):
|
||||
def __init__(
|
||||
self, parent, show_hidden_devices: bool = False, show_back_button=True, **kwargs
|
||||
):
|
||||
@@ -422,7 +423,7 @@ class BluetoothConnections(Box):
|
||||
self.other_devices.set_visible(False)
|
||||
|
||||
# Add pull-to-refresh functionality to scrolled window
|
||||
self.setup_pull_to_refresh()
|
||||
self.setup_pull_to_refresh(self.other_devices_scrolled)
|
||||
|
||||
self.more_settings_button = Button(
|
||||
child=Label("More Settings", h_align="start"),
|
||||
@@ -507,31 +508,6 @@ class BluetoothConnections(Box):
|
||||
# Defer refresh until after the height animation completes
|
||||
idle_add(self._refresh_after_animation)
|
||||
|
||||
def _cancel_pending_refresh(self):
|
||||
if hasattr(self, "_anim_finished_handler") and self._anim_finished_handler:
|
||||
try:
|
||||
self.other_devices_scrolled.height_animator.disconnect(
|
||||
self._anim_finished_handler
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"[bluetooth] self.other_devices_scrolled.height_animator.disconnect( s... failed: {e}"
|
||||
)
|
||||
self._anim_finished_handler = None
|
||||
|
||||
def _refresh_after_animation(self):
|
||||
if self._destroyed:
|
||||
return False
|
||||
anim = self.other_devices_scrolled.height_animator
|
||||
if anim.playing:
|
||||
self._anim_finished_handler = anim.connect(
|
||||
"finished",
|
||||
lambda *_: self.force_device_refresh() if not self._destroyed else None,
|
||||
)
|
||||
else:
|
||||
self.force_device_refresh()
|
||||
return False
|
||||
|
||||
def open_bluetooth_settings(self, *_):
|
||||
"""Open Blueman bluetooth manager"""
|
||||
try:
|
||||
@@ -692,84 +668,22 @@ class BluetoothConnections(Box):
|
||||
self.other_devices.set_visible(False)
|
||||
self.other_devices_scrolled.snap_to_size(0)
|
||||
|
||||
def setup_pull_to_refresh(self):
|
||||
"""Setup pull-to-refresh gesture for the scrolled window"""
|
||||
self.vadjustment = self.other_devices_scrolled.get_vadjustment()
|
||||
def _trigger_scan(self):
|
||||
if not self.client.scanning and hasattr(self.client, "scan"):
|
||||
self.client.scan()
|
||||
|
||||
# Track gesture state
|
||||
self.pull_start_y = 0
|
||||
self.is_pulling = False
|
||||
self.pull_threshold = 50 # pixels to trigger refresh
|
||||
def _trigger_refresh(self):
|
||||
self.force_device_refresh()
|
||||
|
||||
# Connect to scroll events
|
||||
self.other_devices_scrolled.connect("scroll-event", self.on_scroll_event)
|
||||
self.other_devices_scrolled.connect("button-press-event", self.on_button_press)
|
||||
self.other_devices_scrolled.connect(
|
||||
"button-release-event", self.on_button_release
|
||||
)
|
||||
self.other_devices_scrolled.connect(
|
||||
"motion-notify-event", self.on_motion_notify
|
||||
)
|
||||
def _get_pull_normal_label(self):
|
||||
if self.client.scanning:
|
||||
return "↓ Pull to stop scanning"
|
||||
return "↓ Pull to scan for devices"
|
||||
|
||||
# Enable events
|
||||
self.other_devices_scrolled.set_events(
|
||||
Gdk.EventMask.SCROLL_MASK
|
||||
| Gdk.EventMask.BUTTON_PRESS_MASK
|
||||
| Gdk.EventMask.BUTTON_RELEASE_MASK
|
||||
| Gdk.EventMask.POINTER_MOTION_MASK
|
||||
)
|
||||
|
||||
def on_scroll_event(self, widget, event):
|
||||
"""Handle scroll events for pull-to-refresh"""
|
||||
if self.vadjustment.get_value() <= 0:
|
||||
if event.direction == Gdk.ScrollDirection.UP:
|
||||
if not self.client.scanning and hasattr(self.client, "scan"):
|
||||
self.client.scan()
|
||||
self.force_device_refresh()
|
||||
return True
|
||||
return False
|
||||
|
||||
def on_button_press(self, widget, event):
|
||||
"""Handle button press for touch/drag gestures"""
|
||||
if self.vadjustment.get_value() <= 0:
|
||||
self.pull_start_y = event.y
|
||||
self.is_pulling = True
|
||||
return False
|
||||
|
||||
def on_button_release(self, widget, event):
|
||||
"""Handle button release for touch/drag gestures"""
|
||||
if self.is_pulling:
|
||||
pull_distance = event.y - self.pull_start_y
|
||||
if pull_distance > self.pull_threshold:
|
||||
if not self.client.scanning and hasattr(self.client, "scan"):
|
||||
self.client.scan()
|
||||
self.force_device_refresh()
|
||||
self.refresh_indicator.set_visible(False)
|
||||
self.refresh_indicator.remove_style_class("ready-to-refresh")
|
||||
self.is_pulling = False
|
||||
return False
|
||||
|
||||
def on_motion_notify(self, widget, event):
|
||||
"""Handle motion events for visual feedback during pull"""
|
||||
if self.is_pulling and self.vadjustment.get_value() <= 0:
|
||||
pull_distance = event.y - self.pull_start_y
|
||||
if pull_distance > 0:
|
||||
self.refresh_indicator.set_visible(True)
|
||||
if pull_distance >= self.pull_threshold:
|
||||
if self.client.scanning:
|
||||
self.refresh_indicator.set_label("↑ Release to stop scanning")
|
||||
else:
|
||||
self.refresh_indicator.set_label("↑ Release to scan")
|
||||
self.refresh_indicator.add_style_class("ready-to-refresh")
|
||||
else:
|
||||
if self.client.scanning:
|
||||
self.refresh_indicator.set_label("↓ Pull to stop scanning")
|
||||
else:
|
||||
self.refresh_indicator.set_label("↓ Pull to scan for devices")
|
||||
self.refresh_indicator.remove_style_class("ready-to-refresh")
|
||||
else:
|
||||
self.refresh_indicator.set_visible(False)
|
||||
return False
|
||||
def _get_pull_ready_label(self):
|
||||
if self.client.scanning:
|
||||
return "↑ Release to stop scanning"
|
||||
return "↑ Release to scan"
|
||||
|
||||
def on_device_added(self, client: BluetoothClient, address: str):
|
||||
"""Handle when a new device is added"""
|
||||
|
||||
Reference in new issue
Block a user