Skip to content

V5: [MessageList] Update bubbles and text colors in messages#1142

Draft
laevandus wants to merge 20 commits intov5from
v5-message-list-text-messages
Draft

V5: [MessageList] Update bubbles and text colors in messages#1142
laevandus wants to merge 20 commits intov5from
v5-message-list-text-messages

Conversation

@laevandus
Copy link
Contributor

@laevandus laevandus commented Jan 27, 2026

πŸ”— Issue Links

Related: IOS-1379

🎯 Goal

Update bubble colors and message text colors

πŸ“ Summary

  • Message bubble styling refreshed: bubble radius now token-driven with optional override, added outgoing/incoming border colors, updated background colors to new chat tokens, and replaced UIBezierPath with a pure SwiftUI Path for corner rounding.
  • Message text layout updates: new initializer pulls default paddings from tokens; emoji-only messages now get padding and the standard message bubble modifier.
  • Thread replies visual tweak: connector stroke and label colors use new outgoing/incoming thread connector + primary text colors.
  • Message metadata color updates: author name, timestamp, read indicator, pin details, and message text colors updated to new chat palette tokens.
  • Translation footer colors: translated-to, separator, and β€œshow original” colors now use timestamp color token.
  • Typing indicator tweak: spacing now uses tokens; dot size increased and color updated to the typing indicator background token.

No icon changes nor localizable string changes in this PR.

πŸ›  Implementation

🎨 Showcase

πŸ§ͺ Manual Testing Notes

β˜‘οΈ 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

@laevandus laevandus requested a review from a team as a code owner January 27, 2026 08:13
@laevandus laevandus marked this pull request as draft January 27, 2026 08:14
@coderabbitai
Copy link

coderabbitai bot commented Jan 27, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • πŸ” Trigger a full review

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.

Comment on lines -145 to -149
let path = UIBezierPath(
roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bubble corners started to be drawn using the Apple's continuous style instead of circular which does not give what we want (only when message is super small). Creating the path with circular arcs fixes it. Much longer, but works.

Co-authored-by: Stream Bot <ci@getstream.io>
@laevandus laevandus changed the title V5: [MessageList] Update bubble spacings and text colors in messages V5: [MessageList] Update bubbles and text colors in messages Jan 27, 2026
@github-actions
Copy link

github-actions bot commented Jan 27, 2026

1 Warning
⚠️ Big PR
1 Message
πŸ“– There seems to be app changes but CHANGELOG wasn't modified.
Please include an entry if the PR includes user-facing changes.
You can find it at CHANGELOG.md.

Generated by 🚫 Danger

} else {
Text(message.adjustedText)
.font(fonts.emoji)
.padding(.horizontal, tokens.spacingSm)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, emojis have bubbles now

Copy link
Contributor

Choose a reason for hiding this comment

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

let's challenge that, it's not really standard. Raised it in figma, but let's keep it for now.

@laevandus laevandus marked this pull request as ready for review January 27, 2026 08:36
laevandus and others added 3 commits January 27, 2026 11:02
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.

} else {
Text(message.adjustedText)
.font(fonts.emoji)
.padding(.horizontal, tokens.spacingSm)
Copy link
Contributor

Choose a reason for hiding this comment

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

let's challenge that, it's not really standard. Raised it in figma, but let's keep it for now.

@laevandus laevandus marked this pull request as draft January 27, 2026 11:10
laevandus and others added 5 commits January 27, 2026 13:24
Co-authored-by: Stream Bot <ci@getstream.io>
# Conflicts:
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot.1.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshot.1.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_themedNavigationBar_snapshot.1.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerQuotedMessage_translated.default-dark.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerQuotedMessage_translated.default-light.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVoiceRecordingAttachment.default-light.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVoiceRecording.default-light.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.1.png
#	StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewLastGroupHeader_Tests/test_messageListView_headerOnTop.1.png
Co-authored-by: Stream Bot <ci@getstream.io>
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required β‰₯ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

}
)
) : nil,
alignment: messageViewModel.isRightAligned ? .trailing : .leading
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was easier to handle it like this when bubble is really small

laevandus and others added 2 commits January 28, 2026 16:42
Co-authored-by: Stream Bot <ci@getstream.io>
@github-actions
Copy link

