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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@
### ⬆️ Improved

### ✅ Added
- Add `ChatClient.markUnread(String, String, Date)` for marking a channel as unread from a given timestamp. [#6027](https://github.com/GetStream/stream-chat-android/pull/6027)
- Add `ChatClient.markThreadUnread(String, String, String)` for marking a thread as unread. [#6027](https://github.com/GetStream/stream-chat-android/pull/6027)
- Add `ChannelClient.markUnread(Date)` for marking a channel as unread from a given timestamp. [#6027](https://github.com/GetStream/stream-chat-android/pull/6027)
- Add `ChannelClient.markThreadUnread(String)` for marking a thread as unread. [#6027](https://github.com/GetStream/stream-chat-android/pull/6027)

### ⚠️ Changed
- Deprecate `ChatClient.markThreadUnread(String, String, String, String)` because marking a thread as unread from a given message is currently not supported. [#6027](https://github.com/GetStream/stream-chat-android/pull/6027)
- Deprecate `ChannelClient.markThreadUnread(String, String)` because marking a thread as unread from a given message is currently not supported. [#6027](https://github.com/GetStream/stream-chat-android/pull/6027)

### ❌ Removed

Expand Down
2 changes: 2 additions & 0 deletions DEPRECATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This document lists deprecated constructs in the SDK, with their expected time

| API / Feature | Deprecated (warning) | Deprecated (error) | Removed | Notes |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------|-----------------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `ChatClient.markThreadUnread(channelType: String, channelId: String, threadId: String, mesageId: String)` method | 2025.11.24 ⌛ | | | This method is deprecated because marking a thread as unread from a given message is currently not supported, and the passed `messageId` is ignored. Use `ChatClient.markThreadUnread(channelType: String, channelId: String, threadId: String)` instead. |
| `ChannelClient.markThreadUnread(threadId: String, mesageId: String)` method | 2025.11.24 ⌛ | | | This method is deprecated because marking a thread as unread from a given message is currently not supported, and the passed `messageId` is ignored. Use `ChannelClient.markThreadUnread(threadId: String)` instead. |
| `StatePluginConfig.backgroundSyncEnabled` property | 2025.11.24 ⌛ | | | This property has been deprecated and will be removed in the future. We recommend disabling it to avoid unnecessary background work. |
| `PollConfig(String, List<String>, String, VotingVisibility, Boolean, Int, Boolean, Boolean)` constructor | 2025.11.07 ⌛ | | | This constructor has been deprecated. Please use `PollConfig(String, List<PollOption>, String, VotingVisibility, Boolean, Int, Boolean, Boolean, Map<String, Any>)` instead. |
| `ChatClient.suggestPollOption(pollId: String, option: String)` method | 2025.11.07 ⌛ | | | This method has been deprecated. Please use `ChatClient.createPollOption(pollId: String, option: CreatePollOptionRequest)` instead. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,10 @@ public final class io/getstream/chat/android/client/ChatClient {
public final fun markMessageRead (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markRead (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markThreadRead (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markThreadUnread (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markThreadUnread (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markUnread (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markUnread (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;)Lio/getstream/result/call/Call;
public final fun muteChannel (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun muteChannel (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)Lio/getstream/result/call/Call;
public static synthetic fun muteChannel$default (Lio/getstream/chat/android/client/ChatClient;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILjava/lang/Object;)Lio/getstream/result/call/Call;
Expand Down Expand Up @@ -746,8 +748,10 @@ public final class io/getstream/chat/android/client/channel/ChannelClient {
public final fun markMessageRead (Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markRead ()Lio/getstream/result/call/Call;
public final fun markThreadRead (Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markThreadUnread (Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markThreadUnread (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markUnread (Ljava/lang/String;)Lio/getstream/result/call/Call;
public final fun markUnread (Ljava/util/Date;)Lio/getstream/result/call/Call;
public final fun mute ()Lio/getstream/result/call/Call;
public final fun mute (Ljava/lang/Integer;)Lio/getstream/result/call/Call;
public static synthetic fun mute$default (Lio/getstream/chat/android/client/channel/ChannelClient;Ljava/lang/Integer;ILjava/lang/Object;)Lio/getstream/result/call/Call;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3458,31 +3458,62 @@
channelId: String,
messageId: String,
): Call<Unit> {
return api.markUnread(channelType, channelId, messageId)
.doOnStart(userScope) {
logger.d { "[markUnread] #doOnStart; cid: $channelType:$channelId, msgId: $messageId" }
}
.doOnResult(userScope) {
logger.v { "[markUnread] #doOnResult; completed($channelType:$channelId, $messageId): $it" }
}
return api.markUnread(channelType, channelId, messageId = messageId)
}

/**
* Marks all messages in the channel as unread that were created after the specified timestamp.
*
* @param channelType Type of the channel.
* @param channelId Id of the channel.
* @param timestamp The timestamp used to find the first message to mark as unread.
*/
@CheckResult
public fun markUnread(
channelType: String,
channelId: String,
timestamp: Date,
): Call<Unit> {
return api.markUnread(channelType, channelId, messageTimestamp = timestamp)
}

/**
* Marks a given thread starting from the given message as unread.
* Marks a thread as unread.
*
* @param channelType Type of the channel.
* @param channelId Id of the channel.
* @param threadId Id of the thread to mark as unread.
*/
@CheckResult
public fun markThreadUnread(
channelType: String,
channelId: String,
threadId: String,
): Call<Unit> {
return api.markUnread(channelType, channelId, threadId = threadId)
}

/**
* Marks a thread as unread.
*
* @param channelType Type of the channel.
* @param channelId Id of the channel.
* @param threadId Id of the thread to mark as unread.
* @param messageId Id of the message from where the thread should be marked as unread.
*/
@Deprecated(
"Marking a thread as unread from a given message is currently not supported. " +
"Passing messageId has no effect and the whole thread is marked as unread." +
"Use markThreadUnread(channelType, channelId, threadId) instead.",
)
@CheckResult
public fun markThreadUnread(

Check warning on line 3510 in stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-android&issues=AZrVbeymMjhEhvu4bS_y&open=AZrVbeymMjhEhvu4bS_y&pullRequest=6027
channelType: String,
channelId: String,
threadId: String,
messageId: String,
): Call<Unit> {
return api.markThreadUnread(channelType, channelId, threadId = threadId, messageId = messageId)
return api.markUnread(channelType, channelId, messageId = messageId, threadId = threadId)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,9 @@ internal interface ChatApi {
fun markUnread(
channelType: String,
channelId: String,
messageId: String,
): Call<Unit>

@CheckResult
fun markThreadUnread(
channelType: String,
channelId: String,
threadId: String,
messageId: String,
messageId: String? = null,
messageTimestamp: Date? = null,
threadId: String? = null,
): Call<Unit>

@CheckResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -978,28 +978,19 @@ constructor(
).toUnitCall()
}

override fun markUnread(channelType: String, channelId: String, messageId: String): Call<Unit> {
return channelApi.markUnread(
channelType = channelType,
channelId = channelId,
request = MarkUnreadRequest(messageId),
).toUnitCall()
}

override fun markThreadUnread(
override fun markUnread(
channelType: String,
channelId: String,
threadId: String,
messageId: String,
messageId: String?,
messageTimestamp: Date?,
threadId: String?,
): Call<Unit> {
return channelApi.markUnread(
channelType = channelType,
channelId = channelId,
request = MarkUnreadRequest(
thread_id = threadId,
message_id = messageId,
),
).toUnitCall()
val request = MarkUnreadRequest(
message_id = messageId,
message_timestamp = messageTimestamp,
thread_id = threadId,
)
return channelApi.markUnread(channelType, channelId, request).toUnitCall()
}

override fun markAllRead(): Call<Unit> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package io.getstream.chat.android.client.api2.model.requests

import com.squareup.moshi.JsonClass
import java.util.Date

@JsonClass(generateAdapter = true)
internal data class MarkUnreadRequest(
val message_id: String,
val message_id: String? = null,

Check warning on line 24 in stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/MarkUnreadRequest.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this parameter to match the regular expression ^`?[_a-z][a-zA-Z0-9]*`?$

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-android&issues=AZrVbesWMjhEhvu4bS_u&open=AZrVbesWMjhEhvu4bS_u&pullRequest=6027
val message_timestamp: Date? = null,

Check warning on line 25 in stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/MarkUnreadRequest.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this parameter to match the regular expression ^`?[_a-z][a-zA-Z0-9]*`?$

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-android&issues=AZrVbesWMjhEhvu4bS_v&open=AZrVbesWMjhEhvu4bS_v&pullRequest=6027
val thread_id: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -473,15 +473,40 @@
return client.markUnread(channelType, channelId, messageId)
}

/**
* Marks all messages in the channel as unread that were created after the specified timestamp.
*
* @param timestamp The timestamp used to find the first message to mark as unread.
*/
@CheckResult
public fun markUnread(timestamp: Date): Call<Unit> {
return client.markUnread(channelType, channelId, timestamp)
}

/**
* Marks a given thread in the channel as unread.
*
* @param threadId Id of the thread to mark as unread.
*/
@CheckResult
public fun markThreadUnread(threadId: String): Call<Unit> {
return client.markThreadUnread(channelType, channelId, threadId = threadId)
}

/**
* Marks a given thread in the channel starting from the given message as unread.
*
* @param messageId Id of the message from where the thread should be marked as unread.
* @param threadId Id of the thread to mark as unread.
*/
@Deprecated(
"Marking a thread as unread from a given message is currently not supported. " +
"Passing messageId has no effect and the whole thread is marked as unread." +
"Use markThreadUnread(channelType, channelId, threadId) instead.",
)
@CheckResult
public fun markThreadUnread(threadId: String, messageId: String): Call<Unit> {

Check warning on line 508 in stream-chat-android-client/src/main/java/io/getstream/chat/android/client/channel/ChannelClient.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-android&issues=AZrVbew0MjhEhvu4bS_w&open=AZrVbew0MjhEhvu4bS_w&pullRequest=6027
return client.markThreadUnread(channelType, channelId, threadId = threadId, messageId = messageId)

Check warning on line 509 in stream-chat-android-client/src/main/java/io/getstream/chat/android/client/channel/ChannelClient.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Deprecated code should not be used.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-android&issues=AZrVbew0MjhEhvu4bS_x&open=AZrVbew0MjhEhvu4bS_x&pullRequest=6027
}

@CheckResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ internal class ChatClientChannelApiTests : BaseChatClientTest() {
}

@Test
fun markUnreadSuccess() = runTest {
fun markUnreadFromMessageSuccess() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
Expand All @@ -1090,7 +1090,7 @@ internal class ChatClientChannelApiTests : BaseChatClientTest() {
}

@Test
fun markUnreadError() = runTest {
fun markUnreadFromMessageError() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
Expand All @@ -1105,6 +1105,37 @@ internal class ChatClientChannelApiTests : BaseChatClientTest() {
verifyNetworkError(result, errorCode)
}

@Test
fun markUnreadFromTimestampSuccess() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
val timestamp = randomDate()
val sut = Fixture()
.givenMarkUnreadResult(RetroSuccess(Unit).toRetrofitCall())
.get()
// when
val result = sut.markUnread(channelType, channelId, timestamp).await()
// then
verifySuccess(result, Unit)
}

@Test
fun markUnreadFromTimestampError() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
val timestamp = randomDate()
val errorCode = positiveRandomInt()
val sut = Fixture()
.givenMarkUnreadResult(RetroError<Unit>(errorCode).toRetrofitCall())
.get()
// when
val result = sut.markUnread(channelType, channelId, timestamp).await()
// then
verifyNetworkError(result, errorCode)
}

@Test
fun markThreadReadSuccess() = runTest {
// given
Expand Down Expand Up @@ -1138,13 +1169,44 @@ internal class ChatClientChannelApiTests : BaseChatClientTest() {

@Test
fun markThreadUnreadSuccess() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
val threadId = randomString()
val sut = Fixture()
.givenMarkUnreadResult(RetroSuccess(Unit).toRetrofitCall())
.get()
// when
val result = sut.markThreadUnread(channelType, channelId, threadId).await()
// then
verifySuccess(result, Unit)
}

@Test
fun markThreadUnreadError() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
val threadId = randomString()
val errorCode = positiveRandomInt()
val sut = Fixture()
.givenMarkUnreadResult(RetroError<Unit>(errorCode).toRetrofitCall())
.get()
// when
val result = sut.markThreadUnread(channelType, channelId, threadId).await()
// then
verifyNetworkError(result, errorCode)
}

@Test
fun markThreadUnreadFromMessageSuccess() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
val threadId = randomString()
val messageId = randomString()
val sut = Fixture()
.givenMarkThreadUnreadResult(RetroSuccess(Unit).toRetrofitCall())
.givenMarkUnreadResult(RetroSuccess(Unit).toRetrofitCall())
.get()
// when
val result = sut.markThreadUnread(channelType, channelId, threadId, messageId).await()
Expand All @@ -1153,15 +1215,15 @@ internal class ChatClientChannelApiTests : BaseChatClientTest() {
}

@Test
fun markThreadUnreadError() = runTest {
fun markThreadUnreadFromMessageError() = runTest {
// given
val channelType = randomString()
val channelId = randomString()
val threadId = randomString()
val messageId = randomString()
val errorCode = positiveRandomInt()
val sut = Fixture()
.givenMarkThreadUnreadResult(RetroError<Unit>(errorCode).toRetrofitCall())
.givenMarkUnreadResult(RetroError<Unit>(errorCode).toRetrofitCall())
.get()
// when
val result = sut.markThreadUnread(channelType, channelId, threadId, messageId).await()
Expand Down Expand Up @@ -1648,17 +1710,13 @@ internal class ChatClientChannelApiTests : BaseChatClientTest() {
}

fun givenMarkUnreadResult(result: Call<Unit>) = apply {
whenever(api.markUnread(any(), any(), any())).thenReturn(result)
whenever(api.markUnread(any(), any(), anyOrNull(), anyOrNull(), anyOrNull())).thenReturn(result)
}

fun givenMarkThreadReadResult(result: Call<Unit>) = apply {
whenever(api.markThreadRead(any(), any(), any())).thenReturn(result)
}

fun givenMarkThreadUnreadResult(result: Call<Unit>) = apply {
whenever(api.markThreadUnread(any(), any(), any(), any())).thenReturn(result)
}

fun givenStopWatchingResult(result: Call<Unit>) = apply {
whenever(api.stopWatching(any(), any())).thenReturn(result)
}
Expand Down
Loading
Loading