fix: prevent page flickering on rapid sidebar clicks (#8278)

* fix: prevent page flickering on rapid sidebar clicks

* refactor: improve deduplication to check both plugin and view IDs
This commit is contained in:
Rishi Ahuja 2025-11-06 18:37:18 -08:00 committed by GitHub
parent b5a1ccb4ee
commit f0f10b05f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 1 deletions

View File

@ -28,6 +28,11 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
late final MenuSharedState menuSharedState;
String? _lastOpenedPluginId;
String? _lastOpenedViewId;
DateTime? _lastOpenTime;
static const _deduplicationWindow = Duration(milliseconds: 500);
@override
Future<void> close() {
state.dispose();
@ -73,6 +78,22 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
_setLatestOpenView(view);
},
openPlugin: (Plugin plugin, ViewPB? view, bool setLatest) {
final now = DateTime.now();
// deduplicate. skip if same plugin and view were just opened
if (_lastOpenedPluginId == plugin.id &&
_lastOpenedViewId == view?.id &&
_lastOpenTime != null) {
final timeSinceLastOpen = now.difference(_lastOpenTime!);
if (timeSinceLastOpen < _deduplicationWindow) {
return;
}
}
_lastOpenedPluginId = plugin.id;
_lastOpenedViewId = view?.id;
_lastOpenTime = now;
state.currentPageManager
..hideSecondaryPlugin()
..setSecondaryPlugin(BlankPagePlugin());

View File

@ -497,6 +497,23 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
bool isIconPickerOpened = false;
DateTime? _lastClickTime;
static const _clickThrottleDuration = Duration(milliseconds: 200);
void _handleViewTap() {
final now = DateTime.now();
if (_lastClickTime != null) {
final timeSinceLastClick = now.difference(_lastClickTime!);
if (timeSinceLastClick < _clickThrottleDuration) {
return;
}
}
_lastClickTime = now;
widget.onSelected(context, widget.view);
}
@override
Widget build(BuildContext context) {
bool isSelected = widget.isSelected;
@ -586,7 +603,7 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
final child = GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => widget.onSelected(context, widget.view),
onTap: _handleViewTap,
onTertiaryTapDown: (_) =>
widget.onTertiarySelected?.call(context, widget.view),
child: SizedBox(