Add search to the RS comments list#23063
Conversation
Add a Compose comments list backed by wordpress-rs, following the
postsrs/pagesrs pattern. There's no rs mobile-cache support for comments
yet, so each tab pages directly against /wp/v2/comments using the
response's nextPageParams as the cursor.
- 5 filter tabs (All/Pending/Approved/Spam/Trashed). The All and
Approved tabs use CommentStatus.Custom("all"/"approve") because
WP_Comment_Query doesn't recognise the "approved" value the rs enum
serialises to
- Rows show avatar, bold "author on post" title (post titles resolved
via a batched sparse-field request), snippet, date, pending indicator
- Pull-to-refresh, load-more, retry snackbars, shimmer/empty/error states
- Tapping a row opens the rs comment detail; the list refreshes on return
- Gated in ActivityLauncher.viewUnifiedComments by RS_UNIFIED_COMMENTS +
site capability (WP.com REST or application password), falling back to
the legacy list; the now-dead per-tap rs gate inside the legacy list
fragment is removed
Batch moderation and search follow in stacked PRs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generated by 🚫 Danger |
|
|
|
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## trunk #23063 +/- ##
==========================================
- Coverage 37.37% 37.33% -0.04%
==========================================
Files 2337 2337
Lines 126703 126824 +121
Branches 17453 17470 +17
==========================================
Hits 47354 47354
- Misses 75472 75593 +121
Partials 3877 3877 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…rience Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…g and SnackbarMessage Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Danger requires immutable string keys: changed copy gets a new key rather than editing the old one in place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Key the post-title cache by (site, post id) so titles can't leak across sites, and negative-cache unresolvable ids so they aren't re-requested on every page load - Set perPage explicitly on title batches (server default of 10 silently truncated larger batches) and fall back to the pages endpoint for comments left unresolved by the posts endpoint - Discard load-more results whose fetch predates the latest applied first page, preventing stale pages/cursors after a silent refresh - Offer a retry action on load-more failures and auto-advance past pages that dedupe away entirely, so pagination can't stall at the list bottom Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Chunk post-title batches to the server's per_page maximum of 100; larger values are rejected outright with rest_invalid_param - Always attempt the pages endpoint for ids the posts endpoint didn't resolve, and only negative-cache when both endpoints succeeded - Clear negative-cached titles on user-initiated refresh so posts published after first sight can resolve - Cap unattended load-more auto-advance at 3 pages and let it handle empty pages, not just fully-deduplicated ones - Don't cancel/re-fire an identical in-flight title-resolve batch - Add CommentsRsDataSourceTest covering the cache, fallback, and chunking behavior, plus ViewModel tests for the new paging rules Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Cancel a tab's in-flight title-resolve job on user refresh so a job holding pre-clear 'not found' results can't re-apply them via the identical-ids guard - Generation-stamp the negative cache so a fetch already in flight when the user cleared can't re-poison entries with pre-clear results - Make the data source tests execute each request's builder lambda against a mocked uniffi client, asserting the endpoint, include count, and perPage actually sent — the chunking test now fails if chunking is reverted, and the posts-before-pages order is asserted, not assumed Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves the Android Lint code-scanning alerts on CommentsRsDataSourceTest: SparseAnyPostWithViewContext and PostsRequestFilterListWithViewContextResponse are pure data classes, so the tests now build real instances. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Detail opened from the rs list backfills the FluxC cache (WP.com) and resolves the post title via rs, so title and like state are correct - Detail reports RESULT_OK only when the comment changed; the list only refreshes then, keeping paged lists and scroll position intact - Guard against duplicate first-page fetches; skip the retry snackbar when a silent refresh fails on a tab that already shows comments - Clear isLoadingMore when a refresh replaces the list so paging can't stall behind the busy guard - Stop the load-more trigger firing on the empty pre-layout list and re-arm it when the list size changes - Evict all cached post titles for the site on user refresh so renamed posts pick up their new title - Track COMMENT_FILTER_CHANGED on tab changes like the legacy list - Restore the singleTop launch mode the legacy comments activity has - Drop the dead initializingTabs bookkeeping - Merge RsCommentListItem into RsComment (one shared type and mapper) - Move the new unit tests to a follow-up PR to reduce this PR's size Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6cfe5e1 to
57bff96
Compare
- Delete the now-unused ActivityLauncher.viewUnifiedCommentsDetails - Track title-resolve jobs as a plain per-tab Job: cancel-and-relaunch is cheap because the data source caches resolved titles - Drop the dead tab parameter from onCommentClick and the unused snackbarMessages default argument Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Long-press a comment to enter selection mode, then tap rows to build the selection. The top bar swaps to a contextual action bar offering the same per-tab actions as the legacy list's action mode (approve/unapprove/spam/ not-spam/trash/restore/delete), with confirmation dialogs for trash and delete-permanently and COMMENT_BATCH_* analytics. Moderation runs the rs writes in parallel, aggregates any failures into a single snackbar, then refreshes all initialized tabs, since moderated comments move between them. Selection clears on tab change and after each batch action. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Search icon in the top bar opens an inline query field (like the rs posts list): queries are debounced 250ms with a 3-character minimum, keep the active tab's status filter, and clear back to the normal tab content when search closes. Selection mode is cleared when search opens or closes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
57bff96 to
8d90ca5
Compare
…list-search # Conflicts: # WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListActivity.kt # WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListUiState.kt # WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListViewModel.kt # WordPress/src/main/java/org/wordpress/android/ui/commentsrs/screens/CommentsRsListItem.kt # WordPress/src/main/java/org/wordpress/android/ui/commentsrs/screens/CommentsRsListScreen.kt # WordPress/src/main/java/org/wordpress/android/ui/commentsrs/screens/CommentsRsTabListScreen.kt # WordPress/src/main/res/values/strings.xml
- Track and cancel in-flight load-more jobs in clearTabs(): a survivor could land on a reset page-generation counter and append its stale (unfiltered) page into fresh search results, corrupting the cursor chain - Don't resurrect a cleared tab from the stale-load-more discard branch; the ghost entry blocked initTab and left the tab shimmering forever - Keep the tab row visible while searching: the comments endpoint accepts a single status per request (unlike posts), so a search is always scoped to one tab — visible tabs make that scope explicit and switchable - Reset each tab's scroll position when search opens, changes query, or closes, so replaced content renders at the top instead of clamping to the old offset and tripping the load-more trigger - Use trimmed query lengths for the debounce filter and the idle/searching thresholds, so whitespace-only queries can't fetch the unfiltered list - Clear results on any below-minimum query (not just blank) so the previous query's rows can't flash as matches for the next one - Guard initTab against fetching during search-idle (Activity recreation or a late pager settle would bypass the debounce and minimum length) - Only clear the selection on a real tab change, not the settled-page re-emission after recreation, and request search focus once per open so a selection round-trip doesn't pop the keyboard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Re-init the tab the user is looking at (lastTrackedTab, which follows every pager settle) instead of the tab captured at keystroke time; a tab switch inside the debounce window previously left the visible tab as a permanent shimmer with no fetch in flight. Removes the activeSearchTab field and the tab parameter from onSearchQueryChanged - Trim and dedupe the query pipeline so whitespace-only edits neither restart the debounce nor refetch, and send the trimmed query to the API - Clear displayed rows on any trimmed-query change, covering whole-string replacements (select-all + paste, keyboard suggestions, voice input) that never dip below the minimum length - Rework the scroll reset: skip the initial emission so Activity recreation keeps the restored scroll positions, and skip lists already at the top to avoid pointless forced remeasures and fling cancellation - Don't re-select failed batch-moderation ids into a search session opened while the batch ran; the untracked job outlives clearTabs and an invisible selection would swallow back presses and hijack row taps - Consolidate the minimum-length policy into one isSearchable predicate exposed as isQuerySearchable, so the screen no longer re-derives it from the ViewModel's companion constant Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Guard the failed-batch re-selection with a clear-generation counter instead of the instantaneous search flag: a batch run inside an unchanged search keeps the retry re-selection (its failed rows are still displayed), while any clearTabs() during the batch — search opened, closed, or query changed — suppresses it, closing the invisible-selection hole when search was opened and closed mid-batch - Unify the search-query policy in one flow: a shared trim+dedupe normalization feeds an immediate on-change clear and the debounced fetch, so the two halves can't drift; onSearchQueryChanged shrinks to a plain setter. The collector no longer re-clears, so a pager settle that already fetched the same query inside the debounce window keeps its results instead of being cancelled and refetched - Track the pager's current tab in a dedicated field instead of reusing the analytics dedupe key, so tracking changes can't silently retarget the debounced search - Render the blank search-idle screen (not the animated shimmer) for tabs cleared while awaiting the debounce, removing the per-keystroke results/shimmer flicker; shimmer now means an actual fetch in flight - Pass isSearchActive/isQuerySearchable to the tab screen and derive the idle/searching split inside it, removing the representable-but- impossible flag combination - Hoist the once-per-open focus request out of SearchTopBar, dropping its two ferry parameters Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Left behind when SearchTopBar's focus effect was hoisted to the caller. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
I don't see any tab while the query is active 🤔 Other than that, it looks good. |
@adalpari I'm not seeing this - for me, the tabs are still visible during the query. I think this was an issue while the PR was in draft but it was resolved, so please make sure to pull all changes. If the problem persists, can you capture a video of it? |


Description
This PR adds search to the new RS comments list. Note that search was not part of the "legacy" comment list, so this is a new feature.
Design note — search is scoped per tab, with the tab row visible while searching. Unlike the posts endpoint (which accepts a status list, letting postsRS search all statuses at once),
/wp/v2/commentsaccepts a singlestatusper request, so a comments search is always scoped to one status.Testing instructions
Enable the experimental feature flag and open a site with an app-password.