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:

  • Appearance customization now goes through mutable properties instead of initializer parameters.
  • Several SwiftUI-specific helper views were renamed.
  • ViewFactory methods now take a single options object instead of many individual parameters.
  • Several modifier methods moved from ViewFactory to the new Styles protocol.
  • Utils gained new formatter parameters and dropped a few deprecated ones.
  • supportedMoreChannelActions, supportedMessageActions, and navigationBarDisplayMode moved 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:

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)

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.fonts for UIKit font values
  • appearance.fontsSwiftUI for SwiftUI font values

If you are customizing SwiftUI screens, use Appearance.FontsSwiftUI:

var fonts = Appearance.FontsSwiftUI()
fonts.footnoteBold = .footnote

var appearance = Appearance()
appearance.fontsSwiftUI = fonts

If 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 = colors

In 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 tokenv5 token(s)Notes
texttextPrimaryUse inputTextDefault, chatTextOutgoing, or chatTextTypingIndicator when customizing those specific components.
subtitleTexttextSecondaryUse inputTextPlaceholder for input placeholders.
textLowEmphasistextTertiaryBest match for low-emphasis labels and icons.
textInvertedtextOnInverseUse when text is shown on inverse backgrounds.
textLinkColortextLink or chatTextLinkUse chatTextLink inside message content.
staticColorTexttextOnAccentUse chatTextSystem for date separators and system labels.
staticBlackColorTexttextPrimaryUse semantic text tokens instead of static black text.
backgroundbackgroundCoreAppApp and list backgrounds.
background1backgroundCoreSurfaceSubtleSubtle surfaces and secondary containers.
background2backgroundCoreSurfaceStrongStrong surfaces. Chat bubbles may need chatBackgroundOutgoing or chat border tokens instead.
background3backgroundCoreOverlayDarkDark overlay backgrounds.
background4, background5backgroundCoreScrimScrims and dark media overlays.
background6backgroundCoreSurfaceDefaultDefault surfaces. Message bubbles may need chatBackgroundIncoming or chatBackgroundOutgoing.
background7accentNeutral or backgroundCoreSurfaceSubtleUse accentNeutral for neutral icon/control colors, and backgroundCoreSurfaceSubtle for surfaces.
background8backgroundCoreElevation1 or chatBackgroundIncomingUse elevated surface tokens for popovers/cards, and chat tokens for message bubbles.
overlayBackgroundbackgroundCoreOverlayLightTyping indicators now use chatBackgroundIncoming with alpha.
popoverBackgroundbackgroundCoreElevation1Reactions now use reactionBackground.
highlightedBackgroundbackgroundCoreSurfaceStrongHighlighted rows, buttons, or selection surfaces.
highlightedAccentBackgroundaccentPrimaryAccent-highlighted UI now uses the primary accent token.
highlightedAccentBackground1backgroundCoreSurfaceSubtle or backgroundCoreElevation1Pick the surface token that matches the component hierarchy.
messageCellHighlightBackground, pinnedMessageBackgroundbackgroundCoreHighlightHighlighted message and pinned-message backgrounds.
jumpToUnreadButtonBackgroundaccentNeutralUsed by neutral unread controls.
borderborderCoreDefaultReactions now use reactionBorder.
border2borderCoreStrong or controlCheckboxBorderUse a component token for controls when available.
border3chatBorderIncoming, chatBorderOutgoing, or a core border tokenNo general 1:1 replacement. Pick the token that matches the old usage.
lightBorderborderCoreSubtleClosest low-emphasis border replacement.
innerBorderborderCoreDefaultClosest general replacement.
shadow, hoverButtonShadowbackgroundCoreOverlayDarkUsed as the replacement shadow or overlay color in the UIKit migration.
alert, validationErroraccentErrorError and destructive UI.
alternativeActiveTintaccentSuccessPoll progress uses chatPollProgressFillIncoming.
inactiveTintaccentNeutral or inputTextIconUse inputTextIcon for composer/input icons.
alternativeInactiveTintbackgroundUtilityDisabled or inputSendIconDisabledChoose the disabled token that matches the component.
disabledColorForColor, unselectedColorForColortextDisabled, backgroundUtilityDisabled, or component-specific disabled tokensNo direct replacement. Prefer semantic disabled tokens.
highlightedColorForColorhighlightedColorForColorStill available.
navigationBarTitlenavigationBarTitleStill available, but now defaults to textPrimary.
navigationBarSubtitlenavigationBarSubtitleStill available, but now defaults to textTertiary.
navigationBarBackgroundnavigationBarBackgroundStill available.
navigationBarTintColornavigationBarTintColorStill available, defaulting to accentPrimary.
navigationBarGlyphnavigationBarGlyphStill available, now defaulting to .baseWhite.
reactionCurrentUserColor, reactionOtherUserColorreactionText, reactionBackground, reactionBorder, or accentPrimaryPick based on whether you customized reaction text, selected state, background, or border.
selectedReactionBackgroundColorreactionBackground, reactionBorder, or accentPrimaryNo exact replacement. Choose the reaction token that matches the customized selected state.
quotedMessageBackgroundCurrentUser, quotedMessageBackgroundOtherUserbackgroundCoreElevation1, backgroundCoreSurfaceSubtle, or chat attachment/message tokensPick based on whether the quoted content behaves like an elevated surface, subtle surface, attachment, or message bubble.
composerInputHighlightedBorderborderCoreDefaultClosest general composer border replacement.
voiceMessageControlBackgroundcontrolPlaybackThumbBackgroundDefault, controlPlayButtonBackground, or backgroundCoreOnAccentUse the control-specific token that matches the customized voice-message control.
messageCurrentUserBackgroundchatBackgroundOutgoingCurrent-user message bubble background.
messageCurrentUserEmphemeralBackgroundchatBackgroundOutgoing, chatBackgroundIncoming, or backgroundCoreElevation1No exact replacement. Pick the token that matches the old ephemeral-message visual role.
messageOtherUserBackgroundchatBackgroundIncomingOther-user message bubble background.
messageCurrentUserTextColorchatTextOutgoingCurrent-user message text.
messageOtherUserTextColorchatTextIncomingOther-user message text.
bannerBackgroundColortextTertiary or accentNeutralNo exact replacement. Pick based on banner style.
composerInputBackgroundbackgroundCoreApp or a surface tokenChoose the app background or surface token that matches your composer design.
composerPlaceholderColorinputTextPlaceholderComposer placeholder text.
messageLinkAttachmentAuthorColorchatTextLink or textLinkUse chatTextLink inside message/link attachment content.
messageLinkAttachmentTitleColortextPrimaryLink attachment title text.
messageLinkAttachmentTextColortextPrimary or textSecondaryPick 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 -> UserAvatar
  • ChannelAvatarView -> ChannelAvatar
  • TypingIndicatorBottomView -> 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 parameterv5 parameter(s)
