Skip to content

fix(search): empty list when 'Hide seen' filters all (#574)#582

Merged
rainxchzed merged 6 commits into
mainfrom
fix/search-empty-list-display
May 12, 2026
Merged

fix(search): empty list when 'Hide seen' filters all (#574)#582
rainxchzed merged 6 commits into
mainfrom
fix/search-empty-list-display

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented May 12, 2026

Search screen showed "N results found" over an empty grid when the global 'Hide seen' tweak filtered out every API hit. UI had no explanation and no way to recover from the search screen itself — the user had to dig into Tweaks to figure out why.

Add a centered banner + 'Show all results' CTA that disables the global Hide-seen flag in one tap. Triggers only when repositories.isNotEmpty() && visibleRepos.isEmpty() && isHideSeenEnabled — never fires for genuine zero-result searches.

Strings localized across 13 locales (en + 12). Closes #574.

Not compile-verified locally — ~/.gradle/wrapper unreachable (SSD unmounted). Please run before merge:

  • :feature:search:presentation:compileDebugKotlinAndroid
  • :feature:search:presentation:compileKotlinJvm

Summary by CodeRabbit

  • New Features

    • Full-screen message when all search results are hidden by "Hide seen", with a one-tap action to disable the filter and reveal results.
    • Pagination will auto-load more results when hidden items exist but the visible list is empty; shows a centered loading/status while fetching unseen repos.
  • Chores

    • Added localized UI text for hidden-results message, "show all results" action, and searching status across multiple languages.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9edec42f-d6d8-4b47-b62c-b951622b8c77

📥 Commits

Reviewing files that changed from the base of the PR and between e639b30 and ac22549.

📒 Files selected for processing (14)
  • core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml
  • core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml
  • core/presentation/src/commonMain/composeResources/values-es/strings-es.xml
  • core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml
  • core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml
  • core/presentation/src/commonMain/composeResources/values-it/strings-it.xml
  • core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml
  • core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml
  • core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
  • core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
  • core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml
  • core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchRoot.kt
✅ Files skipped from review due to trivial changes (8)
  • core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml
  • core/presentation/src/commonMain/composeResources/values-it/strings-it.xml
  • core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
  • core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml
  • core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml
  • core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
🚧 Files skipped from review as they are similar to previous changes (5)
  • core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml
  • core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml
  • core/presentation/src/commonMain/composeResources/values-es/strings-es.xml
  • core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml
  • core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml

Walkthrough

When the "hide seen" filter hides all search results, the UI auto-loads more pages when available; if exhausted, it shows a localized full-screen banner with a "show all results" button that dispatches a new SearchAction handled by the ViewModel to disable the hide-seen preference.

Changes

Search hide-seen filter empty state

Layer / File(s) Summary
Localized UI strings and release notes
core/presentation/src/commonMain/composeResources/values/strings.xml, core/presentation/src/commonMain/composeResources/values-*/strings-*.xml (12 locales), core/presentation/src/commonMain/composeResources/files/whatsnew/17.json
Default + locale string resources added for search_results_hidden_by_seen_filter, show_all_results (and searching_for_unseen_repos in some locales); whatsnew v1.9.0 updated with the search fix.
Search action contract
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchAction.kt
Added data object OnDisableHideSeenForResults : SearchAction to represent the user's intent to disable the hide-seen filter.
Auto-pagination LaunchedEffect
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchRoot.kt
New LaunchedEffect auto-dispatches SearchAction.LoadMore when repositories are loaded but visibleRepos is empty due to hide-seen and additional pages exist.
Empty-state UI banner
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchRoot.kt
Full-size loading + message while fetching further pages; when pages are exhausted, shows "search results hidden by seen filter" and a CTA that dispatches OnDisableHideSeenForResults.
Action handler and preference update
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchViewModel.kt
ViewModel handles OnDisableHideSeenForResults by calling tweaksRepository.setHideSeenEnabled(false) inside a coroutine to disable the filter.

Sequence Diagram

sequenceDiagram
    participant User
    participant SearchScreen
    participant SearchViewModel
    participant tweaksRepository
    User->>SearchScreen: view search results
    SearchScreen->>SearchScreen: rawRepos non-empty, visibleRepos empty, hide-seen enabled
    alt more pages available
        SearchScreen->>SearchScreen: LaunchedEffect -> dispatch LoadMore
    else no more pages
        SearchScreen->>User: display empty-state banner with "show all results" button
        User->>SearchScreen: tap "show all results"
        SearchScreen->>SearchViewModel: dispatch OnDisableHideSeenForResults
        SearchViewModel->>tweaksRepository: setHideSeenEnabled(false)
        tweaksRepository-->>SearchViewModel: preference updated
        SearchViewModel-->>SearchScreen: state updated (hide-seen=false)
        SearchScreen->>User: previously hidden repositories shown
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 When filters hide each prize and treat,
A gentle banner greets your feet.
Tap once, a tweak, the veil is gone,
Hidden repos hop back at dawn. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(search): empty list when Hide seen filters all (#574)' directly describes the main bug fix: handling the case where the Hide seen filter removes all results from the visible list, causing an empty grid despite a positive result count.
Linked Issues check ✅ Passed The PR implements all coding requirements from #574: auto-pagination to fetch unseen repos when hide-seen filters all results, progress indication during fetching, localized strings for the empty state message and show-all-results action, and the ability to disable hide-seen via UI.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the #574 issue: strings for localization, SearchAction/SearchViewModel/SearchRoot changes for handling hide-seen filtering logic, and whatsnew documentation. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/search-empty-list-display

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 12, 2026

Greptile Summary

  • Adds auto-pagination logic that keeps loading pages when every result is filtered out by "Hide seen", plus a loading spinner for the in-progress state and a CTA banner once all pages are exhausted. The overall design addresses the original blank-screen issue (BUG (Search) : it only shows how much results it found, but not the search results themselves  #574).
  • The auto-paginate LaunchedEffect does not guard against errorMessage, so a failed page load (hasMorePages stays true, isLoadingMore resets to false) immediately re-triggers LoadMore, creating an infinite retry loop that suppresses the error message from ever being shown to the user.
  • The "Disable Hide seen filter" button permanently modifies a global preference (noted in prior review threads); all 13 locale strings now correctly reflect the filter-disable semantics.

Confidence Score: 4/5

Functional P1 bug in the auto-paginate loop must be fixed before merge; all other changes are straightforward.

Single P1 — infinite retry loop on network error during auto-pagination. The rest of the PR (spinner, banner, strings, ViewModel action) is clean. No P0s present.

feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchRoot.kt — the auto-paginate LaunchedEffect condition at lines 245–252.

Important Files Changed

Filename Overview
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchRoot.kt Adds auto-paginate LaunchedEffect and two conditional banners (loading spinner and "all hidden" CTA); the auto-paginate loop lacks an error guard, causing an infinite retry when a page load fails mid-pagination.
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchViewModel.kt Adds handler for OnDisableHideSeenForResults that calls tweaksRepository.setHideSeenEnabled(false); straightforward delegation, no logic issues introduced here.
feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchAction.kt Adds new OnDisableHideSeenForResults action; trivial sealed interface extension.
core/presentation/src/commonMain/composeResources/values/strings.xml Adds three new string resources for the hidden-results banner (search_results_hidden_by_seen_filter, show_all_results, searching_for_unseen_repos).
core/presentation/src/commonMain/composeResources/files/whatsnew/17.json Appends changelog entry for the Hide Seen empty-list fix.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Page loaded
repositories.isNotEmpty] --> B{visibleRepos
empty?}
    B -- No --> C[Show grid normally]
    B -- Yes --> D{isHideSeenEnabled?}
    D -- No --> E[Show empty state
or zero-result UI]
    D -- Yes --> F{hasMorePages?}
    F -- Yes --> G[Show spinner
'Searching for unseen repos']
    G --> H{errorMessage
null?}
    H -- Yes --> I[LaunchedEffect fires
LoadMore]
    H -- No --> J[⚠️ Loop: LaunchedEffect
fires LoadMore again]
    I --> K[isLoadingMore = true
next page fetches]
    K --> L{More unseen
pages exist?}
    L -- Yes, all seen --> F
    L -- No unseen found --> M[hasMorePages = false]
    F -- No --> N[Show banner
'All results hidden by Hide seen'
+ Disable filter button]
    N --> O{User taps
Disable filter}
    O --> P[setHideSeenEnabled false
global preference updated
all repos become visible]
Loading

Reviews (3): Last reviewed commit: "fix(search): show progress during hide-s..." | Re-trigger Greptile

Comment on lines +583 to +588
GithubStoreButton(
text = stringResource(Res.string.show_all_results),
onClick = {
onAction(SearchAction.OnDisableHideSeenForResults)
},
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 "Show all results" silently modifies a global preference

OnDisableHideSeenForResults calls tweaksRepository.setHideSeenEnabled(false), which persists the change app-wide and also affects the home screen. The button label "Show all results" (and all 13 locale equivalents) reads like a search-session action, not a settings toggle. Users who enabled Hide Seen intentionally may be confused when it stays off after leaving the search screen.

Consider either updating the label to make the scope explicit (e.g. "Disable 'Hide seen' filter") or scoping the override to the current search session only.

Comment on lines +245 to +252
if (state.repositories.isNotEmpty() &&
state.visibleRepos.isEmpty() &&
state.isHideSeenEnabled &&
state.hasMorePages &&
!state.isLoadingMore &&
!state.isLoading
) {
currentOnAction(SearchAction.LoadMore)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Infinite retry loop on network error during auto-pagination

When a page load fails, the catch blocks in performSearch set isLoadingMore = false but leave hasMorePages unchanged (still true). This change of isLoadingMore is a LaunchedEffect key, so the effect re-runs immediately, the condition passes again (!isLoadingMore, !isLoading, hasMorePages), and LoadMore fires again — looping until the process crashes or the user navigates away. The errorMessage is also set on each error but cleared immediately by the next attempt, so the error is never shown.

Add state.errorMessage == null to the guard:

Suggested change
if (state.repositories.isNotEmpty() &&
state.visibleRepos.isEmpty() &&
state.isHideSeenEnabled &&
state.hasMorePages &&
!state.isLoadingMore &&
!state.isLoading
) {
currentOnAction(SearchAction.LoadMore)
if (state.repositories.isNotEmpty() &&
state.visibleRepos.isEmpty() &&
state.isHideSeenEnabled &&
state.hasMorePages &&
!state.isLoadingMore &&
!state.isLoading &&
state.errorMessage == null
) {

@rainxchzed rainxchzed merged commit b9c5f6a into main May 12, 2026
1 check passed
@rainxchzed rainxchzed deleted the fix/search-empty-list-display branch May 12, 2026 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG (Search) : it only shows how much results it found, but not the search results themselves

1 participant