var colors = Appearance.ColorPalette()
colors.accentPrimary = .systemPink
colors.navigationBarTintColor = .systemPink
var fonts = Appearance.FontsSwiftUI()
fonts.body = .system(size: 18)
var images = Appearance.Images()
var appearance = Appearance()
appearance.colorPalette = colors
appearance.fontsSwiftUI = fonts
appearance.images = images
let streamChat = StreamChat(chatClient: chatClient, appearance: appearance)Migrating from 4.x to 5.x
Version 5.x of the SwiftUI SDK keeps the overall architecture from 4.x, but it includes several source-breaking API updates in the customization layer. Most migrations are straightforward and fall into these buckets:
Appearancecustomization now goes through mutable properties instead of initializer parameters.- Several SwiftUI-specific helper views were renamed.
ViewFactorymethods now take a single options object instead of many individual parameters.- Several modifier methods moved from
ViewFactoryto the newStylesprotocol. Utilsgained new formatter parameters and dropped a few deprecated ones.supportedMoreChannelActions,supportedMessageActions, andnavigationBarDisplayModemoved to config objects.
If your app mostly uses the default UI components, the upgrade should be limited to dependency updates and a small number of customization fixes.
Please don't hesitate to contact our Support team or open a ticket in our GitHub repository. We'll help you during your migration process and any issues you might face.
Update the SDK Version
First, update your Swift Package Manager dependency to version 5.x.
V5 no longer ships with CocoaPods support. If your project still uses CocoaPods for other dependencies, you can mix CocoaPods and Swift Package Manager in the same project — keep CocoaPods for your existing dependencies and add the Stream Chat SDK through SPM.
Appearance no longer uses parameterized initializers
In v4, many docs and examples initialized Appearance with parameters such as colors, fonts, or images.
In v5, Appearance has a public empty initializer and you customize it by mutating its properties:
Replace usages like these:
let appearance = Appearance(colors: colors)
let appearance = Appearance(colors: colors, fonts: fonts, images: images)with property-based configuration on a mutable Appearance value.
Use Appearance.FontsSwiftUI for SwiftUI font customization
Appearance now exposes both UIKit fonts and SwiftUI fonts:
appearance.fontsfor UIKit font valuesappearance.fontsSwiftUIfor SwiftUI font values
If you are customizing SwiftUI screens, use Appearance.FontsSwiftUI:
var fonts = Appearance.FontsSwiftUI()
fonts.footnoteBold = .footnote
var appearance = Appearance()
appearance.fontsSwiftUI = fontsIf you were previously using Fonts() in SwiftUI snippets, switch those usages to Appearance.FontsSwiftUI().
Replace tintColor customizations with ColorPalette
The SwiftUI SDK reads brand and navigation colors from Appearance.colorPalette.
The most common v4 migration is replacing generic tint configuration with explicit palette values:
var colors = Appearance.ColorPalette()
colors.accentPrimary = .systemPink
colors.navigationBarTintColor = .systemPink
var appearance = Appearance()
appearance.colorPalette = colorsIn custom SwiftUI views, when you need the configured brand color, prefer the palette values:
@Injected(\.colors) private var colors
Text("Create")
.foregroundColor(Color(colors.accentPrimary))Migrate removed ColorPalette tokens
The v5 color palette removed many broad aliases from v4 and now prefers semantic tokens such as textPrimary, backgroundCoreApp, chatBackgroundIncoming, and borderCoreDefault.
The table below lists suggested replacements. Some old tokens do not have a 1:1 replacement because the new palette uses more specific tokens for text, surfaces, chat bubbles, reactions, controls, and overlays.
v4 ColorPalette token | v5 token(s) | Notes |
|---|---|---|
text | textPrimary | Use inputTextDefault, chatTextOutgoing, or chatTextTypingIndicator when customizing those specific components. |
subtitleText | textSecondary | Use inputTextPlaceholder for input placeholders. |
textLowEmphasis | textTertiary | Best match for low-emphasis labels and icons. |
textInverted | textOnInverse | Use when text is shown on inverse backgrounds. |
textLinkColor | textLink or chatTextLink | Use chatTextLink inside message content. |
staticColorText | textOnAccent | Use chatTextSystem for date separators and system labels. |
staticBlackColorText | textPrimary | Use semantic text tokens instead of static black text. |
background | backgroundCoreApp | App and list backgrounds. |
background1 | backgroundCoreSurfaceSubtle | Subtle surfaces and secondary containers. |
background2 | backgroundCoreSurfaceStrong | Strong surfaces. Chat bubbles may need chatBackgroundOutgoing or chat border tokens instead. |
background3 | backgroundCoreOverlayDark | Dark overlay backgrounds. |
background4, background5 | backgroundCoreScrim | Scrims and dark media overlays. |
background6 | backgroundCoreSurfaceDefault | Default surfaces. Message bubbles may need chatBackgroundIncoming or chatBackgroundOutgoing. |
background7 | accentNeutral or backgroundCoreSurfaceSubtle | Use accentNeutral for neutral icon/control colors, and backgroundCoreSurfaceSubtle for surfaces. |
background8 | backgroundCoreElevation1 or chatBackgroundIncoming | Use elevated surface tokens for popovers/cards, and chat tokens for message bubbles. |
overlayBackground | backgroundCoreOverlayLight | Typing indicators now use chatBackgroundIncoming with alpha. |
popoverBackground | backgroundCoreElevation1 | Reactions now use reactionBackground. |
highlightedBackground | backgroundCoreSurfaceStrong | Highlighted rows, buttons, or selection surfaces. |
highlightedAccentBackground | accentPrimary | Accent-highlighted UI now uses the primary accent token. |
highlightedAccentBackground1 | backgroundCoreSurfaceSubtle or backgroundCoreElevation1 | Pick the surface token that matches the component hierarchy. |
messageCellHighlightBackground, pinnedMessageBackground | backgroundCoreHighlight | Highlighted message and pinned-message backgrounds. |
jumpToUnreadButtonBackground | accentNeutral | Used by neutral unread controls. |
border | borderCoreDefault | Reactions now use reactionBorder. |
border2 | borderCoreStrong or controlCheckboxBorder | Use a component token for controls when available. |
border3 | chatBorderIncoming, chatBorderOutgoing, or a core border token | No general 1:1 replacement. Pick the token that matches the old usage. |
lightBorder | borderCoreSubtle | Closest low-emphasis border replacement. |
innerBorder | borderCoreDefault | Closest general replacement. |
shadow, hoverButtonShadow | backgroundCoreOverlayDark | Used as the replacement shadow or overlay color in the UIKit migration. |
alert, validationError | accentError | Error and destructive UI. |
alternativeActiveTint | accentSuccess | Poll progress uses chatPollProgressFillIncoming. |
inactiveTint | accentNeutral or inputTextIcon | Use inputTextIcon for composer/input icons. |
alternativeInactiveTint | backgroundUtilityDisabled or inputSendIconDisabled | Choose the disabled token that matches the component. |
disabledColorForColor, unselectedColorForColor | textDisabled, backgroundUtilityDisabled, or component-specific disabled tokens | No direct replacement. Prefer semantic disabled tokens. |
highlightedColorForColor | highlightedColorForColor | Still available. |
navigationBarTitle | navigationBarTitle | Still available, but now defaults to textPrimary. |
navigationBarSubtitle | navigationBarSubtitle | Still available, but now defaults to textTertiary. |
navigationBarBackground | navigationBarBackground | Still available. |
navigationBarTintColor | navigationBarTintColor | Still available, defaulting to accentPrimary. |
navigationBarGlyph | navigationBarGlyph | Still available, now defaulting to .baseWhite. |
reactionCurrentUserColor, reactionOtherUserColor | reactionText, reactionBackground, reactionBorder, or accentPrimary | Pick based on whether you customized reaction text, selected state, background, or border. |
selectedReactionBackgroundColor | reactionBackground, reactionBorder, or accentPrimary | No exact replacement. Choose the reaction token that matches the customized selected state. |
quotedMessageBackgroundCurrentUser, quotedMessageBackgroundOtherUser | backgroundCoreElevation1, backgroundCoreSurfaceSubtle, or chat attachment/message tokens | Pick based on whether the quoted content behaves like an elevated surface, subtle surface, attachment, or message bubble. |
composerInputHighlightedBorder | borderCoreDefault | Closest general composer border replacement. |
voiceMessageControlBackground | controlPlaybackThumbBackgroundDefault, controlPlayButtonBackground, or backgroundCoreOnAccent | Use the control-specific token that matches the customized voice-message control. |
messageCurrentUserBackground | chatBackgroundOutgoing | Current-user message bubble background. |
messageCurrentUserEmphemeralBackground | chatBackgroundOutgoing, chatBackgroundIncoming, or backgroundCoreElevation1 | No exact replacement. Pick the token that matches the old ephemeral-message visual role. |
messageOtherUserBackground | chatBackgroundIncoming | Other-user message bubble background. |
messageCurrentUserTextColor | chatTextOutgoing | Current-user message text. |
messageOtherUserTextColor | chatTextIncoming | Other-user message text. |
bannerBackgroundColor | textTertiary or accentNeutral | No exact replacement. Pick based on banner style. |
composerInputBackground | backgroundCoreApp or a surface token | Choose the app background or surface token that matches your composer design. |
composerPlaceholderColor | inputTextPlaceholder | Composer placeholder text. |
messageLinkAttachmentAuthorColor | chatTextLink or textLink | Use chatTextLink inside message/link attachment content. |
messageLinkAttachmentTitleColor | textPrimary | Link attachment title text. |
messageLinkAttachmentTextColor | textPrimary or textSecondary | Pick based on text hierarchy. |
Gradient message bubbles
In v4, SwiftUI message bubble colors were arrays, so you could create gradients directly on ColorPalette:
colors.messageCurrentUserBackground = [purple, pink]
colors.messageCurrentUserEmphemeralBackground = [
purple.withAlphaComponent(0.85),
pink.withAlphaComponent(0.85)
]
colors.messageOtherUserBackground = [card]In v5, the main chat background tokens such as chatBackgroundOutgoing and chatBackgroundIncoming are single UIColor values. Migrating the code above directly to colors.chatBackgroundOutgoing = purple keeps the app compiling, but it also changes the outgoing bubble from a gradient to a solid color.
Single-color bubbles can keep using the default MessageBubbleModifier. For gradient bubbles, move the customization to Styles.makeMessageViewModifier(for:) and use the lower-level BubbleModifier, which accepts backgroundColors: [Color] and renders a LinearGradient when more than one color is provided:
RegularStyles is public class (not open), so you cannot subclass it from your own module. Conform to Styles directly and provide the three required methods that have no protocol-extension default (makeComposerInputViewModifier, makeComposerButtonViewModifier, makeSuggestionsContainerModifier) using the public Regular* modifier types:
final class CustomStyles: Styles {
var composerPlacement: ComposerPlacement = .docked
func makeMessageViewModifier(for info: MessageModifierInfo) -> some ViewModifier {
GradientMessageBubbleModifier(info: info)
}
func makeComposerInputViewModifier(options: ComposerInputModifierOptions) -> some ViewModifier {
RegularInputViewModifier()
}
func makeComposerButtonViewModifier(options: ComposerButtonModifierOptions) -> some ViewModifier {
RegularButtonViewModifier()
}
func makeSuggestionsContainerModifier(options: SuggestionsContainerModifierOptions) -> some ViewModifier {
SuggestionsRegularContainerModifier()
}
}
private struct GradientMessageBubbleModifier: ViewModifier {
@Environment(\.layoutDirection) private var layoutDirection
let info: MessageModifierInfo
func body(content: Content) -> some View {
let backgroundColors = info.injectedBackgroundColor.map { [Color($0)] } ?? [.purple, .pink]
content.modifier(
BubbleModifier(
corners: info.message.bubbleCorners(
isFirst: info.isFirst,
forceLeftToRight: info.forceLeftToRight,
layoutDirection: layoutDirection
),
backgroundColors: backgroundColors,
cornerRadius: info.cornerRadius ?? 18
)
)
}
}
DefaultViewFactory.shared.styles = CustomStyles()channelNamer became channelNameFormatter
Channel name customization changed in v5.
Replace:
let channelNamer: ChatChannelNamer = { channel, currentUserId in
"This is our custom name: \(channel.name ?? "no name")"
}
let utils = Utils(channelNamer: channelNamer)with:
final class CustomChannelNameFormatter: ChannelNameFormatter {
func format(channel: ChatChannel, forCurrentUserId currentUserId: UserId?) -> String? {
"This is our custom name: \(channel.name ?? "no name")"
}
}
let utils = Utils(channelNameFormatter: CustomChannelNameFormatter())If you were using DefaultChatChannelNamer, migrate to DefaultChannelNameFormatter.
Update renamed reusable SwiftUI views
If you built custom UI with the SDK's reusable views, update the renamed view types:
MessageAvatarView->UserAvatarChannelAvatarView->ChannelAvatarTypingIndicatorBottomView->TypingIndicatorView
For example, this v4 code:
MessageAvatarView(
url: user.imageURL,
size: 40
)becomes:
UserAvatar(
user: user,
size: 40
)Note that UserAvatar takes a ChatUser value directly rather than a URL, and size is now a CGFloat instead of CGSize. If you only have a URL (for example in a quoted message context), use the URL-and-initials initializer:
UserAvatar(
url: url,
initials: initials,
size: 40,
indicator: .none
)The showOnlineIndicator: Bool parameter was replaced by an AvatarIndicator enum: .online, .offline, or .none.
And this:
TypingIndicatorBottomView(
users: users,
typingIndicatorString: typingText
)becomes:
TypingIndicatorView(
users: users,
typingText: typingText
)MessageDisplayOptions avatar parameters split
In v4, MessageDisplayOptions had a single showAvatars: Bool parameter that controlled both incoming and outgoing message avatars. In v5, this is split into two parameters with different defaults:
| v4 parameter | v5 parameter(s) |
|---|---|
showAvatars: Bool | showIncomingMessageAvatar: Bool (default true), showOutgoingMessageAvatar: Bool (default false) |
Replace:
let displayOptions = MessageDisplayOptions(
showAvatars: false,
showAvatarsInGroups: false
)with:
let displayOptions = MessageDisplayOptions(
showIncomingMessageAvatar: false,
showOutgoingMessageAvatar: false,
showAvatarsInGroups: false
)The default behavior also changed — v5 shows incoming avatars and hides outgoing avatars unless you specify otherwise. If you previously relied on MessageDisplayOptions() defaults, your outgoing-message avatar visibility flips.
Utils API changes
Several parameters were added, removed, or renamed on the Utils initializer. The Utils class itself is now marked @MainActor.
Removed parameters:
| v4 parameter | Notes |
|---|---|
imageMerger | Removed; avatar merging is handled internally. |
channelAvatarsMerger | Removed; avatar merging is handled internally. |
channelHeaderLoader | Removed. |
channelNamer | Renamed — see channelNameFormatter below. |
Renamed parameter:
| v4 | v5 |
|---|---|
channelNamer: ChatChannelNamer (closure) | channelNameFormatter: any ChannelNameFormatter (protocol) |
New parameters in v5:
| Parameter | Purpose |
|---|---|
markdownFormatter | Provides custom Markdown rendering for message text. |
messageTimestampFormatter | Formats the timestamp shown on individual messages. |
galleryHeaderViewDateFormatter | Formats the date in the media gallery header. |
messageDateSeparatorFormatter | Formats the date separator labels in the message list. |
mediaLoader | Unified loader for images and video previews (replaces imageLoader + videoLoader). |
messageAttachmentPreviewIconProvider | Provides icons for attachment preview thumbnails. |
messagePreviewFormatter | Formats the message preview text shown in the channel list. |
channelListConfig | Configuration object for the channel list (see below). |
mediaBadgeDurationFormatter | Formats duration badges on audio and video attachments. |
messageRemindersFormatter | Formats message reminder labels (conforms to MessageRemindersFormatter). |
CDN and Media Loading
v5 replaces several image/video loading and CDN types with a unified architecture. If you customized any of these in v4, update to the new types.
Image and Video Loading
The separate imageLoader and videoLoader on Utils are replaced by a single mediaLoader:
// v4
let utils = Utils(
imageLoader: CustomImageLoader(),
videoLoader: CustomVideoLoader()
)
// v5
let utils = Utils(
mediaLoader: CustomMediaLoader()
)The underlying protocols changed as follows:
| v4 Type | v5 Replacement |
|---|---|
ImageLoading / NukeImageLoader | MediaLoader / StreamMediaLoader |
VideoLoading / VideoPreviewLoader | MediaLoader (via loadVideoPreview) |
StreamVideoLoader / DefaultVideoPreviewLoader | StreamMediaLoader |
CDN Customization
CDN URL handling was split into two distinct concerns: storage (uploads/deletes) and requesting (signed URLs, auth headers, resizing).
| v4 Type | v5 Replacement |
|---|---|
CDNClient | CDNStorage |
AttachmentUploader | CDNStorage + UploadedAttachmentPostProcessor |
ChatClientConfig.customCDNClient | ChatClientConfig.cdnStorage |
ChatClientConfig.customAttachmentUploader | ChatClientConfig.cdnStorage |
ImageCDN / StreamImageCDN | CDNRequester / StreamCDNRequester |
FileCDN | CDNRequester (via fileRequest) |
Configure CDNStorage on ChatClientConfig:
var config = ChatClientConfig(apiKeyString: apiKeyString)
config.cdnStorage = CustomStorage()Configure CDNRequester through StreamMediaLoader:
// UIKit
Components.default.mediaLoader = StreamMediaLoader(downloader: StreamImageDownloader(), cdnRequester: CustomCDNRequester())
// SwiftUI
let loader = StreamMediaLoader(downloader: StreamImageDownloader(), cdnRequester: CustomCDNRequester())
let utils = Utils(mediaLoader: loader)For detailed documentation and examples of CDNStorage, CDNRequester, and MediaLoader, see the Custom CDN guide.
navigationBarDisplayMode, supportedMoreChannelActions, and supportedMessageActions moved to config objects
In v4 these were methods on the ViewFactory protocol. In v5 they are properties on the relevant config objects.
DefaultViewFactory still exposes a compatibility navigationBarDisplayMode() helper on the v5 branch, but the channel list and message list read ChannelListConfig.navigationBarDisplayMode and MessageListConfig.navigationBarDisplayMode. For migrations, move your customization to the config objects.
navigationBarDisplayMode — remove the ViewFactory override and set the property on ChannelListConfig or MessageListConfig instead:
// v4 – ViewFactory override
func navigationBarDisplayMode() -> NavigationBarItem.TitleDisplayMode { .inline }
// v5 – config property
var channelListConfig = ChannelListConfig()
channelListConfig.navigationBarDisplayMode = .inline
var messageListConfig = MessageListConfig()
messageListConfig.navigationBarDisplayMode = .inline
let utils = Utils(channelListConfig: channelListConfig, messageListConfig: messageListConfig)supportedMoreChannelActions — remove the ViewFactory override and supply a closure on ChannelListConfig:
// v4 – ViewFactory override
func supportedMoreChannelActions(
for channel: ChatChannel,
onDismiss: @escaping () -> Void,
onError: @escaping (Error) -> Void
) -> [ChannelAction] { ... }
// v5 – ChannelListConfig closure
var channelListConfig = ChannelListConfig()
channelListConfig.supportedMoreChannelActions = { options in
// options.channel, options.onDismiss, options.onError
return [...]
}supportedMessageActions — remove the ViewFactory override and supply a closure on MessageListConfig:
// v4 – ViewFactory override
func supportedMessageActions(
for message: ChatMessage,
channel: ChatChannel,
onFinish: @escaping (MessageActionInfo) -> Void,
onError: @escaping (Error) -> Void
) -> [MessageAction] { ... }
// v5 – MessageListConfig closure
var messageListConfig = MessageListConfig()
messageListConfig.supportedMessageActions = { options in
// options.message, options.channel, options.onFinish, options.onError
return [...]
}New Styles protocol — modifier customization moved out of ViewFactory
v5 introduces a Styles protocol that owns all ViewModifier-returning customizations. Several methods that were on ViewFactory in v4 now live on Styles instead.
The SDK ships two concrete implementations:
LiquidGlassStyles— uses the iOS 26 Liquid Glass material where available.RegularStyles— the classic appearance for earlier OS versions.
DefaultViewFactory uses RegularStyles by default. If you want the built-in Liquid Glass look, set styles = LiquidGlassStyles() on your custom factory.
RegularStyles and LiquidGlassStyles are both declared public class (not open), so you cannot subclass them from your own module. To customize modifier behavior, conform to Styles directly. The protocol provides default implementations for most methods, but three methods have no default and must be implemented: makeComposerInputViewModifier(options:), makeComposerButtonViewModifier(options:), and makeSuggestionsContainerModifier(options:). The public RegularInputViewModifier, RegularButtonViewModifier, and SuggestionsRegularContainerModifier types match the default appearance and can be reused:
final class MyStyles: Styles {
var composerPlacement: ComposerPlacement = .docked
func makeComposerViewModifier(options: ComposerViewModifierOptions) -> some ViewModifier {
ComposerBackgroundRegularViewModifier()
}
func makeComposerInputViewModifier(options: ComposerInputModifierOptions) -> some ViewModifier {
RegularInputViewModifier()
}
func makeComposerButtonViewModifier(options: ComposerButtonModifierOptions) -> some ViewModifier {
RegularButtonViewModifier()
}
func makeSuggestionsContainerModifier(options: SuggestionsContainerModifierOptions) -> some ViewModifier {
SuggestionsRegularContainerModifier()
}
}
final class CustomFactory: ViewFactory {
@Injected(\.chatClient) public var chatClient
public var styles = MyStyles()
private init() {}
public static let shared = CustomFactory()
}For channel list search, this change is behavioral as well as structural. In v5, search is applied through Styles.makeSearchableModifier(options:). makeChannelListTopView(options:) remains available, but it is now just a top content slot and no longer provides searchText or owns the search bar UI.
Methods moved from ViewFactory to Styles:
v4 ViewFactory method | v5 Styles method |
|---|---|
func makeChannelListContentModifier() -> ChannelListContentModifier | func makeChannelListContentModifier(options: ChannelListContentModifierOptions) -> ChannelListContentModifier |
func makeChannelListModifier() -> ChannelListModifier | func makeChannelListModifier(options: ChannelListModifierOptions) -> ChannelListModifier |
func makeMessageListModifier() -> MessageListModifier | func makeMessageListModifier(options: MessageListModifierOptions) -> MessageListModifier |
func makeMessageListContainerModifier() -> MessageListContainerModifier | func makeMessageListContainerModifier(options: MessageListContainerModifierOptions) -> MessageListContainerModifier |
func makeMessageViewModifier(for messageModifierInfo: MessageModifierInfo) -> MessageViewModifier | func makeMessageViewModifier(for messageModifierInfo: MessageModifierInfo) -> MessageViewModifier |
func makeComposerViewModifier() -> ComposerViewModifier | func makeComposerViewModifier(options: ComposerViewModifierOptions) -> ComposerViewModifier |
New Styles methods with no v4 equivalent:
func makeComposerInputViewModifier(options: ComposerInputModifierOptions) -> ComposerInputViewModifierfunc makeComposerButtonViewModifier(options: ComposerButtonModifierOptions) -> ComposerButtonViewModifierfunc makeScrollToBottomButtonModifier(options: ScrollToBottomButtonModifierOptions) -> ScrollToBottomButtonViewModifierfunc makeBouncedMessageActionsModifier(viewModel: ChatChannelViewModel) -> BouncedMessageActionsModifierTypefunc makeSuggestionsContainerModifier(options: SuggestionsContainerModifierOptions) -> SuggestionsContainerModifierfunc makeToolbarConfirmActionModifier(options: ToolbarConfirmActionModifierOptions) -> ToolbarConfirmActionViewModifierfunc makeSearchableModifier(options: SearchableModifierOptions) -> SearchableModifierType
Translated text rendering changes (LinkDetectionTextView replacement)
Text rendering now goes through StreamTextView, replacing the earlier LinkDetectionTextView path.
For custom text rendering, use ChatMessage.attributedTextContent(layoutDirection:translationLanguage:) to build the attributed content shown in Text(...).
If you have custom text views or custom ViewFactory overrides, pass translationLanguage explicitly through options objects. These types now carry that value:
StreamTextViewOptions(message:translationLanguage:)AttachmentTextViewOptions(message:availableWidth:translationLanguage:)MessageTextViewOptions(..., translationLanguage:)MessageAttachmentsViewOptions(..., translationLanguage:)
// v4
public func makeStreamTextView(options: StreamTextViewOptions) -> some View {
StreamTextView(message: options.message)
}
// v5
public func makeStreamTextView(options: StreamTextViewOptions) -> some View {
MyStreamTextView(
message: options.message,
translationLanguage: options.translationLanguage
)
}
struct MyStreamTextView: View {
@Environment(\.layoutDirection) private var layoutDirection
let message: ChatMessage
let translationLanguage: TranslationLanguage?
var body: some View {
Text(
message.attributedTextContent(
layoutDirection: layoutDirection,
translationLanguage: translationLanguage
)
)
}
}Review your ViewFactory implementations
The biggest ViewFactory change in v5 is that the API moved from many ad-hoc parameters to option objects. If you had a custom factory in v4, you should review every override.
Below is the full mapping validated against the v4 and v5 of stream-chat-swiftui.
Channel List
| v4 | v5 |
|---|---|
func makeChannelAvatarView(for channel: ChatChannel, with options: ChannelAvatarViewOptions) -> ChannelAvatarViewType | func makeChannelAvatarView(options: ChannelAvatarViewOptions) -> ChannelAvatarViewType |
func makeChannelListBackground(colors: ColorPalette) -> ChannelListBackground | func makeChannelListBackground(options: ChannelListBackgroundOptions) -> ChannelListBackground |
func makeChannelListContentModifier() -> ChannelListContentModifier | moved to Styles, see the Styles section above |
func makeChannelListDividerItem() -> ChannelListDividerItem | func makeChannelListDividerItem(options: ChannelListDividerItemOptions) -> ChannelListDividerItem |
func makeChannelListFooterView() -> ChannelListFooterViewType | func makeChannelListFooterView(options: ChannelListFooterViewOptions) -> ChannelListFooterViewType |
func makeChannelListHeaderViewModifier(title: String) -> HeaderViewModifier | func makeChannelListHeaderViewModifier(options: ChannelListHeaderViewModifierOptions) -> HeaderViewModifier |
func makeChannelListItem(channel: ChatChannel, channelName: String, avatar: UIImage, onlineIndicatorShown: Bool, disabled: Bool, selectedChannel: Binding<ChannelSelectionInfo?>, swipedChannelId: Binding<String?>, channelDestination: @escaping (ChannelSelectionInfo) -> ChannelDestination, onItemTap: @escaping (ChatChannel) -> Void, trailingSwipeRightButtonTapped: @escaping (ChatChannel) -> Void, trailingSwipeLeftButtonTapped: @escaping (ChatChannel) -> Void, leadingSwipeButtonTapped: @escaping (ChatChannel) -> Void) -> ChannelListItemType | func makeChannelListItem(options: ChannelListItemOptions<ChannelDestination>) -> ChannelListItemType |
func makeChannelListItemBackground(channel: ChatChannel, isSelected: Bool) -> ChannelListItemBackground | func makeChannelListItemBackground(options: ChannelListItemBackgroundOptions) -> ChannelListItemBackground |
func makeChannelListModifier() -> ChannelListModifier | moved to Styles, see the Styles section above |
func makeChannelListSearchResultItem(searchResult: ChannelSelectionInfo, onlineIndicatorShown: Bool, channelName: String, avatar: UIImage, onSearchResultTap: @escaping (ChannelSelectionInfo) -> Void, channelDestination: @escaping (ChannelSelectionInfo) -> ChannelDestination) -> ChannelListSearchResultItem | func makeChannelListSearchResultItem(options: ChannelListSearchResultItemOptions<ChannelDestination>) -> ChannelListSearchResultItem |
func makeChannelListStickyFooterView() -> ChannelListStickyFooterViewType | func makeChannelListStickyFooterView(options: ChannelListStickyFooterViewOptions) -> ChannelListStickyFooterViewType |
func makeChannelListTopView(searchText: Binding<String>) -> ChannelListTopViewType | func makeChannelListTopView(options: ChannelListTopViewOptions) -> ChannelListTopViewType |
func makeLeadingSwipeActionsView(channel: ChatChannel, offsetX: CGFloat, buttonWidth: CGFloat, swipedChannelId: Binding<String?>, buttonTapped: @escaping (ChatChannel) -> Void) -> LeadingSwipeActionsViewType | func makeLeadingSwipeActionsView(options: LeadingSwipeActionsViewOptions) -> LeadingSwipeActionsViewType |
func makeLoadingView() -> LoadingContent | func makeLoadingView(options: LoadingViewOptions) -> LoadingContent |
func makeMoreChannelActionsView(for channel: ChatChannel, swipedChannelId: Binding<String?>, onDismiss: @escaping () -> Void, onError: @escaping (Error) -> Void) -> MoreActionsView | func makeMoreChannelActionsView(options: MoreChannelActionsViewOptions) -> MoreActionsView |
func makeNoChannelsView() -> NoChannels | func makeEmptyChannelsView(options: EmptyChannelsViewOptions) -> EmptyChannels |
func makeSearchResultsView(selectedChannel: Binding<ChannelSelectionInfo?>, searchResults: [ChannelSelectionInfo], loadingSearchResults: Bool, onlineIndicatorShown: @escaping (ChatChannel) -> Bool, channelNaming: @escaping (ChatChannel) -> String, imageLoader: @escaping (ChatChannel) -> UIImage, onSearchResultTap: @escaping (ChannelSelectionInfo) -> Void, onItemAppear: @escaping (Int) -> Void) -> ChannelListSearchResultsViewType | func makeSearchResultsView(options: SearchResultsViewOptions) -> ChannelListSearchResultsViewType |
func makeTrailingSwipeActionsView(channel: ChatChannel, offsetX: CGFloat, buttonWidth: CGFloat, swipedChannelId: Binding<String?>, leftButtonTapped: @escaping (ChatChannel) -> Void, rightButtonTapped: @escaping (ChatChannel) -> Void) -> TrailingSwipeActionsViewType | func makeTrailingSwipeActionsView(options: TrailingSwipeActionsViewOptions) -> TrailingSwipeActionsViewType |
func supportedMoreChannelActions(for channel: ChatChannel, onDismiss: @escaping () -> Void, onError: @escaping (Error) -> Void) -> [ChannelAction] | moved to Utils.channelListConfig.supportedMoreChannelActions closure |
Channel And Message List
| v4 | v5 |
|---|---|
func makeAssetsAccessPermissionView() -> AssetsAccessPermissionViewType | removed in v5, no direct replacement |
func makeAttachmentPickerView(attachmentPickerState: Binding<AttachmentPickerState>, filePickerShown: Binding<Bool>, cameraPickerShown: Binding<Bool>, addedFileURLs: Binding<[URL]>, onPickerStateChange: @escaping (AttachmentPickerState) -> Void, photoLibraryAssets: PHFetchResult<PHAsset>?, onAssetTap: @escaping (AddedAsset) -> Void, onCustomAttachmentTap: @escaping (CustomAttachment) -> Void, isAssetSelected: @escaping (String) -> Bool, addedCustomAttachments: [CustomAttachment], cameraImageAdded: @escaping (AddedAsset) -> Void, askForAssetsAccessPermissions: @escaping () -> Void, isDisplayed: Bool, height: CGFloat, popupHeight: CGFloat) -> AttachmentPickerViewType | func makeAttachmentPickerView(options: AttachmentPickerViewOptions) -> AttachmentPickerViewType |
func makeAttachmentSourcePickerView(selected: AttachmentPickerState, onPickerStateChange: @escaping (AttachmentPickerState) -> Void) -> AttachmentSourcePickerViewType | func makeAttachmentTypePickerView(options: AttachmentTypePickerViewOptions) -> AttachmentTypePickerViewType |
func makeBottomReactionsView(message: ChatMessage, showsAllInfo: Bool, onTap: @escaping () -> Void, onLongPress: @escaping () -> Void) -> ReactionsBottomViewType | func makeBottomReactionsView(options: ReactionsBottomViewOptions) -> ReactionsBottomViewType |
func makeBouncedMessageActionsModifier(viewModel: ChatChannelViewModel) -> BouncedMessageActionsModifierType | moved to Styles, see the Styles section above |
func makeCameraPickerView(selected: Binding<AttachmentPickerState>, cameraPickerShown: Binding<Bool>, cameraImageAdded: @escaping (AddedAsset) -> Void) -> CameraPickerViewType | func makeAttachmentCameraPickerView(options: AttachmentCameraPickerViewOptions) -> AttachmentCameraPickerViewType |
func makeChannelBarsVisibilityViewModifier(shouldShow: Bool) -> ChangeBarsVisibilityModifier | func makeChannelBarsVisibilityViewModifier(options: ChannelBarsVisibilityViewModifierOptions) -> ChangeBarsVisibilityModifier |
func makeChannelDestination() -> (ChannelSelectionInfo) -> ChannelDestination | func makeChannelDestination(options: ChannelDestinationOptions) -> @MainActor (ChannelSelectionInfo) -> ChannelDestination |
func makeChannelHeaderViewModifier(for channel: ChatChannel) -> ChatHeaderViewModifier | func makeChannelHeaderViewModifier(options: ChannelHeaderViewModifierOptions) -> ChatHeaderViewModifier |
func makeChannelLoadingView() -> ChannelLoadingViewType | func makeChannelLoadingView(options: ChannelLoadingViewOptions) -> ChannelLoadingViewType |
func makeCommandsContainerView(suggestions: [String: Any], handleCommand: @escaping ([String: Any]) -> Void) -> CommandsContainerViewType | func makeSuggestionsContainerView(options: SuggestionsContainerViewOptions) -> SuggestionsContainerViewType |
func makeComposerInputView(text: Binding<String>, selectedRangeLocation: Binding<Int>, command: Binding<ComposerCommand?>, addedAssets: [AddedAsset], addedFileURLs: [URL], addedCustomAttachments: [CustomAttachment], quotedMessage: Binding<ChatMessage?>, maxMessageLength: Int?, cooldownDuration: Int, onCustomAttachmentTap: @escaping (CustomAttachment) -> Void, shouldScroll: Bool, removeAttachmentWithId: @escaping (String) -> Void) -> ComposerInputViewType | func makeComposerInputView(options: ComposerInputViewOptions) -> ComposerInputViewType |
func makeComposerRecordingLockedView(viewModel: MessageComposerViewModel) -> ComposerRecordingLockedViewType | func makeComposerVoiceRecordingInputView(options: ComposerVoiceRecordingInputViewOptions) -> ComposerVoiceRecordingInputViewType |
func makeComposerRecordingTipView() -> ComposerRecordingTipViewType | func makeComposerVoiceRecordingInputView(options: ComposerVoiceRecordingInputViewOptions) -> ComposerVoiceRecordingInputViewType |
func makeComposerRecordingView(viewModel: MessageComposerViewModel, gestureLocation: CGPoint) -> ComposerRecordingViewType | func makeComposerVoiceRecordingInputView(options: ComposerVoiceRecordingInputViewOptions) -> ComposerVoiceRecordingInputViewType |
func makeComposerTextInputView(text: Binding<String>, height: Binding<CGFloat>, selectedRangeLocation: Binding<Int>, placeholder: String, editable: Bool, maxMessageLength: Int?, currentHeight: CGFloat) -> ComposerTextInputViewType | func makeComposerTextInputView(options: ComposerTextInputViewOptions) -> ComposerTextInputViewType |
func makeComposerViewModifier() -> ComposerViewModifier | moved to Styles, see the Styles section above |
func makeCustomAttachmentPreviewView(addedCustomAttachments: [CustomAttachment], onCustomAttachmentTap: @escaping (CustomAttachment) -> Void) -> CustomAttachmentPreviewViewType | func makeCustomAttachmentPreviewView(options: CustomAttachmentPreviewViewOptions) -> CustomAttachmentPreviewViewType |
func makeCustomAttachmentQuotedView(for message: ChatMessage) -> CustomAttachmentQuotedViewType | removed in v5, no direct replacement |
func makeCustomAttachmentView(addedCustomAttachments: [CustomAttachment], onCustomAttachmentTap: @escaping (CustomAttachment) -> Void) -> CustomComposerAttachmentViewType | func makeCustomAttachmentPickerView(options: CustomAttachmentPickerViewOptions) -> CustomAttachmentPickerViewType |
func makeCustomAttachmentViewType(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> CustomAttachmentViewType | func makeCustomAttachmentViewType(options: CustomAttachmentViewTypeOptions) -> CustomAttachmentViewType |
func makeDateIndicatorView(dateString: String) -> DateIndicatorViewType | func makeDateIndicatorView(options: DateIndicatorViewOptions) -> DateIndicatorViewType |
func makeDeletedMessageView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat) -> DeletedMessageViewType | func makeDeletedMessageView(options: DeletedMessageViewOptions) -> DeletedMessageViewType |
func makeEditedMessageHeaderView(editedMessage: Binding<ChatMessage?>) -> EditedMessageHeaderViewType | func makeComposerEditedMessageView(options: ComposerEditedMessageViewOptions) -> ComposerEditedMessageViewType |
func makeEmojiTextView(message: ChatMessage, scrolledId: Binding<String?>, isFirst: Bool) -> EmojiTextViewType | func makeEmojiTextView(options: EmojiTextViewOptions) -> EmojiTextViewType |
func makeEmptyMessagesView(for channel: ChatChannel, colors: ColorPalette) -> EmptyMessagesViewType | func makeEmptyMessagesView(options: EmptyMessagesViewOptions) -> EmptyMessagesViewType |
func makeFileAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> FileAttachmentViewType | func makeFileAttachmentView(options: FileAttachmentViewOptions) -> FileAttachmentViewType |
func makeFilePickerView(filePickerShown: Binding<Bool>, addedFileURLs: Binding<[URL]>) -> FilePickerViewType | func makeAttachmentFilePickerView(options: AttachmentFilePickerViewOptions) -> AttachmentFilePickerViewType |
func makeGalleryHeaderView(title: String, subtitle: String, shown: Binding<Bool>) -> GalleryHeaderViewType | func makeMediaViewerToolbarModifier(options: MediaViewerToolbarModifierOptions) -> MediaViewerToolbarModifierType |
func makeGalleryHeaderView(title: String, subtitle: String, shown: Binding<Bool>) -> GalleryHeaderViewType | func makeMediaViewerFooterView(options: MediaViewerFooterViewOptions) -> MediaViewerFooterViewType |
func makeGalleryView(mediaAttachments: [MediaAttachment], message: ChatMessage, isShown: Binding<Bool>, options: MediaViewsOptions) -> GalleryViewType | func makeMediaViewer(options: MediaViewerOptions) -> MediaViewerType |
func makeGiphyAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> GiphyAttachmentViewType | func makeGiphyAttachmentView(options: GiphyAttachmentViewOptions) -> GiphyAttachmentViewType |
func makeGiphyBadgeViewType(for message: ChatMessage, availableWidth: CGFloat) -> GiphyBadgeViewType | func makeGiphyBadgeViewType(options: GiphyBadgeViewTypeOptions) -> GiphyBadgeViewType |
func makeImageAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> ImageAttachmentViewType | func makeImageAttachmentView(options: ImageAttachmentViewOptions) -> ImageAttachmentViewType |
func makeJumpToUnreadButton(channel: ChatChannel, onJumpToMessage: @escaping () -> Void, onClose: @escaping () -> Void) -> JumpToUnreadButtonType | func makeJumpToUnreadButtonOverlay(options: JumpToUnreadButtonOptions) -> JumpToUnreadButtonOverlayType |
func makeLastInGroupHeaderView(for message: ChatMessage) -> LastInGroupHeaderView | func makeLastInGroupHeaderView(options: LastInGroupHeaderViewOptions) -> LastInGroupHeaderView |
func makeLeadingComposerView(state: Binding<PickerTypeState>, channelConfig: ChannelConfig?) -> LeadingComposerViewType | func makeLeadingComposerView(options: LeadingComposerViewOptions) -> LeadingComposerViewType |
func makeLinkAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> LinkAttachmentViewType | func makeLinkAttachmentView(options: LinkAttachmentViewOptions) -> LinkAttachmentViewType |
func makeMessageActionsView(for message: ChatMessage, channel: ChatChannel, onFinish: @escaping (MessageActionInfo) -> Void, onError: @escaping (Error) -> Void) -> MessageActionsViewType | func makeMessageActionsView(options: MessageActionsViewOptions) -> MessageActionsViewType |
func makeMessageAuthorAndDateView(for message: ChatMessage) -> MessageAuthorAndDateViewType | func makeMessageAuthorAndDateView(options: MessageAuthorAndDateViewOptions) -> MessageAuthorAndDateViewType |
func makeMessageAvatarView(for userDisplayInfo: UserDisplayInfo) -> UserAvatar | func makeUserAvatarView(options: UserAvatarViewOptions) -> UserAvatarViewType |
func makeMessageComposerViewType(with channelController: ChatChannelController, messageController: ChatMessageController?, quotedMessage: Binding<ChatMessage?>, editedMessage: Binding<ChatMessage?>, onMessageSent: @escaping () -> Void) -> MessageComposerViewType | func makeMessageComposerViewType(options: MessageComposerViewTypeOptions) -> MessageComposerViewType |
func makeMessageContainerView(channel: ChatChannel, message: ChatMessage, width: CGFloat?, showsAllInfo: Bool, isInThread: Bool, scrolledId: Binding<String?>, quotedMessage: Binding<ChatMessage?>, onLongPress: @escaping (MessageDisplayInfo) -> Void, isLast: Bool) -> MessageContainerViewType | func makeMessageItemView(options: MessageItemViewOptions) -> MessageItemViewType |
func makeMessageDateView(for message: ChatMessage) -> MessageDateViewType | func makeMessageDateView(options: MessageDateViewOptions) -> MessageDateViewType |
func makeMessageListBackground(colors: ColorPalette, isInThread: Bool) -> MessageListBackground | func makeMessageListBackground(options: MessageListBackgroundOptions) -> MessageListBackground |
func makeMessageListContainerModifier() -> MessageListContainerModifier | moved to Styles, see the Styles section above |
func makeMessageListDateIndicator(date: Date) -> MessageListDateIndicatorViewType | func makeMessageListDateIndicator(options: MessageListDateIndicatorViewOptions) -> MessageListDateIndicatorViewType |
func makeMessageListModifier() -> MessageListModifier | moved to Styles, see the Styles section above |
func makeMessageReactionView(message: ChatMessage, onTapGesture: @escaping () -> Void, onLongPressGesture: @escaping () -> Void) -> MessageReactionViewType | func makeMessageReactionView(options: MessageReactionViewOptions) -> MessageReactionViewType |
func makeMessageReadIndicatorView(channel: ChatChannel, message: ChatMessage) -> MessageReadIndicatorViewType | func makeMessageReadIndicatorView(options: MessageReadIndicatorViewOptions) -> MessageReadIndicatorViewType |
func makeMessageRepliesShownInChannelView(channel: ChatChannel, message: ChatMessage, parentMessage: ChatMessage, replyCount: Int) -> MessageRepliesShownInChannelViewType | removed in v5, compose reply/thread annotations with func makeMessageTopView(options: MessageTopViewOptions) -> MessageTopViewType and keep reply-count customization in func makeMessageRepliesView(options: MessageRepliesViewOptions) -> MessageRepliesViewType |
func makeMessageRepliesView(channel: ChatChannel, message: ChatMessage, replyCount: Int) -> MessageRepliesViewType | func makeMessageRepliesView(options: MessageRepliesViewOptions) -> MessageRepliesViewType |
func makeMessageTextView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> MessageTextViewType | func makeMessageTextView(options: MessageTextViewOptions) -> MessageTextViewType |
func makeMessageThreadDestination() -> (ChatChannel, ChatMessage) -> MessageThreadDestination | func makeMessageThreadDestination(options: MessageThreadDestinationOptions) -> @MainActor (ChatChannel, ChatMessage) -> MessageThreadDestination |
func makeMessageThreadHeaderViewModifier() -> ThreadHeaderViewModifier | func makeMessageThreadHeaderViewModifier(options: MessageThreadHeaderViewModifierOptions) -> ThreadHeaderViewModifier |
func makeMessageTranslationFooterView(messageViewModel: MessageViewModel) -> MessageTranslationFooterViewType | removed in v5, translated/pinned/reply annotations are now composed by func makeMessageTopView(options: MessageTopViewOptions) -> MessageTopViewType |
func makeMessageViewModifier(for messageModifierInfo: MessageModifierInfo) -> MessageViewModifier | moved to Styles, see the Styles section above |
func makeNewMessagesIndicatorView(newMessagesStartId: Binding<String?>, count: Int) -> NewMessagesIndicatorViewType | func makeNewMessagesDividerView(options: NewMessagesDividerViewOptions) -> NewMessagesDividerType |
func makePhotoAttachmentPickerView(assets: PHFetchResultCollection, onAssetTap: @escaping (AddedAsset) -> Void, isAssetSelected: @escaping (String) -> Bool) -> PhotoAttachmentPickerViewType | func makeAttachmentMediaPickerView(options: AttachmentMediaPickerViewOptions) -> AttachmentMediaPickerViewType |
func makeQuotedMessageAvatarView(for userDisplayInfo: UserDisplayInfo, size: CGSize) -> QuotedUserAvatar | func makeUserAvatarView(options: UserAvatarViewOptions) -> UserAvatarViewType |
func makeQuotedMessageContentView(options: QuotedMessageContentViewOptions) -> QuotedMessageContentViewType | removed in v5, compose quoted-message rendering with func makeQuotedMessageView(options: QuotedMessageViewOptions) -> QuotedMessageViewType and func makeChatQuotedMessageView(options: ChatQuotedMessageViewOptions) -> ChatQuotedMessageViewType |
func makeQuotedMessageHeaderView(quotedMessage: Binding<ChatMessage?>) -> QuotedMessageHeaderViewType | func makeComposerQuotedMessageView(options: ComposerQuotedMessageViewOptions) -> ComposerQuotedMessageViewType |
func makeQuotedMessageView(quotedMessage: ChatMessage, fillAvailableSpace: Bool, isInComposer: Bool, scrolledId: Binding<String?>) -> QuotedMessageViewType | func makeQuotedMessageView(options: QuotedMessageViewOptions) -> QuotedMessageViewType |
func makeReactionsBackgroundView(currentSnapshot: UIImage, popInAnimationInProgress: Bool) -> ReactionsBackground | removed in v5, no direct replacement |
func makeReactionsContentView(message: ChatMessage, contentRect: CGRect, onReactionTap: @escaping (MessageReactionType) -> Void) -> ReactionsContentView | func makeReactionsContentView(options: ReactionsContentViewOptions) -> ReactionsContentView |
func makeReactionsOverlayView(channel: ChatChannel, currentSnapshot: UIImage, messageDisplayInfo: MessageDisplayInfo, onBackgroundTap: @escaping () -> Void, onActionExecuted: @escaping (MessageActionInfo) -> Void) -> ReactionsOverlayViewType | func makeReactionsOverlayView(options: ReactionsOverlayViewOptions) -> ReactionsOverlayViewType |
func makeReactionsUsersView(message: ChatMessage, maxHeight: CGFloat) -> ReactionsUsersViewType | func makeReactionsDetailView(options: ReactionsDetailViewOptions) -> ReactionsDetailViewType |
func makeScrollToBottomButton(unreadCount: Int, onScrollToBottom: @escaping () -> Void) -> ScrollToBottomButtonType | func makeScrollToBottomButton(options: ScrollToBottomButtonOptions) -> ScrollToBottomButtonType |
func makeSendInChannelView(showReplyInChannel: Binding<Bool>, isDirectMessage: Bool) -> SendInChannelViewType | func makeSendInChannelView(options: SendInChannelViewOptions) -> SendInChannelViewType |
func makeSystemMessageView(message: ChatMessage) -> SystemMessageViewType | func makeSystemMessageView(options: SystemMessageViewOptions) -> SystemMessageViewType |
func makeTrailingComposerView(enabled: Bool, cooldownDuration: Int, onTap: @escaping () -> Void) -> TrailingComposerViewType | func makeTrailingComposerView(options: TrailingComposerViewOptions) -> TrailingComposerViewType |
func makeTypingIndicatorBottomView(channel: ChatChannel, currentUserId: UserId?) -> TypingIndicatorBottomViewType | func makeInlineTypingIndicatorView(options: TypingIndicatorViewOptions) -> InlineTypingIndicatorViewType |
func makeTypingIndicatorBottomView(channel: ChatChannel, currentUserId: UserId?) -> TypingIndicatorBottomViewType | func makeSubtitleTypingIndicatorView(options: SubtitleTypingIndicatorViewOptions) -> SubtitleTypingIndicatorViewType |
func makeVideoAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> VideoAttachmentViewType | func makeVideoAttachmentView(options: VideoAttachmentViewOptions) -> VideoAttachmentViewType |
func makeVideoPlayerFooterView(attachment: ChatMessageVideoAttachment, shown: Binding<Bool>) -> VideoPlayerFooterViewType | func makeVideoPlayerFooterView(options: VideoPlayerFooterViewOptions) -> VideoPlayerFooterViewType |
func makeVideoPlayerHeaderView(title: String, subtitle: String, shown: Binding<Bool>) -> VideoPlayerHeaderViewType | func makeVideoPlayerHeaderView(options: VideoPlayerHeaderViewOptions) -> VideoPlayerHeaderViewType |
func makeVideoPlayerView(attachment: ChatMessageVideoAttachment, message: ChatMessage, isShown: Binding<Bool>, options: MediaViewsOptions) -> VideoPlayerViewType | removed in v5, use func makeVideoPlayerHeaderView(options: VideoPlayerHeaderViewOptions) -> VideoPlayerHeaderViewType and func makeVideoPlayerFooterView(options: VideoPlayerFooterViewOptions) -> VideoPlayerFooterViewType |
func makeVoiceRecordingView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> VoiceRecordingViewType | func makeVoiceRecordingView(options: VoiceRecordingViewOptions) -> VoiceRecordingViewType |
func navigationBarDisplayMode() -> NavigationBarItem.TitleDisplayMode | moved to Utils.channelListConfig.navigationBarDisplayMode and Utils.messageListConfig.navigationBarDisplayMode |
func supportedMessageActions(for message: ChatMessage, channel: ChatChannel, onFinish: @escaping (MessageActionInfo) -> Void, onError: @escaping (Error) -> Void) -> [MessageAction] | moved to Utils.messageListConfig.supportedMessageActions closure |
no v4 equivalent | func makeAttachmentCommandsPickerView(options: AttachmentCommandsPickerViewOptions) -> AttachmentCommandsPickerViewType |
no v4 equivalent | func makeChatQuotedMessageView(options: ChatQuotedMessageViewOptions) -> ChatQuotedMessageViewType |
no v4 equivalent | func makeComposerInputTrailingView(options: ComposerInputTrailingViewOptions) -> ComposerInputTrailingViewType |
no v4 equivalent | func makeConfirmEditButton(options: ConfirmEditButtonOptions) -> ConfirmEditButtonType |
no v4 equivalent | func makeMessageAttachmentPreviewIconView(options: MessageAttachmentPreviewIconViewOptions) -> MessageAttachmentPreviewIconViewType |
no v4 equivalent | func makeMessageAttachmentPreviewThumbnailView(options: MessageAttachmentPreviewViewOptions) -> MessageAttachmentPreviewViewType |
no v4 equivalent | func makeMessageAttachmentsView(options: MessageAttachmentsViewOptions) -> MessageAttachmentsViewType |
no v4 equivalent | func makeMessageTopView(options: MessageTopViewOptions) -> MessageTopViewType |
no v4 equivalent | func makeMoreReactionsView(options: MoreReactionsViewOptions) -> MoreReactionsViewType |
no v4 equivalent | func makeSendMessageButton(options: SendMessageButtonOptions) -> SendMessageButtonType |
no v4 equivalent | func makeThreadRepliesDividerView(options: ThreadRepliesDividerViewOptions) -> ThreadRepliesDividerType |
Polls
| v4 | v5 |
|---|---|
func makeComposerPollView(channelController: ChatChannelController, messageController: ChatMessageController?) -> ComposerPollViewType | func makeAttachmentPollPickerView(options: AttachmentPollPickerViewOptions) -> AttachmentPollPickerViewType |
func makePollView(message: ChatMessage, poll: Poll, isFirst: Bool) -> PollViewType | func makePollView(options: PollViewOptions) -> PollViewType |
Thread List
| v4 | v5 |
|---|---|
func makeNoThreadsView() -> NoThreads | func makeEmptyThreadsView(options: EmptyThreadsViewOptions) -> EmptyThreads |
func makeThreadDestination() -> (ChatThread) -> ThreadDestination | func makeThreadDestination(options: ThreadDestinationOptions) -> @MainActor (ChatThread) -> ThreadDestination |
func makeThreadListBackground(colors: ColorPalette) -> ThreadListBackground | func makeThreadListBackground(options: ThreadListBackgroundOptions) -> ThreadListBackground |
func makeThreadListContainerViewModifier(viewModel: ChatThreadListViewModel) -> ThreadListContainerModifier | func makeThreadListContainerViewModifier(options: ThreadListContainerModifierOptions) -> ThreadListContainerModifier |
func makeThreadListDividerItem() -> ThreadListDividerItem | func makeThreadListDividerItem(options: ThreadListDividerItemOptions) -> ThreadListDividerItem |
func makeThreadListFooterView(viewModel: ChatThreadListViewModel) -> ThreadListFooterView | func makeThreadListFooterView(options: ThreadListFooterViewOptions) -> ThreadListFooterView |
func makeThreadListHeaderView(viewModel: ChatThreadListViewModel) -> ThreadListHeaderView | func makeThreadListHeaderView(options: ThreadListHeaderViewOptions) -> ThreadListHeaderView |
func makeThreadListHeaderViewModifier(title: String) -> ThreadListHeaderViewModifier | func makeThreadListHeaderViewModifier(options: ThreadListHeaderViewModifierOptions) -> ThreadListHeaderViewModifier |
func makeThreadListItem(thread: ChatThread, threadDestination: @escaping (ChatThread) -> ThreadDestination, selectedThread: Binding<ThreadSelectionInfo?>) -> ThreadListItemType | func makeThreadListItem(options: ThreadListItemOptions<ThreadDestination>) -> ThreadListItemType |
func makeThreadListItemBackground(thread: ChatThread, isSelected: Bool) -> ThreadListItemBackground | func makeThreadListItemBackground(options: ThreadListItemBackgroundOptions) -> ThreadListItemBackground |
func makeThreadListLoadingView() -> ThreadListLoadingView | func makeThreadListLoadingView(options: ThreadListLoadingViewOptions) -> ThreadListLoadingView |
func makeThreadsListErrorBannerView(onRefreshAction: @escaping () -> Void) -> ThreadListErrorBannerView | removed in v5, no direct replacement |
Member Add And Text Rendering
| v4 | v5 |
|---|---|
func makeAddUsersView(options: AddUsersOptions, onUserTap: @escaping (ChatUser) -> Void) -> AddUsersViewType | func makeMemberAddView(options: MemberAddViewOptions) -> MemberAddViewType |
func makeAttachmentTextView(options: AttachmentTextViewOptions) -> AttachmentTextViewType | func makeAttachmentTextView(options: AttachmentTextViewOptions) -> AttachmentTextViewType |
no v4 equivalent | func makeStreamTextView(options: StreamTextViewOptions) -> StreamTextViewType |
The safest migration path is to compile your custom UI against v5, then manually compare every custom override against ViewFactory, Styles, ChannelListConfig, and MessageListConfig.
Do not rely on compile failures alone. v5 still provides broad default implementations, so stale v4-shaped methods can compile while silently falling back to the default behavior. Pay special attention to old leading swipe action overrides, custom attachment picker and preview overrides, factory-level makeMessageViewModifier(for:), and old supportedMoreChannelActions(...) / supportedMessageActions(...) factory methods.
Migration Checklist
- Update your dependency to
5.x. - Replace
Appearance(...)initializers withvar appearance = Appearance()and property assignment. - Use
Appearance.FontsSwiftUI()for SwiftUI font customization. - Move tint customizations to
ColorPalette, usuallyaccentPrimaryandnavigationBarTintColor. - Replace removed
ColorPalettealiases with semanticv5tokens such astextPrimary,backgroundCoreApp,chatBackgroundIncoming, andborderCoreDefault. - Move SwiftUI gradient message bubble customizations from
ColorPalettearrays to a customStyles.makeMessageViewModifier(for:)implementation that usesBubbleModifier(backgroundColors:). - Rename
channelNamertochannelNameFormatterin yourUtilsinitializer. - Replace
ChatChannelNamerclosure type with a class conforming toChannelNameFormatter. - Replace
DefaultChatChannelNamerwithDefaultChannelNameFormatter. - Remove
imageMerger,channelAvatarsMerger, andchannelHeaderLoaderfrom yourUtilsinitializer. - Replace renamed reusable views:
UserAvatar,ChannelAvatar, andTypingIndicatorView. - Update
UserAvatarcall sites: pass aChatUser(or use the URL+initials initializer), useCGFloatfor size, and switchshowOnlineIndicator: Boolto theAvatarIndicatorenum. - Replace
MessageDisplayOptions(showAvatars:)with the newshowIncomingMessageAvatarandshowOutgoingMessageAvatarparameters; note that the new defaults differ (incomingtrue, outgoingfalse). - Migrate message container customizations from
makeMessageContainerView(...)tomakeMessageItemView(options:). - Migrate message translation/reply annotation customizations from
makeMessageTranslationFooterView(...)andmakeMessageRepliesShownInChannelView(...)tomakeMessageTopView(options:)andmakeMessageRepliesView(options:). - For custom text rendering in the message list, replace removed
LinkDetectionTextViewusage withChatMessage.attributedTextContent(layoutDirection:translationLanguage:)by optionally changing attributed string attributes or content through configs - Migrate gallery/media customizations from
makeGalleryView(...)andmakeGalleryHeaderView(...)tomakeMediaViewer(options:),makeMediaViewerToolbarModifier(options:), andmakeMediaViewerFooterView(options:). - Update video player header and footer customizations to
makeVideoPlayerHeaderView(options:)andmakeVideoPlayerFooterView(options:). For the full-screen media experience, usemakeMediaViewer(options:),makeMediaViewerToolbarModifier(options:), andmakeMediaViewerFooterView(options:). - Migrate quoted-message content customization from
makeQuotedMessageContentView(...)tomakeQuotedMessageView(options:)and/ormakeChatQuotedMessageView(options:). - Move
ViewFactorymodifier overrides (makeChannelListContentModifier,makeChannelListModifier,makeMessageListModifier,makeMessageListContainerModifier,makeMessageViewModifier,makeComposerViewModifier) to a customStylesimplementation and assign it tofactory.styles. - When implementing your custom
Styles, conform to theStylesprotocol directly —RegularStylesandLiquidGlassStylesarepublic class(notopen), so you cannot subclass them from your own module. The protocol provides defaults for most methods, but you must implementmakeComposerInputViewModifier(options:),makeComposerButtonViewModifier(options:), andmakeSuggestionsContainerModifier(options:)(useRegularInputViewModifier,RegularButtonViewModifier, andSuggestionsRegularContainerModifierto match the default appearance). - If you customized channel-list search in
v4, move that work out ofmakeChannelListTopView(...)and intoStyles.makeSearchableModifier(options:). TreatmakeChannelListTopView(options:)as a separate top content area inv5. - Move
supportedMoreChannelActionstoChannelListConfig.supportedMoreChannelActions. - Move
supportedMessageActionstoMessageListConfig.supportedMessageActions. - Move
navigationBarDisplayModetoChannelListConfig.navigationBarDisplayModeand/orMessageListConfig.navigationBarDisplayMode; do not rely on the compatibility helper onDefaultViewFactory. - Update all
ViewFactoryoverrides that take individual parameters to use the new single options object signature. - Review every custom
ViewFactoryoverride manually even if your project compiles; stalev4methods can still compile while no longer overriding anything. - Pay special attention to old
makeLeadingSwipeActionsView(...), custom attachment picker and preview overrides, factory-levelmakeMessageViewModifier(for:), and oldsupportedMoreChannelActions(...)/supportedMessageActions(...)methods. - Replace removed
ViewFactorymethods with theirv5equivalents (see the Channel And Message List table above). - Replace
imageLoaderandvideoLoaderonUtilswith a singlemediaLoaderparameter. - Replace
ImageLoading/NukeImageLoaderconformances withMediaLoader/StreamMediaLoader. - Replace
VideoLoading/VideoPreviewLoaderwithMediaLoader'sloadVideoPreviewmethod. - Replace
CDNClient/AttachmentUploaderwithCDNStorageonChatClientConfig.cdnStorage. - Replace
ImageCDN/StreamImageCDN/FileCDNwithCDNRequester/StreamCDNRequesterconfigured throughStreamMediaLoader(cdnRequester:).
After these changes, most v4 SwiftUI integrations should compile against v5, but custom factories still need a manual review to confirm each override is active and mapped to the correct v5 hook.
- Update the SDK Version
- Appearance no longer uses parameterized initializers
- Use Appearance.FontsSwiftUI for SwiftUI font customization
- Replace tintColor customizations with ColorPalette
- Migrate removed ColorPalette tokens
- channelNamer became channelNameFormatter
- Update renamed reusable SwiftUI views
- MessageDisplayOptions avatar parameters split
- Utils API changes
- CDN and Media Loading
- navigationBarDisplayMode, supportedMoreChannelActions, and supportedMessageActions moved to config objects
- New Styles protocol — modifier customization moved out of ViewFactory
- Translated text rendering changes (LinkDetectionTextView replacement)
- Review your ViewFactory implementations
- Migration Checklist