showAvatars: BoolshowIncomingMessageAvatar: 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 parameterNotes
imageMergerRemoved; avatar merging is handled internally.
channelAvatarsMergerRemoved; avatar merging is handled internally.
channelHeaderLoaderRemoved.
channelNamerRenamed — see channelNameFormatter below.

Renamed parameter:

v4v5
channelNamer: ChatChannelNamer (closure)channelNameFormatter: any ChannelNameFormatter (protocol)

New parameters in v5:

ParameterPurpose
markdownFormatterProvides custom Markdown rendering for message text.
messageTimestampFormatterFormats the timestamp shown on individual messages.
galleryHeaderViewDateFormatterFormats the date in the media gallery header.
messageDateSeparatorFormatterFormats the date separator labels in the message list.
mediaLoaderUnified loader for images and video previews (replaces imageLoader + videoLoader).
messageAttachmentPreviewIconProviderProvides icons for attachment preview thumbnails.
messagePreviewFormatterFormats the message preview text shown in the channel list.
channelListConfigConfiguration object for the channel list (see below).
mediaBadgeDurationFormatterFormats duration badges on audio and video attachments.
messageRemindersFormatterFormats 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 Typev5 Replacement
ImageLoading / NukeImageLoaderMediaLoader / StreamMediaLoader
VideoLoading / VideoPreviewLoaderMediaLoader (via loadVideoPreview)
StreamVideoLoader / DefaultVideoPreviewLoaderStreamMediaLoader

CDN Customization

CDN URL handling was split into two distinct concerns: storage (uploads/deletes) and requesting (signed URLs, auth headers, resizing).

