Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AND-25] Threads V2 offline support #5481

Merged
merged 88 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
b83a7bc
[PBE-3749] Update ThreadsApi to match the definition.
Oct 9, 2024
9ac769b
[PBE-3749] Register "notification.thread_message_new" EventType.
Oct 10, 2024
c5187ae
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 11, 2024
e338150
[PBE-3749] Implement initial state-management for 'Query Threads'.
Oct 11, 2024
ce4ab6d
[PBE-3749] Implement ThreadList component.
Oct 14, 2024
8d30835
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 14, 2024
fdb1ac1
[PBE-3749] Implement 'Threads' tab in compose sample app.
Oct 14, 2024
13400dc
[PBE-3749] FIx pagination logic and add a threshold.
Oct 14, 2024
7a44105
[PBE-3749] Add queryThreads preconditions checks.
Oct 14, 2024
7ccf42b
[PBE-3749] Revert ktlint commit.
Oct 14, 2024
7bf4d3f
[PBE-3749] Remove redundant state update in ThreadListController.
Oct 14, 2024
c058190
[PBE-3749] Add handling for different ChatEvents.
Oct 15, 2024
8486cde
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 15, 2024
361e754
[PBE-3749] Remove redundant coroutine creation and docs.
Oct 15, 2024
2e8c1b1
[PBE-3749] Fix detekt and spotless.
Oct 15, 2024
fbc9b3d
Revert "[PBE-3749] Implement 'Threads' tab in compose sample app."
Oct 15, 2024
cd01294
Revert "Revert "[PBE-3749] Implement 'Threads' tab in compose sample …
Oct 15, 2024
b856073
Revert "[PBE-3749] Implement 'Threads' tab in compose sample app."
Oct 15, 2024
76e5f54
[PBE-3749] Hide threads-related public apis.
Oct 15, 2024
6fc64d8
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 17, 2024
b88eca7
[PBE-3749] Fix PR remarks related DTOs.
Oct 17, 2024
b91a89c
[PBE-3749] Fix wrong composable preview.
Oct 17, 2024
3560186
[PBE-3749] Use inheritScope to create ThreadListController coroutine …
Oct 17, 2024
de906ea
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 17, 2024
72d3689
[PBE-3749] Implement ChatClient::markThreadRead operation.
Oct 18, 2024
10e5c9d
[PBE-3749] Update CHANGELOG for markThreadRead.
Oct 18, 2024
93f8f39
[PBE-3749] Fix failing test.
Oct 18, 2024
0b7d384
[PBE-3749] Separate `markThreadRead` from `markRead`.
Oct 18, 2024
321907f
[PBE-3749] Implement unreadThreads logic as part of the GlobalState.
Oct 21, 2024
47e7849
Merge branch 'refs/heads/develop' into feature/threads_v2_global_unre…
Oct 21, 2024
41558f7
[PBE-3749] Add GlobalState::unreadThreadsCount to CHANGELOG.md.
Oct 21, 2024
b93459e
Merge branch 'develop' into feature/threads_v2_mark_thread_as_read
VelikovPetar Oct 21, 2024
71ed93c
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 21, 2024
c3405d3
Merge branch 'refs/heads/feature/threads_v2_global_unread_threads_sta…
Oct 22, 2024
fe5a711
Merge branch 'refs/heads/feature/threads_v2_mark_thread_as_read' into…
Oct 22, 2024
97c93f6
[PBE-3749] Add marking thread as read handling.
Oct 22, 2024
f1fb53a
Merge branch 'refs/heads/develop' into feature/threads_v2_improvements
Oct 22, 2024
55ad64a
Merge branch 'refs/heads/develop' into feature/threads_v2_mark_thread…
Oct 22, 2024
60204d5
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 22, 2024
23a3f18
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Oct 22, 2024
a21abaf
Merge branch 'refs/heads/feature/threads_v2_mark_thread_as_read' into…
Oct 22, 2024
49fe477
Merge branch 'refs/heads/develop' into feature/threads_v2_improvements
Oct 22, 2024
12ede31
[PBE-3749] Fix incrementing unread count for new thread messages.
Oct 22, 2024
0b9397a
[PBE-3749] Add ThreadItem customization options.
Oct 22, 2024
0b946f3
[PBE-3749] Make Threads API public.
Oct 22, 2024
5d4de4c
[PBE-3749] Add Threads tab to compose sample app.
Oct 22, 2024
27c308e
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 22, 2024
520862d
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Oct 22, 2024
b66b1e4
Merge branch 'refs/heads/develop' into feature/threads_v2_improvements
Oct 23, 2024
ecbb061
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 23, 2024
7e3f502
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Oct 23, 2024
86979c1
Merge branch 'refs/heads/develop' into feature/threads_v2_improvements
Oct 23, 2024
266550d
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 23, 2024
18854bc
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Oct 23, 2024
4d89262
[PBE-3749] Add threads state tests.
Oct 23, 2024
2ce1a14
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 24, 2024
b7d3dcc
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Oct 24, 2024
f653f97
Merge branch 'refs/heads/develop' into feature/threads_v2
Oct 25, 2024
10278c6
[PBE-3749] Suppress LongMethod warning.
Oct 25, 2024
e72c974
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Oct 25, 2024
237ca87
[PBE-3749] Add ChatClient::markThreadUnread.
Oct 25, 2024
7123e24
[PBE-3749] Add ChatClient::markThreadUnread to CHANGELOG.md.
Oct 28, 2024
1730bed
Merge branch 'refs/heads/feature/threads_v2_mark_thread_as_unread' in…
Oct 29, 2024
212b895
[PBE-3749] Add stateless ThreadList.
Oct 30, 2024
fcfd281
[PBE-3749] Add ThreadList to CHANGELOG and add docusaurus documentation
Oct 30, 2024
88a1f05
[PBE-3749] Ensure threads state is updated on different client operat…
Oct 31, 2024
ecae6d1
[PBE-3749] Fix failing tests.
Oct 31, 2024
5c7c963
Merge branch 'refs/heads/develop' into feature/threads_v2
Nov 5, 2024
564666f
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Nov 5, 2024
c58e458
Merge branch 'refs/heads/develop' into feature/threads_v2_improvements
Nov 5, 2024
a823a89
[PBE-3749] Add 'Mark thread as unread' handling.
Nov 5, 2024
e153761
Merge branch 'refs/heads/develop' into feature/threads_v2
Nov 5, 2024
b159d5c
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Nov 5, 2024
aec80bb
Merge branch 'refs/heads/develop' into feature/threads_v2
Nov 6, 2024
acca8de
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Nov 6, 2024
a317992
Merge branch 'refs/heads/develop' into feature/threads_v2
Nov 6, 2024
6ade7ba
Merge branch 'refs/heads/feature/threads_v2' into feature/threads_v2_…
Nov 6, 2024
5f0aa68
[PBE-3749] Add Threads offline support.
Nov 7, 2024
7941d4e
Merge branch 'develop' into feature/threads_v2
Nov 13, 2024
55e71f8
[PBE-3749] apply spotless.
Nov 13, 2024
e52aede
Merge branch 'feature/threads_v2' into feature/threads_v2_improvements
Nov 13, 2024
3acbf81
Merge branch 'feature/threads_v2_improvements' into feature/threads_o…
Nov 13, 2024
281c47a
Merge branch 'develop' into feature/threads_offline
Nov 20, 2024
38655a5
[PBE-3749] Post-merge clean-up.
Nov 20, 2024
086d9cb
[PBE-3749] Remove docs.
Nov 20, 2024
29e66d2
[PBE-3749] Update NotificationMarkUnreadEvent with threadId for threa…
Nov 20, 2024
b743b19
[PBE-3749] Add threads offline support to CHANGELOG.md.
Nov 20, 2024
2bff40c
[AND-25] Delegate Thread::replyCount to Thread::parentMessage.
Nov 20, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
### ⬆️ Improved

