Skip to content

compose: Resolve local attachment dimensions with EXIF orientation#6519

Merged
gpunto merged 1 commit into
v6from
backport/local-attachment-dimensions
Jun 26, 2026
Merged

compose: Resolve local attachment dimensions with EXIF orientation#6519
gpunto merged 1 commit into
v6from
backport/local-attachment-dimensions

Conversation

@gpunto

@gpunto gpunto commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Goal

On v6, locally picked images/videos never get Attachment.originalWidth/originalHeight, so they render as a square (1:1 fallback). The backend only backfills dimensions from Stream CloudFront ow/oh params, so custom-CDN customers never get them. Fix has to be client-side.

Backports the v7 client-side dimension resolution (with EXIF orientation) to v6.

Closes AND-1263

Implementation

  • New internal LocalAttachmentDimensionsResolver (Compose): resolves dimensions from the local file when both are null, copies them onto the Attachment.
    • Images: BitmapFactory bounds, swapped for EXIF orientations that flip the ratio (ROTATE_90/270, TRANSPOSE, TRANSVERSE).
    • Videos: MediaMetadataRetriever width/height, swapped for 90/270 rotation.
  • Called from StorageHelperWrapper.getAttachmentsFromMetaData (already off the main thread). Adds the androidx.exifinterface dependency.

No public API change. v6 has no AttachmentStorageHelper, so only the Compose pick flow is touched (no XML changes).

UI Changes

Before After
Screen_recording_20260625_103615.webm
Screen_recording_20260625_103451.webm

Testing

  • 13 Robolectric cases: image EXIF swaps (real JPEG decode), video rotation swaps, and guards (null file, already-populated, non-media).
  • Manual: I tested the Compose sample against a custom CDN (Cloudinary, no ow/oh in URL).

Summary by CodeRabbit

  • New Features

    • Local image and video attachments now retain or derive original dimensions more reliably before upload, including rotation-aware handling for media files.
    • Added support for reading image orientation metadata so displayed dimensions are more accurate.
  • Bug Fixes

    • Prevented missing width/height values for locally picked attachments when metadata is available.
    • Preserved existing attachment dimensions and left unsupported or file-less items unchanged.
  • Tests

    • Added coverage for media rotation, orientation, and dimension-preservation scenarios.

@gpunto gpunto added the pr:bug Bug fix label Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled (or ignored for dependabot PRs).

🎉 Great job! This PR is ready for review.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.26 MB 5.31 MB 0.05 MB 🟢
stream-chat-android-offline 5.49 MB 5.53 MB 0.04 MB 🟢
stream-chat-android-ui-components 10.64 MB 10.74 MB 0.10 MB 🟢
stream-chat-android-compose 12.87 MB 12.95 MB 0.08 MB 🟢

@gpunto gpunto force-pushed the backport/local-attachment-dimensions branch from c90fd87 to c79725b Compare June 25, 2026 09:14
@gpunto gpunto marked this pull request as ready for review June 25, 2026 09:19
@gpunto gpunto requested a review from a team as a code owner June 25, 2026 09:19
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The compose module now resolves local image and video attachment dimensions before returning attachments. A new utility reads bitmap bounds, EXIF orientation, and media metadata, and tests cover image and video rotation cases.

Changes

Local attachment dimension resolution

Layer / File(s) Summary
Dependency and resolver implementation
gradle/libs.versions.toml, stream-chat-android-compose/build.gradle.kts, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/LocalAttachmentDimensionsResolver.kt
Adds the androidx.exifinterface dependency and introduces LocalAttachmentDimensionsResolver for image bounds, EXIF-based orientation handling, and video metadata-based dimension extraction.
Metadata wiring and tests
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/StorageHelperWrapper.kt, stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/LocalAttachmentDimensionsResolver*
getAttachmentsFromMetaData now resolves local attachment dimensions before returning, and Robolectric tests verify EXIF orientation, video rotation, null-file behavior, and existing-dimension preservation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • andremion

Poem

A bunny hops by moonlit streams,
Fixing photo widths and video dreams.
EXIF twitches, metadata sighs,
Little ears cheer: “Now dimensions lie wise!” 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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
Title check ✅ Passed The title clearly summarizes the main change: resolving local attachment dimensions with EXIF-aware image handling.
Description check ✅ Passed The description covers Goal, Implementation, UI Changes, and Testing; only optional checklist and GIF sections are missing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 backport/local-attachment-dimensions

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/StorageHelperWrapper.kt`:
- Around line 92-100: `getSelectedAttachments()` and the attachment-building
flow in `StorageHelperWrapper` are doing blocking dimension resolution on the
caller thread. Move the work in
`getAttachmentsFromUris`/`getAttachmentsForUpload` and the
`LocalAttachmentDimensionsResolver.resolveDimensions(...)` call behind
`withContext(Dispatchers.Default)` or make the API suspend so
`AttachmentsPickerViewModel` does not run `BitmapFactory.decodeFile` /
`MediaMetadataRetriever` on Main. Keep the change localized around
`StorageHelperWrapper` and the helper methods that create `Attachment` objects.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a3696281-1e04-4fa7-bd8c-cc0b555742bd

📥 Commits

Reviewing files that changed from the base of the PR and between f87cac6 and c79725b.

📒 Files selected for processing (6)
  • gradle/libs.versions.toml
  • stream-chat-android-compose/build.gradle.kts
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/LocalAttachmentDimensionsResolver.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/StorageHelperWrapper.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/LocalAttachmentDimensionsResolverExifTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/LocalAttachmentDimensionsResolverTest.kt

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
77.4% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@gpunto gpunto merged commit d486b38 into v6 Jun 26, 2026
19 of 20 checks passed
@gpunto gpunto deleted the backport/local-attachment-dimensions branch June 26, 2026 07:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants