Skip to content

Update design of attachment uploading state#6227

Draft
gpunto wants to merge 3 commits intov7from
redesign/upload-progress
Draft

Update design of attachment uploading state#6227
gpunto wants to merge 3 commits intov7from
redesign/upload-progress

Conversation

@gpunto
Copy link
Contributor

@gpunto gpunto commented Mar 9, 2026

Goal

Update design of attachment uploading state

Implementation

  • Remove the generic FileUploadContent
  • Update FileAttachmentContent & MediaAttachmentContent to show the new upload state
  • Make uploads happen concurrently

🎨 UI Changes

Screen_recording_20260309_105046.webm

Note, in the video you see the PDF file having size 0. It seems it comes like that from the backend:
Screenshot 2026-03-09 at 11 21 02

Testing

Try uploading attachments in the sample

Summary by CodeRabbit

Release Notes

  • New Features

    • File attachments now upload in parallel for faster uploads
    • Upload progress indicators integrated directly into file attachment displays
  • Refactor

    • Consolidated attachment upload UI handling and simplified message content rendering
    • Removed separate upload footer and dedicated upload content display components

@gpunto gpunto added pr:breaking-change Breaking change pr:improvement Improvement labels Mar 9, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

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.

🎉 Great job! This PR is ready for review.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.25 MB 5.70 MB 0.45 MB 🟡
stream-chat-android-ui-components 10.60 MB 11.00 MB 0.40 MB 🟡
stream-chat-android-compose 12.81 MB 12.03 MB -0.79 MB 🚀

@gpunto
Copy link
Contributor Author

gpunto commented Mar 9, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

Walkthrough

This PR parallelizes attachment uploads in the worker and refactors the Compose UI to integrate upload progress indicators into existing attachment content components, removing dedicated upload-specific UI components (FileUploadContent, UploadAttachmentFactory, UploadingFooter) and their related APIs.

Changes

Cohort / File(s) Summary
Attachment Upload Parallelization
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/attachment/worker/UploadAttachmentsWorker.kt
Parallelizes per-attachment upload calls using coroutineScope and async, replacing sequential invocation. Moves progress callback setup into per-attachment async block and retains error handling with try/catch wrapping.
Removal of Upload-Specific UI Components
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileUploadContent.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/factory/UploadAttachmentFactory.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/UploadingFooter.kt
Removes dedicated upload UI components: FileUploadContent (228 lines), UploadAttachmentFactory (39 lines), and UploadingFooter (62 lines).
Factory API Updates
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/StreamAttachmentFactories.kt
Removes onUploadContentItemClick parameter from defaultFactories and defaults function signatures; removes UploadAttachmentFactory from default factory list.
File Attachment Upload Progress Integration
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentContent.kt
Adds isUploading parameter and renders FileUploadProgressIndicator with progress fraction when attachment has InProgress upload state; introduces new progress display UI.
Media Attachment Rendering Refactor
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/MediaAttachmentContent.kt
Replaces single/grid branching with Box-based layout; adds forceShimmer parameter to items; introduces anyOverflowUploading logic; always renders overflow overlay when hidden items exist; adds per-item shimmer and loading visuals based on upload state.
Progress Indicator Enhancements
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/LoadingIndicator.kt
Adds overload for determinate progress indicator accepting progress: () -> Float with CircularProgressIndicator; updates indeterminate variant to use themed colors.
Message Content Simplification
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/MessageContent.kt
Removes upload-specific handling and hasUploads logic; consolidates media/attachment branches; replaces FileUploadContent invocation with MediaAttachmentContent via componentFactory.
Factory Theme API Updates
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
Removes public API functions FileUploadContent and FileUploadItem; empties MessageFooterUploadingContent body while preserving signature.
API Surface Changes
stream-chat-android-compose/api/stream-chat-android-compose.api
Reflects all public API changes: removed classes (UploadAttachmentFactory, FileUploadContentKt, UploadingFooterKt), updated StreamAttachmentFactories signatures, added LoadingIndicator overload, added lambda fields in ComposableSingletons.
Test and Documentation Updates
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/content/AttachmentsContentTest.kt, stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/CustomizingImageAndVideoPreviews.kt, stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/MessagesActivity.kt
Updates test to render FileAttachmentContent with isUploading = true instead of FileUploadContent; removes UploadAttachmentFactory usage from documentation and guide examples.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • andremion
  • VelikovPetar

Poem

🐰 Uploads now flow in streams so grand,
Parallel async, hand in hand,
Progress bars shine bright and new,
Old upload screens say "adieu!"
Components merged, the UI stays true!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is incomplete. It lacks UI change images (only a video link), testing details are minimal, and the contributor/reviewer checklists are missing entirely. Add before/after comparison images, provide more detailed testing instructions, and include the full contributor and reviewer checklists as required by the template.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Update design of attachment uploading state' accurately and concisely describes the main change: redesigning how attachment uploads are visually presented and handled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch redesign/upload-progress

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/LoadingIndicator.kt (1)

47-54: Clarify the new progress lambda contract in KDoc.

The new overload takes a lambda, but the KDoc still reads like progress is a plain value. Please document that it must return 0f..1f and is read during composition so SDK consumers know it needs Compose-backed state.

📝 Suggested KDoc tweak
- * `@param` progress The current progress value between 0f and 1f.
+ * `@param` progress Lambda returning the current progress in the `0f..1f` range.
+ * It is read during composition and should be backed by Compose state.