v4 Typev5 Replacement
CDNClientCDNStorage
AttachmentUploaderCDNStorage + UploadedAttachmentPostProcessor
ChatClientConfig.customCDNClientChatClientConfig.cdnStorage
ChatClientConfig.customAttachmentUploaderChatClientConfig.cdnStorage
ImageCDN / StreamImageCDNCDNRequester / StreamCDNRequester
FileCDNCDNRequester (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.

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 methodv5 Styles method
func makeChannelListContentModifier() -> ChannelListContentModifierfunc makeChannelListContentModifier(options: ChannelListContentModifierOptions) -> ChannelListContentModifier
func makeChannelListModifier() -> ChannelListModifierfunc makeChannelListModifier(options: ChannelListModifierOptions) -> ChannelListModifier
func makeMessageListModifier() -> MessageListModifierfunc makeMessageListModifier(options: MessageListModifierOptions) -> MessageListModifier
func makeMessageListContainerModifier() -> MessageListContainerModifierfunc makeMessageListContainerModifier(options: MessageListContainerModifierOptions) -> MessageListContainerModifier
func makeMessageViewModifier(for messageModifierInfo: MessageModifierInfo) -> MessageViewModifierfunc makeMessageViewModifier(for messageModifierInfo: MessageModifierInfo) -> MessageViewModifier
func makeComposerViewModifier() -> ComposerViewModifierfunc makeComposerViewModifier(options: ComposerViewModifierOptions) -> ComposerViewModifier

New Styles methods with no v4 equivalent:

  • func makeComposerInputViewModifier(options: ComposerInputModifierOptions) -> ComposerInputViewModifier
  • func makeComposerButtonViewModifier(options: ComposerButtonModifierOptions) -> ComposerButtonViewModifier
  • func makeScrollToBottomButtonModifier(options: ScrollToBottomButtonModifierOptions) -> ScrollToBottomButtonViewModifier
  • func makeBouncedMessageActionsModifier(viewModel: ChatChannelViewModel) -> BouncedMessageActionsModifierType
  • func makeSuggestionsContainerModifier(options: SuggestionsContainerModifierOptions) -> SuggestionsContainerModifier
  • func makeToolbarConfirmActionModifier(options: ToolbarConfirmActionModifierOptions) -> ToolbarConfirmActionViewModifier
  • func 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
v4v5
func makeChannelAvatarView(for channel: ChatChannel, with options: ChannelAvatarViewOptions) -> ChannelAvatarViewTypefunc makeChannelAvatarView(options: ChannelAvatarViewOptions) -> ChannelAvatarViewType
func makeChannelListBackground(colors: ColorPalette) -> ChannelListBackgroundfunc makeChannelListBackground(options: ChannelListBackgroundOptions) -> ChannelListBackground
func makeChannelListContentModifier() -> ChannelListContentModifiermoved to Styles, see the Styles section above
func makeChannelListDividerItem() -> ChannelListDividerItemfunc makeChannelListDividerItem(options: ChannelListDividerItemOptions) -> ChannelListDividerItem
func makeChannelListFooterView() -> ChannelListFooterViewTypefunc makeChannelListFooterView(options: ChannelListFooterViewOptions) -> ChannelListFooterViewType
func makeChannelListHeaderViewModifier(title: String) -> HeaderViewModifierfunc 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) -> ChannelListItemTypefunc makeChannelListItem(options: ChannelListItemOptions<ChannelDestination>) -> ChannelListItemType
func makeChannelListItemBackground(channel: ChatChannel, isSelected: Bool) -> ChannelListItemBackgroundfunc makeChannelListItemBackground(options: ChannelListItemBackgroundOptions) -> ChannelListItemBackground
func makeChannelListModifier() -> ChannelListModifiermoved 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) -> ChannelListSearchResultItemfunc makeChannelListSearchResultItem(options: ChannelListSearchResultItemOptions<ChannelDestination>) -> ChannelListSearchResultItem
func makeChannelListStickyFooterView() -> ChannelListStickyFooterViewTypefunc makeChannelListStickyFooterView(options: ChannelListStickyFooterViewOptions) -> ChannelListStickyFooterViewType
func makeChannelListTopView(searchText: Binding<String>) -> ChannelListTopViewTypefunc makeChannelListTopView(options: ChannelListTopViewOptions) -> ChannelListTopViewType
func makeLeadingSwipeActionsView(channel: ChatChannel, offsetX: CGFloat, buttonWidth: CGFloat, swipedChannelId: Binding<String?>, buttonTapped: @escaping (ChatChannel) -> Void) -> LeadingSwipeActionsViewTypefunc makeLeadingSwipeActionsView(options: LeadingSwipeActionsViewOptions) -> LeadingSwipeActionsViewType
func makeLoadingView() -> LoadingContentfunc makeLoadingView(options: LoadingViewOptions) -> LoadingContent
func makeMoreChannelActionsView(for channel: ChatChannel, swipedChannelId: Binding<String?>, onDismiss: @escaping () -> Void, onError: @escaping (Error) -> Void) -> MoreActionsViewfunc makeMoreChannelActionsView(options: MoreChannelActionsViewOptions) -> MoreActionsView
func makeNoChannelsView() -> NoChannelsfunc 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) -> ChannelListSearchResultsViewTypefunc makeSearchResultsView(options: SearchResultsViewOptions) -> ChannelListSearchResultsViewType
func makeTrailingSwipeActionsView(channel: ChatChannel, offsetX: CGFloat, buttonWidth: CGFloat, swipedChannelId: Binding<String?>, leftButtonTapped: @escaping (ChatChannel) -> Void, rightButtonTapped: @escaping (ChatChannel) -> Void) -> TrailingSwipeActionsViewTypefunc 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
v4v5
func makeAssetsAccessPermissionView() -> AssetsAccessPermissionViewTyperemoved 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) -> AttachmentPickerViewTypefunc makeAttachmentPickerView(options: AttachmentPickerViewOptions) -> AttachmentPickerViewType
func makeAttachmentSourcePickerView(selected: AttachmentPickerState, onPickerStateChange: @escaping (AttachmentPickerState) -> Void) -> AttachmentSourcePickerViewTypefunc makeAttachmentTypePickerView(options: AttachmentTypePickerViewOptions) -> AttachmentTypePickerViewType
func makeBottomReactionsView(message: ChatMessage, showsAllInfo: Bool, onTap: @escaping () -> Void, onLongPress: @escaping () -> Void) -> ReactionsBottomViewTypefunc makeBottomReactionsView(options: ReactionsBottomViewOptions) -> ReactionsBottomViewType
func makeBouncedMessageActionsModifier(viewModel: ChatChannelViewModel) -> BouncedMessageActionsModifierTypemoved to Styles, see the Styles section above
func makeCameraPickerView(selected: Binding<AttachmentPickerState>, cameraPickerShown: Binding<Bool>, cameraImageAdded: @escaping (AddedAsset) -> Void) -> CameraPickerViewTypefunc makeAttachmentCameraPickerView(options: AttachmentCameraPickerViewOptions) -> AttachmentCameraPickerViewType
func makeChannelBarsVisibilityViewModifier(shouldShow: Bool) -> ChangeBarsVisibilityModifierfunc makeChannelBarsVisibilityViewModifier(options: ChannelBarsVisibilityViewModifierOptions) -> ChangeBarsVisibilityModifier
func makeChannelDestination() -> (ChannelSelectionInfo) -> ChannelDestinationfunc makeChannelDestination(options: ChannelDestinationOptions) -> @MainActor (ChannelSelectionInfo) -> ChannelDestination
func makeChannelHeaderViewModifier(for channel: ChatChannel) -> ChatHeaderViewModifierfunc makeChannelHeaderViewModifier(options: ChannelHeaderViewModifierOptions) -> ChatHeaderViewModifier
func makeChannelLoadingView() -> ChannelLoadingViewTypefunc makeChannelLoadingView(options: ChannelLoadingViewOptions) -> ChannelLoadingViewType
func makeCommandsContainerView(suggestions: [String: Any], handleCommand: @escaping ([String: Any]) -> Void) -> CommandsContainerViewTypefunc 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) -> ComposerInputViewTypefunc makeComposerInputView(options: ComposerInputViewOptions) -> ComposerInputViewType
func makeComposerRecordingLockedView(viewModel: MessageComposerViewModel) -> ComposerRecordingLockedViewTypefunc makeComposerVoiceRecordingInputView(options: ComposerVoiceRecordingInputViewOptions) -> ComposerVoiceRecordingInputViewType
func makeComposerRecordingTipView() -> ComposerRecordingTipViewTypefunc makeComposerVoiceRecordingInputView(options: ComposerVoiceRecordingInputViewOptions) -> ComposerVoiceRecordingInputViewType
func makeComposerRecordingView(viewModel: MessageComposerViewModel, gestureLocation: CGPoint) -> ComposerRecordingViewTypefunc makeComposerVoiceRecordingInputView(options: ComposerVoiceRecordingInputViewOptions) -> ComposerVoiceRecordingInputViewType
func makeComposerTextInputView(text: Binding<String>, height: Binding<CGFloat>, selectedRangeLocation: Binding<Int>, placeholder: String, editable: Bool, maxMessageLength: Int?, currentHeight: CGFloat) -> ComposerTextInputViewTypefunc makeComposerTextInputView(options: ComposerTextInputViewOptions) -> ComposerTextInputViewType
func makeComposerViewModifier() -> ComposerViewModifiermoved to Styles, see the Styles section above
func makeCustomAttachmentPreviewView(addedCustomAttachments: [CustomAttachment], onCustomAttachmentTap: @escaping (CustomAttachment) -> Void) -> CustomAttachmentPreviewViewTypefunc makeCustomAttachmentPreviewView(options: CustomAttachmentPreviewViewOptions) -> CustomAttachmentPreviewViewType
func makeCustomAttachmentQuotedView(for message: ChatMessage) -> CustomAttachmentQuotedViewTyperemoved in v5, no direct replacement
func makeCustomAttachmentView(addedCustomAttachments: [CustomAttachment], onCustomAttachmentTap: @escaping (CustomAttachment) -> Void) -> CustomComposerAttachmentViewTypefunc makeCustomAttachmentPickerView(options: CustomAttachmentPickerViewOptions) -> CustomAttachmentPickerViewType
func makeCustomAttachmentViewType(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> CustomAttachmentViewTypefunc makeCustomAttachmentViewType(options: CustomAttachmentViewTypeOptions) -> CustomAttachmentViewType
func makeDateIndicatorView(dateString: String) -> DateIndicatorViewTypefunc makeDateIndicatorView(options: DateIndicatorViewOptions) -> DateIndicatorViewType
func makeDeletedMessageView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat) -> DeletedMessageViewTypefunc makeDeletedMessageView(options: DeletedMessageViewOptions) -> DeletedMessageViewType
func makeEditedMessageHeaderView(editedMessage: Binding<ChatMessage?>) -> EditedMessageHeaderViewTypefunc makeComposerEditedMessageView(options: ComposerEditedMessageViewOptions) -> ComposerEditedMessageViewType
func makeEmojiTextView(message: ChatMessage, scrolledId: Binding<String?>, isFirst: Bool) -> EmojiTextViewTypefunc makeEmojiTextView(options: EmojiTextViewOptions) -> EmojiTextViewType
func makeEmptyMessagesView(for channel: ChatChannel, colors: ColorPalette) -> EmptyMessagesViewTypefunc makeEmptyMessagesView(options: EmptyMessagesViewOptions) -> EmptyMessagesViewType
func makeFileAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> FileAttachmentViewTypefunc makeFileAttachmentView(options: FileAttachmentViewOptions) -> FileAttachmentViewType
func makeFilePickerView(filePickerShown: Binding<Bool>, addedFileURLs: Binding<[URL]>) -> FilePickerViewTypefunc makeAttachmentFilePickerView(options: AttachmentFilePickerViewOptions) -> AttachmentFilePickerViewType
func makeGalleryHeaderView(title: String, subtitle: String, shown: Binding<Bool>) -> GalleryHeaderViewTypefunc makeMediaViewerToolbarModifier(options: MediaViewerToolbarModifierOptions) -> MediaViewerToolbarModifierType
func makeGalleryHeaderView(title: String, subtitle: String, shown: Binding<Bool>) -> GalleryHeaderViewTypefunc makeMediaViewerFooterView(options: MediaViewerFooterViewOptions) -> MediaViewerFooterViewType
func makeGalleryView(mediaAttachments: [MediaAttachment], message: ChatMessage, isShown: Binding<Bool>, options: MediaViewsOptions) -> GalleryViewTypefunc makeMediaViewer(options: MediaViewerOptions) -> MediaViewerType
func makeGiphyAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> GiphyAttachmentViewTypefunc makeGiphyAttachmentView(options: GiphyAttachmentViewOptions) -> GiphyAttachmentViewType
func makeGiphyBadgeViewType(for message: ChatMessage, availableWidth: CGFloat) -> GiphyBadgeViewTypefunc makeGiphyBadgeViewType(options: GiphyBadgeViewTypeOptions) -> GiphyBadgeViewType
func makeImageAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> ImageAttachmentViewTypefunc makeImageAttachmentView(options: ImageAttachmentViewOptions) -> ImageAttachmentViewType
func makeJumpToUnreadButton(channel: ChatChannel, onJumpToMessage: @escaping () -> Void, onClose: @escaping () -> Void) -> JumpToUnreadButtonTypefunc makeJumpToUnreadButtonOverlay(options: JumpToUnreadButtonOptions) -> JumpToUnreadButtonOverlayType
func makeLastInGroupHeaderView(for message: ChatMessage) -> LastInGroupHeaderViewfunc makeLastInGroupHeaderView(options: LastInGroupHeaderViewOptions) -> LastInGroupHeaderView
func makeLeadingComposerView(state: Binding<PickerTypeState>, channelConfig: ChannelConfig?) -> LeadingComposerViewTypefunc makeLeadingComposerView(options: LeadingComposerViewOptions) -> LeadingComposerViewType
func makeLinkAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> LinkAttachmentViewTypefunc makeLinkAttachmentView(options: LinkAttachmentViewOptions) -> LinkAttachmentViewType
func makeMessageActionsView(for message: ChatMessage, channel: ChatChannel, onFinish: @escaping (MessageActionInfo) -> Void, onError: @escaping (Error) -> Void) -> MessageActionsViewTypefunc makeMessageActionsView(options: MessageActionsViewOptions) -> MessageActionsViewType
func makeMessageAuthorAndDateView(for message: ChatMessage) -> MessageAuthorAndDateViewTypefunc makeMessageAuthorAndDateView(options: MessageAuthorAndDateViewOptions) -> MessageAuthorAndDateViewType
func makeMessageAvatarView(for userDisplayInfo: UserDisplayInfo) -> UserAvatarfunc makeUserAvatarView(options: UserAvatarViewOptions) -> UserAvatarViewType
func makeMessageComposerViewType(with channelController: ChatChannelController, messageController: ChatMessageController?, quotedMessage: Binding<ChatMessage?>, editedMessage: Binding<ChatMessage?>, onMessageSent: @escaping () -> Void) -> MessageComposerViewTypefunc 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) -> MessageContainerViewTypefunc makeMessageItemView(options: MessageItemViewOptions) -> MessageItemViewType
func makeMessageDateView(for message: ChatMessage) -> MessageDateViewTypefunc makeMessageDateView(options: MessageDateViewOptions) -> MessageDateViewType
func makeMessageListBackground(colors: ColorPalette, isInThread: Bool) -> MessageListBackgroundfunc makeMessageListBackground(options: MessageListBackgroundOptions) -> MessageListBackground
func makeMessageListContainerModifier() -> MessageListContainerModifiermoved to Styles, see the Styles section above
func makeMessageListDateIndicator(date: Date) -> MessageListDateIndicatorViewTypefunc makeMessageListDateIndicator(options: MessageListDateIndicatorViewOptions) -> MessageListDateIndicatorViewType
func makeMessageListModifier() -> MessageListModifiermoved to Styles, see the Styles section above
func makeMessageReactionView(message: ChatMessage, onTapGesture: @escaping () -> Void, onLongPressGesture: @escaping () -> Void) -> MessageReactionViewTypefunc makeMessageReactionView(options: MessageReactionViewOptions) -> MessageReactionViewType
func makeMessageReadIndicatorView(channel: ChatChannel, message: ChatMessage) -> MessageReadIndicatorViewTypefunc makeMessageReadIndicatorView(options: MessageReadIndicatorViewOptions) -> MessageReadIndicatorViewType
func makeMessageRepliesShownInChannelView(channel: ChatChannel, message: ChatMessage, parentMessage: ChatMessage, replyCount: Int) -> MessageRepliesShownInChannelViewTyperemoved 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) -> MessageRepliesViewTypefunc makeMessageRepliesView(options: MessageRepliesViewOptions) -> MessageRepliesViewType
func makeMessageTextView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> MessageTextViewTypefunc makeMessageTextView(options: MessageTextViewOptions) -> MessageTextViewType
func makeMessageThreadDestination() -> (ChatChannel, ChatMessage) -> MessageThreadDestinationfunc makeMessageThreadDestination(options: MessageThreadDestinationOptions) -> @MainActor (ChatChannel, ChatMessage) -> MessageThreadDestination
func makeMessageThreadHeaderViewModifier() -> ThreadHeaderViewModifierfunc makeMessageThreadHeaderViewModifier(options: MessageThreadHeaderViewModifierOptions) -> ThreadHeaderViewModifier
func makeMessageTranslationFooterView(messageViewModel: MessageViewModel) -> MessageTranslationFooterViewTyperemoved in v5, translated/pinned/reply annotations are now composed by func makeMessageTopView(options: MessageTopViewOptions) -> MessageTopViewType
func makeMessageViewModifier(for messageModifierInfo: MessageModifierInfo) -> MessageViewModifiermoved to Styles, see the Styles section above
func makeNewMessagesIndicatorView(newMessagesStartId: Binding<String?>, count: Int) -> NewMessagesIndicatorViewTypefunc makeNewMessagesDividerView(options: NewMessagesDividerViewOptions) -> NewMessagesDividerType
func makePhotoAttachmentPickerView(assets: PHFetchResultCollection, onAssetTap: @escaping (AddedAsset) -> Void, isAssetSelected: @escaping (String) -> Bool) -> PhotoAttachmentPickerViewTypefunc makeAttachmentMediaPickerView(options: AttachmentMediaPickerViewOptions) -> AttachmentMediaPickerViewType
func makeQuotedMessageAvatarView(for userDisplayInfo: UserDisplayInfo, size: CGSize) -> QuotedUserAvatarfunc makeUserAvatarView(options: UserAvatarViewOptions) -> UserAvatarViewType
func makeQuotedMessageContentView(options: QuotedMessageContentViewOptions) -> QuotedMessageContentViewTyperemoved in v5, compose quoted-message rendering with func makeQuotedMessageView(options: QuotedMessageViewOptions) -> QuotedMessageViewType and func makeChatQuotedMessageView(options: ChatQuotedMessageViewOptions) -> ChatQuotedMessageViewType
func makeQuotedMessageHeaderView(quotedMessage: Binding<ChatMessage?>) -> QuotedMessageHeaderViewTypefunc makeComposerQuotedMessageView(options: ComposerQuotedMessageViewOptions) -> ComposerQuotedMessageViewType
func makeQuotedMessageView(quotedMessage: ChatMessage, fillAvailableSpace: Bool, isInComposer: Bool, scrolledId: Binding<String?>) -> QuotedMessageViewTypefunc makeQuotedMessageView(options: QuotedMessageViewOptions) -> QuotedMessageViewType
func makeReactionsBackgroundView(currentSnapshot: UIImage, popInAnimationInProgress: Bool) -> ReactionsBackgroundremoved in v5, no direct replacement
func makeReactionsContentView(message: ChatMessage, contentRect: CGRect, onReactionTap: @escaping (MessageReactionType) -> Void) -> ReactionsContentViewfunc makeReactionsContentView(options: ReactionsContentViewOptions) -> ReactionsContentView
func makeReactionsOverlayView(channel: ChatChannel, currentSnapshot: UIImage, messageDisplayInfo: MessageDisplayInfo, onBackgroundTap: @escaping () -> Void, onActionExecuted: @escaping (MessageActionInfo) -> Void) -> ReactionsOverlayViewTypefunc makeReactionsOverlayView(options: ReactionsOverlayViewOptions) -> ReactionsOverlayViewType
func makeReactionsUsersView(message: ChatMessage, maxHeight: CGFloat) -> ReactionsUsersViewTypefunc makeReactionsDetailView(options: ReactionsDetailViewOptions) -> ReactionsDetailViewType
func makeScrollToBottomButton(unreadCount: Int, onScrollToBottom: @escaping () -> Void) -> ScrollToBottomButtonTypefunc makeScrollToBottomButton(options: ScrollToBottomButtonOptions) -> ScrollToBottomButtonType
func makeSendInChannelView(showReplyInChannel: Binding<Bool>, isDirectMessage: Bool) -> SendInChannelViewTypefunc makeSendInChannelView(options: SendInChannelViewOptions) -> SendInChannelViewType
func makeSystemMessageView(message: ChatMessage) -> SystemMessageViewTypefunc makeSystemMessageView(options: SystemMessageViewOptions) -> SystemMessageViewType
func makeTrailingComposerView(enabled: Bool, cooldownDuration: Int, onTap: @escaping () -> Void) -> TrailingComposerViewTypefunc makeTrailingComposerView(options: TrailingComposerViewOptions) -> TrailingComposerViewType
func makeTypingIndicatorBottomView(channel: ChatChannel, currentUserId: UserId?) -> TypingIndicatorBottomViewTypefunc makeInlineTypingIndicatorView(options: TypingIndicatorViewOptions) -> InlineTypingIndicatorViewType
func makeTypingIndicatorBottomView(channel: ChatChannel, currentUserId: UserId?) -> TypingIndicatorBottomViewTypefunc makeSubtitleTypingIndicatorView(options: SubtitleTypingIndicatorViewOptions) -> SubtitleTypingIndicatorViewType
func makeVideoAttachmentView(for message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, scrolledId: Binding<String?>) -> VideoAttachmentViewTypefunc makeVideoAttachmentView(options: VideoAttachmentViewOptions) -> VideoAttachmentViewType
func makeVideoPlayerFooterView(attachment: ChatMessageVideoAttachment, shown: Binding<Bool>) -> VideoPlayerFooterViewTypefunc makeVideoPlayerFooterView(options: VideoPlayerFooterViewOptions) -> VideoPlayerFooterViewType
func makeVideoPlayerHeaderView(title: String, subtitle: String, shown: Binding<Bool>) -> VideoPlayerHeaderViewTypefunc makeVideoPlayerHeaderView(options: VideoPlayerHeaderViewOptions) -> VideoPlayerHeaderViewType
func makeVideoPlayerView(attachment: ChatMessageVideoAttachment, message: ChatMessage, isShown: Binding<Bool>, options: MediaViewsOptions) -> VideoPlayerViewTyperemoved 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?>) -> VoiceRecordingViewTypefunc makeVoiceRecordingView(options: VoiceRecordingViewOptions) -> VoiceRecordingViewType
func navigationBarDisplayMode() -> NavigationBarItem.TitleDisplayModemoved 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 equivalentfunc makeAttachmentCommandsPickerView(options: AttachmentCommandsPickerViewOptions) -> AttachmentCommandsPickerViewType
no v4 equivalentfunc makeChatQuotedMessageView(options: ChatQuotedMessageViewOptions) -> ChatQuotedMessageViewType
no v4 equivalentfunc makeComposerInputTrailingView(options: ComposerInputTrailingViewOptions) -> ComposerInputTrailingViewType
no v4 equivalentfunc makeConfirmEditButton(options: ConfirmEditButtonOptions) -> ConfirmEditButtonType
no v4 equivalentfunc makeMessageAttachmentPreviewIconView(options: MessageAttachmentPreviewIconViewOptions) -> MessageAttachmentPreviewIconViewType
no v4 equivalentfunc makeMessageAttachmentPreviewThumbnailView(options: MessageAttachmentPreviewViewOptions) -> MessageAttachmentPreviewViewType
no v4 equivalentfunc makeMessageAttachmentsView(options: MessageAttachmentsViewOptions) -> MessageAttachmentsViewType
no v4 equivalentfunc makeMessageTopView(options: MessageTopViewOptions) -> MessageTopViewType
no v4 equivalentfunc makeMoreReactionsView(options: MoreReactionsViewOptions) -> MoreReactionsViewType
no v4 equivalentfunc makeSendMessageButton(options: SendMessageButtonOptions) -> SendMessageButtonType
no v4 equivalentfunc makeThreadRepliesDividerView(options: ThreadRepliesDividerViewOptions) -> ThreadRepliesDividerType
Polls
v4v5
func makeComposerPollView(channelController: ChatChannelController, messageController: ChatMessageController?) -> ComposerPollViewTypefunc makeAttachmentPollPickerView(options: AttachmentPollPickerViewOptions) -> AttachmentPollPickerViewType
func makePollView(message: ChatMessage, poll: Poll, isFirst: Bool) -> PollViewTypefunc makePollView(options: PollViewOptions) -> PollViewType
Thread List
v4v5
func makeNoThreadsView() -> NoThreadsfunc makeEmptyThreadsView(options: EmptyThreadsViewOptions) -> EmptyThreads
func makeThreadDestination() -> (ChatThread) -> ThreadDestinationfunc makeThreadDestination(options: ThreadDestinationOptions) -> @MainActor (ChatThread) -> ThreadDestination
func makeThreadListBackground(colors: ColorPalette) -> ThreadListBackgroundfunc makeThreadListBackground(options: ThreadListBackgroundOptions) -> ThreadListBackground
func makeThreadListContainerViewModifier(viewModel: ChatThreadListViewModel) -> ThreadListContainerModifierfunc makeThreadListContainerViewModifier(options: ThreadListContainerModifierOptions) -> ThreadListContainerModifier
func makeThreadListDividerItem() -> ThreadListDividerItemfunc makeThreadListDividerItem(options: ThreadListDividerItemOptions) -> ThreadListDividerItem
func makeThreadListFooterView(viewModel: ChatThreadListViewModel) -> ThreadListFooterViewfunc makeThreadListFooterView(options: ThreadListFooterViewOptions) -> ThreadListFooterView
func makeThreadListHeaderView(viewModel: ChatThreadListViewModel) -> ThreadListHeaderViewfunc makeThreadListHeaderView(options: ThreadListHeaderViewOptions) -> ThreadListHeaderView
func makeThreadListHeaderViewModifier(title: String) -> ThreadListHeaderViewModifierfunc makeThreadListHeaderViewModifier(options: ThreadListHeaderViewModifierOptions) -> ThreadListHeaderViewModifier
func makeThreadListItem(thread: ChatThread, threadDestination: @escaping (ChatThread) -> ThreadDestination, selectedThread: Binding<ThreadSelectionInfo?>) -> ThreadListItemTypefunc makeThreadListItem(options: ThreadListItemOptions<ThreadDestination>) -> ThreadListItemType
func makeThreadListItemBackground(thread: ChatThread, isSelected: Bool) -> ThreadListItemBackgroundfunc makeThreadListItemBackground(options: ThreadListItemBackgroundOptions) -> ThreadListItemBackground
func makeThreadListLoadingView() -> ThreadListLoadingViewfunc makeThreadListLoadingView(options: ThreadListLoadingViewOptions) -> ThreadListLoadingView
func makeThreadsListErrorBannerView(onRefreshAction: @escaping () -> Void) -> ThreadListErrorBannerViewremoved in v5, no direct replacement
Member Add And Text Rendering
v4v5
func makeAddUsersView(options: AddUsersOptions, onUserTap: @escaping (ChatUser) -> Void) -> AddUsersViewTypefunc makeMemberAddView(options: MemberAddViewOptions) -> MemberAddViewType
func makeAttachmentTextView(options: AttachmentTextViewOptions) -> AttachmentTextViewTypefunc makeAttachmentTextView(options: AttachmentTextViewOptions) -> AttachmentTextViewType
no v4 equivalentfunc 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 with var appearance = Appearance() and property assignment.
  • Use Appearance.FontsSwiftUI() for SwiftUI font customization.
  • Move tint customizations to ColorPalette, usually accentPrimary and navigationBarTintColor.
  • Replace removed ColorPalette aliases with semantic v5 tokens such as textPrimary, backgroundCoreApp, chatBackgroundIncoming, and borderCoreDefault.
  • Move SwiftUI gradient message bubble customizations from ColorPalette arrays to a custom Styles.makeMessageViewModifier(for:) implementation that uses BubbleModifier(backgroundColors:).
  • Rename channelNamer to channelNameFormatter in your Utils initializer.
  • Replace ChatChannelNamer closure type with a class conforming to ChannelNameFormatter.
  • Replace DefaultChatChannelNamer with DefaultChannelNameFormatter.
  • Remove imageMerger, channelAvatarsMerger, and channelHeaderLoader from your Utils initializer.
  • Replace renamed reusable views: UserAvatar, ChannelAvatar, and TypingIndicatorView.
  • Update UserAvatar call sites: pass a ChatUser (or use the URL+initials initializer), use CGFloat for size, and switch showOnlineIndicator: Bool to the AvatarIndicator enum.
  • Replace MessageDisplayOptions(showAvatars:) with the new showIncomingMessageAvatar and showOutgoingMessageAvatar parameters; note that the new defaults differ (incoming true, outgoing false).
  • Migrate message container customizations from makeMessageContainerView(...) to makeMessageItemView(options:).
  • Migrate message translation/reply annotation customizations from makeMessageTranslationFooterView(...) and makeMessageRepliesShownInChannelView(...) to makeMessageTopView(options:) and makeMessageRepliesView(options:).
  • For custom text rendering in the message list, replace removed LinkDetectionTextView usage with ChatMessage.attributedTextContent(layoutDirection:translationLanguage:) by optionally changing attributed string attributes or content through configs
  • Migrate gallery/media customizations from makeGalleryView(...) and makeGalleryHeaderView(...) to makeMediaViewer(options:), makeMediaViewerToolbarModifier(options:), and makeMediaViewerFooterView(options:).
  • Update video player header and footer customizations to makeVideoPlayerHeaderView(options:) and makeVideoPlayerFooterView(options:). For the full-screen media experience, use makeMediaViewer(options:), makeMediaViewerToolbarModifier(options:), and makeMediaViewerFooterView(options:).
  • Migrate quoted-message content customization from makeQuotedMessageContentView(...) to makeQuotedMessageView(options:) and/or makeChatQuotedMessageView(options:).
  • Move ViewFactory modifier overrides (makeChannelListContentModifier, makeChannelListModifier, makeMessageListModifier, makeMessageListContainerModifier, makeMessageViewModifier, makeComposerViewModifier) to a custom Styles implementation and assign it to factory.styles.
  • When implementing your custom Styles, conform to the Styles protocol directly — RegularStyles and LiquidGlassStyles are public class (not open), so you cannot subclass them from your own module. The protocol provides defaults for most methods, but you must implement makeComposerInputViewModifier(options:), makeComposerButtonViewModifier(options:), and makeSuggestionsContainerModifier(options:) (use RegularInputViewModifier, RegularButtonViewModifier, and SuggestionsRegularContainerModifier to match the default appearance).
  • If you customized channel-list search in v4, move that work out of makeChannelListTopView(...) and into Styles.makeSearchableModifier(options:). Treat makeChannelListTopView(options:) as a separate top content area in v5.
  • Move supportedMoreChannelActions to ChannelListConfig.supportedMoreChannelActions.
  • Move supportedMessageActions to MessageListConfig.supportedMessageActions.
  • Move navigationBarDisplayMode to ChannelListConfig.navigationBarDisplayMode and/or MessageListConfig.navigationBarDisplayMode; do not rely on the compatibility helper on DefaultViewFactory.
  • Update all ViewFactory overrides that take individual parameters to use the new single options object signature.
  • Review every custom ViewFactory override manually even if your project compiles; stale v4 methods can still compile while no longer overriding anything.
  • Pay special attention to old makeLeadingSwipeActionsView(...), custom attachment picker and preview overrides, factory-level makeMessageViewModifier(for:), and old supportedMoreChannelActions(...) / supportedMessageActions(...) methods.
  • Replace removed ViewFactory methods with their v5 equivalents (see the Channel And Message List table above).
  • Replace imageLoader and videoLoader on Utils with a single mediaLoader parameter.
  • Replace ImageLoading/NukeImageLoader conformances with MediaLoader/StreamMediaLoader.
  • Replace VideoLoading/VideoPreviewLoader with MediaLoader's loadVideoPreview method.
  • Replace CDNClient / AttachmentUploader with CDNStorage on ChatClientConfig.cdnStorage.
  • Replace ImageCDN / StreamImageCDN / FileCDN with CDNRequester / StreamCDNRequester configured through StreamMediaLoader(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.