Public Interface

+ public enum ReactionsStyle  
+ 
+   case clustered
+   case segmented



 public struct MessageModifierInfo  
-   public var cornerRadius: CGFloat
+   public var cornerRadius: CGFloat?
-   public init(message: ChatMessage,isFirst: Bool,injectedBackgroundColor: UIColor? = nil,cornerRadius: CGFloat = 18,forceLeftToRight: Bool = false)
+   public init(message: ChatMessage,isFirst: Bool,injectedBackgroundColor: UIColor? = nil,cornerRadius: CGFloat? = nil,forceLeftToRight: Bool = false)

 public struct MessageDisplayOptions  
-   public let showOriginalTranslatedButton: Bool
+   public let reactionsStyle: ReactionsStyle
-   public let messageLinkDisplayResolver: @MainActor (ChatMessage) -> [NSAttributedString.Key: Any]
+   public let showOriginalTranslatedButton: Bool
-   public let spacerWidth: (CGFloat) -> CGFloat
+   public let messageLinkDisplayResolver: @MainActor (ChatMessage) -> [NSAttributedString.Key: Any]
-   public let reactionsTopPadding: (ChatMessage) -> CGFloat
+   public let spacerWidth: (CGFloat) -> CGFloat
-   public let dateSeparator: (ChatMessage, ChatMessage) -> Date?
+   public let reactionsTopPadding: (ChatMessage) -> CGFloat
-   public static var defaultLinkDisplay: @MainActor (ChatMessage) -> [NSAttributedString.Key: Any]
+   public let dateSeparator: (ChatMessage, ChatMessage) -> Date?
-   public static var defaultSpacerWidth: (CGFloat) -> (CGFloat)
+   public static var defaultLinkDisplay: @MainActor (ChatMessage) -> [NSAttributedString.Key: Any]
-   public static var defaultReactionsTopPadding: (ChatMessage) -> CGFloat
+   public static var defaultSpacerWidth: (CGFloat) -> (CGFloat)
-   
+   public static var defaultReactionsTopPadding: (ChatMessage) -> CGFloat
- 
+   
-   public init(showAvatars: Bool = true,showAvatarsInGroups: Bool? = nil,showMessageDate: Bool = true,showAuthorName: Bool = true,animateChanges: Bool = true,overlayDateLabelSize: CGFloat = 40,lastInGroupHeaderSize: CGFloat = 0,newMessagesSeparatorSize: CGFloat = 50,minimumSwipeGestureDistance: CGFloat = 20,currentUserMessageTransition: AnyTransition = .identity,otherUserMessageTransition: AnyTransition = .identity,shouldAnimateReactions: Bool = true,reactionsPlacement: ReactionsPlacement = .top,showOriginalTranslatedButton: Bool = false,messageLinkDisplayResolver: @escaping @MainActor (ChatMessage) -> [NSAttributedString.Key: Any] = MessageDisplayOptions
+ 
-             .defaultLinkDisplay,spacerWidth: @escaping (CGFloat) -> CGFloat = MessageDisplayOptions.defaultSpacerWidth,reactionsTopPadding: @escaping (ChatMessage) -> CGFloat = MessageDisplayOptions.defaultReactionsTopPadding,dateSeparator: @escaping (ChatMessage, ChatMessage) -> Date? = MessageDisplayOptions.defaultDateSeparator)
+   public init(showAvatars: Bool = true,showAvatarsInGroups: Bool? = nil,showMessageDate: Bool = true,showAuthorName: Bool = true,animateChanges: Bool = true,overlayDateLabelSize: CGFloat = 40,lastInGroupHeaderSize: CGFloat = 0,newMessagesSeparatorSize: CGFloat = 50,minimumSwipeGestureDistance: CGFloat = 20,currentUserMessageTransition: AnyTransition = .identity,otherUserMessageTransition: AnyTransition = .identity,shouldAnimateReactions: Bool = true,reactionsPlacement: ReactionsPlacement = .top,reactionsStyle: ReactionsStyle = .segmented,showOriginalTranslatedButton: Bool = false,messageLinkDisplayResolver: @escaping @MainActor (ChatMessage) -> [NSAttributedString.Key: Any] = MessageDisplayOptions
-   
+             .defaultLinkDisplay,spacerWidth: @escaping (CGFloat) -> CGFloat = MessageDisplayOptions.defaultSpacerWidth,reactionsTopPadding: @escaping (ChatMessage) -> CGFloat = MessageDisplayOptions.defaultReactionsTopPadding,dateSeparator: @escaping (ChatMessage, ChatMessage) -> Date? = MessageDisplayOptions.defaultDateSeparator)
- 
+   
-   public func showAvatars(for channel: ChatChannel)-> Bool
+ 
-   public static func defaultDateSeparator(message: ChatMessage,previous: ChatMessage)-> Date?
+   public func showAvatars(for channel: ChatChannel)-> Bool
+   public static func defaultDateSeparator(message: ChatMessage,previous: ChatMessage)-> Date?

 public struct MessageBubbleModifier: ViewModifier  
