Skip to content

Redesign attachment uploading and error states#1408

Merged
nuno-vieira merged 18 commits intodevelopfrom
add/attachments-error-and-uploading-state-redesign
Apr 10, 2026
Merged

Redesign attachment uploading and error states#1408
nuno-vieira merged 18 commits intodevelopfrom
add/attachments-error-and-uploading-state-redesign

Conversation

@nuno-vieira
Copy link
Copy Markdown
Member

@nuno-vieira nuno-vieira commented Apr 10, 2026

πŸ”— Issue Links

IOS-1610

🎯 Goal

Redesign the uploading progress and error state indicators for media and file attachments to match the updated Figma design system specs.

πŸ“ Summary

  • Replace the old percentage progress overlay with a new LoadingSpinnerView that supports both indeterminate (loading) and determinate (upload progress) modes
  • Add a RetryBadgeView for upload and thumbnail load failures on media attachments, with tap-to-retry support
  • Show inline upload progress (spinner + byte count) and failure state (warning icon + retry link) for file attachments inside FileAttachmentDisplayView
  • Remove PercentageProgressView and AttachmentDownloadingStateView (no longer used)
  • Stop shimmer animation when a media thumbnail fails to load

πŸ›  Implementation

LoadingSpinnerView now accepts an optional progress: Double?. When nil, it renders the existing indeterminate spinning animation. When set, it draws a determinate arc proportional to the value (0–1). Predefined sizes include a new .medium (24pt) tier.

RetryBadgeView is a new 32Γ—32 red circular badge with a white border and a retry icon, shown when an upload or thumbnail load fails. Tapping it on media attachments retries the thumbnail load; tapping it on file attachments triggers resendMessage().

MessageMediaAttachmentContentView was refactored to manage overlay states internally β€” the withUploadingStateIndicator modifier is no longer applied at the container level for media. The video play icon is now hidden during uploads and errors. A loading-error overlay stops the shimmer and shows the retry badge.

FileAttachmentDisplayView was extended with optional uploadingState and onRetry parameters so the same view handles the normal, uploading, and failed layouts without duplicating the file row structure. FileAttachmentView delegates to it, passing upload state and a retry closure.

πŸ§ͺ Manual Testing Notes

  • Send a message with image/video/file attachments on a slow or failing network
  • Verify the spinner shows determinate progress during upload
  • Simulate upload failure and confirm the retry badge appears; tap to retry
  • Verify file attachments show inline progress text and "Retry upload" link on failure

β˜‘οΈ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change should be manually QAed
  • Changelog is updated with client-facing changes
  • Changelog is updated with new localization keys
  • New code is covered by unit tests
  • Documentation has been updated in the docs-content repo

Summary by CodeRabbit

  • New Features

    • Added inline upload progress and retry functionality for file attachments
    • Introduced retry badge for failed uploads
  • Improvements

    • Redesigned attachment uploading progress and error state indicators
  • Localization

    • Added new strings for upload status messages

@nuno-vieira nuno-vieira requested a review from a team as a code owner April 10, 2026 13:53
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

πŸ“ Walkthrough

Walkthrough

This PR refactors the attachment upload and download UI by removing downloading state indicators, replacing bottom-right progress/error overlays with inline overlay UI rendering, introducing a new RetryBadgeView component for failed uploads, and enhancing LoadingSpinnerView to support determinate progress visualization.

Changes

Cohort / File(s) Summary
Removed Components
AttachmentDownloadingStateView.swift, PercentageProgressView.swift
Deleted two view components and their public APIs previously used for download state and percentage progress rendering.
Core Upload UI Refactoring
AttachmentUploadingStateView.swift, FileAttachmentView.swift, MessageMediaAttachmentContentView.swift, MessageMediaAttachmentsContainerView.swift
Replaced downloading/uploading state modifiers with inline overlay logic; added onUploadRetry callback support; integrated RetryBadgeView and LoadingSpinnerView for upload state visualization; added chatClient injection for resend message functionality.
New Component
RetryBadgeView.swift
Added public circular error retry badge view with themed styling and system SF Symbol icon for failed attachment retries.
Common View Enhancement
LoadingSpinnerView.swift
Extended with medium size constant and optional progress parameter to support both indeterminate loading and determinate progress visualization.
View Container Updates
FileAttachmentsView.swift
Removed downloading state indicator modifier and updated ForEach to use implicit Identifiable conformance instead of explicit id: \.self.
Localization
Localizable.strings
Added two new localization keys: message.sending.attachment-upload-failed ("Upload failed") and message.sending.attachment-retry-upload ("Retry upload").
Test Updates
ChatChannelTestHelpers.swift, FileAttachmentView_Tests.swift, MessageItemView_Tests.swift
Updated test helpers to accept state parameter; replaced download state snapshot tests with upload state tests; added four new image attachment upload scenario tests.
Documentation
CHANGELOG.md
Added three changelog entries describing redesigned attachment upload progress/error states and the new RetryBadgeView component.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • martinmitrevski

