From 80456fa00e12f47115bd93f436f8aac276a186fa Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Sun, 20 Oct 2024 22:21:07 +0800 Subject: [PATCH] Fix toolbar flicker issue --- .../lib/components/wox_list_item_view.dart | 10 +-- .../views/wox_query_toolbar_view.dart | 16 +++- .../launcher/wox_launcher_controller.dart | 78 ++++++++++++------- Wox/plugin/system/app/app_darwin.go | 3 + 4 files changed, 72 insertions(+), 35 deletions(-) diff --git a/Wox.UI.Flutter/wox/lib/components/wox_list_item_view.dart b/Wox.UI.Flutter/wox/lib/components/wox_list_item_view.dart index 7dd6bab4a..e598ba335 100644 --- a/Wox.UI.Flutter/wox/lib/components/wox_list_item_view.dart +++ b/Wox.UI.Flutter/wox/lib/components/wox_list_item_view.dart @@ -102,7 +102,7 @@ class WoxListItemView extends StatelessWidget { @override Widget build(BuildContext context) { - if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view $key - container"); + if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view ${title.value} - container"); return Container( decoration: BoxDecoration( @@ -131,7 +131,7 @@ class WoxListItemView extends StatelessWidget { : Padding( padding: const EdgeInsets.only(left: 5.0, right: 10.0), child: Obx(() { - if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view $key - icon"); + if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view ${title.value} - icon"); return WoxImageView( woxImage: icon.value, @@ -142,7 +142,7 @@ class WoxListItemView extends StatelessWidget { Expanded( child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() { - if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view $key - title"); + if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view ${title.value} - title"); return Text( title.value, @@ -160,7 +160,7 @@ class WoxListItemView extends StatelessWidget { ); }), Obx(() { - if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view $key - subtitle"); + if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view ${title.value} - subtitle"); return subTitle.isNotEmpty ? Padding( @@ -184,7 +184,7 @@ class WoxListItemView extends StatelessWidget { ), // Tails Obx(() { - if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view $key - tails"); + if (LoggerSwitch.enablePaintLog) Logger.instance.info(const UuidV4().generate(), "repaint: list item view ${title.value} - tails"); if (tails.isNotEmpty) { return buildTails(); } else { diff --git a/Wox.UI.Flutter/wox/lib/modules/launcher/views/wox_query_toolbar_view.dart b/Wox.UI.Flutter/wox/lib/modules/launcher/views/wox_query_toolbar_view.dart index 6d71edb10..3ea7b843f 100644 --- a/Wox.UI.Flutter/wox/lib/modules/launcher/views/wox_query_toolbar_view.dart +++ b/Wox.UI.Flutter/wox/lib/modules/launcher/views/wox_query_toolbar_view.dart @@ -2,16 +2,20 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:from_css_color/from_css_color.dart'; import 'package:get/get.dart'; +import 'package:uuid/v4.dart'; import 'package:wox/components/wox_hotkey_view.dart'; import 'package:wox/components/wox_image_view.dart'; import 'package:wox/entity/wox_hotkey.dart'; import 'package:wox/modules/launcher/wox_launcher_controller.dart'; +import 'package:wox/utils/log.dart'; import 'package:wox/utils/wox_theme_util.dart'; class WoxQueryToolbarView extends GetView { const WoxQueryToolbarView({super.key}); - Widget leftTip() { + Widget leftPart() { + if (LoggerSwitch.enablePaintLog) Logger.instance.debug(const UuidV4().generate(), "repaint: toolbar view - left part"); + return Obx(() { final toolbarInfo = controller.toolbar.value; return SizedBox( @@ -83,7 +87,9 @@ class WoxQueryToolbarView extends GetView { }); } - Widget rightTip() { + Widget rightPart() { + if (LoggerSwitch.enablePaintLog) Logger.instance.debug(const UuidV4().generate(), "repaint: toolbar view - right part"); + return Obx(() { final toolbarInfo = controller.toolbar.value; if (toolbarInfo.hotkey == null || toolbarInfo.hotkey!.isEmpty) { @@ -113,6 +119,8 @@ class WoxQueryToolbarView extends GetView { @override Widget build(BuildContext context) { + if (LoggerSwitch.enablePaintLog) Logger.instance.debug(const UuidV4().generate(), "repaint: query toolbar view - container"); + return Obx(() { return SizedBox( height: WoxThemeUtil.instance.getToolbarHeight(), @@ -132,8 +140,8 @@ class WoxQueryToolbarView extends GetView { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - leftTip(), - rightTip(), + leftPart(), + rightPart(), ], ), ), diff --git a/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart b/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart index 7f02747f1..861fe34a0 100644 --- a/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart +++ b/Wox.UI.Flutter/wox/lib/modules/launcher/wox_launcher_controller.dart @@ -56,7 +56,8 @@ class WoxLauncherController extends GetxController { /// The timer to clear query results. /// On every query changed, it will reset the timer and will clear the query results after N ms. /// If there is no this delay mechanism, the window will flicker for fast typing. - var clearQueryResultsTimer = Timer(const Duration(), () => {}); + Timer clearQueryResultsTimer = Timer(const Duration(), () => {}); + final clearQueryResultDelay = 1000; // action related variables /// The list of result actions for the active query result. @@ -78,16 +79,20 @@ class WoxLauncherController extends GetxController { final isInSettingView = false.obs; var positionBeforeOpenSetting = const Offset(0, 0); - /// toolbar at bottom of launcher - final toolbar = ToolbarInfo.empty().obs; - /// The icon at end of query box. final queryIcon = QueryIconInfo.empty().obs; /// The result of the doctor check. var doctorCheckPassed = true; + // toolbar related variables + final toolbar = ToolbarInfo.empty().obs; final toolbarCopyText = 'Copy'.obs; + // The timer to clean the toolbar when query changed + // on every query changed, it will reset the timer and will clear the toolbar after N ms + // If there is no this delay mechanism, the toolbar will flicker for fast typing + Timer cleanToolbarTimer = Timer(const Duration(), () => {}); + final cleanToolbarDelay = 1000; /// Triggered when received query results from the server. void onReceivedQueryResults(String traceId, List receivedResults) { @@ -379,7 +384,7 @@ class WoxLauncherController extends GetxController { // and then the query result is received which will expand the windows height. so it will causes window flicker clearQueryResultsTimer.cancel(); clearQueryResultsTimer = Timer( - const Duration(milliseconds: 100), + Duration(milliseconds: clearQueryResultDelay), () { clearQueryResults(); }, @@ -849,6 +854,9 @@ class WoxLauncherController extends GetxController { } void showToolbarMsg(String traceId, ToolbarMsg msg) { + // cancel the timer if it is running + cleanToolbarTimer.cancel(); + toolbar.value = ToolbarInfo( text: msg.text, icon: msg.icon, @@ -972,23 +980,34 @@ class WoxLauncherController extends GetxController { } void updateToolbarOnQueryChanged(String traceId, PlainQuery query) { - //if doctor check is not passed and query is empty, show doctor tip - if (query.isEmpty && !doctorCheckPassed) { - Logger.instance.debug(traceId, "update toolbar to doctor warning, query is empty and doctor check not passed"); - toolbar.value = ToolbarInfo( - text: "Doctor check not passed", - icon: WoxImage(imageType: WoxImageTypeEnum.WOX_IMAGE_TYPE_BASE64.code, imageData: QUERY_ICON_DOCTOR_WARNING), - hotkey: "enter", - actionName: "Check", - action: () { - onQueryChanged(traceId, PlainQuery.text("doctor "), "user click query icon"); - }, - ); + cleanToolbarTimer.cancel(); + + // if query is empty, we need to immediately update the toolbar + if (query.isEmpty) { + // if query is empty and doctor check is not passed, show doctor warning + if (!doctorCheckPassed) { + Logger.instance.debug(traceId, "update toolbar to doctor warning, query is empty and doctor check not passed"); + toolbar.value = ToolbarInfo( + text: "Doctor check not passed", + icon: WoxImage(imageType: WoxImageTypeEnum.WOX_IMAGE_TYPE_BASE64.code, imageData: QUERY_ICON_DOCTOR_WARNING), + hotkey: "enter", + actionName: "Check", + action: () { + onQueryChanged(traceId, PlainQuery.text("doctor "), "user click query icon"); + }, + ); + } else { + Logger.instance.debug(traceId, "update toolbar to empty because of query changed and is empty"); + toolbar.value = ToolbarInfo.empty(); + } return; } - Logger.instance.debug(traceId, "update toolbar to empty because of query changed"); - toolbar.value = ToolbarInfo.empty(); + // if query is not empty, update the toolbar after 100ms to avoid flickering + cleanToolbarTimer = Timer(Duration(milliseconds: cleanToolbarDelay), () { + Logger.instance.debug(traceId, "update toolbar to empty because of query changed"); + toolbar.value = ToolbarInfo.empty(); + }); } /// Update the toolbar based on the active action @@ -996,13 +1015,20 @@ class WoxLauncherController extends GetxController { var activeAction = getActiveAction(); if (activeAction != null) { Logger.instance.debug(traceId, "update toolbar to active action: ${activeAction.name.value}"); - toolbar.value = ToolbarInfo( - hotkey: "enter", - actionName: activeAction.name.value, - action: () { - executeAction(traceId, getActiveResult(), activeAction); - }, - ); + + // cancel the timer if it is running + cleanToolbarTimer.cancel(); + + // only update action and hotkey if it's different from the current one + if (toolbar.value.actionName != activeAction.name.value || toolbar.value.hotkey != activeAction.hotkey) { + toolbar.value = ToolbarInfo( + hotkey: "enter", + actionName: activeAction.name.value, + action: () { + executeAction(traceId, getActiveResult(), activeAction); + }, + ); + } } else { Logger.instance.debug(traceId, "update toolbar to empty, no active action"); toolbar.value = ToolbarInfo.empty(); diff --git a/Wox/plugin/system/app/app_darwin.go b/Wox/plugin/system/app/app_darwin.go index 7e7ee43bf..452cf3871 100644 --- a/Wox/plugin/system/app/app_darwin.go +++ b/Wox/plugin/system/app/app_darwin.go @@ -68,6 +68,9 @@ func (a *MacRetriever) GetAppDirectories(ctx context.Context) []appDirectory { { Path: "/System/Applications", Recursive: true, RecursiveDepth: 2, }, + { + Path: "/System/Library/CoreServices/Applications", Recursive: false, + }, { Path: "/System/Library/PreferencePanes", Recursive: false, },