Skip to content

Allow customisation of message previews in lists #839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `Utils.originalTranslationsStore` to keep track of messages that should show the original text [#815](https://github.com/GetStream/stream-chat-swiftui/pull/815)
- Add `ViewFactory.makeGalleryHeaderView` for customising header view in `GalleryView` [#837](https://github.com/GetStream/stream-chat-swiftui/pull/837)
- Add `ViewFactory.makeVideoPlayerHeaderView` for customising header view in `VideoPlayerView` [#837](https://github.com/GetStream/stream-chat-swiftui/pull/837)
- Add `Utils.messagePreviewFormatter` for customising message previews in lists [#839](https://github.com/GetStream/stream-chat-swiftui/pull/839)
### 🐞 Fixed
- Fix swipe to reply enabled when quoting a message is disabled [#824](https://github.com/GetStream/stream-chat-swiftui/pull/824)
- Fix mark unread action not removed when read events are disabled [#823](https://github.com/GetStream/stream-chat-swiftui/pull/823)
Expand Down
5 changes: 3 additions & 2 deletions Sources/StreamChatSwiftUI/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import StreamChat
/// Class providing implementations of several utilities used in the SDK.
/// The default implementations can be replaced in the init method, or directly via the variables.
public class Utils {
// TODO: Make it public in future versions.
internal var messagePreviewFormatter = MessagePreviewFormatter()
var markdownFormatter = MarkdownFormatter()

public var dateFormatter: DateFormatter
Expand All @@ -29,6 +27,7 @@ public class Utils {
public var channelAvatarsMerger: ChannelAvatarsMerging
public var messageTypeResolver: MessageTypeResolving
public var messageActionsResolver: MessageActionsResolving
public var messagePreviewFormatter: MessagePreviewFormatting
public var commandsConfig: CommandsConfig
public var channelListConfig: ChannelListConfig
public var messageListConfig: MessageListConfig
Expand Down Expand Up @@ -87,6 +86,7 @@ public class Utils {
channelAvatarsMerger: ChannelAvatarsMerging = ChannelAvatarsMerger(),
messageTypeResolver: MessageTypeResolving = MessageTypeResolver(),
messageActionResolver: MessageActionsResolving = MessageActionsResolver(),
messagePreviewFormatter: MessagePreviewFormatting = MessagePreviewFormatter(),
commandsConfig: CommandsConfig = DefaultCommandsConfig(),
channelListConfig: ChannelListConfig = ChannelListConfig(),
messageListConfig: MessageListConfig = MessageListConfig(),
Expand Down Expand Up @@ -115,6 +115,7 @@ public class Utils {
self.channelAvatarsMerger = channelAvatarsMerger
self.messageTypeResolver = messageTypeResolver
messageActionsResolver = messageActionResolver
self.messagePreviewFormatter = messagePreviewFormatter
self.commandsConfig = commandsConfig
self.channelListConfig = channelListConfig
self.messageListConfig = messageListConfig
Expand Down
20 changes: 15 additions & 5 deletions Sources/StreamChatSwiftUI/Utils/MessagePreviewFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,33 @@
import StreamChat
import SwiftUI

/// Provides message preview representation for lists.
public protocol MessagePreviewFormatting {
/// Formats the message including the author's name.
func format(_ previewMessage: ChatMessage, in channel: ChatChannel) -> String
/// Formats only the content of the message without the author's name.
func formatContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String
/// Formats only the attachment content of the message in case it contains attachments.
func formatAttachmentContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String?
}
Copy link
Member

Choose a reason for hiding this comment

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

I think it is probably better to just use the MessagePreviewFormatter function directly here 🤔 There is a chance we add new function here, for example, for Draft Message etc... and if we introduce a new function, it will be a breaking change.

Copy link
Member

Choose a reason for hiding this comment

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

The other formatters, we use a protocol, but usually it is just one function, and for one use case. This one is a bit different, since we use it in multiple places, and there is a chance to extend it further

Copy link
Contributor

@martinmitrevski martinmitrevski May 27, 2025

Choose a reason for hiding this comment

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

It's also fine like this, you can add a protocol extension with a default implementation to avoid breaking changes.

Copy link
Contributor Author

@laevandus laevandus May 28, 2025

Choose a reason for hiding this comment

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

I did consider skipping the protocol part completely, but then only added it because many existing types in Utils had it. I guess it makes sense to skip it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, let's go for no protocol here

Copy link
Member

@nuno-vieira nuno-vieira May 28, 2025

Choose a reason for hiding this comment

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

Yeah the default extension is a good point, forgot about it. In that case I'm fine with both approaches 👍


/// A formatter that converts a message to a text preview representation.
/// By default it is used to show message previews in the Channel List and Thread List.
struct MessagePreviewFormatter {
open class MessagePreviewFormatter: MessagePreviewFormatting {
@Injected(\.chatClient) var chatClient

init() {}
public init() {}

/// Formats the message including the author's name.
func format(_ previewMessage: ChatMessage, in channel: ChatChannel) -> String {
open func format(_ previewMessage: ChatMessage, in channel: ChatChannel) -> String {
if let poll = previewMessage.poll {
return formatPoll(poll)
}
return "\(previewMessage.author.name ?? previewMessage.author.id): \(formatContent(for: previewMessage, in: channel))"
}

/// Formats only the content of the message without the author's name.
func formatContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String {
open func formatContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String {
if let attachmentPreviewText = formatAttachmentContent(for: previewMessage, in: channel) {
return attachmentPreviewText
}
Expand All @@ -32,7 +42,7 @@ struct MessagePreviewFormatter {
}

/// Formats only the attachment content of the message in case it contains attachments.
func formatAttachmentContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String? {
open func formatAttachmentContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String? {
if let poll = previewMessage.poll {
return "📊 \(poll.name)"
}
Expand Down
Loading