Refactor the RoomMessageEventStringBuilder to take a Style instead of a Destination

This make its usage clearer and makes different styles reusable
This commit is contained in:
Stefan Ceriu
2026-03-23 17:39:38 +02:00
committed by Stefan Ceriu
parent 644a79aa5f
commit 0104ad06aa
7 changed files with 38 additions and 28 deletions

View File

@@ -1332,7 +1332,8 @@ private struct ClientProxyServices {
let roomListService = syncService.roomListService()
let roomMessageEventStringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(cacheKey: "roomList",
mentionBuilder: PlainMentionBuilder()), destination: .roomList)
mentionBuilder: PlainMentionBuilder()),
style: .senderPrefixed)
let eventStringBuilder = try RoomEventStringBuilder(stateEventStringBuilder: RoomStateEventStringBuilder(userID: client.userId(), shouldDisambiguateDisplayNames: false),
messageEventStringBuilder: roomMessageEventStringBuilder,
shouldDisambiguateDisplayNames: false,

View File

@@ -34,14 +34,14 @@ struct RoomEventStringBuilder {
case .message(let messageContent):
return messageEventStringBuilder.buildAttributedString(for: messageContent.msgType, senderDisplayName: displayName, isOutgoing: isOutgoing)
case .sticker:
if messageEventStringBuilder.destination == .pinnedEvent {
if messageEventStringBuilder.style == .typeBolded {
var string = AttributedString(L10n.commonSticker)
string.bold()
return string
}
return prefix(L10n.commonSticker, with: displayName, isOutgoing: isOutgoing)
case .poll(let question, _, _, _, _, _, _):
if messageEventStringBuilder.destination == .pinnedEvent {
if messageEventStringBuilder.style == .typeBolded {
let questionPlaceholder = "{question}"
var finalString = AttributedString(L10n.commonPollSummary(questionPlaceholder))
finalString.bold()
@@ -106,10 +106,19 @@ struct RoomEventStringBuilder {
static func pinnedEventStringBuilder(userID: String) -> Self {
RoomEventStringBuilder(stateEventStringBuilder: .init(userID: userID,
shouldDisambiguateDisplayNames: false),
shouldDisambiguateDisplayNames: true),
messageEventStringBuilder: .init(attributedStringBuilder: AttributedStringBuilder(cacheKey: "pinnedEvents", mentionBuilder: PlainMentionBuilder()),
destination: .pinnedEvent),
shouldDisambiguateDisplayNames: false,
style: .typeBolded),
shouldDisambiguateDisplayNames: true,
shouldPrefixSenderName: false)
}
static func threadListEventStringBuilder(userID: String) -> Self {
RoomEventStringBuilder(stateEventStringBuilder: .init(userID: userID,
shouldDisambiguateDisplayNames: true),
messageEventStringBuilder: .init(attributedStringBuilder: AttributedStringBuilder(cacheKey: "threadList", mentionBuilder: PlainMentionBuilder()),
style: .plain),
shouldDisambiguateDisplayNames: true,
shouldPrefixSenderName: false)
}
}

View File

@@ -10,20 +10,20 @@ import Foundation
import MatrixRustSDK
struct RoomMessageEventStringBuilder {
enum Destination {
enum Style {
/// Plain: no prefix, no special text treatment
/// Shown in push notifications and thread lists
case plain
/// Strings show on the room list as the last message
/// The sender will be prefixed in bold
case roomList
case senderPrefixed
/// Events pinned to the banner on the top of the timeline
/// The message type will be prefixed in bold
case pinnedEvent
/// Shown in push notifications
/// No prefix
case notification
case typeBolded
}
let attributedStringBuilder: AttributedStringBuilderProtocol
let destination: Destination
let style: Style
func buildAttributedString(for messageType: MessageType, senderDisplayName: String, isOutgoing: Bool) -> AttributedString {
let message: AttributedString
@@ -37,19 +37,19 @@ struct RoomMessageEventStringBuilder {
case .audio(content: let content):
let isVoiceMessage = content.voice != nil
var content = AttributedString(isVoiceMessage ? L10n.commonVoiceMessage : L10n.commonAudio)
if destination == .pinnedEvent {
if style == .typeBolded {
content.bold()
}
message = content
case .image(let content):
message = buildMessage(for: destination, caption: content.caption, type: L10n.commonImage)
message = buildMessage(for: style, caption: content.caption, type: L10n.commonImage)
case .video(let content):
message = buildMessage(for: destination, caption: content.caption, type: L10n.commonVideo)
message = buildMessage(for: style, caption: content.caption, type: L10n.commonVideo)
case .file(let content):
message = buildMessage(for: destination, caption: content.caption, type: L10n.commonFile)
message = buildMessage(for: style, caption: content.caption, type: L10n.commonFile)
case .location:
var content = AttributedString(L10n.commonSharedLocation)
if destination == .pinnedEvent {
if style == .typeBolded {
content.bold()
}
message = content
@@ -71,7 +71,7 @@ struct RoomMessageEventStringBuilder {
message = AttributedString(body)
}
if destination == .roomList {
if style == .senderPrefixed {
return prefix(message, with: isOutgoing ? L10n.commonYou : senderDisplayName)
} else {
return message
@@ -80,23 +80,23 @@ struct RoomMessageEventStringBuilder {
func buildAttributedStringForLiveLocation(senderDisplayName: String, isOutgoing: Bool) -> AttributedString {
var message = AttributedString(L10n.commonSharedLiveLocation)
if destination == .pinnedEvent {
if style == .typeBolded {
message.bold()
}
if destination == .roomList {
if style == .senderPrefixed {
return prefix(message, with: isOutgoing ? L10n.commonYou : senderDisplayName)
} else {
return message
}
}
private func buildMessage(for destination: Destination, caption: String?, type: String) -> AttributedString {
private func buildMessage(for style: Style, caption: String?, type: String) -> AttributedString {
guard let caption else {
return AttributedString(type)
}
if destination == .pinnedEvent {
if style == .typeBolded {
return prefix(AttributedString(caption), with: type)
} else {
return AttributedString("\(type) - \(caption)")

View File

@@ -34,7 +34,7 @@ class NotificationHandler {
self.tag = tag
let eventStringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(mentionBuilder: PlainMentionBuilder()),
destination: .notification)
style: .plain)
notificationContentBuilder = NotificationContentBuilder(messageEventStringBuilder: eventStringBuilder,
notificationSoundName: settings.notificationSoundName.publisher.value,

View File

@@ -19,7 +19,7 @@ struct NotificationContentBuilderTests {
init() {
notificationContent = .init()
let stringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(mentionBuilder: PlainMentionBuilder()),
destination: .notification)
style: .plain)
mediaProvider = MediaProviderMock(configuration: .init())
notificationContentBuilder = NotificationContentBuilder(messageEventStringBuilder: stringBuilder,
notificationSoundName: UNNotificationSoundName("message.caf"),

View File

@@ -21,7 +21,7 @@ struct RoomEventStringBuilderTests {
stringBuilder = RoomEventStringBuilder(stateEventStringBuilder: stateEventStringBuilder,
messageEventStringBuilder: RoomMessageEventStringBuilder(attributedStringBuilder: attributedStringBuilder,
destination: .roomList),
style: .senderPrefixed),
shouldDisambiguateDisplayNames: true,
shouldPrefixSenderName: true)
}

View File

@@ -102,7 +102,7 @@ final class RoomSummaryProviderTests {
let attributedStringBuilder = AttributedStringBuilder(mentionBuilder: MentionBuilder())
let eventStringBuilder = RoomEventStringBuilder(stateEventStringBuilder: stateEventStringBuilder,
messageEventStringBuilder: RoomMessageEventStringBuilder(attributedStringBuilder: attributedStringBuilder,
destination: .roomList),
style: .senderPrefixed),
shouldDisambiguateDisplayNames: true,
shouldPrefixSenderName: true)