-   public var cornerRadius: CGFloat
+   public var cornerRadius: CGFloat?
-   public init(message: ChatMessage,isFirst: Bool,injectedBackgroundColor: UIColor? = nil,cornerRadius: CGFloat = 18,forceLeftToRight: Bool = false,topPadding: CGFloat = 0,bottomPadding: CGFloat = 0)
+   public init(message: ChatMessage,isFirst: Bool,injectedBackgroundColor: UIColor? = nil,cornerRadius: CGFloat?,forceLeftToRight: Bool = false,topPadding: CGFloat = 0,bottomPadding: CGFloat = 0)

 public struct MessageTextView: View  
-   public init(factory: Factory,message: ChatMessage,isFirst: Bool,leadingPadding: CGFloat = 16,trailingPadding: CGFloat = 16,topPadding: CGFloat = 8,bottomPadding: CGFloat = 8,scrolledId: Binding<String?>)
+   public init(factory: Factory,message: ChatMessage,isFirst: Bool,scrolledId: Binding<String?>)
+   public init(factory: Factory,message: ChatMessage,isFirst: Bool,leadingPadding: CGFloat,trailingPadding: CGFloat,topPadding: CGFloat,bottomPadding: CGFloat,scrolledId: Binding<String?>)

@Stream-SDK-Bot
Copy link
Collaborator

SDK Size

title v5 branch diff status
StreamChatSwiftUI 10.12 MB 10.1 MB -24 KB πŸš€

@Stream-SDK-Bot
Copy link
Collaborator

StreamChatSwiftUI XCSize

Object Diff (bytes)
BottomReactionsView.o -20644
ReactionsOverlayContainer.o +8773
ReactionsView.o -3128
CreatePollViewModel.o +2796
ReactionsIconProvider.o -2590
Show 39 more objects
Object Diff (bytes)
MessageBubble.o +1250
ChatChannelViewModel.o -944
MessageListConfig.o +830
StreamAsyncImage.o +616
DefaultViewFactory.o -474
ReactionUserView.o -432
MessageComposerViewModel+Recording.o -416
AvatarIndicatorViewModifier.o +402
MessageView.o +352
ComposerAttachmentPickerButton.o -336
ChatChannelInfoViewModel.o -332
StreamChatCommonUI_-2A9222176197F8FB_PackageProduct +320
MoreChannelActionsView.o +319
ChannelAvatar.o +254
ChatChannelHeaderViewModifier.o +220
MessageContainerView.o -198
KeyboardHandling.o +176
ChatChannelListItem.o +172
TitleWithCloseButton.o -168
AsyncTask.o +140
AttachmentViewFactoryOptions.o -140
ViewModelsFactory.o +140
MessageTranslationFooterView.o -136
GalleryHeaderView.o -124
TypingIndicatorView.o +120
ReactionsBubbleView.o -105
DeletedMessageView.o +104
ImageAttachmentView.o -104
PhotoAttachmentPickerView.o -104
VideoPlayerView.o +98
ShareButtonView.o -66
SwiftUICore.tbd +60
ReactionsUsersView.o +60
MessageActionsView.o +59
MediaAttachmentsView.o +56
MessageRepliesView.o +56
SearchBar.o +56
ChatChannelInfoHelperViews.o +48
MessageListView.o +44

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