Skip to content

Scope Reader photo viewer swiping to gallery images#22762

Open
nbradbury wants to merge 98 commits intotrunkfrom
issue/CMM-1994-reader-galleries
Open

Scope Reader photo viewer swiping to gallery images#22762
nbradbury wants to merge 98 commits intotrunkfrom
issue/CMM-1994-reader-galleries

Conversation

@nbradbury
Copy link
Copy Markdown
Contributor

@nbradbury nbradbury commented Apr 3, 2026

Description

Previously, tapping an image in a gallery would show that image full screen and enable swiping between images, but instead of swiping through just the images in that gallery it would swipe between all images in the post. This PR resolves this by only swiping through the gallery's images.

Testing instructions

Gallery-scoped swiping:

  1. Open a Reader post that contains a gallery block as well as a standalone image
  2. Tap a gallery image
  • Photo viewer shows only that gallery's images when swiping
  1. Tap a standalone (non-gallery) image
  • Photo viewer shows all post images (unchanged behavior)

Multiple galleries:

  1. Open a post with two separate gallery blocks
  2. Tap an image in the second gallery
  • Only that gallery's images are shown
  1. Tap an image in the first gallery
  • Only that gallery's images are shown (not all post images)
gallery.mp4

nbradbury and others added 30 commits March 25, 2026 10:21
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only use editorial.image, featured_image, or featured_media.uri
as featured image sources instead of scanning post content for
suitable images or videos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reorder ConstraintLayout constraints so the visual hierarchy is:
blog header → featured image → title → excerpt → interactions → footer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a Reader post has a portrait featured image, the image is now
scaled to fit the container height and centered horizontally with a
gray background fill, instead of being center-cropped which often
cuts off heads and other important content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move featured image from collapsing AppBar to inline in the header view
with adaptive aspect ratio. Restructure blog section so site name,
author, and date each appear on their own line with absolute date+time
format. Add reading time indicator and excerpt display to the header.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract Regex and date format constants in header UI state builder
- Replace verbose null-check patterns with setTextOrHide helper
- Hoist Paint allocation to class property in PortraitAwareCropTransformation
- Remove unnecessary list allocation in applyInteractionSectionTheme

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

Replace ?attr/colorOnSurfaceVariant (Material3-only) with compatible
alternatives since the reading preferences ContextThemeWrapper uses
Theme.MaterialComponents.DayNight which lacks this attribute.

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

- Remove unused postDetailsHeaderViewUiStateBuilder injection from fragment
- Replace per-scroll toolbar coloring with one-time setup in initAppBar
- Inline trivial buildPostDetailsHeaderUiState delegation
- Remove unnecessary default values in ReaderFeaturedImageUiState

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace HtmlCompat.fromHtml() with lighter HtmlUtils.fastStripHtml()
for word counting, fix detekt ReturnCount and checkstyle empty-line
violations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Chain blog name and author vertically against the avatar, add
marginStart with goneMarginStart so text aligns flush when there
is no avatar.

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

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move blog name to top, post title second, avatar with author and
date below title, then featured image, blog description (up to 3
lines), and reading time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Anchor dateline start directly to avatar so it stays positioned
when author name is hidden. Add barrier below blog name and follow
button so the post title clears both.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
findPost() excludes the text column for performance, so
shouldAddFeaturedImage() couldn't detect the image was already
in the post body HTML. Fetch with text column included when
returning from comments to preserve deduplication.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Flatten ReaderPostDetailsHeaderViewUiState sealed class into
  top-level data classes (only had one subclass)
- Inline trivial wrapper methods in the header UI state builder
- Inline single-line delegation methods in the header view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d, rename excerpt to blogDescription

- Cache SimpleDateFormat as a class property instead of allocating per call
- Wrap ReaderBlogTableWrapper.getBlogInfo() in withContext(Dispatchers.IO)
  and propagate suspend through the call chain
- Rename excerpt/text_excerpt to blogDescription/text_blog_description
  since the field shows blog description, not post excerpt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This drawable was only referenced by the collapsing toolbar featured
