Skip to content

Commit 9b737d8

Browse files
committed
Automatically mark messages as delivered when querying channels
Introduced a `MessageDeliveredPlugin` that automatically marks messages as delivered upon a successful `queryChannels` call. This plugin is enabled by default.
1 parent cf4565d commit 9b737d8

File tree

4 files changed

+156
-1
lines changed

4 files changed

+156
-1
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ import io.getstream.chat.android.client.persistance.repository.RepositoryFacade
123123
import io.getstream.chat.android.client.persistance.repository.factory.RepositoryFactory
124124
import io.getstream.chat.android.client.persistance.repository.noop.NoOpRepositoryFactory
125125
import io.getstream.chat.android.client.plugin.DependencyResolver
126+
import io.getstream.chat.android.client.plugin.MessageDeliveredPluginFactory
126127
import io.getstream.chat.android.client.plugin.Plugin
127128
import io.getstream.chat.android.client.plugin.factory.PluginFactory
128129
import io.getstream.chat.android.client.plugin.factory.ThrottlingPluginFactory
@@ -4817,7 +4818,10 @@ internal constructor(
48174818
* @see [Plugin]
48184819
* @see [PluginFactory]
48194820
*/
4820-
protected val pluginFactories: MutableList<PluginFactory> = mutableListOf(ThrottlingPluginFactory)
4821+
protected val pluginFactories: MutableList<PluginFactory> = mutableListOf(
4822+
ThrottlingPluginFactory,
4823+
MessageDeliveredPluginFactory,
4824+
)
48214825

48224826
/**
48234827
* Create a [ChatClient] instance based on the current configuration
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2014-2025 Stream.io Inc. All rights reserved.
3+
*
4+
* Licensed under the Stream License;
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.getstream.chat.android.client.plugin
18+
19+
import io.getstream.chat.android.client.ChatClient
20+
import io.getstream.chat.android.client.api.models.QueryChannelsRequest
21+
import io.getstream.chat.android.client.plugin.factory.PluginFactory
22+
import io.getstream.chat.android.client.receipts.MessageReceiptManager
23+
import io.getstream.chat.android.models.Channel
24+
import io.getstream.chat.android.models.User
25+
import io.getstream.result.Result
26+
27+
/**
28+
* A plugin that marks messages as delivered when channels are queried.
29+
*/
30+
internal class MessageDeliveredPlugin(
31+
chatClient: ChatClient = ChatClient.instance(),
32+
private val messageReceiptManager: MessageReceiptManager = chatClient.messageReceiptManager,
33+
) : Plugin {
34+
override suspend fun onQueryChannelsResult(result: Result<List<Channel>>, request: QueryChannelsRequest) {
35+
result.onSuccess { channels ->
36+
messageReceiptManager.markChannelsAsDelivered(channels)
37+
}
38+
}
39+
}
40+
41+
internal object MessageDeliveredPluginFactory : PluginFactory {
42+
override fun get(user: User): Plugin = MessageDeliveredPlugin()
43+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2014-2025 Stream.io Inc. All rights reserved.
3+
*
4+
* Licensed under the Stream License;
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.getstream.chat.android.client.plugin
18+
19+
import io.getstream.chat.android.client.ChatClient
20+
import org.junit.Test
21+
import org.junit.jupiter.api.assertInstanceOf
22+
import org.mockito.kotlin.doReturn
23+
import org.mockito.kotlin.mock
24+
25+
internal class MessageDeliveredPluginFactoryTest {
26+
27+
@Test
28+
fun `factory should create MessageDeliveredPlugin`() {
29+
val mockChatClient = mock<ChatClient> { on { messageReceiptManager } doReturn mock() }
30+
object : ChatClient.ChatClientBuilder() {
31+
override fun internalBuild(): ChatClient = mockChatClient
32+
}.build()
33+
34+
val actual = MessageDeliveredPluginFactory.get(mock())
35+
36+
assertInstanceOf<MessageDeliveredPlugin>(actual)
37+
}
38+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2014-2025 Stream.io Inc. All rights reserved.
3+
*
4+
* Licensed under the Stream License;
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://github.com/GetStream/stream-chat-android/blob/main/LICENSE
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.getstream.chat.android.client.plugin
18+
19+
import io.getstream.chat.android.client.receipts.MessageReceiptManager
20+
import io.getstream.chat.android.models.Channel
21+
import io.getstream.chat.android.randomChannel
22+
import io.getstream.result.Result
23+
import kotlinx.coroutines.test.runTest
24+
import org.junit.Test
25+
import org.mockito.kotlin.any
26+
import org.mockito.kotlin.mock
27+
import org.mockito.kotlin.never
28+
import org.mockito.kotlin.times
29+
import org.mockito.kotlin.verify
30+
import org.mockito.verification.VerificationMode
31+
32+
internal class MessageDeliveredPluginTest {
33+
34+
@Test
35+
fun `on query channels with successful result, should mark channels as delivered`() = runTest {
36+
val channels = listOf(randomChannel())
37+
val fixture = Fixture()
38+
val sut = fixture.get()
39+
40+
sut.onQueryChannelsResult(result = Result.Success(channels), request = mock())
41+
42+
fixture.verifyMarkChannelsAsDeliveredCalled(channels = channels)
43+
}
44+
45+
@Test
46+
fun `on query channels with failure result, should not mark channels as delivered`() = runTest {
47+
val fixture = Fixture()
48+
val sut = fixture.get()
49+
50+
sut.onQueryChannelsResult(result = Result.Failure(mock()), request = mock())
51+
52+
fixture.verifyMarkChannelsAsDeliveredCalled(never())
53+
}
54+
55+
private class Fixture {
56+
private val mockMessageReceiptManager = mock<MessageReceiptManager>()
57+
58+
fun verifyMarkChannelsAsDeliveredCalled(
59+
mode: VerificationMode = times(1),
60+
channels: List<Channel>? = null,
61+
) {
62+
verify(mockMessageReceiptManager, mode).markChannelsAsDelivered(channels ?: any())
63+
}
64+
65+
fun get() = MessageDeliveredPlugin(
66+
chatClient = mock(),
67+
messageReceiptManager = mockMessageReceiptManager,
68+
)
69+
}
70+
}

0 commit comments

Comments
 (0)