From bfbe384280a18eadf33830cff3e14ea887dac57a Mon Sep 17 00:00:00 2001 From: Alexey Alter-Pesotskiy Date: Fri, 8 Mar 2024 14:08:06 +0000 Subject: [PATCH 1/2] Get branch --- fastlane/Fastfile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 0795abdb..3ef4eb9e 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -573,7 +573,20 @@ private_lane :create_pr do |options| end private_lane :current_branch do - ENV['BRANCH_NAME'].to_s.empty? ? git_branch : ENV.fetch('BRANCH_NAME') + github_pr_branch_name = ENV['BRANCH_NAME'].to_s + github_ref_branch_name = ENV['GITHUB_REF'].to_s.sub('refs/heads/', '') + fastlane_branch_name = git_branch + + branch_name = if !github_pr_branch_name.empty? + github_pr_branch_name + elsif !fastlane_branch_name.empty? + fastlane_branch_name + elsif !github_ref_branch_name.empty? + github_ref_branch_name + end + + UI.important("Current branch: #{branch_name} 🕊️") + branch_name end private_lane :git_status do |options| From eec945e26c98b599aa8de494d2e293e315a60a5b Mon Sep 17 00:00:00 2001 From: Alexey Alter-Pesotskiy Date: Fri, 8 Mar 2024 14:10:22 +0000 Subject: [PATCH 2/2] [REMOVE THIS COMMIT] Implement edited feature --- CHANGELOG.md | 1 + .../ChatChannel/ChatChannelViewModel.swift | 5 ++++- .../MessageList/MessageIdBuilder.swift | 3 +++ .../MessageList/MessageListConfig.swift | 5 ++++- .../MessageList/MessageListHelperViews.swift | 13 +++++++++++- .../StreamChatSwiftUI/Generated/L10n.swift | 2 ++ .../Resources/en.lproj/Localizable.strings | 1 + .../MessageContainerView_Tests.swift | 19 ++++++++++++++++++ ...test_messageContainerEdited_snapshot.1.png | Bin 0 -> 31730 bytes .../Performance/MessageListScrollTime.swift | 11 ++++++++-- 10 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_messageContainerEdited_snapshot.1.png 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 0000000000000000000000000000000000000000..d9277a1561371c5fa514cda4df273e3ab9122e75 GIT binary patch literal 31730 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