image FrameLayout which was removed in the header redesign.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove redundant likeCount/commentCount local variables
- Simplify featured image null handling with if/else
- Make ReaderFeaturedImageUiState.url and onFeaturedImageClicked
  non-null since the state object is only created with valid values
- Rewrite buildReadingTime with early returns for readability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nbradbury and others added 13 commits April 1, 2026 11:18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When tapping an image inside a gallery block, the full-screen photo
viewer now only allows swiping between images in that specific gallery
instead of all images in the post. Uses WebView JS evaluation to detect
gallery containers and extract their image URLs at tap time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The HitTestResult returns the full-size image URL (e.g., image.jpg)
while the DOM img src contains the resized variant (e.g.,
image-819x1024.jpg). Strip the -WxH size suffix before comparing
pathnames so gallery images are correctly matched.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix duplicate first image in gallery viewer by matching the initial
  URL to its resized gallery variant (stripping -WxH size suffixes)
- Route anchor-wrapped images to onImageUrlClick when the anchor href
  points to an image URL, so gallery images linked to media files open
  in the photo viewer instead of navigating to a web page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Trust WebView's HitTestResult type (IMAGE_TYPE, SRC_IMAGE_ANCHOR_TYPE)
for image detection instead of relying solely on UrlUtils.isImageUrl()
which only recognizes jpg/jpeg/gif/png. For anchor-wrapped images, only
defer to WebView for fragment links (footnote back-references); all
other cases route to the photo viewer.

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

dangermattic commented Apr 3, 2026

2 Warnings
⚠️ Class ReaderGalleryDetector is missing tests, but unit-tests-exemption label was set to ignore this.
⚠️ PR is not assigned to a milestone.

Generated by 🚫 Danger

Merge the duplicate 7-param and 8-param showReaderPhotoViewer overloads
into a single method with a default parameter. Remove unnecessary
@Suppress("LongMethod") from showPhotoViewerWithGalleryCheck.

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

wpmobilebot commented Apr 3, 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
Versionpr22762-1dd9698
Build Number1488
Application IDorg.wordpress.android.prealpha
Commit1dd9698
Installation URL3b34dokuibgkg
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 3, 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
Versionpr22762-1dd9698
Build Number1488
Application IDcom.jetpack.android.prealpha
Commit1dd9698
Installation URL4jnopbahsjpo0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

Move java.util.ArrayList import to correct position after android/
androidx groups. Add comment explaining single-image gallery fallback
and Javadoc on stripSizeSuffix cross-referencing the JS counterpart.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
private boolean mIsPrivate;
private boolean mIsGallery;
private String mContent;
private ArrayList<String> mGalleryImageUrls;

Check notice

Code scanning / Android Lint

Nullable/NonNull annotation missing on field Note

Missing null annotation
Extract gallery collection JS into separate method to fix LongMethod,
restructure parseGalleryUrlsResult to fix ReturnCount, and fix import
ordering in ReaderPhotoViewerActivity.

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

codecov bot commented Apr 3, 2026

Codecov Report

❌ Patch coverage is 0% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.39%. Comparing base (8c0b6d4) to head (1dd9698).

Files with missing lines Patch % Lines
...rdpress/android/ui/reader/ReaderGalleryDetector.kt 0.00% 27 Missing ⚠️
...dpress/android/ui/reader/ReaderActivityLauncher.kt 0.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #22762      +/-   ##
==========================================
- Coverage   37.40%   37.39%   -0.01%     
==========================================
  Files        2320     2321       +1     
  Lines      123674   123706      +32     
  Branches    16791    16796       +5     
==========================================
  Hits        46256    46256              
- Misses      73707    73739      +32     
  Partials     3711     3711              

☔ 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 3, 2026 13:35
Replace manual DOM walking with closest() and merge two JS builder
methods into one, reducing the gallery detection code by ~40 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move JS building and result parsing out of the already-large
ReaderPostDetailFragment into a focused, reusable class.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nbradbury nbradbury marked this pull request as ready for review April 3, 2026 19:12
@nbradbury nbradbury requested review from adalpari and dcalhoun April 3, 2026 19:12
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.

4 participants