Skip to content

Reader: Add Discover sub-tabs (Freshly Pressed, Recommended, Latest)#22793

Draft
nbradbury wants to merge 15 commits intotrunkfrom
issue/reader-discover
Draft

Reader: Add Discover sub-tabs (Freshly Pressed, Recommended, Latest)#22793
nbradbury wants to merge 15 commits intotrunkfrom
issue/reader-discover

Conversation

@nbradbury
Copy link
Copy Markdown
Contributor

@nbradbury nbradbury commented Apr 14, 2026

Description

Replaces the single Discover feed with a tabbed experience containing three sub-tabs: Freshly Pressed, Recommended, and Latest, matching the web Reader Discover layout and using the same endpoints as it does. Note that I left Tags out of the sub-tabs because they're already handled separately by the app.

Testing instructions

  1. Open the Reader and tap Discover in the top-bar dropdown
  2. Verify three sub-tabs appear: Freshly Pressed, Recommended, Latest
  • Each tab loads its own stream of posts
  • Swiping between tabs works
  • Tapping a tab switches to it
  1. Scroll down in any tab and pull to refresh
  • Posts refresh correctly
  1. Scroll to the bottom of Recommended or Latest
  • "Load more" pagination works
  1. Switch to a different Reader feed (e.g. Subscriptions), then return to Discover
  • The last-selected sub-tab is restored
  1. Kill and relaunch the app, navigate to Discover
  • The last-selected sub-tab is still restored
Screen_recording_20260414_105039.mp4

nbradbury and others added 13 commits April 10, 2026 10:57
Apply a new WordPress.TabLayout.Material3 style to the Discover sub-tab
strip so it visually matches the Compose PrimaryTabRow used in the new
Stats and RS post list screens: text-width indicator with rounded top,
elastic animation, MD3 title-small typography, primary-colored selected
text, and a surface background flush with the app bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Route the Recommended and Latest Discover sub-tabs through the v2
/read/streams/discover endpoint to match iOS ReaderCardService, instead
of the legacy /read/tags/{slug}/posts endpoint. Both sub-tabs hit the
same endpoint and are distinguished by the tag slug — Latest adds
sort=date while Recommended uses the server's default editorial order.

Pagination is cursor-based via an opaque page_handle stored per-stream
in AppPrefs, and first-page requests include the shared reader refresh
counter so the server rotates the visible shard on pull-to-refresh.
The tags request param uses the user's followed tag slugs, falling
back to "dailyprompt,wordpress" when the user isn't following anything
(mirroring the existing ReaderDiscoverLogic behavior).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply post-review cleanups to the Recommended/Latest Discover streams:
drop the RECOMMENDED_PATH/LATEST_PATH aliases in favor of
DISCOVER_STREAMS_PATH, remove the single-use isDiscoverStream() helper,
inline the get/setPageHandleForStream helpers at their one-call-site
each, and rewire handleDiscoverStreamResponse to run on the existing
coroutine scope instead of spawning a raw Thread per response.

Also give the Recommended and Latest sub-tab ReaderTags proper display
titles (TAG_TITLE_RECOMMENDED / TAG_TITLE_LATEST) instead of reusing
their lowercase slugs, and make the tabTitleResFor when-expression
fail fast on unknown positions instead of silently falling back to
Freshly Pressed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Match the unselected tab text color to the selected color so the
Discover sub-tab strip is visually consistent with the New Stats and
new RS Post List tabbed screens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate the Freshly Pressed sub-tab from the legacy v1.2
/freshly-pressed endpoint to the v2 /read/streams/freshly-pressed
endpoint, matching iOS ReaderPostServiceRemote.fetchStreamCards and
reusing the same pipeline already in place for the Recommended and
Latest sub-tabs. Freshly Pressed now shares the cards parser, opaque
page_handle pagination, and shared refresh counter with the other two
Discover streams — only the per-stream page_handle is stored in its
own AppPrefs key so the three cursors don't collide.

Parameterise requestPostsForDiscoverStream on the tag's endpoint
instead of the hardcoded DISCOVER_STREAMS_PATH constant, and extract
get/setDiscoverStreamPageHandle helpers to keep the per-stream prefs
selection in one place. isFreshlyPressed() now checks by tag slug
(matching isRecommended / isLatest) instead of an endpoint suffix,
which is more robust now that the endpoint carries the v2 path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Collapse duplication that built up while wiring the Discover sub-tabs:
dedupe the three near-identical tag factories in ReaderDiscoverTabsFragment,
inline the tab title res lookup, fold the three per-stream page-handle
prefs into a single keyed accessor, drop the single-use isRecommended/
isLatest predicates in favor of slug comparisons, and replace the ad-hoc
SupervisorJob scope in requestPostsForDiscoverStream with the injected
application scope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The detailed streams-pipeline comment duplicated the KDoc already
present on ReaderPostRepository.requestPostsForDiscoverStream.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Freshly Pressed now uses the legacy v1.2 /freshly-pressed endpoint
(matching web and iOS) instead of the v2 /read/streams/freshly-pressed
path which returned 404. Latest matches iOS using read/streams/discover
with sort=date.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eritance

Remove the duplicate member `formatRelativeEndpointForTag` in
ReaderPostRepository (the companion version is sufficient), and
simplify ReaderDiscoverTabsFragment to extend Fragment directly
since it opted out of ViewPagerFragment behavior by returning null.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract card-parsing logic into parsePostCards/parsePostCard helpers
to fix NestedBlockDepth, LoopWithTooManyJumpStatements, and
TooGenericExceptionCaught detekt violations. Narrows catch blocks
from Exception to JSONException.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove redundant tabSelectedTextColor (identical to tabTextColor)
- Make FRESHLY_PRESSED_PATH and DISCOVER_STREAMS_PATH private
- Use idiomatic mutableMapOf instead of HashMap constructor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dangermattic
Copy link
Copy Markdown
Collaborator

1 Warning
⚠️ This PR is larger than 300 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 14, 2026

App Icon📲 You can test the changes from this Pull Request in Jetpack Android by scanning the QR code below to install the corresponding build.

App NameJetpack Android
Build TypeDebug
Versionpr22793-7717606
Build Number1488
Application IDcom.jetpack.android.prealpha
Commit7717606
Installation URL2uve2vgdr7uvg
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 14, 2026

App Icon📲 You can test the changes from this Pull Request in WordPress Android by scanning the QR code below to install the corresponding build.

App NameWordPress Android
Build TypeDebug
Versionpr22793-7717606
Build Number1488
Application IDorg.wordpress.android.prealpha
Commit7717606
Installation URL6je9b6f688878
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 14, 2026

Codecov Report

❌ Patch coverage is 4.59770% with 83 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.25%. Comparing base (72b5295) to head (7717606).

Files with missing lines Patch % Lines
...droid/ui/reader/repository/ReaderPostRepository.kt 4.22% 68 Missing ⚠️
.../java/org/wordpress/android/ui/prefs/AppPrefs.java 0.00% 10 Missing ⚠️
.../org/wordpress/android/ui/prefs/AppPrefsWrapper.kt 0.00% 4 Missing ⚠️
...ui/reader/services/discover/ReaderDiscoverLogic.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #22793      +/-   ##
==========================================
- Coverage   37.28%   37.25%   -0.03%     
==========================================
  Files        2324     2324              
  Lines      124567   124636      +69     
  Branches    16899    16915      +16     
==========================================
- Hits        46444    46437       -7     
- Misses      74372    74448      +76     
  Partials     3751     3751              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

nbradbury and others added 2 commits April 14, 2026 10:51
…states

Set tabSelectedTextColor to colorPrimary so both states use the same
color, matching the Compose PrimaryTabRow behavior in Stats and RS
post list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants