From 2a745e2fec44d0baca620a4150ddbadd64119977 Mon Sep 17 00:00:00 2001 From: Tatiana Elfimova Date: Sat, 21 Jun 2025 22:42:53 +0200 Subject: [PATCH] Search Everywhere: the list is flickering in a particular case - Remove redundant `activeTab.setActive(true)` call - Make `SeTabVm._searchResults` nullable to prevent empty flow from leaking to UI before proper initialization, set `_searchResults.value = null` on tab deactivation, and ignore nulls in UI using `it.searchResults.filterNotNull()` - Fix warning: Remove `toolbar.updateActionsAsync()`, because "toolbar manual update is ignored. Newly created toolbars are updated automatically on `addNotify`" GitOrigin-RevId: 775552dab090c99c7989ee52715fb4e710a625bc --- .../frontend/src/ui/SePopupContentPane.kt | 16 ++++++++-------- .../frontend/src/ui/SePopupHeaderPane.kt | 4 ---- .../frontend/src/vm/SePopupVm.kt | 2 -- .../searchEverywhere/frontend/src/vm/SeTabVm.kt | 10 +++++++--- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/platform/searchEverywhere/frontend/src/ui/SePopupContentPane.kt b/platform/searchEverywhere/frontend/src/ui/SePopupContentPane.kt index 6740f46bed66..e0af59bfc814 100644 --- a/platform/searchEverywhere/frontend/src/ui/SePopupContentPane.kt +++ b/platform/searchEverywhere/frontend/src/ui/SePopupContentPane.kt @@ -141,7 +141,7 @@ class SePopupContentPane(private val project: Project?, private val vm: SePopupV withContext(Dispatchers.EDT) { resultListModel.reset() } - it.searchResults + it.searchResults.filterNotNull() }.collectLatest { throttledResultEventFlow -> coroutineScope { withContext(Dispatchers.EDT) { @@ -164,6 +164,13 @@ class SePopupContentPane(private val project: Project?, private val vm: SePopupV SeLog.log(SeLog.THROTTLING) { "Throttled flow completed" } resultListModel.removeLoadingItem() + if (!resultListModel.isValid) { + if (!textField.text.isEmpty() && + (vm.currentTab.getSearchEverywhereToggleAction() as? AutoToggleAction)?.autoToggle(true) ?: false) { + return@withContext + } + } + if (!resultListModel.isValid) resultListModel.reset() if (resultListModel.isEmpty) { @@ -171,13 +178,6 @@ class SePopupContentPane(private val project: Project?, private val vm: SePopupV updateEmptyStatus() } } - }.onEmpty { - withContext(Dispatchers.EDT) { - val action = vm.currentTab.getSearchEverywhereToggleAction() - if (!textField.text.isEmpty() && (action as? AutoToggleAction)?.autoToggle(true) ?: false) { - headerPane.updateToolbarActions() - } - } }.collect { event -> withContext(Dispatchers.EDT) { textField.setSearchInProgress(false) diff --git a/platform/searchEverywhere/frontend/src/ui/SePopupHeaderPane.kt b/platform/searchEverywhere/frontend/src/ui/SePopupHeaderPane.kt index 6c3d81bc6787..24c6bda348dc 100644 --- a/platform/searchEverywhere/frontend/src/ui/SePopupHeaderPane.kt +++ b/platform/searchEverywhere/frontend/src/ui/SePopupHeaderPane.kt @@ -130,10 +130,6 @@ class SePopupHeaderPane( } } - fun updateToolbarActions() { - toolbar.updateActionsAsync() - } - class Tab(val name: @Nls String, val id: String, val reportableId: String) { constructor(tabVm: SeTabVm) : this(tabVm.name, tabVm.tabId, tabVm.reportableTabId) } diff --git a/platform/searchEverywhere/frontend/src/vm/SePopupVm.kt b/platform/searchEverywhere/frontend/src/vm/SePopupVm.kt index 569792682f61..34ddb20ae6a9 100644 --- a/platform/searchEverywhere/frontend/src/vm/SePopupVm.kt +++ b/platform/searchEverywhere/frontend/src/vm/SePopupVm.kt @@ -60,7 +60,6 @@ class SePopupVm( init { check(tabVms.isNotEmpty()) { "Search Everywhere tabs must not be empty" } - val activeTab = tabVms.first() currentTabFlow = currentTabIndex.map { tabVms[it.coerceIn(tabVms.indices)] }.withPrevious().map { (prev, next) -> @@ -68,7 +67,6 @@ class SePopupVm( next.setActive(true) next } - activeTab.setActive(true) searchPattern.value = initialSearchPattern ?: run { // History could be suppressed by the user for some reason (creating promo video, conference demo etc.) diff --git a/platform/searchEverywhere/frontend/src/vm/SeTabVm.kt b/platform/searchEverywhere/frontend/src/vm/SeTabVm.kt index 30bab018842b..cf703408e886 100644 --- a/platform/searchEverywhere/frontend/src/vm/SeTabVm.kt +++ b/platform/searchEverywhere/frontend/src/vm/SeTabVm.kt @@ -37,7 +37,7 @@ class SeTabVm( private val tab: SeTab, private val searchPattern: StateFlow, ) { - val searchResults: StateFlow>> get() = _searchResults.asStateFlow() + val searchResults: StateFlow>?> get() = _searchResults.asStateFlow() val name: String get() = tab.name val filterEditor: SuspendLazyProperty = initAsync(coroutineScope) { tab.getFilterEditor() } val tabId: String get() = tab.id @@ -52,7 +52,7 @@ class SeTabVm( shouldLoadMoreFlow.value = value } - private val _searchResults: MutableStateFlow>> = MutableStateFlow(emptyFlow()) + private val _searchResults: MutableStateFlow>?> = MutableStateFlow(null) private val isActiveFlow: MutableStateFlow = MutableStateFlow(false) private val dumbModeStateFlow = @@ -76,7 +76,10 @@ class SeTabVm( isActiveFlow.combine(dumbModeStateFlow) { isActive, _ -> isActive }.collectLatest { isActive -> - if (!isActive) return@collectLatest + if (!isActive) { + _searchResults.value = null + return@collectLatest + } val searchPatternWithAutoToggle = searchPattern.onEach { withContext(Dispatchers.EDT) { @@ -102,6 +105,7 @@ class SeTabVm( shouldThrottle.store(true) resultsFlow }.collect { + if (!isActiveFlow.value) return@collect _searchResults.value = it } }