Poem

🐰 Uploads now shimmer with retry delight,
No more bottom corners, just overlays bright,
LoadingSpinners twirl with progress so true,
RetryBadges shine when uploads turn blue,
The UI flows smoothly, refactored with care! ✨

πŸš₯ Pre-merge checks | βœ… 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (2 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The title 'Redesign attachment uploading and error states' directly summarizes the main changes: replacing old uploading/error indicators with new UI components (LoadingSpinnerView, RetryBadgeView) and refactoring how upload and error states are displayed across attachment views.

✏️ 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 add/attachments-error-and-uploading-state-redesign

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.

@github-actions
Copy link
Copy Markdown

1 Error
🚫 Please remove period from end of commit subject line.
bdbbe3e
1 Warning
⚠️ Big PR

Generated by 🚫 Danger

@github-actions
Copy link
Copy Markdown

Public Interface

+ public struct RetryBadgeView: View  
+ 
+   public var body: some View
+   
+ 
+   public init()



 public struct FileAttachmentDisplayView: View  
-   public init(url: URL,title: String,sizeString: String)
+   public init(url: URL,title: String,sizeString: String,uploadingState: AttachmentUploadingState? = nil,onRetry: (() -> Void)? = nil)

 public struct MessageMediaAttachmentContentView: View  
-   public init(factory: Factory,source: MediaAttachment,width: CGFloat,height: CGFloat,cornerRadius: CGFloat? = nil,corners: UIRectCorner? = nil,isOutgoing: Bool = false)
+   public init(factory: Factory,source: MediaAttachment,width: CGFloat,height: CGFloat,cornerRadius: CGFloat? = nil,corners: UIRectCorner? = nil,isOutgoing: Bool = false,onUploadRetry: (() -> Void)? = nil)

 public struct LoadingSpinnerView: View  
-   public init(size: CGFloat,bordered: Bool)
+   public init(size: CGFloat,bordered: Bool = false,progress: Double? = nil)

 public enum LoadingSpinnerSize: Sendable  
-   @MainActor public static var small: CGFloat
+   @MainActor public static var medium: CGFloat
-   @MainActor public static var extraSmall: CGFloat
+   @MainActor public static var small: CGFloat
+   @MainActor public static var extraSmall: CGFloat

@Stream-SDK-Bot
Copy link
Copy Markdown
Collaborator

SDK Size

title develop branch diff status
StreamChatSwiftUI 8.06 MB 8.07 MB +11 KB 🟒

@Stream-SDK-Bot
Copy link
Copy Markdown
Collaborator

StreamChatSwiftUI XCSize

Object Diff (bytes)
AttachmentDownloadingStateView.o -12746
FileAttachmentView.o +12344
MessageMediaAttachmentContentView.o +7269
RetryBadgeView.o +4436
PercentageProgressView.o -4265
LoadingSpinnerView.o +2047
AttachmentUploadingStateView.o +649
FileAttachmentsView.o -410
ChatThreadListItem.o -160
SwiftUI.tbd -84

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (5)
Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift (1)

272-279: Consider adding error handling for resendMessage().

The retry closure follows the same fire-and-forget pattern as FileAttachmentView.retryUpload(), which is consistent. However, resendMessage() is an async operation that could fail. Consider whether users should receive feedback on retry failures.

This is a minor suggestion since the pattern matches existing code in FileAttachmentView and the SDK likely handles state updates internally. If error handling is desired, it could be addressed in a follow-up.

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift`
around lines 272 - 279, The retry closure for onUploadRetry currently calls
controller.resendMessage() fire-and-forget; change it to handle possible errors
by calling the async resendMessage() method and capturing its result, e.g., call
controller.resendMessage() within an async Task and handle failures by logging
or surfacing a user-visible error; update the closure that builds the
messageController (referencing message, chatClient, messageController, and
resendMessage) to create Task { do { try await controller.resendMessage() }
catch { /* handle: processLogger.error / show toast / update UI state */ } } so
retry failures are not silently dropped.
Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift (1)

20-38: Consider adding an accessibility label for VoiceOver users.

The view has an accessibilityIdentifier for UI testing but lacks an accessibilityLabel to describe the badge's purpose to VoiceOver users. Since this badge indicates a failed upload with retry capability, consider adding a descriptive label.

♻️ Suggested improvement
         .frame(width: size, height: size)
         .accessibilityIdentifier("RetryBadgeView")
+        .accessibilityLabel(L10n.Message.Sending.attachmentRetryUpload)

As per coding guidelines: "Ensure components have accessibility labels, traits, and dynamic type support"

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift` around lines 20 -
38, The RetryBadgeView's body currently sets only an accessibilityIdentifier but
lacks an accessibilityLabel; update the view (in the RetryBadgeView body/ZStack)
to add a descriptive accessibilityLabel like "Failed upload. Tap to retry"
(localized) and appropriate accessibilityTraits (e.g., .isButton) so VoiceOver
users understand the badge's purpose; ensure the label is localized and attach
it to the same view that has accessibilityIdentifier("RetryBadgeView").
Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift (2)

96-101: Consider adding error handling for resendMessage().

The resendMessage() call has no completion handler, so upload failures will occur silently without user feedback. The similar implementation in DefaultMessageActions.swift (lines 729-748) handles the completion callback to report errors.

For consistency and better UX, consider adding error handling or logging:

Proposed improvement
 private func retryUpload() {
     let messageId = attachment.id.messageId
     let cid = attachment.id.cid
     let controller = chatClient.messageController(cid: cid, messageId: messageId)
-    controller.resendMessage()
+    controller.resendMessage { error in
+        if let error {
+            log.error("Failed to resend message: \(error.localizedDescription)")
+        }
+    }
 }
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift` around
lines 96 - 101, The retryUpload() implementation calls
controller.resendMessage() without handling its completion, so upload failures
are silent; update retryUpload() to call resendMessage(completion:) on the
MessageController returned by chatClient.messageController(cid:cid,messageId:)
and handle the Result/Error in the completion (log the error via process/console
or call the app’s error reporting, update attachment state or show user-facing
feedback) similar to the error handling in DefaultMessageActions.swift (lines
around DefaultMessageActions.resendMessage / resend flow) so failures are
surfaced to the user and metrics.

193-200: Consider adding an accessibility label to the retry button.

The retry button currently relies on the text content for accessibility. Adding an explicit accessibility label would improve VoiceOver support.

Proposed improvement
 if let onRetry {
     Button(action: onRetry) {
         Text(L10n.Message.Sending.attachmentRetryUpload)
             .font(fonts.subheadline)
             .foregroundColor(Color(colors.textLink))
     }
     .buttonStyle(.plain)
+    .accessibilityLabel(L10n.Message.Sending.attachmentRetryUpload)
 }

Based on learnings: "Ensure components have accessibility labels, traits, and dynamic type support".

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift` around
lines 193 - 200, The retry Button inside FileAttachmentView (the optional
onRetry Button) lacks an explicit accessibility label; update the Button by
adding an accessibilityLabel that describes its action (e.g., "Retry attachment
upload" or localized equivalent using L10n) and appropriate accessibilityTraits
(e.g., .button) so VoiceOver announces it correctly; ensure you reference the
optional onRetry closure and set the accessibility label on that Button instance
to preserve dynamic type/localization.
Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift (1)

147-155: Consider adding an accessibility label to the retry button.

The retryOverlay function wraps the RetryBadgeView in a Button, but there's no accessibility label to describe the action to VoiceOver users.

Proposed improvement
 private func retryOverlay(action: `@escaping` () -> Void) -> some View {
     Button(action: action) {
         ZStack {
             Color(colors.backgroundCoreOverlayLight)
             RetryBadgeView()
         }
     }
     .buttonStyle(.plain)
+    .accessibilityLabel(L10n.Message.Sending.attachmentRetryUpload)
 }

Based on learnings: "Ensure components have accessibility labels, traits, and dynamic type support".

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift`
around lines 147 - 155, The Button returned by retryOverlay lacks an
accessibility label; update retryOverlay to add an accessibilityLabel (and
optionally accessibilityHint and .accessibilityAddTraits(.isButton)) to the
Button wrapping RetryBadgeView so VoiceOver users get a descriptive text like
"Retry sending message" (use a localized string); reference the
retryOverlay(action:) function and the RetryBadgeView so you add the
accessibility modifiers directly on the Button before returning it.
πŸ€– Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift`:
- Around line 96-101: The retryUpload() implementation calls
controller.resendMessage() without handling its completion, so upload failures
are silent; update retryUpload() to call resendMessage(completion:) on the
MessageController returned by chatClient.messageController(cid:cid,messageId:)
and handle the Result/Error in the completion (log the error via process/console
or call the app’s error reporting, update attachment state or show user-facing
feedback) similar to the error handling in DefaultMessageActions.swift (lines
around DefaultMessageActions.resendMessage / resend flow) so failures are
surfaced to the user and metrics.
- Around line 193-200: The retry Button inside FileAttachmentView (the optional
onRetry Button) lacks an explicit accessibility label; update the Button by
adding an accessibilityLabel that describes its action (e.g., "Retry attachment
upload" or localized equivalent using L10n) and appropriate accessibilityTraits
(e.g., .button) so VoiceOver announces it correctly; ensure you reference the
optional onRetry closure and set the accessibility label on that Button instance
to preserve dynamic type/localization.

In
`@Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift`:
- Around line 147-155: The Button returned by retryOverlay lacks an
accessibility label; update retryOverlay to add an accessibilityLabel (and
optionally accessibilityHint and .accessibilityAddTraits(.isButton)) to the
Button wrapping RetryBadgeView so VoiceOver users get a descriptive text like
"Retry sending message" (use a localized string); reference the
retryOverlay(action:) function and the RetryBadgeView so you add the
accessibility modifiers directly on the Button before returning it.

In
`@Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift`:
- Around line 272-279: The retry closure for onUploadRetry currently calls
controller.resendMessage() fire-and-forget; change it to handle possible errors
by calling the async resendMessage() method and capturing its result, e.g., call
controller.resendMessage() within an async Task and handle failures by logging
or surfacing a user-visible error; update the closure that builds the
messageController (referencing message, chatClient, messageController, and
resendMessage) to create Task { do { try await controller.resendMessage() }
catch { /* handle: processLogger.error / show toast / update UI state */ } } so
retry failures are not silently dropped.

In `@Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift`:
- Around line 20-38: The RetryBadgeView's body currently sets only an
accessibilityIdentifier but lacks an accessibilityLabel; update the view (in the
RetryBadgeView body/ZStack) to add a descriptive accessibilityLabel like "Failed
upload. Tap to retry" (localized) and appropriate accessibilityTraits (e.g.,
.isButton) so VoiceOver users understand the badge's purpose; ensure the label
is localized and attach it to the same view that has
accessibilityIdentifier("RetryBadgeView").

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1108b05-a40f-408a-a823-d9f9e4535a70

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 2f6d88d and 1161cf5.

β›” Files ignored due to path filters (20)
  • Sources/StreamChatSwiftUI/Generated/L10n.swift is excluded by !**/generated/**
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadDisabled.1.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadedState.1.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadingState.1.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failed_snapshot.1.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-light.png is excluded by !**/*.png
πŸ“’ Files selected for processing (14)
  • CHANGELOG.md
  • Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/FileAttachmentsView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/AttachmentDownloadingStateView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/AttachmentUploadingStateView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/PercentageProgressView.swift
  • Sources/StreamChatSwiftUI/CommonViews/LoadingSpinnerView.swift
  • Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift
  • Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings
  • StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/FileAttachmentView_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/MessageItemView_Tests.swift
πŸ’€ Files with no reviewable changes (2)
  • Sources/StreamChatSwiftUI/ChatMessageList/PercentageProgressView.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/AttachmentDownloadingStateView.swift

Copy link
Copy Markdown
Contributor

@martinmitrevski martinmitrevski left a comment

Choose a reason for hiding this comment

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

LGTM βœ… I would just move the resend logic to the vm

private func retryUpload() {
let messageId = attachment.id.messageId
let cid = attachment.id.cid
let controller = chatClient.messageController(cid: cid, messageId: messageId)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

hmm, is this ideal here? Shall we move it to the VM via the options?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We don't have any view model here. I can set it up, but I'm not sure what additional changes will be required

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

no, that's not what I meant. Just put it a handler onRetry or similar in the FileAttachmentViewOptions, and the factory method will pass the view model resend method. So just the method, not the whole VM - that will slow things down a lot.

isOutgoing: message.isSentByCurrentUser,
onUploadRetry: item.uploadingState?.state == .uploadingFailed ? { [message, chatClient] in
guard let cid = message.cid else { return }
let controller = chatClient.messageController(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

similarly here, we can have one method in the vm doing this

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Same here, there is no view model on this view, so we need to pass an existing one or create one for this.

I think we can do it later if we think it is worth it and customers request it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

anyway, if it's a lot of changes, ignore it

Copy link
Copy Markdown
Member Author

@nuno-vieira nuno-vieira Apr 10, 2026

Choose a reason for hiding this comment

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

I've tried to change this, but TBH I prefer the current solution for now. Without a proper view model, it will just forward the action to the factory, which is not good. The factory should just create things, not do actions

@sonarqubecloud
Copy link
Copy Markdown

@nuno-vieira nuno-vieira merged commit 61ede5e into develop Apr 10, 2026
18 of 20 checks passed
@nuno-vieira nuno-vieira deleted the add/attachments-error-and-uploading-state-redesign branch April 10, 2026 16:08
@Stream-SDK-Bot Stream-SDK-Bot mentioned this pull request Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants