Skip to content

Commit d913aed

Browse files
authored
Prioritize createdLocallyAt over createdAt for sorting messages. (#5993)
* Prioritize createdLocallyAt over createdAt for sorting messages. * Fix existing and add new tests. * Update CHANGELOG.md. * Fix tests. * Fix tests. * Fix tests. * Add tests. * Add tests. * Add tests. * Simplify tests.
1 parent 94f4bba commit d913aed

File tree

33 files changed

+461
-89
lines changed

33 files changed

+461
-89
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
### 🐞 Fixed
3737

3838
### ⬆️ Improved
39+
- Prioritize `Message.createdLocallyAt` over `Message.createdAt` when sorting messages, to ensure the message order is consistent before the messages are synced with the server. [#5993](https://github.com/GetStream/stream-chat-android/pull/5993)
3940

4041
### ✅ Added
4142

stream-chat-android-ai-assistant/src/main/kotlin/io/getstream/chat/android/ai/assistant/AiMessageContentFactory.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.compose.ui.platform.LocalContext
2727
import androidx.compose.ui.platform.testTag
2828
import androidx.compose.ui.text.style.TextOverflow
2929
import androidx.compose.ui.unit.dp
30+
import io.getstream.chat.android.client.extensions.getCreatedAtOrNull
3031
import io.getstream.chat.android.client.utils.message.belongsToThread
3132
import io.getstream.chat.android.compose.R
3233
import io.getstream.chat.android.compose.state.DateFormatType
@@ -91,7 +92,7 @@ internal class AiMessageContentFactory : MessageContentFactory() {
9192
}
9293

9394
val updatedAt = message.updatedAt
94-
val createdAt = message.createdAt ?: message.createdLocallyAt
95+
val createdAt = message.getCreatedAtOrNull()
9596
val date = when {
9697
createdAt == null -> updatedAt
9798
updatedAt == null -> createdAt

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/extensions/MessageExtensions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public fun Message.getCreatedAtOrThrow(): Date {
7474
* @return when the message was created or null.
7575
*/
7676
public fun Message.getCreatedAtOrNull(): Date? {
77-
return createdAt ?: createdLocallyAt
77+
return createdLocallyAt ?: createdAt
7878
}
7979

8080
/**

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/extensions/internal/Channel.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.getstream.chat.android.client.extensions.internal
1818

19+
import io.getstream.chat.android.client.extensions.getCreatedAtOrDefault
20+
import io.getstream.chat.android.client.extensions.getCreatedAtOrNull
1921
import io.getstream.chat.android.client.extensions.syncUnreadCountWithReads
2022
import io.getstream.chat.android.client.query.pagination.AnyChannelPaginationRequest
2123
import io.getstream.chat.android.client.utils.message.isDeleted
@@ -53,7 +55,7 @@ public fun Channel.users(): List<User> {
5355
public val Channel.lastMessage: Message?
5456
get() = messages
5557
.filterNot { it.isDeleted() }
56-
.maxByOrNull { it.createdAt ?: it.createdLocallyAt ?: Date(0) }
58+
.maxByOrNull { it.getCreatedAtOrDefault(NEVER) }
5759

5860
/**
5961
* Updates the [Channel] with newest [Message].
@@ -68,7 +70,7 @@ public fun Channel.updateLastMessage(
6870
message: Message,
6971
currentUserId: String,
7072
): Channel {
71-
val createdAt = message.createdAt ?: message.createdLocallyAt
73+
val createdAt = message.getCreatedAtOrNull()
7274
checkNotNull(createdAt) { "created at cant be null, be sure to set message.createdAt" }
7375

7476
val newMessages = (
@@ -77,7 +79,7 @@ public fun Channel.updateLastMessage(
7779
)
7880
.values
7981
.filterNot { it.isDeleted() }
80-
.sortedBy { it.createdAt ?: it.createdLocallyAt }
82+
.sortedBy { it.getCreatedAtOrNull() }
8183

8284
val newReads = read.map { read ->
8385
read.takeUnless { it.user.id == currentUserId }

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/extensions/internal/Message.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.getstream.chat.android.client.extensions.internal
1818

19+
import io.getstream.chat.android.client.extensions.getCreatedAtOrDefault
1920
import io.getstream.chat.android.core.internal.InternalStreamChatApi
2021
import io.getstream.chat.android.models.Attachment
2122
import io.getstream.chat.android.models.Channel
@@ -92,31 +93,31 @@ public val NEVER: Date = Date(0)
9293
*/
9394
@InternalStreamChatApi
9495
public fun Message.wasCreatedAfterOrAt(date: Date?): Boolean {
95-
return (createdAt ?: createdLocallyAt ?: NEVER) >= date
96+
return getCreatedAtOrDefault(NEVER) >= date
9697
}
9798

9899
/**
99100
* Checks if the message was created after the given [date].
100101
*/
101102
@InternalStreamChatApi
102103
public fun Message.wasCreatedAfter(date: Date?): Boolean {
103-
return (createdAt ?: createdLocallyAt ?: NEVER) > date
104+
return getCreatedAtOrDefault(NEVER) > date
104105
}
105106

106107
/**
107108
* Checks if the message was created before the given [date].
108109
*/
109110
@InternalStreamChatApi
110111
public fun Message.wasCreatedBefore(date: Date?): Boolean {
111-
return (createdAt ?: createdLocallyAt ?: NEVER) < date
112+
return getCreatedAtOrDefault(NEVER) < date
112113
}
113114

114115
/**
115116
* Checks if the message was created before or at the given [date].
116117
*/
117118
@InternalStreamChatApi
118119
public fun Message.wasCreatedBeforeOrAt(date: Date?): Boolean {
119-
return (createdAt ?: createdLocallyAt ?: NEVER) <= date
120+
return getCreatedAtOrDefault(NEVER) <= date
120121
}
121122

122123
/**

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/extensions/internal/Thread.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.getstream.chat.android.client.extensions.internal
1818

19+
import io.getstream.chat.android.client.extensions.getCreatedAtOrNull
1920
import io.getstream.chat.android.core.internal.InternalStreamChatApi
2021
import io.getstream.chat.android.models.ChannelUserRead
2122
import io.getstream.chat.android.models.Message
@@ -64,11 +65,9 @@ public fun Thread.upsertReply(reply: Message): Thread {
6465
val newReplies = upsertMessageInList(reply, this.latestReplies)
6566
val isInsert = newReplies.size > this.latestReplies.size
6667
val sortedNewReplies = newReplies.sortedBy {
67-
it.createdAt ?: it.createdLocallyAt
68-
}
69-
val lastMessageAt = sortedNewReplies.lastOrNull()?.let { latestReply ->
70-
latestReply.createdAt ?: latestReply.createdLocallyAt
68+
it.getCreatedAtOrNull()
7169
}
70+
val lastMessageAt = sortedNewReplies.lastOrNull()?.getCreatedAtOrNull()
7271
// The new message could be from a new thread participant
7372
val threadParticipants = if (isInsert) {
7473
upsertThreadParticipantInList(

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/interceptor/message/internal/PrepareMessageLogicImpl.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package io.getstream.chat.android.client.interceptor.message.internal
1919
import io.getstream.chat.android.client.channel.state.ChannelStateLogicProvider
2020
import io.getstream.chat.android.client.extensions.EXTRA_UPLOAD_ID
2121
import io.getstream.chat.android.client.extensions.enrichWithCid
22+
import io.getstream.chat.android.client.extensions.getCreatedAtOrDefault
2223
import io.getstream.chat.android.client.extensions.internal.populateMentions
2324
import io.getstream.chat.android.client.extensions.uploadId
2425
import io.getstream.chat.android.client.interceptor.message.PrepareMessageLogic
@@ -66,7 +67,7 @@ internal class PrepareMessageLogicImpl(
6667
user = user,
6768
attachments = attachments,
6869
type = getMessageType(message),
69-
createdLocallyAt = message.createdAt ?: message.createdLocallyAt ?: Date(),
70+
createdLocallyAt = message.getCreatedAtOrDefault(Date()),
7071
syncStatus = when {
7172
attachments.any { it.uploadState is Attachment.UploadState.Idle } -> SyncStatus.AWAITING_ATTACHMENTS
7273
clientState.isNetworkAvailable -> SyncStatus.IN_PROGRESS

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/MessagingStyleNotificationFactory.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import androidx.core.app.Person
2929
import androidx.core.content.ContextCompat
3030
import io.getstream.chat.android.client.ChatClient
3131
import io.getstream.chat.android.client.R
32+
import io.getstream.chat.android.client.extensions.getCreatedAtOrDefault
3233
import io.getstream.chat.android.models.Channel
3334
import io.getstream.chat.android.models.Message
3435
import io.getstream.chat.android.models.User
@@ -176,7 +177,7 @@ internal class MessagingStyleNotificationFactory(
176177
private suspend fun Message.person(context: Context): Person = user.toPerson(context)
177178

178179
private val Message.timestamp: Long
179-
get() = (createdAt ?: createdLocallyAt ?: Date()).time
180+
get() = getCreatedAtOrDefault(Date()).time
180181

181182
private suspend fun User.toPerson(context: Context): Person =
182183
Person.Builder()

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/utils/message/MessageUtils.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package io.getstream.chat.android.client.utils.message
2121

22+
import io.getstream.chat.android.client.extensions.getCreatedAtOrNull
2223
import io.getstream.chat.android.core.internal.InternalStreamChatApi
2324
import io.getstream.chat.android.core.utils.date.after
2425
import io.getstream.chat.android.models.AttachmentType
@@ -55,8 +56,8 @@ public fun List<Message>.latestOrNull(): Message? = when (size >= ITEM_COUNT_OF_
5556
*/
5657
@InternalStreamChatApi
5758
public fun Message.createdAfter(that: Message): Boolean {
58-
val thisDate = this.createdAt ?: this.createdLocallyAt
59-
val thatDate = that.createdAt ?: that.createdLocallyAt
59+
val thisDate = this.getCreatedAtOrNull()
60+
val thatDate = that.getCreatedAtOrNull()
6061
return thisDate after thatDate
6162
}
6263

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/extensions/ChannelExtensionsTests.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,18 @@ internal class ChannelExtensionsTests {
127127
text = "Hello @${user.id}",
128128
mentionedUsers = listOf(user),
129129
createdAt = Date(lastReadDate.time - 1000),
130+
createdLocallyAt = null,
130131
),
131132
randomMessage(
132133
text = "Hi @${user.id}",
133134
mentionedUsers = listOf(user),
134135
createdAt = Date(lastReadDate.time + 1000),
136+
createdLocallyAt = null,
135137
),
136138
randomMessage(
137139
text = "No mention here",
138140
createdAt = Date(lastReadDate.time + 2000),
141+
createdLocallyAt = null,
139142
),
140143
)
141144
val channelRead = randomChannelUserRead(user = user, lastRead = lastReadDate)

0 commit comments

Comments
 (0)