refactor(controlcenter): simplify refresh handling and add cancellation hooks
The changes replace timeout‑based refreshes with animation‑aware callbacks, improving responsiveness and preventing stale pending operations.
This commit is contained in:
3 files changed
+92
-41
No files matched your search
@@ -382,7 +382,6 @@ class BluetoothConnections(Box):
|
||||
on_clicked=self.toggle_other_devices,
|
||||
)
|
||||
self.other_devices = Box(spacing=4, orientation="vertical")
|
||||
self.other_devices.set_size_request(-1, 150)
|
||||
|
||||
self.other_devices_scrolled = AnimatedScrollable(
|
||||
min_content_size=(303, 0),
|
||||
@@ -441,6 +440,7 @@ class BluetoothConnections(Box):
|
||||
def on_hide(self, *_):
|
||||
"""Called when the widget is hidden (popup closed)"""
|
||||
self.stop_device_monitoring()
|
||||
self._cancel_pending_refresh()
|
||||
if self.other_devices.get_visible():
|
||||
self.other_devices.set_visible(False)
|
||||
self.other_devices_scrolled.snap_to_size(0)
|
||||
@@ -456,25 +456,51 @@ class BluetoothConnections(Box):
|
||||
def toggle_other_devices(self, *_):
|
||||
"""Toggle the visibility of other devices section"""
|
||||
current_state = self.other_devices.get_visible()
|
||||
self.other_devices.set_visible(not current_state)
|
||||
self.update_scan_label()
|
||||
self._cancel_pending_refresh()
|
||||
if current_state:
|
||||
self.other_devices.set_visible(False)
|
||||
self.other_devices_scrolled.snap_to_size(0)
|
||||
self.update_scan_label()
|
||||
if (
|
||||
self.client
|
||||
and self.client.scanning
|
||||
and hasattr(self.client, "stop_scan")
|
||||
):
|
||||
self.client.stop_scan()
|
||||
else:
|
||||
self.other_devices.set_visible(True)
|
||||
self.update_scan_label()
|
||||
if (
|
||||
self.client
|
||||
and not self.client.scanning
|
||||
and hasattr(self.client, "scan")
|
||||
):
|
||||
self.client.scan()
|
||||
# Defer refresh until after the height animation completes
|
||||
GLib.idle_add(self._refresh_after_animation)
|
||||
|
||||
if self.client:
|
||||
if self.other_devices.get_visible():
|
||||
if not self.client.scanning and hasattr(self.client, "scan"):
|
||||
GLib.timeout_add(100, self.client.scan)
|
||||
if hasattr(self, "_refresh_timeout_id") and self._refresh_timeout_id:
|
||||
GLib.source_remove(self._refresh_timeout_id)
|
||||
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:
|
||||
pass
|
||||
self._anim_finished_handler = None
|
||||
|
||||
def _do_refresh():
|
||||
self.force_device_refresh()
|
||||
self._refresh_timeout_id = None
|
||||
return False
|
||||
|
||||
self._refresh_timeout_id = GLib.timeout_add(150, _do_refresh)
|
||||
else:
|
||||
if self.client.scanning and hasattr(self.client, "stop_scan"):
|
||||
self.client.stop_scan()
|
||||
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"""
|
||||
@@ -650,6 +676,7 @@ class BluetoothConnections(Box):
|
||||
"""Cleanup when widget is destroyed"""
|
||||
self._destroyed = True
|
||||
self.stop_device_monitoring()
|
||||
self._cancel_pending_refresh()
|
||||
for sig_id in self._client_signal_ids:
|
||||
try:
|
||||
self.client.disconnect(sig_id)
|
||||
@@ -658,14 +685,12 @@ class BluetoothConnections(Box):
|
||||
f"[Bluetooth] Failed to disconnect client signal {sig_id}: {e}"
|
||||
)
|
||||
self._client_signal_ids.clear()
|
||||
try:
|
||||
self.other_devices_revealer.child_revealed = False
|
||||
except Exception as e:
|
||||
logger.error(f"[Bluetooth] Failed to hide other devices revealer: {e}")
|
||||
|
||||
def close_bluetooth(self):
|
||||
"""Called when Bluetooth panel is being closed"""
|
||||
self.other_devices_revealer.child_revealed = False
|
||||
if self.other_devices.get_visible():
|
||||
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"""
|
||||
|
||||
@@ -342,7 +342,6 @@ class WifiConnections(Box):
|
||||
on_clicked=self.toggle_other_networks,
|
||||
)
|
||||
self.other_networks = Box(spacing=4, orientation="vertical")
|
||||
self.other_networks.set_size_request(-1, 150)
|
||||
|
||||
# Create scrolled window for other networks
|
||||
self.other_networks_scrolled = AnimatedScrollable(
|
||||
@@ -388,6 +387,7 @@ class WifiConnections(Box):
|
||||
def on_hide(self, *_):
|
||||
"""Called when the widget is hidden (popup closed)"""
|
||||
self.stop_network_monitoring()
|
||||
self._cancel_pending_refresh()
|
||||
if self.other_networks.get_visible():
|
||||
self.other_networks.set_visible(False)
|
||||
self.other_networks_scrolled.snap_to_size(0)
|
||||
@@ -395,20 +395,41 @@ class WifiConnections(Box):
|
||||
def toggle_other_networks(self, *_):
|
||||
"""Toggle the visibility of other networks section"""
|
||||
current_state = self.other_networks.get_visible()
|
||||
self.other_networks.set_visible(not current_state)
|
||||
|
||||
if self.other_networks.get_visible():
|
||||
self._cancel_pending_refresh()
|
||||
if current_state:
|
||||
self.other_networks.set_visible(False)
|
||||
self.other_networks_scrolled.snap_to_size(0)
|
||||
else:
|
||||
self.other_networks.set_visible(True)
|
||||
if self.wifi_service:
|
||||
self.wifi_service.scan()
|
||||
if hasattr(self, "_refresh_timeout_id") and self._refresh_timeout_id:
|
||||
GLib.source_remove(self._refresh_timeout_id)
|
||||
# Defer refresh until after the height animation completes
|
||||
GLib.idle_add(self._refresh_after_animation)
|
||||
|
||||
def _do_refresh():
|
||||
self.force_network_refresh()
|
||||
self._refresh_timeout_id = None
|
||||
return False
|
||||
def _cancel_pending_refresh(self):
|
||||
if hasattr(self, "_anim_finished_handler") and self._anim_finished_handler:
|
||||
try:
|
||||
self.other_networks_scrolled.height_animator.disconnect(
|
||||
self._anim_finished_handler
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
self._anim_finished_handler = None
|
||||
|
||||
self._refresh_timeout_id = GLib.timeout_add(150, _do_refresh)
|
||||
def _refresh_after_animation(self):
|
||||
if self._destroyed:
|
||||
return False
|
||||
anim = self.other_networks_scrolled.height_animator
|
||||
if anim.playing:
|
||||
self._anim_finished_handler = anim.connect(
|
||||
"finished",
|
||||
lambda *_: (
|
||||
self.force_network_refresh() if not self._destroyed else None
|
||||
),
|
||||
)
|
||||
else:
|
||||
self.force_network_refresh()
|
||||
return False
|
||||
|
||||
def on_network_ready(self, *_):
|
||||
"""Called when network service is ready"""
|
||||
@@ -720,6 +741,7 @@ class WifiConnections(Box):
|
||||
"""Cleanup when widget is destroyed"""
|
||||
self._destroyed = True
|
||||
self.stop_network_monitoring()
|
||||
self._cancel_pending_refresh()
|
||||
for obj, sig_id in self._signal_ids:
|
||||
try:
|
||||
obj.disconnect(sig_id)
|
||||
@@ -728,11 +750,9 @@ class WifiConnections(Box):
|
||||
self._signal_ids.clear()
|
||||
self.wifi_service = None
|
||||
self.network_service = None
|
||||
try:
|
||||
self.other_networks_revealer.child_revealed = False
|
||||
except Exception as e:
|
||||
logger.error(f"[WiFi] Failed to hide other networks revealer: {e}")
|
||||
|
||||
def close_wifi(self):
|
||||
"""Called when WiFi panel is being closed"""
|
||||
self.other_networks_revealer.child_revealed = False
|
||||
if self.other_networks.get_visible():
|
||||
self.other_networks.set_visible(False)
|
||||
self.other_networks_scrolled.snap_to_size(0)
|
||||
@@ -172,6 +172,9 @@ class Launcher(Window):
|
||||
|
||||
self.show_all()
|
||||
|
||||
if not self.results:
|
||||
self.results_scroll.hide()
|
||||
|
||||
if trigger_keyword:
|
||||
# Set flag to track that launcher was opened with a trigger keyword
|
||||
self.opened_with_trigger = True
|
||||
@@ -764,7 +767,10 @@ class Launcher(Window):
|
||||
|
||||
self.results_box.show_all()
|
||||
|
||||
self.results_scroll.show()
|
||||
if self.results:
|
||||
self.results_scroll.show()
|
||||
else:
|
||||
self.results_scroll.hide()
|
||||
|
||||
def _update_input_action_text(self):
|
||||
"""Update the input field with action text (Spotlight-style)."""
|
||||
@@ -810,7 +816,7 @@ class Launcher(Window):
|
||||
child.destroy()
|
||||
else:
|
||||
self.results_box.remove(child)
|
||||
# Keep the results scroll visible even when empty
|
||||
self.results_scroll.hide()
|
||||
|
||||
def _handle_escape_key(self) -> bool:
|
||||
"""Handle escape key press."""
|
||||
|
||||
Reference in new issue
Block a user