As per coding guidelines, "Document public APIs with KDoc, including thread expectations and state notes".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/LoadingIndicator.kt`
around lines 47 - 54, Update the KDoc for the public Composable LoadingIndicator
to describe that the parameter progress is a lambda (progress: () -> Float) that
must return a value in the 0f..1f range and that it is invoked during
composition, so callers should supply Compose-backed state (e.g.,
remember/State<Float>) or other thread-safe state to provide updates; reference
the LoadingIndicator(progress: () -> Float, modifier: Modifier = Modifier)
signature and note the composition/read expectation.
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/content/AttachmentsContentTest.kt (1)

81-84: Add a Paparazzi case for uploading media as well.

Line 83 updates the file-upload snapshot, but this PR also changes the upload state UI for media attachments. Please add a matching MediaAttachmentContent/message-level snapshot so the new image/video upload treatment is covered too.

As per coding guidelines, "Applies to /stream-chat-android-compose//*Test.kt: Add Paparazzi snapshots for Compose UI regressions and run verifyPaparazziDebug".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/content/AttachmentsContentTest.kt`
around lines 81 - 84, Add a Paparazzi snapshot test for the media upload UI
analogous to the existing file-upload test: create a new test function (e.g.,
`media upload content`) that calls `snapshotWithDarkModeRow {
MediaAttachmentContent(isMine = true, isUploading = true) }` so the new
image/video upload treatment is covered; place it alongside the `file upload
content` test in `AttachmentsContentTest.kt` and follow the same
naming/structure conventions so it runs under `verifyPaparazziDebug`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/MediaAttachmentContent.kt`:
- Around line 409-423: The overflow shimmer calculation currently includes the
visible last-slot attachment because anyOverflowUploading is computed with
attachments.drop(maximumNumberOfPreviewedItems - 1); change the scan to exclude
the visible tile by starting the drop at maximumNumberOfPreviewedItems (or
alternatively filter out the attachment at attachmentIndex) so only hidden
attachments are considered; update the anyOverflowUploading computation used
when creating MediaAttachmentContentItem (in MediaAttachmentContent.kt near the
MediaAttachmentContentItem call) to reflect this exclusion.

---

Nitpick comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/LoadingIndicator.kt`:
- Around line 47-54: Update the KDoc for the public Composable LoadingIndicator
to describe that the parameter progress is a lambda (progress: () -> Float) that
must return a value in the 0f..1f range and that it is invoked during
composition, so callers should supply Compose-backed state (e.g.,
remember/State<Float>) or other thread-safe state to provide updates; reference
the LoadingIndicator(progress: () -> Float, modifier: Modifier = Modifier)
signature and note the composition/read expectation.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/content/AttachmentsContentTest.kt`:
- Around line 81-84: Add a Paparazzi snapshot test for the media upload UI
analogous to the existing file-upload test: create a new test function (e.g.,
`media upload content`) that calls `snapshotWithDarkModeRow {
MediaAttachmentContent(isMine = true, isUploading = true) }` so the new
image/video upload treatment is covered; place it alongside the `file upload
content` test in `AttachmentsContentTest.kt` and follow the same
naming/structure conventions so it runs under `verifyPaparazziDebug`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 77397de3-18bf-49dc-8145-6dfffed391d3

📥 Commits

Reviewing files that changed from the base of the PR and between dd111d5 and 56f3cc7.

⛔ Files ignored due to path filters (26)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.content_AttachmentsContentTest_file_attachment_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.content_AttachmentsContentTest_file_upload_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelFilesAttachmentsContentTest_loading.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelFilesAttachmentsContentTest_loading_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelFilesAttachmentsContentTest_loading_more.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelFilesAttachmentsContentTest_loading_more_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsContentTest_loading.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsContentTest_loading_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_DirectChannelInfoContentTest_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_DirectChannelInfoContentTest_content_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_DirectChannelInfoContentTest_loading.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_DirectChannelInfoContentTest_loading_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelInfoContentTest_loading.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelInfoContentTest_loading_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_in_light_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more_in_light_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.mentions_MentionListTest_loading_mention_list.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.mentions_MentionListTest_loading_more_mention_list.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageListTest_loading_messages.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageListTest_loading_older_messages.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.pinned_PinnedMessageListTest_loading_more_pinned_messages.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.pinned_PinnedMessageListTest_loading_pinned_messages.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListTest_loading_more_threads.png is excluded by !**/*.png
  • stream-chat-android-ui-components/src/test/snapshots/images/io.getstream.chat.android.ui.feature.channels.list_ChannelListViewTest_loaded_channels.png is excluded by !**/*.png
📒 Files selected for processing (14)
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/attachment/worker/UploadAttachmentsWorker.kt
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/StreamAttachmentFactories.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileUploadContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/MediaAttachmentContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/factory/UploadAttachmentFactory.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/LoadingIndicator.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/MessageContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/UploadingFooter.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/content/AttachmentsContentTest.kt
  • stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/CustomizingImageAndVideoPreviews.kt
  • stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/MessagesActivity.kt
💤 Files with no reviewable changes (5)
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/UploadingFooter.kt
  • stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/MessagesActivity.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/StreamAttachmentFactories.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileUploadContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/factory/UploadAttachmentFactory.kt

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 9, 2026

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:breaking-change Breaking change pr:improvement Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant