Skip to content

Conversation

@nuno-vieira
Copy link
Member

@nuno-vieira nuno-vieira commented Nov 20, 2025

🔗 Issue Links

https://linear.app/stream/issue/IOS-1224

🎯 Goal

Improve customization of the quoted message view.

📝 Summary

  • Exposes QuotedMessageViewContainer
  • Adds new QuotedMessageContentView
  • Adds new ViewFactory.makeQuotedMessageContentView()
  • Allows customizing the attachment size of the quoted message view
  • Allows customizing the quoted author avatar size of the quoted message view
  • Allows replacing the content view of the quoted message view

🛠 Implementation

Problem

Previously, the SDK only allowed customisation of the quoted message view's attachment through makeCustomAttachmentQuotedView(), but this was very limited because it did not allow changing the size and the layout of the quoted message view.

Solution

  1. Size changes: The PR exposes the QuotedMessageViewContainer and creates attachment size and author avatar size parameters.
  2. Layout changes: The PR allows replacing the whole content view of the quoted message view through the makeQuotedMessageContentView(). This is the only way to totally customise the layout of the quoted message, whether the message contains a custom attachment or not. A snapshot test is provided as an example on how to render a custom quoted message view for a custom attachment, but it falls back to the existing quoted message content view for everything else.

🧪 Manual Testing Notes

N/A. Covered by snapshot tests.

☑️ 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

@nuno-vieira nuno-vieira requested a review from a team as a code owner November 20, 2025 11:13
@nuno-vieira nuno-vieira force-pushed the add/improve-customization-of-quoted-message-view branch from c9930bb to 4c3d2d4 Compare November 20, 2025 11:29
Copy link
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.

Looks good, I just think we should update the factory method params.

func test_quotedMessageView_customContentView_snapshot() {
// Given - Create a custom football game result attachment
let footballGamePayload = FootballGameAttachmentPayload(
homeTeam: "Benfica",
Copy link
Contributor

Choose a reason for hiding this comment

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

nice payload 🤣

@github-actions
Copy link

Public Interface

+ public struct QuotedMessageContentViewOptions  
+ 
+   public let quotedMessage: ChatMessage
+   public let fillAvailableSpace: Bool
+   public let forceLeftToRight: Bool
+   public let attachmentSize: CGSize
+   
+ 
+   public init(quotedMessage: ChatMessage,fillAvailableSpace: Bool,forceLeftToRight: Bool,attachmentSize: CGSize = CGSize(width: 36, height: 36))

+ public struct QuotedMessageViewContainer: View  
+ 
+   public var factory: Factory
+   public var quotedMessage: ChatMessage
+   public var fillAvailableSpace: Bool
+   public var forceLeftToRight: Bool
+   @Binding public var scrolledId: String?
+   public let attachmentSize: CGSize
+   public let quotedAuthorAvatarSize: CGSize
+   public var body: some View
+   
+ 
+   public init(factory: Factory,quotedMessage: ChatMessage,fillAvailableSpace: Bool,forceLeftToRight: Bool = false,scrolledId: Binding<String?>,attachmentSize: CGSize = CGSize(width: 36, height: 36),quotedAuthorAvatarSize: CGSize = CGSize(width: 24, height: 24))

+ public struct QuotedMessageContentView: View  
+ 
+   public var factory: Factory
+   public var options: QuotedMessageContentViewOptions
+   public var body: some View
+   
+ 
+   public init(factory: Factory,options: QuotedMessageContentViewOptions)



 public struct QuotedMessageView: View  
-   public var body: some View
+   public let attachmentSize: CGSize
-   
+   public var body: some View
- 
+   
-   public init(factory: Factory,quotedMessage: ChatMessage,fillAvailableSpace: Bool,forceLeftToRight: Bool)
+ 
+   public init(factory: Factory,quotedMessage: ChatMessage,fillAvailableSpace: Bool,forceLeftToRight: Bool,attachmentSize: CGSize = CGSize(width: 36, height: 36))

 extension ViewFactory  
-   public func makeCustomAttachmentQuotedView(for message: ChatMessage)-> some View
+   public func makeQuotedMessageContentView(options: QuotedMessageContentViewOptions)-> some View
-   public func makeEditedMessageHeaderView(editedMessage: Binding<ChatMessage?>)-> some View
+   public func makeCustomAttachmentQuotedView(for message: ChatMessage)-> some View
-   public func makeCommandsContainerView(suggestions: [String: Any],handleCommand: @escaping ([String: Any]) -> Void)-> some View
+   public func makeEditedMessageHeaderView(editedMessage: Binding<ChatMessage?>)-> some View
-   public func makeMessageReadIndicatorView(channel: ChatChannel,message: ChatMessage)-> some View
+   public func makeCommandsContainerView(suggestions: [String: Any],handleCommand: @escaping ([String: Any]) -> Void)-> some View
-   public func makeNewMessagesIndicatorView(newMessagesStartId: Binding<String?>,count: Int)-> some View
+   public func makeMessageReadIndicatorView(channel: ChatChannel,message: ChatMessage)-> some View
-   public func makeJumpToUnreadButton(channel: ChatChannel,onJumpToMessage: @escaping () -> Void,onClose: @escaping () -> Void)-> some View
+   public func makeNewMessagesIndicatorView(newMessagesStartId: Binding<String?>,count: Int)-> some View
-   public func makeComposerPollView(channelController: ChatChannelController,messageController: ChatMessageController?)-> some View
+   public func makeJumpToUnreadButton(channel: ChatChannel,onJumpToMessage: @escaping () -> Void,onClose: @escaping () -> Void)-> some View
-   public func makePollView(message: ChatMessage,poll: Poll,isFirst: Bool)-> some View
+   public func makeComposerPollView(channelController: ChatChannelController,messageController: ChatMessageController?)-> some View
-   public func makeThreadDestination()-> (ChatThread) -> ChatChannelView<Self>
+   public func makePollView(message: ChatMessage,poll: Poll,isFirst: Bool)-> some View
-   public func makeThreadListItem(thread: ChatThread,threadDestination: @escaping (ChatThread) -> ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>)-> some View
+   public func makeThreadDestination()-> (ChatThread) -> ChatChannelView<Self>
-   public func makeNoThreadsView()-> some View
+   public func makeThreadListItem(thread: ChatThread,threadDestination: @escaping (ChatThread) -> ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>)-> some View
-   public func makeThreadsListErrorBannerView(onRefreshAction: @escaping () -> Void)-> some View
+   public func makeNoThreadsView()-> some View
-   public func makeThreadListLoadingView()-> some View
+   public func makeThreadsListErrorBannerView(onRefreshAction: @escaping () -> Void)-> some View
-   public func makeThreadListContainerViewModifier(viewModel: ChatThreadListViewModel)-> some ViewModifier
+   public func makeThreadListLoadingView()-> some View
-   public func makeThreadListHeaderViewModifier(title: String)-> some ViewModifier
+   public func makeThreadListContainerViewModifier(viewModel: ChatThreadListViewModel)-> some ViewModifier
-   public func makeThreadListHeaderView(viewModel: ChatThreadListViewModel)-> some View
+   public func makeThreadListHeaderViewModifier(title: String)-> some ViewModifier
-   public func makeThreadListFooterView(viewModel: ChatThreadListViewModel)-> some View
+   public func makeThreadListHeaderView(viewModel: ChatThreadListViewModel)-> some View
-   public func makeThreadListBackground(colors: ColorPalette)-> some View
+   public func makeThreadListFooterView(viewModel: ChatThreadListViewModel)-> some View
-   public func makeThreadListItemBackground(thread: ChatThread,isSelected: Bool)-> some View
+   public func makeThreadListBackground(colors: ColorPalette)-> some View
-   public func makeThreadListDividerItem()-> some View
+   public func makeThreadListItemBackground(thread: ChatThread,isSelected: Bool)-> some View
-   public func makeAddUsersView(options: AddUsersOptions,onUserTap: @escaping (ChatUser) -> Void)-> some View
+   public func makeThreadListDividerItem()-> some View
-   public func makeAttachmentTextView(options: AttachmentTextViewOptions)-> some View
+   public func makeAddUsersView(options: AddUsersOptions,onUserTap: @escaping (ChatUser) -> Void)-> some View
+   public func makeAttachmentTextView(options: AttachmentTextViewOptions)-> some View

@Stream-SDK-Bot
Copy link
Collaborator

SDK Size

title develop branch diff status
StreamChatSwiftUI 9.63 MB 9.68 MB +52 KB 🟢

@sonarqubecloud
Copy link

@Stream-SDK-Bot
Copy link
Collaborator

StreamChatSwiftUI XCSize

Object Diff (bytes)
QuotedMessageView.o +46157
FileAttachmentView.o -1436
DefaultViewFactory.o +592
PollAllOptionsView.o -448
MessageAvatarView.o -392
MessageView.o -112
ViewFactory.o +102
PollCommentsView.o -72
MessageBubble.o +68

Copy link
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! ✅

@nuno-vieira nuno-vieira merged commit 8829152 into develop Nov 20, 2025
11 checks passed
@nuno-vieira nuno-vieira deleted the add/improve-customization-of-quoted-message-view branch November 20, 2025 16:45
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.

4 participants