diff --git a/CHANGELOG.md b/CHANGELOG.md index ef689ba6..f063ea60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### ✅ Added - Link detection in the text views +- Indicator when a message was edited # [4.49.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.49.0) _February 28, 2024_ diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift index fcaa95c9..167773c7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift @@ -350,8 +350,11 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { } let delay = previousMessage.createdAt.timeIntervalSince(date) + let showMessageEditedLabel = utils.messageListConfig.isMessageEditedLabelEnabled + && message.textUpdatedAt != nil - if delay > utils.messageListConfig.maxTimeIntervalBetweenMessagesInGroup { + if delay > utils.messageListConfig.maxTimeIntervalBetweenMessagesInGroup + || showMessageEditedLabel { temp[message.id]?.append(firstMessageKey) var prevInfo = temp[previousMessage.id] ?? [] prevInfo.append(lastMessageKey) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageIdBuilder.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageIdBuilder.swift index 9020b0ac..86b53751 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageIdBuilder.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageIdBuilder.swift @@ -20,6 +20,9 @@ public class DefaultMessageIdBuilder: MessageIdBuilder { if message.localState != nil { statesId = message.uploadingStatesId } + if message.textUpdatedAt != nil { + statesId = "edited" + } return message.baseId + statesId + message.reactionScoresId + message.repliesCountId + "\(message.updatedAt)" + message.pinStateId } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift index e872dc9d..2439c86a 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift @@ -28,7 +28,8 @@ public struct MessageListConfig { handleTabBarVisibility: Bool = true, messageListAlignment: MessageListAlignment = .standard, uniqueReactionsEnabled: Bool = false, - localLinkDetectionEnabled: Bool = true + localLinkDetectionEnabled: Bool = true, + isMessageEditedLabelEnabled: Bool = true ) { self.messageListType = messageListType self.typingIndicatorPlacement = typingIndicatorPlacement @@ -50,6 +51,7 @@ public struct MessageListConfig { self.messageListAlignment = messageListAlignment self.uniqueReactionsEnabled = uniqueReactionsEnabled self.localLinkDetectionEnabled = localLinkDetectionEnabled + self.isMessageEditedLabelEnabled = isMessageEditedLabelEnabled } public let messageListType: MessageListType @@ -72,6 +74,7 @@ public struct MessageListConfig { public let messageListAlignment: MessageListAlignment public let uniqueReactionsEnabled: Bool public let localLinkDetectionEnabled: Bool + public let isMessageEditedLabelEnabled: Bool } /// Contains information about the message paddings. diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift index 85e3b637..6c409894 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift @@ -64,8 +64,19 @@ struct MessageDateView: View { var message: ChatMessage + var text: String { + var text = dateFormatter.string(from: message.createdAt) + let showMessageEditedLabel = utils.messageListConfig.isMessageEditedLabelEnabled + && message.textUpdatedAt != nil + && !message.isDeleted + if showMessageEditedLabel { + text = text + " • " + L10n.Message.Cell.edited + } + return text + } + var body: some View { - Text(dateFormatter.string(from: message.createdAt)) + Text(text) .font(fonts.footnote) .foregroundColor(Color(colors.textLowEmphasis)) .animation(nil) diff --git a/Sources/StreamChatSwiftUI/Generated/L10n.swift b/Sources/StreamChatSwiftUI/Generated/L10n.swift index 4a046e63..5bffca0a 100644 --- a/Sources/StreamChatSwiftUI/Generated/L10n.swift +++ b/Sources/StreamChatSwiftUI/Generated/L10n.swift @@ -315,6 +315,8 @@ internal enum L10n { internal static var title: String { L10n.tr("Localizable", "message.bounce.title") } } internal enum Cell { + /// Edited + internal static var edited: String { L10n.tr("Localizable", "message.cell.edited") } /// Pinned by internal static var pinnedBy: String { L10n.tr("Localizable", "message.cell.pinnedBy") } /// unknown diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings index 35c8d987..2ccc032a 100644 --- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings +++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings @@ -47,6 +47,7 @@ "message.gallery.photos" = "Photos"; "message.cell.pinnedBy" = "Pinned by"; "message.cell.unknownPin" = "unknown"; +"message.cell.edited" = "Edited"; "message.reactions.currentUser" = "You"; "alert.actions.cancel" = "Cancel"; diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift index e751ba86..b4cee913 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift @@ -33,6 +33,25 @@ class MessageContainerView_Tests: StreamChatTestCase { // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + + func test_messageContainerEdited_snapshot() { + // Given + streamChat = StreamChat(chatClient: chatClient) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Message sent by current user", + author: .mock(id: Self.currentUserId, name: "Martin"), + isSentByCurrentUser: true, + textUpdatedAt: Date() + ) + + // When + let view = testMessageViewContainer(message: message) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } func test_messageContainerViewSentOtherUser_snapshot() { // Given diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_messageContainerEdited_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_messageContainerEdited_snapshot.1.png new file mode 100644 index 00000000..d9277a15 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_messageContainerEdited_snapshot.1.png differ diff --git a/StreamChatSwiftUITestsAppTests/Tests/Performance/MessageListScrollTime.swift b/StreamChatSwiftUITestsAppTests/Tests/Performance/MessageListScrollTime.swift index 1a83213b..1d1284de 100644 --- a/StreamChatSwiftUITestsAppTests/Tests/Performance/MessageListScrollTime.swift +++ b/StreamChatSwiftUITestsAppTests/Tests/Performance/MessageListScrollTime.swift @@ -6,11 +6,18 @@ import XCTest @available(iOS 15.0, *) class MessageListScrollTime: StreamTestCase { + + // FIXME + override func setUpWithError() throws { + mockServerEnabled = false + try super.setUpWithError() + } func testMessageListScrollTime() { WHEN("user opens the message list") { - backendRobot.generateChannels(count: 1, messagesCount: 100, withAttachments: true) - participantRobot.addReaction(type: .like) + // FIXME + // backendRobot.generateChannels(count: 1, messagesCount: 100, withAttachments: true) + // participantRobot.addReaction(type: .like) userRobot.login().openChannel() } THEN("user scrolls the message list") {