From 569147d1ba6d2518fc2ccbf362978a3c7d8a843b Mon Sep 17 00:00:00 2001 From: Wilhelm Oks Date: Mon, 22 Sep 2025 16:15:05 +0200 Subject: [PATCH 1/4] feat: 5min time window for chat bubble grouping --- .../Content/ConversationTableViewDataSource.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift index 2f679fe0d62..384c7c016ec 100644 --- a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift +++ b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift @@ -771,7 +771,11 @@ extension ConversationTableViewDataSource { let previousMessage = messageBeforeMessage(at: index, messages: messages) if let currentMessage = message.serverTimestamp, let prevMessage = previousMessage?.serverTimestamp { - isTimestampInSameMinuteAsPreviousMessage = currentMessage.isInSameMinute(asDate: prevMessage) + if isChatBubbleSimpleEnabled { + isTimestampInSameMinuteAsPreviousMessage = currentMessage.isWithin(minutes: 5, fromDate: prevMessage) + } else { + isTimestampInSameMinuteAsPreviousMessage = currentMessage.isInSameMinute(asDate: prevMessage) + } } else { isTimestampInSameMinuteAsPreviousMessage = false } @@ -986,6 +990,10 @@ extension Date { return components == otherComponents } + func isWithin(minutes: Double, fromDate date: Date) -> Bool { + date.addingTimeInterval(minutes * 60) > self + } + } extension ZMConversationMessage { From 5bcd2a92c83864d07bbda81934e1e924d354a272 Mon Sep 17 00:00:00 2001 From: Wilhelm Oks Date: Tue, 23 Sep 2025 10:50:31 +0200 Subject: [PATCH 2/4] refactor/rename --- .../ConversationMessageSectionController.swift | 6 +++--- .../Content/ConversationTableViewDataSource.swift | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift index 969a8045805..b75fb3f01d7 100644 --- a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift +++ b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift @@ -22,7 +22,7 @@ import WireSyncEngine struct ConversationMessageContext: Equatable { var isSameSenderAsPrevious: Bool = false - var isTimestampInSameMinuteAsPreviousMessage: Bool = false + var isGroupedWithPreviousMessage: Bool = false var isFirstMessageOfTheDay: Bool = false var isFirstUnreadMessage: Bool = false var isLastMessage: Bool = false @@ -561,8 +561,8 @@ final class ConversationMessageSectionController: NSObject, ZMMessageObserver { return true } - // This message is from the same sender but in a different minute. - if !context.isTimestampInSameMinuteAsPreviousMessage { + // This message is from the same sender and is visually grouped with the previous message. + if !context.isGroupedWithPreviousMessage { return true } diff --git a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift index 384c7c016ec..cc423279892 100644 --- a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift +++ b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationTableViewDataSource.swift @@ -766,24 +766,24 @@ extension ConversationTableViewDataSource { messages: [ZMMessage] ) -> ConversationMessageContext { - let isTimestampInSameMinuteAsPreviousMessage: Bool + let isGroupedWithPreviousMessage: Bool let previousMessage = messageBeforeMessage(at: index, messages: messages) if let currentMessage = message.serverTimestamp, let prevMessage = previousMessage?.serverTimestamp { if isChatBubbleSimpleEnabled { - isTimestampInSameMinuteAsPreviousMessage = currentMessage.isWithin(minutes: 5, fromDate: prevMessage) + isGroupedWithPreviousMessage = currentMessage.isWithin(minutes: 5, fromDate: prevMessage) } else { - isTimestampInSameMinuteAsPreviousMessage = currentMessage.isInSameMinute(asDate: prevMessage) + isGroupedWithPreviousMessage = currentMessage.isInSameMinute(asDate: prevMessage) } } else { - isTimestampInSameMinuteAsPreviousMessage = false + isGroupedWithPreviousMessage = false } let isLastMessage = (index == 0) && !hasNewerMessagesToLoad return ConversationMessageContext( isSameSenderAsPrevious: isPreviousSenderSame(forMessage: message, at: index, messages: messages), - isTimestampInSameMinuteAsPreviousMessage: isTimestampInSameMinuteAsPreviousMessage, + isGroupedWithPreviousMessage: isGroupedWithPreviousMessage, isFirstMessageOfTheDay: isFirstMessageOfTheDay(for: message, at: index, messages: messages), isFirstUnreadMessage: message.nonce == firstUnreadMessageNonce, isLastMessage: isLastMessage, From 888ca2855e73c42177e450fdbb47f845115a4f0a Mon Sep 17 00:00:00 2001 From: Wilhelm Oks Date: Tue, 23 Sep 2025 11:22:58 +0200 Subject: [PATCH 3/4] rename in tests --- .../ConversationMessageSectionControllerTests.swift | 8 ++++---- .../ConversationMessageSnapshotTestCase.swift | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSectionControllerTests.swift b/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSectionControllerTests.swift index b80a1579006..f4250ff1e5f 100644 --- a/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSectionControllerTests.swift +++ b/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSectionControllerTests.swift @@ -40,7 +40,7 @@ final class ConversationMessageSectionControllerTests: XCTestCase { userSession = UserSessionMock(mockUser: mockSelfUser) context = ConversationMessageContext( isSameSenderAsPrevious: false, - isTimestampInSameMinuteAsPreviousMessage: false, + isGroupedWithPreviousMessage: false, isFirstMessageOfTheDay: false, isFirstUnreadMessage: false, isLastMessage: false, @@ -121,7 +121,7 @@ final class ConversationMessageSectionControllerTests: XCTestCase { let message = MockMessageFactory.textMessage(withText: "Welcome to Dub Dub") let context = ConversationMessageContext( isSameSenderAsPrevious: true, - isTimestampInSameMinuteAsPreviousMessage: true + isGroupedWithPreviousMessage: true ) // WHEN @@ -161,7 +161,7 @@ final class ConversationMessageSectionControllerTests: XCTestCase { let message = MockMessageFactory.textMessage(withText: "Hello") let context = ConversationMessageContext( isSameSenderAsPrevious: true, - isTimestampInSameMinuteAsPreviousMessage: false + isGroupedWithPreviousMessage: false ) // WHEN let section = makeSUT(message: message, context: context) @@ -181,7 +181,7 @@ final class ConversationMessageSectionControllerTests: XCTestCase { let message = MockMessageFactory.textMessage(withText: "Hello") let context = ConversationMessageContext( isSameSenderAsPrevious: true, - isTimestampInSameMinuteAsPreviousMessage: false + isGroupedWithPreviousMessage: false ) // WHEN let section = makeSUT(message: message, context: context) diff --git a/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSnapshotTestCase.swift b/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSnapshotTestCase.swift index f7508aa9388..c27b617e656 100644 --- a/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSnapshotTestCase.swift +++ b/wire-ios/Wire-iOS Tests/ConversationMessageCell/ConversationMessageSnapshotTestCase.swift @@ -24,7 +24,7 @@ import XCTest private extension ConversationMessageContext { static let defaultContext = ConversationMessageContext( isSameSenderAsPrevious: false, - isTimestampInSameMinuteAsPreviousMessage: false, + isGroupedWithPreviousMessage: false, isFirstMessageOfTheDay: false, isFirstUnreadMessage: false, isLastMessage: false, From abf69705b0042876495a566a0c7a0bdb0144ea8e Mon Sep 17 00:00:00 2001 From: Wilhelm Oks Date: Tue, 23 Sep 2025 16:52:14 +0200 Subject: [PATCH 4/4] corrected lying comment --- .../ConversationMessageSectionController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift index b75fb3f01d7..4f8431a6950 100644 --- a/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift +++ b/wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift @@ -561,7 +561,7 @@ final class ConversationMessageSectionController: NSObject, ZMMessageObserver { return true } - // This message is from the same sender and is visually grouped with the previous message. + // This message is from the same sender but is not visually grouped with the previous message. if !context.isGroupedWithPreviousMessage { return true }