From 6480034a63e8e4cba34e787fc601beebbcfbad86 Mon Sep 17 00:00:00 2001 From: Strycher Date: Wed, 29 Jul 2026 21:19:22 -0400 Subject: [PATCH] fix(#429): debounce 0x91 channel-change push to coalesce burst re-syncs Gemini review (standards#145) flagged that a burst of 0x91 pushes (e.g. a bulk channel edit on the device) would each trigger a full getChannels re-sync. getChannels already guards concurrent syncs (_isSyncingChannels), so there is no request flooding, but sequential re-syncs after each completes would repeatedly clear+repopulate the channel list (UI flicker). Coalesce the burst with a 400ms debounce so it settles into a single re-sync. Timer is cancelled in dispose(). Citadel: meshcore-open-p12 --- lib/connector/meshcore_connector.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index 17ead0a..79d4ed4 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -378,6 +378,7 @@ class MeshCoreConnector extends ChangeNotifier { bool _isSyncingChannels = false; bool _channelSyncInFlight = false; Timer? _channelSyncTimeout; + Timer? _channelsChangedDebounce; int _channelSyncRetries = 0; int _nextChannelIndexToRequest = 0; int _totalChannelsToRequest = 0; @@ -4796,8 +4797,14 @@ class MeshCoreConnector extends ChangeNotifier { break; case pushCodeChannelsChanged: // Device's channel table changed (add/update/delete). Re-poll instead - // of only refreshing on reconnect (#429 part A). - unawaited(getChannels(force: true)); + // of only refreshing on reconnect (#429 part A). Debounce so a burst + // (e.g. a bulk edit on the device) coalesces into one re-sync rather + // than repeatedly clearing and repopulating the channel list. + _channelsChangedDebounce?.cancel(); + _channelsChangedDebounce = Timer( + const Duration(milliseconds: 400), + () => unawaited(getChannels(force: true)), + ); break; case respCodeChannelInfo: _handleChannelInfo(frame); @@ -7552,6 +7559,7 @@ class MeshCoreConnector extends ChangeNotifier { _batteryPollTimer?.cancel(); _gpsLocationPollTimer?.cancel(); _radioStatsPollTimer?.cancel(); + _channelsChangedDebounce?.cancel(); radioStatsNotifier.dispose(); _receivedFramesController.close(); _usbManager.dispose();