Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -731,8 +731,8 @@ style:
active: false
ReturnCount:
active: true
max: 2
excludedFunctions: 'equals'
max: 10
excludedFunctions: ['equals']
excludeLabeled: false
excludeReturnFromLambda: true
excludeGuardClauses: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,22 @@ internal class UnreadLabelCalculator {
val lastReadMessage = messages
.firstOrNull { it.id == channelUserRead.lastReadMessageId }

// Step 2.1: If lastReadMessage is not found in the messages list, skip complex ownership
// checks and create a standard unread label with the provided lastReadMessageId.
// Step 2.1: If lastReadMessage is not found in the messages list, we still need to check
// if all unread messages are from the current user (similar to when lastReadMessage exists).
// This handles cases where the message list was loaded around a specific message that
// doesn't include the actual last read message.
// doesn't include the actual last read message, or after logout/login when read state
// might be out of sync.
if (lastReadMessage == null) {
// Check if all unread messages are from the current user
val allUnreadMessagesAreFromCurrentUser = unreadMessages.isNotEmpty() &&
unreadMessages.all { it.user.id == currentUserId }

// If all unread messages are from the current user, don't show the label
// (user has already seen their own messages)
if (allUnreadMessagesAreFromCurrentUser) {
return null
}

return calculateStandardUnreadLabel(
channelUserRead = channelUserRead,
unreadMessages = unreadMessages,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,47 @@ internal class UnreadLabelCalculatorTest {
)
}

/**
* Test Case 15: Logout/Login Scenario - All Unread Messages Are From Current User
* When lastReadMessageId is not in the messages list (after logout/login, read state might be out of sync)
* AND all unread messages are from the current user, should return null.
* This simulates the scenario where:
* 1. User sends message offline
* 2. User logs out (clears history)
* 3. User logs back in
* 4. User reopens chat - lastReadMessageId from server doesn't exist in loaded messages
* 5. All messages are from the current user (their own synced message)
*/
@Test
fun `should return null when last read message not found and all unread messages are from current user`() {
// Given: lastReadMessageId doesn't exist in the messages list (read state out of sync after logout/login)
// and all messages are from the current user (their own message that was sent offline and synced)
val ownMessage1 = createMessage(id = "msg-1", user = currentUser, createdAt = Date(1000))
val ownMessage2 = createMessage(id = "msg-2", user = currentUser, createdAt = Date(2000))

val messages = listOf(
ownMessage1,
ownMessage2,
)

val channelUserRead = createChannelUserRead(
lastReadMessageId = "msg-nonexistent", // Doesn't exist in messages (read state out of sync)
unreadMessages = 2, // Server might have incorrect count
lastRead = Date(500), // Before all messages
)

// When: Calculate unread label
val result = calculator.calculateUnreadLabel(
channelUserRead = channelUserRead,
messages = messages,
currentUserId = currentUser.id,
shouldShowButton = true,
)

// Then: Should return null - user has already seen their own messages
result shouldBe null
}

// Helper functions

private fun createMessage(
Expand Down
Loading