diff --git a/Flipcash/Core/Screens/Conversation/ChatItem+Conversation.swift b/Flipcash/Core/Screens/Conversation/ChatItem+Conversation.swift index 7c28c65c9..8c35a9a74 100644 --- a/Flipcash/Core/Screens/Conversation/ChatItem+Conversation.swift +++ b/Flipcash/Core/Screens/Conversation/ChatItem+Conversation.swift @@ -81,9 +81,9 @@ extension ChatItem { _ messages: [ConversationMessage], selfUserID: UserID, // How long a pause has to be before it heads the next message with its own separator and - // ends the run above it. Android's `SeparatorConfig.Continuous` gap, so a pause of minutes - // keeps one exchange together on both platforms instead of cutting it into single bubbles. - gap: TimeInterval = 3 * 60 * 60, + // ends the run above it. Android's `SeparatorConfig.Continuous` gap (one hour), so a pause of + // minutes keeps one exchange together on both platforms instead of cutting it into single bubbles. + gap: TimeInterval = 60 * 60, counterpartRead: (pointer: MessageID, date: Date?)? = nil, suppressReceiptFor: String? = nil, cashBranding: (ExchangedFiat) -> (token: String, iconURL: URL?) = { _ in ("Cash", nil) }, diff --git a/FlipcashCore/Sources/FlipcashCore/Models/Chat/ChatPreviewMapping.swift b/FlipcashCore/Sources/FlipcashCore/Models/Chat/ChatPreviewMapping.swift index c73ab3c89..82a1d6113 100644 --- a/FlipcashCore/Sources/FlipcashCore/Models/Chat/ChatPreviewMapping.swift +++ b/FlipcashCore/Sources/FlipcashCore/Models/Chat/ChatPreviewMapping.swift @@ -156,5 +156,5 @@ extension ChatItem { /// Matches the in-app chat: a separator opens the transcript and breaks any run whose gap from /// the previous message exceeds this. - private static let separatorGap: TimeInterval = 15 * 60 + private static let separatorGap: TimeInterval = 60 * 60 } diff --git a/FlipcashTests/Chat/ChatMessageMappingTests.swift b/FlipcashTests/Chat/ChatMessageMappingTests.swift index d63b1f716..62dac3f0a 100644 --- a/FlipcashTests/Chat/ChatMessageMappingTests.swift +++ b/FlipcashTests/Chat/ChatMessageMappingTests.swift @@ -322,6 +322,20 @@ struct ChatMessageMappingTests { #expect(!broken[1].isContinuationFromPrevious) } + @Test("A 90-minute pause opens a date separator; a 30-minute pause does not") + func hourGapOpensSeparator() { + func separators(afterPause pause: TimeInterval) -> Int { + let rows = [ + ConversationMessage(id: MessageID(value: 1), senderID: me, content: .text("a"), date: base, unreadSeq: 1), + ConversationMessage(id: MessageID(value: 2), senderID: me, content: .text("b"), date: base.addingTimeInterval(pause), unreadSeq: 2), + ] + return separatorCount(ChatItem.from(rows, selfUserID: me)) + } + + #expect(separators(afterPause: 30 * 60) == 1) // only the one opening the transcript + #expect(separators(afterPause: 90 * 60) == 2) // the pause heads the second message + } + @Test("A run does not carry across a change of day, however short the pause") func dayChangeBreaksRun() { // Straddling local midnight, so the two rows are minutes apart but on different dates. diff --git a/FlipcashTests/ChatPreviewMappingTests.swift b/FlipcashTests/ChatPreviewMappingTests.swift index 9e7241c13..d39be8be3 100644 --- a/FlipcashTests/ChatPreviewMappingTests.swift +++ b/FlipcashTests/ChatPreviewMappingTests.swift @@ -244,7 +244,7 @@ struct ChatPreviewMappingTests { @Test("Messages within the gap share a single opening separator") func messagesWithinGapShareSeparator() { - // ids 1 and 2 → dates 1s apart, well under the 15-minute gap. + // ids 1 and 2 → dates 1s apart, well under the one-hour gap. let messages = [ textMessage(id: 1, senderID: meID, text: "a"), textMessage(id: 2, senderID: meID, text: "b"), @@ -253,17 +253,28 @@ struct ChatPreviewMappingTests { #expect(separators(items).count == 1) } - @Test("A gap longer than 15 minutes inserts another separator") + @Test("A gap longer than one hour inserts another separator") func gapInsertsSeparator() { - // ids 1 and 1000 → dates 999s (~16.6 min) apart, beyond the 15-minute gap. + // ids 1 and 5401 → dates 5400s (90 min) apart, beyond the one-hour gap. let messages = [ textMessage(id: 1, senderID: meID, text: "a"), - textMessage(id: 1000, senderID: meID, text: "b"), + textMessage(id: 5401, senderID: meID, text: "b"), ] let items = ChatItem.preview(from: messages, selfUserID: meID) #expect(separators(items).count == 2) } + @Test("A pause of 30 minutes does not insert another separator") + func shortPauseKeepsOneSeparator() { + // ids 1 and 1801 → dates 1800s (30 min) apart, under the one-hour gap. + let messages = [ + textMessage(id: 1, senderID: meID, text: "a"), + textMessage(id: 1801, senderID: meID, text: "b"), + ] + let items = ChatItem.preview(from: messages, selfUserID: meID) + #expect(separators(items).count == 1) + } + // MARK: - Cache serialization @Test("Preview round-trips through Codable unchanged — the notification cache's mechanism")