From b83a7bcd1efc5403fa0e7a03ddb9bbbd6a3826f8 Mon Sep 17 00:00:00 2001 From: PetarVelikov Date: Wed, 9 Oct 2024 09:32:26 +0200 Subject: [PATCH 01/46] [PBE-3749] Update ThreadsApi to match the definition. --- .../api/stream-chat-android-client.api | 24 +++++--- .../chat/android/client/ChatClient.kt | 13 +++++ .../chat/android/client/api/ChatApi.kt | 3 +- .../client/api/models/QueryThreadsRequest.kt | 22 +++++--- .../chat/android/client/api2/MoshiChatApi.kt | 27 +++++---- .../client/api2/mapping/ThreadMapping.kt | 12 ++-- .../client/api2/model/dto/ThreadDtos.kt | 18 +++--- .../model/requests/QueryThreadsRequest.kt | 20 ++++--- .../model/response/QueryThreadsResponse.kt | 4 ++ .../api/stream-chat-android-core.api | 55 +++++++++++++------ .../chat/android/models/QueryThreadsResult.kt | 33 +++++++++++ .../getstream/chat/android/models/Thread.kt | 16 +++--- 12 files changed, 177 insertions(+), 70 deletions(-) create mode 100644 stream-chat-android-core/src/main/java/io/getstream/chat/android/models/QueryThreadsResult.kt diff --git a/stream-chat-android-client/api/stream-chat-android-client.api b/stream-chat-android-client/api/stream-chat-android-client.api index 76e0d789faa..14d1671f685 100644 --- a/stream-chat-android-client/api/stream-chat-android-client.api +++ b/stream-chat-android-client/api/stream-chat-android-client.api @@ -130,6 +130,7 @@ public final class io/getstream/chat/android/client/ChatClient { public final fun queryMembers (Ljava/lang/String;Ljava/lang/String;IILio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Ljava/util/List;)Lio/getstream/result/call/Call; public static synthetic fun queryMembers$default (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/lang/String;IILio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/result/call/Call; public final fun queryThreads (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;)Lio/getstream/result/call/Call; + public final fun queryThreadsResult (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;)Lio/getstream/result/call/Call; public final fun queryUsers (Lio/getstream/chat/android/client/api/models/QueryUsersRequest;)Lio/getstream/result/call/Call; public final fun reconnectSocket ()Lio/getstream/result/call/Call; public final fun rejectInvite (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call; @@ -473,24 +474,33 @@ public final class io/getstream/chat/android/client/api/models/QueryThreadsReque public fun (Z)V public fun (ZI)V public fun (ZII)V - public fun (ZIII)V - public fun (ZIIII)V - public fun (ZIIIILjava/lang/String;)V - public synthetic fun (ZIIIILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (ZIILjava/lang/String;)V + public fun (ZIILjava/lang/String;I)V + public fun (ZIILjava/lang/String;ILjava/lang/String;)V + public fun (ZIILjava/lang/String;ILjava/lang/String;I)V + public fun (ZIILjava/lang/String;ILjava/lang/String;ILio/getstream/chat/android/models/User;)V + public fun (ZIILjava/lang/String;ILjava/lang/String;ILio/getstream/chat/android/models/User;Ljava/lang/String;)V + public synthetic fun (ZIILjava/lang/String;ILjava/lang/String;ILio/getstream/chat/android/models/User;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Z public final fun component2 ()I public final fun component3 ()I - public final fun component4 ()I + public final fun component4 ()Ljava/lang/String; public final fun component5 ()I public final fun component6 ()Ljava/lang/String; - public final fun copy (ZIIIILjava/lang/String;)Lio/getstream/chat/android/client/api/models/QueryThreadsRequest; - public static synthetic fun copy$default (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;ZIIIILjava/lang/String;ILjava/lang/Object;)Lio/getstream/chat/android/client/api/models/QueryThreadsRequest; + public final fun component7 ()I + public final fun component8 ()Lio/getstream/chat/android/models/User; + public final fun component9 ()Ljava/lang/String; + public final fun copy (ZIILjava/lang/String;ILjava/lang/String;ILio/getstream/chat/android/models/User;Ljava/lang/String;)Lio/getstream/chat/android/client/api/models/QueryThreadsRequest; + public static synthetic fun copy$default (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;ZIILjava/lang/String;ILjava/lang/String;ILio/getstream/chat/android/models/User;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/chat/android/client/api/models/QueryThreadsRequest; public fun equals (Ljava/lang/Object;)Z public final fun getLimit ()I public final fun getMemberLimit ()I public final fun getNext ()Ljava/lang/String; public final fun getParticipantLimit ()I + public final fun getPrev ()Ljava/lang/String; public final fun getReplyLimit ()I + public final fun getUser ()Lio/getstream/chat/android/models/User; + public final fun getUserId ()Ljava/lang/String; public final fun getWatch ()Z public fun hashCode ()I public fun toString ()Ljava/lang/String; diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt index ff0e04d1c7f..e8ca97c138d 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt @@ -167,6 +167,7 @@ import io.getstream.chat.android.models.Option import io.getstream.chat.android.models.Poll import io.getstream.chat.android.models.PollConfig import io.getstream.chat.android.models.PushMessage +import io.getstream.chat.android.models.QueryThreadsResult import io.getstream.chat.android.models.Reaction import io.getstream.chat.android.models.SearchMessagesResult import io.getstream.chat.android.models.Thread @@ -3204,6 +3205,18 @@ internal constructor( public fun queryThreads( query: QueryThreadsRequest, ): Call> { + return queryThreadsResult(query).map { it.threads } + } + + /** + * Query threads matching [query] request. + * + * @param query [QueryThreadsRequest] with query parameters to get matching users. + */ + @CheckResult + public fun queryThreadsResult( + query: QueryThreadsRequest, + ): Call { return api.queryThreads(query) } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/ChatApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/ChatApi.kt index ee072845168..046a0c00e50 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/ChatApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/ChatApi.kt @@ -41,6 +41,7 @@ import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.Mute import io.getstream.chat.android.models.Poll import io.getstream.chat.android.models.PollConfig +import io.getstream.chat.android.models.QueryThreadsResult import io.getstream.chat.android.models.Reaction import io.getstream.chat.android.models.SearchMessagesResult import io.getstream.chat.android.models.Thread @@ -458,7 +459,7 @@ internal interface ChatApi { * @param query [QueryThreadsRequest] with query parameters to get matching users. */ @CheckResult - fun queryThreads(query: QueryThreadsRequest): Call> + fun queryThreads(query: QueryThreadsRequest): Call /** * Get a thread by [messageId]. diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/QueryThreadsRequest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/QueryThreadsRequest.kt index 436a82d2b23..dc6e44bb1d7 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/QueryThreadsRequest.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/QueryThreadsRequest.kt @@ -16,22 +16,30 @@ package io.getstream.chat.android.client.api.models +import io.getstream.chat.android.models.User + /** * Query threads request. * * @property watch If true, all the channels corresponding to threads returned in response will be watched. * Defaults to true. - * @property replyLimit The number of latest replies to fetch per thread. Defaults to 2. - * @property participantLimit The number of thread participants to request per thread. Defaults to 100. - * @property memberLimit The number of members to request per thread. Defaults to 100. - * @property limit The number of threads to return. Defaults to 10. * @property limit The number of threads to return. Defaults to 10. + * @property memberLimit The number of members to request per thread. Defaults to 100. + * @property next The next pagination token. This token can be used to fetch the next page of threads. + * @property participantLimit The number of thread participants to request per thread. Defaults to 100. + * @property prev The previous pagination token. This token can be used to fetch the previous page of threads. + * @property replyLimit The number of latest replies to fetch per thread. Defaults to 2. + * @property user The user for which the threads are queried. Defaults to null. + * @property userId The user ID for which the threads are queried. Defaults to null. */ public data class QueryThreadsRequest @JvmOverloads constructor( public val watch: Boolean = true, - public val replyLimit: Int = 2, - public val participantLimit: Int = 100, - public val memberLimit: Int = 100, public val limit: Int = 10, + public val memberLimit: Int = 100, public val next: String? = null, + public val participantLimit: Int = 100, + public val prev: String? = null, + public val replyLimit: Int = 2, + public val user: User? = null, + public val userId: String? = null, ) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt index 496141d1a69..891c55d96ef 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt @@ -111,6 +111,7 @@ import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.Mute import io.getstream.chat.android.models.Poll import io.getstream.chat.android.models.PollConfig +import io.getstream.chat.android.models.QueryThreadsResult import io.getstream.chat.android.models.Reaction import io.getstream.chat.android.models.SearchMessagesResult import io.getstream.chat.android.models.Thread @@ -1092,28 +1093,32 @@ constructor( /** * Queries a list of threads for the current user. * - * @param replyLimit The number of latest replies to fetch per thread. Defaults to 2. - * @param participantLimit The number of thread participants to request per thread. Defaults to 100. - * @param limit The number of threads to return. Defaults to 10. - * @param watch If true, all the channels corresponding to threads returned in response will be watched. - * Defaults to true. - * @param memberLimit The number of members to request per thread. Defaults to 100. + * @param query The [QueryThreadsRequest] model holding the data relevant for the `queryThreads` call. */ override fun queryThreads( query: QueryThreadsRequest, - ): Call> { + ): Call { val lazyQueryThreads = { threadsApi.queryThreads( connectionId, io.getstream.chat.android.client.api2.model.requests.QueryThreadsRequest( - reply_limit = query.replyLimit, - participant_limit = query.participantLimit, - limit = query.limit, watch = query.watch, + limit = query.limit, member_limit = query.memberLimit, next = query.next, + participant_limit = query.participantLimit, + prev = query.prev, + reply_limit = query.replyLimit, + user = query.user?.toDto(), + user_id = query.userId, ), - ).map { response -> response.threads.map { it.toDomain(currentUserIdProvider()) } } + ).map { response -> + QueryThreadsResult( + threads = response.threads.map { it.toDomain(currentUserIdProvider()) }, + prev = response.prev, + next = response.next, + ) + } } return if (connectionId.isBlank() && query.watch) { logger.i { "[queryThreads] postponing because an active connection is required" } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/ThreadMapping.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/ThreadMapping.kt index e07217c01e9..f16de87797a 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/ThreadMapping.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/ThreadMapping.kt @@ -24,21 +24,23 @@ import io.getstream.chat.android.models.UserId internal fun DownstreamThreadDto.toDomain(currentUserId: UserId?): Thread = Thread( + activeParticipantCount = active_participant_count, cid = channel_cid, - channelInfo = channel.toDomain(), + channelInfo = channel?.toDomain(), parentMessageId = parent_message_id, - parentMessage = parent_message.toDomain(currentUserId), + parentMessage = parent_message?.toDomain(currentUserId), createdByUserId = created_by_user_id, - createdBy = created_by.toDomain(currentUserId), + createdBy = created_by?.toDomain(currentUserId), replyCount = reply_count, participantCount = participant_count, - threadParticipants = thread_participants.map { it.toDomain(currentUserId) }, + threadParticipants = thread_participants?.map { it.toDomain(currentUserId) }, lastMessageAt = last_message_at, createdAt = created_at, updatedAt = updated_at, + deletedAt = deleted_at, title = title, latestReplies = latest_replies.map { it.toDomain(currentUserId) }, - read = read.map { it.toDomain(currentUserId, last_message_at) }, + read = read?.map { it.toDomain(currentUserId, last_message_at) }, ) internal fun DownstreamThreadParticipantDto.toDomain(currentUserId: UserId?): User = user.toDomain(currentUserId) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/ThreadDtos.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/ThreadDtos.kt index fd2b9d674f1..e3c322b6877 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/ThreadDtos.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/ThreadDtos.kt @@ -22,6 +22,7 @@ import java.util.Date /** * The DTO for a thread. * + * @param active_participant_count: The number of active participants. * @param channel_cid: The channel CID. * @param channel: The channel info. * @param parent_message_id: The parent message ID. @@ -34,27 +35,30 @@ import java.util.Date * @param last_message_at: The date of the last message in the thread. * @param created_at: The date when the thread was created. * @param updated_at: The date when the thread was updated. + * @param deleted_at: The date when the thread was deleted. * @param title: The title of the thread. * @param latest_replies: The latest replies in the thread. * @param read: The read states of the thread. */ @JsonClass(generateAdapter = true) internal data class DownstreamThreadDto( + val active_participant_count: Int?, val channel_cid: String, - val channel: ChannelInfoDto, + val channel: ChannelInfoDto?, val parent_message_id: String, - val parent_message: DownstreamMessageDto, + 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, + val created_by: DownstreamUserDto?, + val reply_count: Int?, + val participant_count: Int?, + val thread_participants: List?, val last_message_at: Date, val created_at: Date, val updated_at: Date?, + val deleted_at: Date?, val title: String, val latest_replies: List, - val read: List, + val read: List?, ) /** diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/QueryThreadsRequest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/QueryThreadsRequest.kt index 12725dfb738..8cc1c8b8b04 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/QueryThreadsRequest.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/QueryThreadsRequest.kt @@ -18,25 +18,31 @@ package io.getstream.chat.android.client.api2.model.requests import com.squareup.moshi.JsonClass import io.getstream.chat.android.client.api2.endpoint.ThreadsApi +import io.getstream.chat.android.client.api2.model.dto.UpstreamUserDto /** * Used for querying threads. * @see [ThreadsApi.queryThreads] * * @param watch If true, all the channels corresponding to threads returned in response will be watched. - * Defaults to true. - * @param reply_limit The number of latest replies to fetch per thread. Defaults to 2. Max limit is 10. - * @param participant_limit The number of thread participants to request per thread. Defaults to 100. Max limit is 100. - * @param member_limit The number of members to request per thread. Defaults to 100. Max limit is 100. * @param limit The number of threads to return. Defaults to 10. Max limit is 25. + * @param member_limit The number of members to request per thread. Defaults to 100. Max limit is 100. * @param next The next pagination token. This token can be used to fetch the next page of threads. + * @param participant_limit The number of thread participants to request per thread. Defaults to 100. Max limit is 100. + * @param prev The previous pagination token. This token can be used to fetch the previous page of threads. + * @param reply_limit The number of latest replies to fetch per thread. Defaults to 2. Max limit is 10. + * @param user The user for which the threads are queried. Defaults to null. + * @param user_id The user ID for which the threads are queried. Defaults to null. */ @JsonClass(generateAdapter = true) internal data class QueryThreadsRequest( val watch: Boolean = true, - val reply_limit: Int = 2, - val participant_limit: Int = 100, - val member_limit: Int = 100, val limit: Int = 10, + val member_limit: Int = 100, val next: String? = null, + val participant_limit: Int = 100, + val prev: String? = null, + val reply_limit: Int = 2, + val user: UpstreamUserDto? = null, + val user_id: String? = null, ) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/QueryThreadsResponse.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/QueryThreadsResponse.kt index f464d044aee..776b185e1f1 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/QueryThreadsResponse.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/QueryThreadsResponse.kt @@ -25,9 +25,13 @@ import io.getstream.chat.android.client.api2.model.dto.DownstreamThreadDto * * @param threads: The list of threads. * @param duration: The duration of the request. + * @param prev: The identifier for the previous page of threads. + * @param next: The identifier for the next page of threads. */ @JsonClass(generateAdapter = true) internal data class QueryThreadsResponse( val threads: List, val duration: String, + val prev: String?, + val next: String?, ) diff --git a/stream-chat-android-core/api/stream-chat-android-core.api b/stream-chat-android-core/api/stream-chat-android-core.api index fa46572f5c8..dc5747d498f 100644 --- a/stream-chat-android-core/api/stream-chat-android-core.api +++ b/stream-chat-android-core/api/stream-chat-android-core.api @@ -1465,6 +1465,21 @@ public final class io/getstream/chat/android/models/PushProvider$Companion { public final fun fromKey (Ljava/lang/String;)Lio/getstream/chat/android/models/PushProvider; } +public final class io/getstream/chat/android/models/QueryThreadsResult { + public fun (Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun copy (Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/chat/android/models/QueryThreadsResult; + public static synthetic fun copy$default (Lio/getstream/chat/android/models/QueryThreadsResult;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/chat/android/models/QueryThreadsResult; + public fun equals (Ljava/lang/Object;)Z + public final fun getNext ()Ljava/lang/String; + public final fun getPrev ()Ljava/lang/String; + public final fun getThreads ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/chat/android/models/Reaction : io/getstream/chat/android/models/CustomObject { public fun ()V public fun (Ljava/lang/String;Ljava/lang/String;ILio/getstream/chat/android/models/User;Ljava/lang/String;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Lio/getstream/chat/android/models/SyncStatus;Ljava/util/Map;Z)V @@ -1647,37 +1662,41 @@ public final class io/getstream/chat/android/models/SyncStatus$Companion { } public final class io/getstream/chat/android/models/Thread { - public fun (Ljava/lang/String;Lio/getstream/chat/android/models/ChannelInfo;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Ljava/lang/String;Lio/getstream/chat/android/models/User;IILjava/util/List;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V - public final fun component1 ()Ljava/lang/String; - public final fun component10 ()Ljava/util/Date; + public fun (Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/chat/android/models/ChannelInfo;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/util/List;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V + public final fun component1 ()Ljava/lang/Integer; + public final fun component10 ()Ljava/util/List; public final fun component11 ()Ljava/util/Date; public final fun component12 ()Ljava/util/Date; - public final fun component13 ()Ljava/lang/String; - public final fun component14 ()Ljava/util/List; - public final fun component15 ()Ljava/util/List; - public final fun component2 ()Lio/getstream/chat/android/models/ChannelInfo; - public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Lio/getstream/chat/android/models/Message; - public final fun component5 ()Ljava/lang/String; - public final fun component6 ()Lio/getstream/chat/android/models/User; - public final fun component7 ()I - public final fun component8 ()I - public final fun component9 ()Ljava/util/List; - public final fun copy (Ljava/lang/String;Lio/getstream/chat/android/models/ChannelInfo;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Ljava/lang/String;Lio/getstream/chat/android/models/User;IILjava/util/List;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Lio/getstream/chat/android/models/Thread; - public static synthetic fun copy$default (Lio/getstream/chat/android/models/Thread;Ljava/lang/String;Lio/getstream/chat/android/models/ChannelInfo;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Ljava/lang/String;Lio/getstream/chat/android/models/User;IILjava/util/List;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/chat/android/models/Thread; + public final fun component13 ()Ljava/util/Date; + public final fun component14 ()Ljava/util/Date; + public final fun component15 ()Ljava/lang/String; + public final fun component16 ()Ljava/util/List; + public final fun component17 ()Ljava/util/List; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Lio/getstream/chat/android/models/ChannelInfo; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Lio/getstream/chat/android/models/Message; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Lio/getstream/chat/android/models/User; + public final fun component8 ()Ljava/lang/Integer; + public final fun component9 ()Ljava/lang/Integer; + public final fun copy (Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/chat/android/models/ChannelInfo;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/util/List;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Lio/getstream/chat/android/models/Thread; + public static synthetic fun copy$default (Lio/getstream/chat/android/models/Thread;Ljava/lang/Integer;Ljava/lang/String;Lio/getstream/chat/android/models/ChannelInfo;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Ljava/lang/String;Lio/getstream/chat/android/models/User;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/util/List;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lio/getstream/chat/android/models/Thread; public fun equals (Ljava/lang/Object;)Z + public final fun getActiveParticipantCount ()Ljava/lang/Integer; public final fun getChannelInfo ()Lio/getstream/chat/android/models/ChannelInfo; public final fun getCid ()Ljava/lang/String; public final fun getCreatedAt ()Ljava/util/Date; public final fun getCreatedBy ()Lio/getstream/chat/android/models/User; public final fun getCreatedByUserId ()Ljava/lang/String; + public final fun getDeletedAt ()Ljava/util/Date; public final fun getLastMessageAt ()Ljava/util/Date; public final fun getLatestReplies ()Ljava/util/List; public final fun getParentMessage ()Lio/getstream/chat/android/models/Message; public final fun getParentMessageId ()Ljava/lang/String; - public final fun getParticipantCount ()I + public final fun getParticipantCount ()Ljava/lang/Integer; public final fun getRead ()Ljava/util/List; - public final fun getReplyCount ()I + public final fun getReplyCount ()Ljava/lang/Integer; public final fun getThreadParticipants ()Ljava/util/List; public final fun getTitle ()Ljava/lang/String; public final fun getUpdatedAt ()Ljava/util/Date; diff --git a/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/QueryThreadsResult.kt b/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/QueryThreadsResult.kt new file mode 100644 index 00000000000..281040caf04 --- /dev/null +++ b/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/QueryThreadsResult.kt @@ -0,0 +1,33 @@ +/* + * 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.models + +import androidx.compose.runtime.Immutable + +/** + * Model representing the result of a 'Query Threads' operation. + * + * @param threads: The list of threads. + * @param prev: The identifier for the previous page of threads. + * @param next: The identifier for the next page of threads. + */ +@Immutable +public data class QueryThreadsResult( + val threads: List, + val prev: String?, + val next: String?, +) diff --git a/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/Thread.kt b/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/Thread.kt index d1072655ed7..7f209c241dd 100644 --- a/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/Thread.kt +++ b/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/Thread.kt @@ -21,19 +21,21 @@ import java.util.Date @Immutable public data class Thread( + val activeParticipantCount: Int?, val cid: String, - val channelInfo: ChannelInfo, + val channelInfo: ChannelInfo?, val parentMessageId: String, - val parentMessage: Message, + val parentMessage: Message?, val createdByUserId: String, - val createdBy: User, - val replyCount: Int, - val participantCount: Int, - val threadParticipants: List, + val createdBy: User?, + val replyCount: Int?, + val participantCount: Int?, + val threadParticipants: List?, val lastMessageAt: Date, val createdAt: Date, val updatedAt: Date?, + val deletedAt: Date?, val title: String, val latestReplies: List, - val read: List, + val read: List?, ) From 9ac769bc71550fc82936368bfaad6d2a94ebf2c1 Mon Sep 17 00:00:00 2001 From: PetarVelikov Date: Thu, 10 Oct 2024 17:00:45 +0200 Subject: [PATCH 02/46] [PBE-3749] Register "notification.thread_message_new" EventType. --- .../api/stream-chat-android-client.api | 34 +++++++++++++++++++ .../client/api2/mapping/EventMapping.kt | 18 ++++++++++ .../client/api2/model/dto/EventDtos.kt | 13 +++++++ .../android/client/channel/ChannelClient.kt | 2 ++ .../chat/android/client/events/ChatEvent.kt | 27 +++++++++++++++ .../client/parser2/adapters/EventAdapter.kt | 4 +++ .../api/stream-chat-android-core.api | 1 + .../chat/android/models/EventType.kt | 1 + .../logic/channel/internal/ChannelLogic.kt | 4 +++ 9 files changed, 104 insertions(+) diff --git a/stream-chat-android-client/api/stream-chat-android-client.api b/stream-chat-android-client/api/stream-chat-android-client.api index 14d1671f685..d25894eabd4 100644 --- a/stream-chat-android-client/api/stream-chat-android-client.api +++ b/stream-chat-android-client/api/stream-chat-android-client.api @@ -1282,6 +1282,11 @@ public abstract interface class io/getstream/chat/android/client/events/HasUnrea public abstract fun getUnreadChannels ()I } +public abstract interface class io/getstream/chat/android/client/events/HasUnreadThreadCounts { + public abstract fun getUnreadThreadMessages ()I + public abstract fun getUnreadThreads ()I +} + public abstract interface class io/getstream/chat/android/client/events/HasWatcherCount { public abstract fun getWatcherCount ()I } @@ -1827,6 +1832,35 @@ public final class io/getstream/chat/android/client/events/NotificationRemovedFr public fun toString ()Ljava/lang/String; } +public final class io/getstream/chat/android/client/events/NotificationThreadMessageNewEvent : io/getstream/chat/android/client/events/CidEvent, io/getstream/chat/android/client/events/HasChannel, io/getstream/chat/android/client/events/HasMessage, io/getstream/chat/android/client/events/HasUnreadThreadCounts { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/Channel;Ljava/util/Date;Ljava/lang/String;II)V + public final fun component1 ()Ljava/lang/String; + public final fun component10 ()I + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Lio/getstream/chat/android/models/Message; + public final fun component6 ()Lio/getstream/chat/android/models/Channel; + public final fun component7 ()Ljava/util/Date; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()I + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/Channel;Ljava/util/Date;Ljava/lang/String;II)Lio/getstream/chat/android/client/events/NotificationThreadMessageNewEvent; + public static synthetic fun copy$default (Lio/getstream/chat/android/client/events/NotificationThreadMessageNewEvent;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/Channel;Ljava/util/Date;Ljava/lang/String;IIILjava/lang/Object;)Lio/getstream/chat/android/client/events/NotificationThreadMessageNewEvent; + public fun equals (Ljava/lang/Object;)Z + public fun getChannel ()Lio/getstream/chat/android/models/Channel; + public fun getChannelId ()Ljava/lang/String; + public fun getChannelType ()Ljava/lang/String; + public fun getCid ()Ljava/lang/String; + public fun getCreatedAt ()Ljava/util/Date; + public fun getMessage ()Lio/getstream/chat/android/models/Message; + public fun getRawCreatedAt ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public fun getUnreadThreadMessages ()I + public fun getUnreadThreads ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/chat/android/client/events/PollClosedEvent : io/getstream/chat/android/client/events/CidEvent, io/getstream/chat/android/client/events/HasPoll { public fun (Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/getstream/chat/android/models/Poll;)V public final fun component1 ()Ljava/lang/String; diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/EventMapping.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/EventMapping.kt index 7b66fc65963..ef30d1afbf7 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/EventMapping.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/EventMapping.kt @@ -55,6 +55,7 @@ import io.getstream.chat.android.client.api2.model.dto.NotificationMarkUnreadEve import io.getstream.chat.android.client.api2.model.dto.NotificationMessageNewEventDto import io.getstream.chat.android.client.api2.model.dto.NotificationMutesUpdatedEventDto import io.getstream.chat.android.client.api2.model.dto.NotificationRemovedFromChannelEventDto +import io.getstream.chat.android.client.api2.model.dto.NotificationThreadMessageNewEventDto import io.getstream.chat.android.client.api2.model.dto.PollClosedEventDto import io.getstream.chat.android.client.api2.model.dto.PollDeletedEventDto import io.getstream.chat.android.client.api2.model.dto.PollUpdatedEventDto @@ -110,6 +111,7 @@ import io.getstream.chat.android.client.events.NotificationMarkUnreadEvent import io.getstream.chat.android.client.events.NotificationMessageNewEvent import io.getstream.chat.android.client.events.NotificationMutesUpdatedEvent import io.getstream.chat.android.client.events.NotificationRemovedFromChannelEvent +import io.getstream.chat.android.client.events.NotificationThreadMessageNewEvent import io.getstream.chat.android.client.events.PollClosedEvent import io.getstream.chat.android.client.events.PollDeletedEvent import io.getstream.chat.android.client.events.PollUpdatedEvent @@ -176,6 +178,7 @@ internal fun ChatEventDto.toDomain(currentUserId: UserId?): ChatEvent { is NotificationMarkReadEventDto -> toDomain(currentUserId) is NotificationMarkUnreadEventDto -> toDomain(currentUserId) is NotificationMessageNewEventDto -> toDomain(currentUserId) + is NotificationThreadMessageNewEventDto -> toDomain(currentUserId) is NotificationMutesUpdatedEventDto -> toDomain(currentUserId) is NotificationRemovedFromChannelEventDto -> toDomain(currentUserId) is ReactionDeletedEventDto -> toDomain(currentUserId) @@ -534,6 +537,21 @@ private fun NotificationMessageNewEventDto.toDomain(currentUserId: UserId?): Not ) } +private fun NotificationThreadMessageNewEventDto.toDomain(currentUserId: UserId?): NotificationThreadMessageNewEvent { + return NotificationThreadMessageNewEvent( + type = type, + cid = cid, + channelId = channel_id, + channelType = channel_type, + message = message.toDomain(currentUserId), + channel = channel.toDomain(currentUserId), + createdAt = created_at.date, + rawCreatedAt = created_at.rawDate, + unreadThreads = unread_threads, + unreadThreadMessages = unread_thread_messages, + ) +} + private fun NotificationMutesUpdatedEventDto.toDomain(currentUserId: UserId?): NotificationMutesUpdatedEvent { return NotificationMutesUpdatedEvent( type = type, diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/EventDtos.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/EventDtos.kt index 47a860c1e24..00580e1218d 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/EventDtos.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/EventDtos.kt @@ -306,6 +306,19 @@ internal data class NotificationMessageNewEventDto( val unread_channels: Int = 0, ) : ChatEventDto() +@JsonClass(generateAdapter = true) +internal data class NotificationThreadMessageNewEventDto( + val type: String, + val cid: String, + val channel_id: String, + val channel_type: String, + val message: DownstreamMessageDto, + val channel: DownstreamChannelDto, + val created_at: ExactDate, + val unread_threads: Int, + val unread_thread_messages: Int, +) : ChatEventDto() + @JsonClass(generateAdapter = true) internal data class NotificationMutesUpdatedEventDto( val type: String, diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/channel/ChannelClient.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/channel/ChannelClient.kt index 7bc44409800..e90295cb19b 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/channel/ChannelClient.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/channel/ChannelClient.kt @@ -61,6 +61,7 @@ import io.getstream.chat.android.client.events.NotificationMarkUnreadEvent import io.getstream.chat.android.client.events.NotificationMessageNewEvent import io.getstream.chat.android.client.events.NotificationMutesUpdatedEvent import io.getstream.chat.android.client.events.NotificationRemovedFromChannelEvent +import io.getstream.chat.android.client.events.NotificationThreadMessageNewEvent import io.getstream.chat.android.client.events.PollClosedEvent import io.getstream.chat.android.client.events.PollDeletedEvent import io.getstream.chat.android.client.events.PollUpdatedEvent @@ -241,6 +242,7 @@ public class ChannelClient internal constructor( is NotificationMarkReadEvent -> event.cid == cid is NotificationMarkUnreadEvent -> event.cid == cid is NotificationMessageNewEvent -> event.cid == cid + is NotificationThreadMessageNewEvent -> event.cid == cid is NotificationRemovedFromChannelEvent -> event.cid == cid is ReactionDeletedEvent -> event.cid == cid is ReactionNewEvent -> event.cid == cid diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/events/ChatEvent.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/events/ChatEvent.kt index c633d514fd6..da9e3769847 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/events/ChatEvent.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/events/ChatEvent.kt @@ -103,6 +103,17 @@ public sealed interface HasUnreadCounts { public val unreadChannels: Int } +/** + * Interface that marks a [ChatEvent] as having the information about unread thread counts. + * + * The list of events which contains unread counts: + * - notification.thread_message_new + */ +public sealed interface HasUnreadThreadCounts { + public val unreadThreads: Int + public val unreadThreadMessages: Int +} + /** * Triggered when a channel is deleted */ @@ -461,6 +472,22 @@ public data class NotificationMessageNewEvent( override val unreadChannels: Int = 0, ) : CidEvent(), HasChannel, HasMessage, HasUnreadCounts +/** + * Triggered when a message is added to a channel as a thread reply. + */ +public data class NotificationThreadMessageNewEvent( + override val type: String, + override val cid: String, + override val channelId: String, + override val channelType: String, + override val message: Message, + override val channel: Channel, + override val createdAt: Date, + override val rawCreatedAt: String?, + override val unreadThreads: Int, + override val unreadThreadMessages: Int, +) : CidEvent(), HasMessage, HasChannel, HasUnreadThreadCounts + /** * Triggered when the user mutes are updated */ diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventAdapter.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventAdapter.kt index 03f45263ee5..a6c433fd488 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventAdapter.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventAdapter.kt @@ -57,6 +57,7 @@ import io.getstream.chat.android.client.api2.model.dto.NotificationMarkUnreadEve import io.getstream.chat.android.client.api2.model.dto.NotificationMessageNewEventDto import io.getstream.chat.android.client.api2.model.dto.NotificationMutesUpdatedEventDto import io.getstream.chat.android.client.api2.model.dto.NotificationRemovedFromChannelEventDto +import io.getstream.chat.android.client.api2.model.dto.NotificationThreadMessageNewEventDto import io.getstream.chat.android.client.api2.model.dto.PollClosedEventDto import io.getstream.chat.android.client.api2.model.dto.PollDeletedEventDto import io.getstream.chat.android.client.api2.model.dto.PollUpdatedEventDto @@ -122,6 +123,8 @@ internal class EventDtoAdapter( private val notificationMarkUnreadEventAdapter = moshi.adapter(NotificationMarkUnreadEventDto::class.java) private val markAllReadEventAdapter = moshi.adapter(MarkAllReadEventDto::class.java) private val notificationMessageNewEventAdapter = moshi.adapter(NotificationMessageNewEventDto::class.java) + private val notificationThreadMessageNewEventAdapter = + moshi.adapter(NotificationThreadMessageNewEventDto::class.java) private val notificationInvitedEventAdapter = moshi.adapter(NotificationInvitedEventDto::class.java) private val notificationInviteAcceptedEventAdapter = moshi.adapter(NotificationInviteAcceptedEventDto::class.java) private val notificationInviteRejectedEventAdapter = moshi.adapter(NotificationInviteRejectedEventDto::class.java) @@ -194,6 +197,7 @@ internal class EventDtoAdapter( } EventType.NOTIFICATION_MARK_UNREAD -> notificationMarkUnreadEventAdapter EventType.NOTIFICATION_MESSAGE_NEW -> notificationMessageNewEventAdapter + EventType.NOTIFICATION_THREAD_MESSAGE_NEW -> notificationThreadMessageNewEventAdapter EventType.NOTIFICATION_INVITED -> notificationInvitedEventAdapter EventType.NOTIFICATION_INVITE_ACCEPTED -> notificationInviteAcceptedEventAdapter EventType.NOTIFICATION_INVITE_REJECTED -> notificationInviteRejectedEventAdapter diff --git a/stream-chat-android-core/api/stream-chat-android-core.api b/stream-chat-android-core/api/stream-chat-android-core.api index dc5747d498f..56107f20c29 100644 --- a/stream-chat-android-core/api/stream-chat-android-core.api +++ b/stream-chat-android-core/api/stream-chat-android-core.api @@ -796,6 +796,7 @@ public final class io/getstream/chat/android/models/EventType { public static final field NOTIFICATION_MESSAGE_NEW Ljava/lang/String; public static final field NOTIFICATION_MUTES_UPDATED Ljava/lang/String; public static final field NOTIFICATION_REMOVED_FROM_CHANNEL Ljava/lang/String; + public static final field NOTIFICATION_THREAD_MESSAGE_NEW Ljava/lang/String; public static final field POLL_CLOSED Ljava/lang/String; public static final field POLL_DELETED Ljava/lang/String; public static final field POLL_UPDATED Ljava/lang/String; diff --git a/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/EventType.kt b/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/EventType.kt index 5acea5a768f..5a5b0505728 100644 --- a/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/EventType.kt +++ b/stream-chat-android-core/src/main/java/io/getstream/chat/android/models/EventType.kt @@ -50,6 +50,7 @@ public object EventType { public const val CHANNEL_TRUNCATED: String = "channel.truncated" public const val HEALTH_CHECK: String = "health.check" public const val NOTIFICATION_MESSAGE_NEW: String = "notification.message_new" + public const val NOTIFICATION_THREAD_MESSAGE_NEW: String = "notification.thread_message_new" public const val NOTIFICATION_CHANNEL_TRUNCATED: String = "notification.channel_truncated" public const val NOTIFICATION_CHANNEL_DELETED: String = "notification.channel_deleted" public const val NOTIFICATION_MARK_READ: String = "notification.mark_read" diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/internal/ChannelLogic.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/internal/ChannelLogic.kt index 86105bb4ad7..20a4a2bf7e3 100644 --- a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/internal/ChannelLogic.kt +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/internal/ChannelLogic.kt @@ -58,6 +58,7 @@ import io.getstream.chat.android.client.events.NotificationMarkUnreadEvent import io.getstream.chat.android.client.events.NotificationMessageNewEvent import io.getstream.chat.android.client.events.NotificationMutesUpdatedEvent import io.getstream.chat.android.client.events.NotificationRemovedFromChannelEvent +import io.getstream.chat.android.client.events.NotificationThreadMessageNewEvent import io.getstream.chat.android.client.events.PollClosedEvent import io.getstream.chat.android.client.events.PollDeletedEvent import io.getstream.chat.android.client.events.PollUpdatedEvent @@ -547,6 +548,9 @@ internal class ChannelLogic( channelStateLogic.updateCurrentUserRead(event.createdAt, event.message) channelStateLogic.toggleHidden(false) } + is NotificationThreadMessageNewEvent -> { + // TODO: See what to do here + } is ReactionNewEvent -> { upsertEventMessage(event.message) } From e338150067ad9564e49e6f1c54b1467951a285c3 Mon Sep 17 00:00:00 2001 From: PetarVelikov Date: Fri, 11 Oct 2024 10:00:22 +0200 Subject: [PATCH 03/46] [PBE-3749] Implement initial state-management for 'Query Threads'. --- .../api/stream-chat-android-client.api | 14 ++- .../chat/android/client/ChatClient.kt | 28 +++++- .../chat/android/client/plugin/Plugin.kt | 16 +++- .../plugin/listeners/QueryThreadsListener.kt | 53 +++++++++++ .../api/stream-chat-android-state.api | 10 ++ .../android/state/extensions/ChatClient.kt | 21 +++- .../state/plugin/internal/StatePlugin.kt | 5 +- .../internal/QueryThreadsListenerState.kt | 44 +++++++++ .../thread/internal/QueryThreadsLogic.kt | 79 +++++++++++++++ .../thread/internal/QueryThreadsStateLogic.kt | 68 +++++++++++++ .../plugin/logic/internal/LogicRegistry.kt | 18 +++- .../state/plugin/state/StateRegistry.kt | 17 ++++ .../state/internal/ChatClientStateCalls.kt | 15 +++ .../state/querythreads/QueryThreadsState.kt | 38 ++++++++ .../internal/QueryThreadsMutableState.kt | 95 +++++++++++++++++++ 15 files changed, 512 insertions(+), 9 deletions(-) create mode 100644 stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/listeners/QueryThreadsListener.kt create mode 100644 stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/listener/internal/QueryThreadsListenerState.kt create mode 100644 stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsLogic.kt create mode 100644 stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsStateLogic.kt create mode 100644 stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/QueryThreadsState.kt create mode 100644 stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/internal/QueryThreadsMutableState.kt diff --git a/stream-chat-android-client/api/stream-chat-android-client.api b/stream-chat-android-client/api/stream-chat-android-client.api index d25894eabd4..a059ab5e736 100644 --- a/stream-chat-android-client/api/stream-chat-android-client.api +++ b/stream-chat-android-client/api/stream-chat-android-client.api @@ -2526,7 +2526,7 @@ public abstract interface class io/getstream/chat/android/client/persistance/rep public abstract fun createRepositoryFactory (Lio/getstream/chat/android/models/User;)Lio/getstream/chat/android/client/persistance/repository/factory/RepositoryFactory; } -public abstract interface class io/getstream/chat/android/client/plugin/Plugin : io/getstream/chat/android/client/plugin/DependencyResolver, io/getstream/chat/android/client/plugin/listeners/ChannelMarkReadListener, io/getstream/chat/android/client/plugin/listeners/CreateChannelListener, io/getstream/chat/android/client/plugin/listeners/DeleteChannelListener, io/getstream/chat/android/client/plugin/listeners/DeleteMessageListener, io/getstream/chat/android/client/plugin/listeners/DeleteReactionListener, io/getstream/chat/android/client/plugin/listeners/EditMessageListener, io/getstream/chat/android/client/plugin/listeners/FetchCurrentUserListener, io/getstream/chat/android/client/plugin/listeners/GetMessageListener, io/getstream/chat/android/client/plugin/listeners/HideChannelListener, io/getstream/chat/android/client/plugin/listeners/MarkAllReadListener, io/getstream/chat/android/client/plugin/listeners/QueryChannelListener, io/getstream/chat/android/client/plugin/listeners/QueryChannelsListener, io/getstream/chat/android/client/plugin/listeners/QueryMembersListener, io/getstream/chat/android/client/plugin/listeners/SendAttachmentListener, io/getstream/chat/android/client/plugin/listeners/SendGiphyListener, io/getstream/chat/android/client/plugin/listeners/SendMessageListener, io/getstream/chat/android/client/plugin/listeners/SendReactionListener, io/getstream/chat/android/client/plugin/listeners/ShuffleGiphyListener, io/getstream/chat/android/client/plugin/listeners/ThreadQueryListener, io/getstream/chat/android/client/plugin/listeners/TypingEventListener { +public abstract interface class io/getstream/chat/android/client/plugin/Plugin : io/getstream/chat/android/client/plugin/DependencyResolver, io/getstream/chat/android/client/plugin/listeners/ChannelMarkReadListener, io/getstream/chat/android/client/plugin/listeners/CreateChannelListener, io/getstream/chat/android/client/plugin/listeners/DeleteChannelListener, io/getstream/chat/android/client/plugin/listeners/DeleteMessageListener, io/getstream/chat/android/client/plugin/listeners/DeleteReactionListener, io/getstream/chat/android/client/plugin/listeners/EditMessageListener, io/getstream/chat/android/client/plugin/listeners/FetchCurrentUserListener, io/getstream/chat/android/client/plugin/listeners/GetMessageListener, io/getstream/chat/android/client/plugin/listeners/HideChannelListener, io/getstream/chat/android/client/plugin/listeners/MarkAllReadListener, io/getstream/chat/android/client/plugin/listeners/QueryChannelListener, io/getstream/chat/android/client/plugin/listeners/QueryChannelsListener, io/getstream/chat/android/client/plugin/listeners/QueryMembersListener, io/getstream/chat/android/client/plugin/listeners/QueryThreadsListener, io/getstream/chat/android/client/plugin/listeners/SendAttachmentListener, io/getstream/chat/android/client/plugin/listeners/SendGiphyListener, io/getstream/chat/android/client/plugin/listeners/SendMessageListener, io/getstream/chat/android/client/plugin/listeners/SendReactionListener, io/getstream/chat/android/client/plugin/listeners/ShuffleGiphyListener, io/getstream/chat/android/client/plugin/listeners/ThreadQueryListener, io/getstream/chat/android/client/plugin/listeners/TypingEventListener { public abstract fun getErrorHandler ()Lio/getstream/chat/android/client/errorhandler/ErrorHandler; public abstract fun onAttachmentSendRequest (Ljava/lang/String;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun onChannelMarkReadPrecondition (Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2565,6 +2565,9 @@ public abstract interface class io/getstream/chat/android/client/plugin/Plugin : public abstract fun onQueryChannelsRequest (Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun onQueryChannelsResult (Lio/getstream/result/Result;Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun onQueryMembersResult (Lio/getstream/result/Result;Ljava/lang/String;Ljava/lang/String;IILio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun onQueryThreadsPrecondition (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun onQueryThreadsRequest (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun onQueryThreadsResult (Lio/getstream/result/Result;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun onSendReactionPrecondition (Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/models/Reaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun onSendReactionRequest (Ljava/lang/String;Lio/getstream/chat/android/models/Reaction;ZLio/getstream/chat/android/models/User;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun onSendReactionResult (Ljava/lang/String;Lio/getstream/chat/android/models/Reaction;ZLio/getstream/chat/android/models/User;Lio/getstream/result/Result;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2616,6 +2619,9 @@ public final class io/getstream/chat/android/client/plugin/Plugin$DefaultImpls { public static fun onQueryChannelsRequest (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun onQueryChannelsResult (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/result/Result;Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun onQueryMembersResult (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/result/Result;Ljava/lang/String;Ljava/lang/String;IILio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onQueryThreadsPrecondition (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onQueryThreadsRequest (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onQueryThreadsResult (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/result/Result;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun onSendReactionPrecondition (Lio/getstream/chat/android/client/plugin/Plugin;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/models/Reaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun onSendReactionRequest (Lio/getstream/chat/android/client/plugin/Plugin;Ljava/lang/String;Lio/getstream/chat/android/models/Reaction;ZLio/getstream/chat/android/models/User;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun onSendReactionResult (Lio/getstream/chat/android/client/plugin/Plugin;Ljava/lang/String;Lio/getstream/chat/android/models/Reaction;ZLio/getstream/chat/android/models/User;Lio/getstream/result/Result;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2696,6 +2702,12 @@ public abstract interface class io/getstream/chat/android/client/plugin/listener public abstract fun onQueryMembersResult (Lio/getstream/result/Result;Ljava/lang/String;Ljava/lang/String;IILio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } +public abstract interface class io/getstream/chat/android/client/plugin/listeners/QueryThreadsListener { + public abstract fun onQueryThreadsPrecondition (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun onQueryThreadsRequest (Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun onQueryThreadsResult (Lio/getstream/result/Result;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + public abstract interface class io/getstream/chat/android/client/plugin/listeners/SendAttachmentListener { public abstract fun onAttachmentSendRequest (Ljava/lang/String;Ljava/lang/String;Lio/getstream/chat/android/models/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt index e8ca97c138d..3e53b4054fb 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt @@ -3214,9 +3214,31 @@ internal constructor( * @param query [QueryThreadsRequest] with query parameters to get matching users. */ @CheckResult - public fun queryThreadsResult( - query: QueryThreadsRequest, - ): Call { + public fun queryThreadsResult(query: QueryThreadsRequest): Call { + return queryThreadsInternal(query) + .doOnStart(userScope) { + plugins.forEach { plugin -> + plugin.onQueryThreadsRequest(query) + } + } + .doOnResult(userScope) { result -> + plugins.forEach { plugin -> + plugin.onQueryThreadsResult(result, query) + } + } + .precondition(plugins) { + onQueryThreadsPrecondition(query) + } + } + + /** + * Queries the threads without applying side-effects. + * + * @param query The [QueryThreadsRequest] holding query parameters to be applied for the search. + */ + @CheckResult + @InternalStreamChatApi + public fun queryThreadsInternal(query: QueryThreadsRequest): Call { return api.queryThreads(query) } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/Plugin.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/Plugin.kt index fed44a71668..4abf9c222f2 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/Plugin.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/Plugin.kt @@ -19,6 +19,7 @@ package io.getstream.chat.android.client.plugin import io.getstream.chat.android.client.ChatClient import io.getstream.chat.android.client.api.models.QueryChannelRequest import io.getstream.chat.android.client.api.models.QueryChannelsRequest +import io.getstream.chat.android.client.api.models.QueryThreadsRequest import io.getstream.chat.android.client.errorhandler.ErrorHandler import io.getstream.chat.android.client.events.ChatEvent import io.getstream.chat.android.client.plugin.listeners.ChannelMarkReadListener @@ -34,6 +35,7 @@ import io.getstream.chat.android.client.plugin.listeners.MarkAllReadListener import io.getstream.chat.android.client.plugin.listeners.QueryChannelListener import io.getstream.chat.android.client.plugin.listeners.QueryChannelsListener import io.getstream.chat.android.client.plugin.listeners.QueryMembersListener +import io.getstream.chat.android.client.plugin.listeners.QueryThreadsListener import io.getstream.chat.android.client.plugin.listeners.SendAttachmentListener import io.getstream.chat.android.client.plugin.listeners.SendGiphyListener import io.getstream.chat.android.client.plugin.listeners.SendMessageListener @@ -45,6 +47,7 @@ import io.getstream.chat.android.models.Channel import io.getstream.chat.android.models.FilterObject import io.getstream.chat.android.models.Member import io.getstream.chat.android.models.Message +import io.getstream.chat.android.models.QueryThreadsResult import io.getstream.chat.android.models.Reaction import io.getstream.chat.android.models.User import io.getstream.chat.android.models.querysort.QuerySorter @@ -76,7 +79,8 @@ public interface Plugin : CreateChannelListener, DeleteChannelListener, GetMessageListener, - FetchCurrentUserListener { + FetchCurrentUserListener, + QueryThreadsListener { public fun getErrorHandler(): ErrorHandler? = null @@ -390,4 +394,14 @@ public interface Plugin : ) { /* No-Op */ } + + override suspend fun onQueryThreadsPrecondition(request: QueryThreadsRequest): Result = Result.Success(Unit) + + override suspend fun onQueryThreadsRequest(request: QueryThreadsRequest) { + /* No-Op */ + } + + override suspend fun onQueryThreadsResult(result: Result, request: QueryThreadsRequest) { + /* No-Op */ + } } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/listeners/QueryThreadsListener.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/listeners/QueryThreadsListener.kt new file mode 100644 index 00000000000..30006467806 --- /dev/null +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/plugin/listeners/QueryThreadsListener.kt @@ -0,0 +1,53 @@ +/* + * 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.plugin.listeners + +import io.getstream.chat.android.client.ChatClient +import io.getstream.chat.android.client.api.models.QueryThreadsRequest +import io.getstream.chat.android.models.QueryThreadsResult +import io.getstream.result.Result + +/** + * Listener for [ChatClient.queryChannels] requests. + */ +public interface QueryThreadsListener { + + /** + * Run precondition for the request. If it returns [Result.Success] then the request is run otherwise it returns + * [Result.Failure] and no request is made. + * + * @param request [QueryThreadsRequest] which is going to be used for the request. + * + * @return [Result.Success] if precondition passes otherwise [Result.Failure] + */ + public suspend fun onQueryThreadsPrecondition(request: QueryThreadsRequest): Result + + /** + * Runs side effect before the request is launched. + * + * @param request [QueryThreadsRequest] which is going to be used for the request. + */ + public suspend fun onQueryThreadsRequest(request: QueryThreadsRequest) + + /** + * Runs side effect the request was completed. + * + * @param result The [Result] containing the successfully retrieved [QueryThreadsResult] or the error. + * @param request [QueryThreadsRequest] which is was used for the request. + */ + public suspend fun onQueryThreadsResult(result: Result, request: QueryThreadsRequest) +} diff --git a/stream-chat-android-state/api/stream-chat-android-state.api b/stream-chat-android-state/api/stream-chat-android-state.api index e4c0a3f766a..75134bb56c4 100644 --- a/stream-chat-android-state/api/stream-chat-android-state.api +++ b/stream-chat-android-state/api/stream-chat-android-state.api @@ -87,6 +87,8 @@ public final class io/getstream/chat/android/state/extensions/ChatClientExtensio public static final fun queryChannelsAsState (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lio/getstream/chat/android/state/event/handler/chat/factory/ChatEventHandlerFactory;)Lkotlinx/coroutines/flow/StateFlow; public static final fun queryChannelsAsState (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lio/getstream/chat/android/state/event/handler/chat/factory/ChatEventHandlerFactory;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/flow/StateFlow; public static synthetic fun queryChannelsAsState$default (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/client/api/models/QueryChannelsRequest;Lio/getstream/chat/android/state/event/handler/chat/factory/ChatEventHandlerFactory;Lkotlinx/coroutines/CoroutineScope;ILjava/lang/Object;)Lkotlinx/coroutines/flow/StateFlow; + public static final fun queryThreadsAsState (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/flow/StateFlow; + public static synthetic fun queryThreadsAsState$default (Lio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/client/api/models/QueryThreadsRequest;Lkotlinx/coroutines/CoroutineScope;ILjava/lang/Object;)Lkotlinx/coroutines/flow/StateFlow; public static final fun setMessageForReply (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Lio/getstream/chat/android/models/Message;)Lio/getstream/result/call/Call; public static final fun watchChannelAsState (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;I)Lkotlinx/coroutines/flow/StateFlow; public static final fun watchChannelAsState (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;ILkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/flow/StateFlow; @@ -125,6 +127,7 @@ public final class io/getstream/chat/android/state/plugin/state/StateRegistry { public final fun channel (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/chat/android/client/channel/state/ChannelState; public final fun clear ()V public final fun queryChannels (Lio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;)Lio/getstream/chat/android/state/plugin/state/querychannels/QueryChannelsState; + public final fun queryThreads ()Lio/getstream/chat/android/state/plugin/state/querythreads/QueryThreadsState; public final fun thread (Ljava/lang/String;)Lio/getstream/chat/android/state/plugin/state/channel/thread/ThreadState; } @@ -191,6 +194,13 @@ public abstract interface class io/getstream/chat/android/state/plugin/state/que public abstract fun setChatEventHandlerFactory (Lio/getstream/chat/android/state/event/handler/chat/factory/ChatEventHandlerFactory;)V } +public abstract interface class io/getstream/chat/android/state/plugin/state/querythreads/QueryThreadsState { + public abstract fun getEndOfThreads ()Lkotlinx/coroutines/flow/StateFlow; + public abstract fun getLoading ()Lkotlinx/coroutines/flow/StateFlow; + public abstract fun getLoadingMore ()Lkotlinx/coroutines/flow/StateFlow; + public abstract fun getThreads ()Lkotlinx/coroutines/flow/StateFlow; +} + public class io/getstream/chat/android/state/utils/Event { public fun (Ljava/lang/Object;)V public final fun getContentIfNotHandled ()Ljava/lang/Object; diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/extensions/ChatClient.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/extensions/ChatClient.kt index 00383f7c39e..dac9933fcf4 100644 --- a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/extensions/ChatClient.kt +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/extensions/ChatClient.kt @@ -25,6 +25,7 @@ import android.os.Environment import androidx.annotation.CheckResult import io.getstream.chat.android.client.ChatClient import io.getstream.chat.android.client.api.models.QueryChannelsRequest +import io.getstream.chat.android.client.api.models.QueryThreadsRequest import io.getstream.chat.android.client.channel.state.ChannelState import io.getstream.chat.android.client.extensions.cidToTypeAndId import io.getstream.chat.android.client.utils.internal.validateCidWithResult @@ -47,6 +48,7 @@ import io.getstream.chat.android.state.plugin.state.StateRegistry import io.getstream.chat.android.state.plugin.state.channel.thread.ThreadState import io.getstream.chat.android.state.plugin.state.global.GlobalState import io.getstream.chat.android.state.plugin.state.querychannels.QueryChannelsState +import io.getstream.chat.android.state.plugin.state.querythreads.QueryThreadsState import io.getstream.log.StreamLog import io.getstream.log.taggedLogger import io.getstream.result.Error @@ -60,7 +62,6 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import java.text.SimpleDateFormat import java.util.Date @@ -145,6 +146,23 @@ public fun ChatClient.watchChannelAsState( } } +/** + * Performs [ChatClient.queryThreadsResult] under the hood and returns [QueryThreadsState]. + * The [QueryThreadsState] cannot be created before connecting the user therefore, the method returns a StateFlow + * that emits a null when the user has not been connected yet and the new value every time the user changes. + * + * @param request The [QueryThreadsRequest] used to perform the query threads operation. + * @return A [StateFlow] emitting changes in the [QueryThreadsState]. + */ +public fun ChatClient.queryThreadsAsState( + request: QueryThreadsRequest, + coroutineScope: CoroutineScope = CoroutineScope(DispatcherProvider.IO), +): StateFlow { + return getStateOrNull(coroutineScope) { + requestsAsState(coroutineScope).queryThreads(request) + } +} + /** * Same class of ChatClient.getReplies, but provides the result as [ThreadState] * @@ -177,7 +195,6 @@ public suspend fun ChatClient.getRepliesAsState( * @param messageId The ID of the original message the replies were made to. * @param messageLimit The number of messages that will be initially loaded. * @param olderToNewer The flag that determines the order of the messages. - * @param coroutineScope The [CoroutineScope] used for executing the request. * * @return [ThreadState] wrapped inside a [Call]. */ diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/internal/StatePlugin.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/internal/StatePlugin.kt index be354a69764..0434f530ab0 100644 --- a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/internal/StatePlugin.kt +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/internal/StatePlugin.kt @@ -30,6 +30,7 @@ import io.getstream.chat.android.client.plugin.listeners.HideChannelListener import io.getstream.chat.android.client.plugin.listeners.MarkAllReadListener import io.getstream.chat.android.client.plugin.listeners.QueryChannelListener import io.getstream.chat.android.client.plugin.listeners.QueryChannelsListener +import io.getstream.chat.android.client.plugin.listeners.QueryThreadsListener import io.getstream.chat.android.client.plugin.listeners.SendAttachmentListener import io.getstream.chat.android.client.plugin.listeners.SendGiphyListener import io.getstream.chat.android.client.plugin.listeners.SendMessageListener @@ -52,6 +53,7 @@ import io.getstream.chat.android.state.plugin.listener.internal.HideChannelListe import io.getstream.chat.android.state.plugin.listener.internal.MarkAllReadListenerState import io.getstream.chat.android.state.plugin.listener.internal.QueryChannelListenerState import io.getstream.chat.android.state.plugin.listener.internal.QueryChannelsListenerState +import io.getstream.chat.android.state.plugin.listener.internal.QueryThreadsListenerState import io.getstream.chat.android.state.plugin.listener.internal.SendAttachmentListenerState import io.getstream.chat.android.state.plugin.listener.internal.SendGiphyListenerState import io.getstream.chat.android.state.plugin.listener.internal.SendMessageListenerState @@ -110,7 +112,8 @@ public class StatePlugin internal constructor( SendMessageListener by SendMessageListenerState(logic), TypingEventListener by TypingEventListenerState(stateRegistry), SendAttachmentListener by SendAttachmentListenerState(logic), - FetchCurrentUserListener by FetchCurrentUserListenerState(clientState, globalState) { + FetchCurrentUserListener by FetchCurrentUserListenerState(clientState, globalState), + QueryThreadsListener by QueryThreadsListenerState(logic) { private val lazyErrorHandler: ErrorHandler by lazy { errorHandlerFactory.create() } override fun getErrorHandler(): ErrorHandler = lazyErrorHandler diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/listener/internal/QueryThreadsListenerState.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/listener/internal/QueryThreadsListenerState.kt new file mode 100644 index 00000000000..cff626976fe --- /dev/null +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/listener/internal/QueryThreadsListenerState.kt @@ -0,0 +1,44 @@ +/* + * 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.state.plugin.listener.internal + +import io.getstream.chat.android.client.api.models.QueryThreadsRequest +import io.getstream.chat.android.client.plugin.listeners.QueryThreadsListener +import io.getstream.chat.android.models.QueryThreadsResult +import io.getstream.chat.android.state.plugin.logic.internal.LogicRegistry +import io.getstream.result.Result + +/** + * [QueryThreadsListener] implementation for the [StatePlugin]. + * Ensures that the "Query Threads" state is properly populated by using the [LogicRegistry.queryThreads]. + * + * @param logic The [LogicRegistry] providing the business logic. + */ +internal class QueryThreadsListenerState(private val logic: LogicRegistry) : QueryThreadsListener { + + override suspend fun onQueryThreadsPrecondition(request: QueryThreadsRequest): Result { + return Result.Success(Unit) + } + + override suspend fun onQueryThreadsRequest(request: QueryThreadsRequest) { + logic.queryThreads().onQueryThreadsRequest(request) + } + + override suspend fun onQueryThreadsResult(result: Result, request: QueryThreadsRequest) { + logic.queryThreads().onQueryThreadsResult(result, request) + } +} diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsLogic.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsLogic.kt new file mode 100644 index 00000000000..c00eab70ac7 --- /dev/null +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsLogic.kt @@ -0,0 +1,79 @@ +/* + * 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.state.plugin.logic.channel.thread.internal + +import io.getstream.chat.android.client.api.models.QueryThreadsRequest +import io.getstream.chat.android.models.QueryThreadsResult +import io.getstream.result.Result + +/** + * Logic class for "Query Threads" operations. + * + * @param stateLogic The [QueryThreadsStateLogic] managing the global state of the threads list. + */ +internal class QueryThreadsLogic(private val stateLogic: QueryThreadsStateLogic) { + + /** + * Handles the actions that are needed to update the threads state before the attempt to load the threads + * from the network. + * + * @param request The [QueryThreadsRequest] used to fetch the threads. + */ + fun onQueryThreadsRequest(request: QueryThreadsRequest) { + if (isLoadingMore(request)) { + stateLogic.setLoadingMore(true) + } else { + stateLogic.setLoading(true) + } + } + + /** + * Handles the actions that are needed to update the threads state after the loading of the threads from network was + * completed. + * + * @param result The [Result] holding the [QueryThreadsResult] if the operation was successful, or an [Error] if the + * operation failed. + * @param request The [QueryThreadsRequest] used to fetch the threads. + */ + fun onQueryThreadsResult(result: Result, request: QueryThreadsRequest) { + val isLoadingMore = isLoadingMore(request) + if (isLoadingMore) { + stateLogic.setLoadingMore(false) + } else { + stateLogic.setLoading(false) + } + when (result) { + is Result.Success -> { + if (isLoadingMore) { + stateLogic.appendThreads(result.value.threads) + } else { + stateLogic.setThreads(result.value.threads) + } + val isEndReached = isEndReached(result.value) + stateLogic.setEndOfThreadsReached(isEndReached) + } + + is Result.Failure -> { + // TODO: What to do in this case?? + } + } + } + + private fun isLoadingMore(request: QueryThreadsRequest) = request.next != null + + private fun isEndReached(result: QueryThreadsResult) = result.next == null +} diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsStateLogic.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsStateLogic.kt new file mode 100644 index 00000000000..9839cac2876 --- /dev/null +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/channel/thread/internal/QueryThreadsStateLogic.kt @@ -0,0 +1,68 @@ +/* + * 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.state.plugin.logic.channel.thread.internal + +import io.getstream.chat.android.models.Thread +import io.getstream.chat.android.state.plugin.state.querythreads.internal.QueryThreadsMutableState + +/** + * Logic for managing the state of the threads list. + * + * @param mutableState Reference to the global [QueryThreadsMutableState]. + */ +internal class QueryThreadsStateLogic(private val mutableState: QueryThreadsMutableState) { + + /** + * Updates the loading state of the [mutableState]. + * + * @param loading The new loading state. + */ + internal fun setLoading(loading: Boolean) = + mutableState.setLoading(loading) + + /** + * Updates the loading more state of the [mutableState]. + * + * @param loading The new loading more state. + */ + internal fun setLoadingMore(loading: Boolean) = + mutableState.setLoadingMore(loading) + + /** + * Updates the thread state of the [mutableState]. + * + * @param threads The new threads state. + */ + internal fun setThreads(threads: List) = + mutableState.setThreads(threads) + + /** + * Appends the new page of [threads] to the current thread list. + * + * @param threads The new page of threads. + */ + internal fun appendThreads(threads: List) = + mutableState.appendThreads(threads) + + /** + * Updates the end of threads reached indicator in the [mutableState]. + * + * @param endOfThreadsReached The new end of threads indicator. + */ + internal fun setEndOfThreadsReached(endOfThreadsReached: Boolean) = + mutableState.setEndOfThreadsReached(endOfThreadsReached) +} diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/internal/LogicRegistry.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/internal/LogicRegistry.kt index b1ad388b796..60736fc48d7 100644 --- a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/internal/LogicRegistry.kt +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/internal/LogicRegistry.kt @@ -29,6 +29,8 @@ import io.getstream.chat.android.models.querysort.QuerySorter import io.getstream.chat.android.state.plugin.logic.channel.internal.ChannelLogic import io.getstream.chat.android.state.plugin.logic.channel.internal.ChannelStateLogic import io.getstream.chat.android.state.plugin.logic.channel.internal.SearchLogic +import io.getstream.chat.android.state.plugin.logic.channel.thread.internal.QueryThreadsLogic +import io.getstream.chat.android.state.plugin.logic.channel.thread.internal.QueryThreadsStateLogic import io.getstream.chat.android.state.plugin.logic.channel.thread.internal.ThreadLogic import io.getstream.chat.android.state.plugin.logic.channel.thread.internal.ThreadStateLogic import io.getstream.chat.android.state.plugin.logic.querychannels.internal.QueryChannelsDatabaseLogic @@ -46,7 +48,8 @@ import java.util.concurrent.ConcurrentHashMap * Registry-container for logic objects related to: * 1. Query channels * 2. Query channel - * 3. Query thread + * 3. Query threads + * 4. Query thread */ @Suppress("LongParameterList") internal class LogicRegistry internal constructor( @@ -64,6 +67,14 @@ internal class LogicRegistry internal constructor( private val queryChannels: ConcurrentHashMap>, QueryChannelsLogic> = ConcurrentHashMap() private val channels: ConcurrentHashMap, ChannelLogic> = ConcurrentHashMap() + + // Note: At the moment, there is no need for multiple instances of QueryThreadsLogic, as we always load all threads, + // without the option for filtering. Update this is we decide to support different queries. + private val queryThreads: QueryThreadsLogic = QueryThreadsLogic( + stateLogic = QueryThreadsStateLogic( + mutableState = stateRegistry.mutableQueryThreads(), + ), + ) private val threads: ConcurrentHashMap = ConcurrentHashMap() internal fun queryChannels(filter: FilterObject, sort: QuerySorter): QueryChannelsLogic { @@ -200,6 +211,11 @@ internal class LogicRegistry internal constructor( return channel(channelType, channelId).stateLogic() } + /** + * Provides the [QueryThreadsLogic] handling the business logic and state management related to thread queries. + */ + fun queryThreads(): QueryThreadsLogic = queryThreads + /** Returns [ThreadLogic] of thread replies with parent message that has id equal to [messageId]. */ fun thread(messageId: String): ThreadLogic { return threads.getOrPut(messageId) { diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/StateRegistry.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/StateRegistry.kt index 98f6c765d57..d420eac6c78 100644 --- a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/StateRegistry.kt +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/StateRegistry.kt @@ -29,6 +29,8 @@ import io.getstream.chat.android.state.plugin.state.channel.thread.ThreadState import io.getstream.chat.android.state.plugin.state.channel.thread.internal.ThreadMutableState import io.getstream.chat.android.state.plugin.state.querychannels.QueryChannelsState import io.getstream.chat.android.state.plugin.state.querychannels.internal.QueryChannelsMutableState +import io.getstream.chat.android.state.plugin.state.querythreads.QueryThreadsState +import io.getstream.chat.android.state.plugin.state.querythreads.internal.QueryThreadsMutableState import io.getstream.log.taggedLogger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -57,6 +59,10 @@ public class StateRegistry constructor( private val queryChannels: ConcurrentHashMap>, QueryChannelsMutableState> = ConcurrentHashMap() private val channels: ConcurrentHashMap, ChannelMutableState> = ConcurrentHashMap() + + // Note: At the moment, there is no need for multiple instances of QueryThreadsLogic, as we always load all threads, + // without the option for filtering. Update this is we decide to support different queries. + private val queryThreads: QueryThreadsMutableState = QueryThreadsMutableState() private val threads: ConcurrentHashMap = ConcurrentHashMap() /** @@ -113,6 +119,16 @@ public class StateRegistry constructor( return channels.containsKey(channelType to channelId) } + /** + * Returns a [QueryThreadsState] holding the current state of the threads data. + */ + public fun queryThreads(): QueryThreadsState = queryThreads + + /** + * Returns a [QueryThreadsState] holding the current state of the threads data. + */ + internal fun mutableQueryThreads(): QueryThreadsMutableState = queryThreads + /** * Returns [ThreadState] of thread replies with parent message that has id equal to [messageId]. * @@ -146,6 +162,7 @@ public class StateRegistry constructor( queryChannels.clear() channels.forEach { it.value.destroy() } channels.clear() + queryThreads.destroy() threads.forEach { it.value.destroy() } threads.clear() } diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/internal/ChatClientStateCalls.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/internal/ChatClientStateCalls.kt index 3892925405c..3fa4bf37a14 100644 --- a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/internal/ChatClientStateCalls.kt +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/internal/ChatClientStateCalls.kt @@ -19,6 +19,7 @@ package io.getstream.chat.android.state.plugin.state.internal import io.getstream.chat.android.client.ChatClient import io.getstream.chat.android.client.api.models.QueryChannelRequest import io.getstream.chat.android.client.api.models.QueryChannelsRequest +import io.getstream.chat.android.client.api.models.QueryThreadsRequest import io.getstream.chat.android.client.channel.state.ChannelState import io.getstream.chat.android.client.extensions.cidToTypeAndId import io.getstream.chat.android.models.Message @@ -28,6 +29,7 @@ import io.getstream.chat.android.state.model.querychannels.pagination.internal.Q import io.getstream.chat.android.state.plugin.state.StateRegistry import io.getstream.chat.android.state.plugin.state.channel.thread.ThreadState import io.getstream.chat.android.state.plugin.state.querychannels.QueryChannelsState +import io.getstream.chat.android.state.plugin.state.querythreads.QueryThreadsState import io.getstream.log.taggedLogger import io.getstream.result.call.Call import io.getstream.result.call.launch @@ -94,6 +96,19 @@ internal class ChatClientStateCalls( return queryChannel(channelType, channelId, request) } + /** + * Runs the [ChatClient.queryThreadsResult] operation with the provided [QueryThreadsRequest], and returns the + * [QueryThreadsState]. + * + * @param request The [QueryThreadsRequest] used to perform the query threads operation. + */ + internal suspend fun queryThreads(request: QueryThreadsRequest): QueryThreadsState { + chatClient.queryThreadsResult(request).launch(scope) + return deferredState + .await() + .queryThreads() + } + /** Reference request of the get thread replies query. */ internal suspend fun getReplies( messageId: String, diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/QueryThreadsState.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/QueryThreadsState.kt new file mode 100644 index 00000000000..0a903f870f0 --- /dev/null +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/QueryThreadsState.kt @@ -0,0 +1,38 @@ +/* + * 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.state.plugin.state.querythreads + +import io.getstream.chat.android.models.Thread +import kotlinx.coroutines.flow.StateFlow + +/** + * Contains the state related to threads queries. + */ +public interface QueryThreadsState { + + /** Sorted list of [Thread]s. */ + public val threads: StateFlow> + + /** Indicator if the current state is being loaded. */ + public val loading: StateFlow + + /** Indicator if the current state is loading more threads (a next page is being loaded). */ + public val loadingMore: StateFlow + + /** Indicator if the end of the threads was reached (last page). */ + public val endOfThreads: StateFlow +} diff --git a/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/internal/QueryThreadsMutableState.kt b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/internal/QueryThreadsMutableState.kt new file mode 100644 index 00000000000..ff30a97727f --- /dev/null +++ b/stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/state/querythreads/internal/QueryThreadsMutableState.kt @@ -0,0 +1,95 @@ +/* + * 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.state.plugin.state.querythreads.internal + +import io.getstream.chat.android.models.Thread +import io.getstream.chat.android.state.plugin.state.querythreads.QueryThreadsState +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** + * Mutable state holder of [QueryThreadsState] type. + */ +internal class QueryThreadsMutableState : QueryThreadsState { + + private var _threads: MutableStateFlow>? = MutableStateFlow(emptyList()) + private var _loading: MutableStateFlow? = MutableStateFlow(false) + private var _loadingMore: MutableStateFlow? = MutableStateFlow(false) + private var _endOfThreads: MutableStateFlow? = MutableStateFlow(false) + + // Note: The backing flow will always be initialized at this point + override val threads: StateFlow> = _threads!! + override val loading: StateFlow = _loading!! + override val loadingMore: StateFlow = _loadingMore!! + override val endOfThreads: StateFlow = _endOfThreads!! + + /** + * Updates the loading state. Will be true only during the initial load, or during a full reload. + * + * @param loading The new loading state. + */ + internal fun setLoading(loading: Boolean) { + _loading?.value = loading + } + + /** + * Updates the loading more state. Will be true only during the loading of pages after the first one. + * + * @param loading The new loading more state. + */ + internal fun setLoadingMore(loading: Boolean) { + _loadingMore?.value = loading + } + + /** + * Updates the threads state with the new [threads] list. Overwrites the current threads list. + * + * @param threads The new threads state. + */ + internal fun setThreads(threads: List) { + _threads?.value = threads + } + + /** + * Append the new page of [threads] to the current list of threads. + * + * @param threads The new page of threads. + */ + internal fun appendThreads(threads: List) { + val currentThreads = _threads?.value.orEmpty() + _threads?.value = currentThreads + threads + } + + /** + * Updates the flag whether the end of the threads list has been reached. + * + * @param endOfThreadsReached The new end of threads indicator. + */ + internal fun setEndOfThreadsReached(endOfThreadsReached: Boolean) { + _endOfThreads?.value = endOfThreadsReached + } + + /** + * Clears all data from the state. + */ + internal fun destroy() { + _threads = null + _loading = null + _loadingMore = null + _endOfThreads = null + } +} From ce4ab6d029349948da89d425120366d124c833ad Mon Sep 17 00:00:00 2001 From: PetarVelikov Date: Mon, 14 Oct 2024 11:39:15 +0200 Subject: [PATCH 04/46] [PBE-3749] Implement ThreadList component. --- .idea/inspectionProfiles/ktlint.xml | 28 ++ .../client/api2/mapping/ThreadMapping.kt | 2 +- .../client/api2/model/dto/ThreadDtos.kt | 2 +- .../api/stream-chat-android-compose.api | 73 +++++ .../android/compose/ui/threads/ThreadItem.kt | 297 +++++++++++++++++ .../android/compose/ui/threads/ThreadList.kt | 302 ++++++++++++++++++ .../compose/ui/threads/UnreadThreadsBanner.kt | 111 +++++++ .../viewmodel/threads/ThreadListViewModel.kt | 53 +++ .../threads/ThreadsViewModelFactory.kt | 37 +++ .../stream_compose_ic_threads_empty.xml | 27 ++ .../res/drawable/stream_compose_ic_union.xml | 25 ++ .../src/main/res/values/strings.xml | 8 + .../api/stream-chat-android-core.api | 10 +- .../getstream/chat/android/models/Thread.kt | 2 +- .../api/stream-chat-android-state.api | 3 +- .../internal/EventHandlerSequential.kt | 6 + .../logic/channel/internal/ChannelLogic.kt | 1 + .../thread/internal/QueryThreadsLogic.kt | 149 ++++++++- .../thread/internal/QueryThreadsStateLogic.kt | 27 +- .../state/querythreads/QueryThreadsState.kt | 10 +- .../internal/QueryThreadsMutableState.kt | 38 ++- .../api/stream-chat-android-ui-common.api | 18 ++ .../feature/threads/ThreadListController.kt | 128 ++++++++ .../common/state/threads/ThreadListState.kt | 34 ++ 24 files changed, 1364 insertions(+), 27 deletions(-) create mode 100644 stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadItem.kt create mode 100644 stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadList.kt create mode 100644 stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/UnreadThreadsBanner.kt create mode 100644 stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/threads/ThreadListViewModel.kt create mode 100644 stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/threads/ThreadsViewModelFactory.kt create mode 100644 stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_threads_empty.xml create mode 100644 stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_union.xml create mode 100644 stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/threads/ThreadListController.kt create mode 100644 stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/state/threads/ThreadListState.kt diff --git a/.idea/inspectionProfiles/ktlint.xml b/.idea/inspectionProfiles/ktlint.xml index f6edbe71abf..0fa939a4016 100644 --- a/.idea/inspectionProfiles/ktlint.xml +++ b/.idea/inspectionProfiles/ktlint.xml @@ -1,6 +1,34 @@