diff --git a/lib/screens/home_search_logic.dart b/lib/screens/home_search_logic.dart index 32042f8c..8d7fe487 100644 --- a/lib/screens/home_search_logic.dart +++ b/lib/screens/home_search_logic.dart @@ -137,6 +137,24 @@ class HomeSearchProviderPolicy { return resolveProvider(explicitSearchProvider, extensions) != null; } + /// Keeps the Home search surface stable while extension/provider state is + /// being reconciled. A transient missing search capability must not remove + /// the field above an already-visible Home feed; changing providers should + /// never be required just to make Search reappear. + static bool shouldShowSearchBar({ + required bool hasSearchProvider, + required bool isSearchProviderLoading, + required bool hasHomeFeedExtension, + required bool hasExploreContent, + required bool hasSearchInput, + }) { + return hasSearchProvider || + isSearchProviderLoading || + hasHomeFeedExtension || + hasExploreContent || + hasSearchInput; + } + static String? sanitizeFilter( String? filter, String? currentSearchProvider, diff --git a/lib/screens/home_tab.dart b/lib/screens/home_tab.dart index 4d1be1a6..1d6635bd 100644 --- a/lib/screens/home_tab.dart +++ b/lib/screens/home_tab.dart @@ -768,7 +768,13 @@ class _HomeTabState extends ConsumerState explicitSearchProvider, extensions, ); - final showSearchBar = hasSearchProvider || isSearchProviderLoading; + final showSearchBar = HomeSearchProviderPolicy.shouldShowSearchBar( + hasSearchProvider: hasSearchProvider, + isSearchProviderLoading: isSearchProviderLoading, + hasHomeFeedExtension: hasHomeFeedExtension, + hasExploreContent: hasExploreContent, + hasSearchInput: hasSearchInput, + ); final hasResults = hasSearchInput || hasActualResults || isLoading || showRecentAccess; final showExplore = diff --git a/test/maintainability_contracts_test.dart b/test/maintainability_contracts_test.dart index 7804f558..ef4eb750 100644 --- a/test/maintainability_contracts_test.dart +++ b/test/maintainability_contracts_test.dart @@ -121,6 +121,39 @@ void main() { ); }); + test('keeps Search visible across transient provider reconciliation', () { + expect( + HomeSearchProviderPolicy.shouldShowSearchBar( + hasSearchProvider: false, + isSearchProviderLoading: false, + hasHomeFeedExtension: true, + hasExploreContent: true, + hasSearchInput: false, + ), + isTrue, + ); + expect( + HomeSearchProviderPolicy.shouldShowSearchBar( + hasSearchProvider: false, + isSearchProviderLoading: false, + hasHomeFeedExtension: false, + hasExploreContent: false, + hasSearchInput: true, + ), + isTrue, + ); + expect( + HomeSearchProviderPolicy.shouldShowSearchBar( + hasSearchProvider: false, + isSearchProviderLoading: false, + hasHomeFeedExtension: false, + hasExploreContent: false, + hasSearchInput: false, + ), + isFalse, + ); + }); + test('canonicalizes built-in and extension search filters', () { final extension = _searchExtension( id: 'provider',