### ✅ Added
- Add support for Threads. [#5481](https://github.com/GetStream/stream-chat-android/pull/5481)

### ⚠️ Changed

Expand Down
25 changes: 20 additions & 5 deletions stream-chat-android-client/api/stream-chat-android-client.api
Original file line number Diff line number Diff line change
Expand Up @@ -1766,14 +1766,15 @@ public final class io/getstream/chat/android/client/events/NotificationMarkReadE
}

public final class io/getstream/chat/android/client/events/NotificationMarkUnreadEvent : io/getstream/chat/android/client/events/CidEvent, io/getstream/chat/android/client/events/HasUnreadCounts, io/getstream/chat/android/client/events/UserEvent {
public fun <init> (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;I)V
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;I)V
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component10 ()I
public final fun component11 ()Ljava/lang/String;
public final fun component12 ()Ljava/util/Date;
public final fun component13 ()Ljava/lang/String;
public final fun component14 ()I
public final fun component14 ()Ljava/lang/String;
public final fun component15 ()I
public final fun component2 ()Ljava/util/Date;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()Lio/getstream/chat/android/models/User;
Expand All @@ -1782,8 +1783,8 @@ public final class io/getstream/chat/android/client/events/NotificationMarkUnrea
public final fun component7 ()Ljava/lang/String;
public final fun component8 ()I
public final fun component9 ()I
public final fun copy (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;I)Lio/getstream/chat/android/client/events/NotificationMarkUnreadEvent;
public static synthetic fun copy$default (Lio/getstream/chat/android/client/events/NotificationMarkUnreadEvent;Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;IILjava/lang/Object;)Lio/getstream/chat/android/client/events/NotificationMarkUnreadEvent;
public final fun copy (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;I)Lio/getstream/chat/android/client/events/NotificationMarkUnreadEvent;
public static synthetic fun copy$default (Lio/getstream/chat/android/client/events/NotificationMarkUnreadEvent;Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;IILjava/lang/Object;)Lio/getstream/chat/android/client/events/NotificationMarkUnreadEvent;
public fun equals (Ljava/lang/Object;)Z
public fun getChannelId ()Ljava/lang/String;
public fun getChannelType ()Ljava/lang/String;
Expand All @@ -1793,6 +1794,7 @@ public final class io/getstream/chat/android/client/events/NotificationMarkUnrea
public final fun getLastReadMessageAt ()Ljava/util/Date;
public final fun getLastReadMessageId ()Ljava/lang/String;
public fun getRawCreatedAt ()Ljava/lang/String;
public final fun getThreadId ()Ljava/lang/String;
public fun getTotalUnreadCount ()I
public fun getType ()Ljava/lang/String;
public fun getUnreadChannels ()I
Expand Down Expand Up @@ -2547,6 +2549,18 @@ public abstract interface class io/getstream/chat/android/client/persistance/rep
public abstract fun selectSyncState (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class io/getstream/chat/android/client/persistance/repository/ThreadsRepository {
public abstract fun clear (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun deleteChannelThreads (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun insertThreadOrder (Ljava/lang/String;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun insertThreads (Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun selectThread (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun selectThreadOrder (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun selectThreads (Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun upsertMessageInThread (Lio/getstream/chat/android/models/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun upsertMessagesInThread (Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class io/getstream/chat/android/client/persistance/repository/UserRepository {
public abstract fun clear (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun insertCurrentUser (Lio/getstream/chat/android/models/User;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand All @@ -2564,6 +2578,7 @@ public abstract interface class io/getstream/chat/android/client/persistance/rep
public abstract fun createQueryChannelsRepository ()Lio/getstream/chat/android/client/persistance/repository/QueryChannelsRepository;
public abstract fun createReactionRepository (Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/client/persistance/repository/ReactionRepository;
public abstract fun createSyncStateRepository ()Lio/getstream/chat/android/client/persistance/repository/SyncStateRepository;
public abstract fun createThreadsRepository (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/client/persistance/repository/ThreadsRepository;
public abstract fun createUserRepository ()Lio/getstream/chat/android/client/persistance/repository/UserRepository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ private fun NotificationMarkUnreadEventDto.toDomain(currentUserId: UserId?): Not
lastReadMessageId = last_read_message_id,
lastReadMessageAt = last_read_at.date,
unreadMessages = unread_messages,
threadId = thread_id,
unreadThreads = unread_threads,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ internal fun DownstreamThreadDto.toDomain(currentUserId: UserId?): Thread =
parentMessage = parent_message.toDomain(currentUserId),
createdByUserId = created_by_user_id,
createdBy = created_by?.toDomain(currentUserId),
replyCount = reply_count,
participantCount = participant_count,
threadParticipants = thread_participants.orEmpty().map { it.toDomain(currentUserId) },
lastMessageAt = last_message_at,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ internal data class NotificationMarkUnreadEventDto(
val unread_messages: Int,
val total_unread_count: Int,
val unread_channels: Int,
val thread_id: String? = null,
val unread_threads: Int = 0,
) : ChatEventDto()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import java.util.Date
* @param parent_message: The parent message.
* @param created_by_user_id: The ID of the user who created the thread.
* @param created_by: The user who created the thread.
* @param reply_count: The number of replies in the thread.
* @param participant_count: The number of participants in the thread.
* @param thread_participants: The participants in the thread.
* @param last_message_at: The date of the last message in the thread.
Expand All @@ -50,7 +49,6 @@ internal data class DownstreamThreadDto(
val parent_message: DownstreamMessageDto,
val created_by_user_id: String,
val created_by: DownstreamUserDto?,
val reply_count: Int,
val participant_count: Int,
val thread_participants: List<DownstreamThreadParticipantDto>?,
val last_message_at: Date,
Expand All @@ -77,7 +75,6 @@ internal data class DownstreamThreadDto(
* @param parent_message_id: The parent message ID.
* @param participant_count: The number of participants in the thread.
* @param reply_count: The number of replies in the thread.
* @param thread_participants: The participants in the thread.
* @param title: The title of the thread.
* @param updated_at: The date when the thread was updated.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ public data class NotificationMarkUnreadEvent(
val firstUnreadMessageId: String,
val lastReadMessageAt: Date,
val lastReadMessageId: String?,
val threadId: String? = null,
val unreadThreads: Int = 0,
) : CidEvent(), UserEvent, HasUnreadCounts

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
* Copyright (c) 2014-2024 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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

import io.getstream.chat.android.core.internal.InternalStreamChatApi
import io.getstream.chat.android.models.ChannelUserRead
import io.getstream.chat.android.models.Message
import io.getstream.chat.android.models.Thread
import io.getstream.chat.android.models.ThreadInfo
import io.getstream.chat.android.models.ThreadParticipant
import io.getstream.chat.android.models.User
import java.util.Date

/**
* Updates the given Thread with the new message (parent or reply).
*/
@InternalStreamChatApi
public fun Thread.updateParentOrReply(message: Message): Thread {
return when (this.parentMessageId) {
message.id -> updateParent(parent = message)
message.parentId -> upsertReply(reply = message)
else -> this
}
}

/**
* Updates the parent message of a Thread.
*/
@InternalStreamChatApi
public fun Thread.updateParent(parent: Message): Thread {
// Skip update if [parent] is not related to this Thread
if (this.parentMessageId != parent.id) return this
return this.copy(
parentMessage = parent,
deletedAt = parent.deletedAt,
updatedAt = parent.updatedAt ?: this.updatedAt,
)
}

/**
* Inserts a new reply (or updates and existing one) in a Thread.
*/
@InternalStreamChatApi
public fun Thread.upsertReply(reply: Message): Thread {
// Ship update if [reply] is not related to this Thread
if (this.parentMessageId != reply.parentId) return this
val newReplies = upsertMessageInList(reply, this.latestReplies)
val isInsert = newReplies.size > this.latestReplies.size
val sortedNewReplies = newReplies.sortedBy {
it.createdAt ?: it.createdLocallyAt
}
val lastMessageAt = sortedNewReplies.lastOrNull()?.let { latestReply ->
latestReply.createdAt ?: latestReply.createdLocallyAt
}
// The new message could be from a new thread participant
val threadParticipants = if (isInsert) {
upsertThreadParticipantInList(
newParticipant = ThreadParticipant(user = reply.user),
participants = this.threadParticipants,
)
} else {
this.threadParticipants
}
val participantCount = threadParticipants.size
// Update read counts (+1 for each non-sender of the message)
val read = if (isInsert) {
updateReadCounts(this.read, reply)
} else {
this.read
}
return this.copy(
lastMessageAt = lastMessageAt ?: this.lastMessageAt,
updatedAt = lastMessageAt ?: this.updatedAt,
participantCount = participantCount,
threadParticipants = threadParticipants,
latestReplies = sortedNewReplies,
read = read,
)
}

/**
* Marks the given thread as read by the given user.
*
* @param threadInfo The [ThreadInfo] holding info about the [Thread] which should be marked as read.
* @param user The [User] for which the thread should be marked as read.
* @param createdAt The [Date] of the 'mark read' event.
*/
@InternalStreamChatApi
public fun Thread.markAsReadByUser(threadInfo: ThreadInfo, user: User, createdAt: Date): Thread {
// Skip update if [threadInfo] is not related to this Thread
if (this.parentMessageId != threadInfo.parentMessageId) return this
val updatedRead = this.read.map { read ->
if (read.user.id == user.id) {
read.copy(
user = user,
unreadMessages = 0,
lastReceivedEventDate = createdAt,
)
} else {
read
}
}
return this.copy(
activeParticipantCount = threadInfo.activeParticipantCount,
deletedAt = threadInfo.deletedAt,
lastMessageAt = threadInfo.lastMessageAt ?: this.lastMessageAt,
parentMessage = threadInfo.parentMessage ?: this.parentMessage,
participantCount = threadInfo.participantCount,
title = threadInfo.title,
updatedAt = threadInfo.updatedAt,
read = updatedRead,
)
}

/**
* Marks the given thread as unread by the given user.
*
* @param user The [User] for which the thread should be marked as read.
* @param createdAt The [Date] of the 'mark read' event.
*/
@InternalStreamChatApi
public fun Thread.markAsUnreadByUser(user: User, createdAt: Date): Thread {
val updatedRead = this.read.map { read ->
if (read.user.id == user.id) {
read.copy(
user = user,
// Update this value to what the backend returns (when implemented)
unreadMessages = read.unreadMessages + 1,
lastReceivedEventDate = createdAt,
)
} else {
read
}
}
return this.copy(read = updatedRead)
}

private fun upsertMessageInList(newMessage: Message, messages: List<Message>): List<Message> {
// Insert
if (messages.none { it.id == newMessage.id }) {
return messages + listOf(newMessage)
}
// Update
return messages.map { message ->
if (message.id == newMessage.id) {
newMessage
} else {
message
}
}
}

private fun upsertThreadParticipantInList(
newParticipant: ThreadParticipant,
participants: List<ThreadParticipant>,
): List<ThreadParticipant> {
// Insert
if (participants.none { it.getUserId() == newParticipant.getUserId() }) {
return participants + listOf(newParticipant)
}
// Update
return participants.map { participant ->
if (participant.getUserId() == newParticipant.getUserId()) {
newParticipant
} else {
participant
}
}
}

private fun updateReadCounts(read: List<ChannelUserRead>, reply: Message): List<ChannelUserRead> {
return read.map { userRead ->
if (userRead.user.id != reply.user.id) {
userRead.copy(unreadMessages = userRead.unreadMessages + 1)
} else {
userRead
}
}
}
Loading
Loading