Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9085015
Delete unused classes.
VelikovPetar Jan 2, 2026
5740d7a
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Jan 5, 2026
a5e8076
Move state support to LLC.
VelikovPetar Jan 5, 2026
214ff8a
Revert wrong commit.
VelikovPetar Jan 5, 2026
1090023
Merge remote-tracking branch 'origin/feature/AND-775_move_state_suppo…
VelikovPetar Jan 5, 2026
deaf276
Post merge fix.
VelikovPetar Jan 5, 2026
ee16527
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Jan 6, 2026
f5708fa
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Jan 8, 2026
144ddc2
Post merge fixes.
VelikovPetar Jan 8, 2026
5c83deb
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Jan 14, 2026
c044078
Post merge cleanup.
VelikovPetar Jan 14, 2026
6bc4e45
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Jan 26, 2026
515ab69
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Feb 4, 2026
21057cd
Post-merge cleanup
VelikovPetar Feb 4, 2026
a954d10
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Feb 9, 2026
c2aa491
Post-merge clean-up
VelikovPetar Feb 9, 2026
e251b13
Post-merge clean-up
VelikovPetar Feb 9, 2026
89bddc0
Remove unused logger.
VelikovPetar Feb 10, 2026
1e8debe
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Feb 10, 2026
aed5e31
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Feb 12, 2026
bf06b1a
Merge branch 'v7' into feature/AND-775_move_state_support_to_client
VelikovPetar Feb 13, 2026
e2d7a48
ApiDump.
VelikovPetar Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ stream-chat-android-offline @GetStream/android-developers
stream-chat-android-pushprovider-firebase @GetStream/android-developers
stream-chat-android-pushprovider-huawei @GetStream/android-developers
stream-chat-android-pushprovider-xiaomi @GetStream/android-developers
stream-chat-android-state @GetStream/android-developers
stream-chat-android-test @GetStream/android-developers

# UI
Expand Down
3 changes: 1 addition & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ This project delivers **Stream Chat Android**, a modular SDK spanning low-level
- Testing: JUnit4/5, Mockito-Kotlin, Turbine, Robolectric, Espresso, Paparazzi, Shot

## Project structure
- `stream-chat-android-client/` – core API client, REST/WebSocket, plugin hooks
- `stream-chat-android-client/` – core API client, REST/WebSocket, plugin hooks, state container
- `stream-chat-android-offline/` – persistence, sync, caching, retry workers
- `stream-chat-android-state/` – state container shared by UI layers
- `stream-chat-android-ui-common/` – theming, assets, shared UI helpers
- `stream-chat-android-compose/` & `stream-chat-android-ui-components/` – Compose and XML UI kits
- `*-sample/`, `stream-chat-android-ui-uitests/`, `stream-chat-android-test/` – samples, integration, and shared test harnesses
Expand Down
11 changes: 0 additions & 11 deletions CHANGELOG_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@

### ❌ Removed

## stream-chat-android-state
### 🐞 Fixed

### ⬆️ Improved

### ✅ Added

### ⚠️ Changed

### ❌ Removed

## stream-chat-android-ui-common
### 🐞 Fixed

Expand Down
1 change: 0 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ If you haven't already, make sure to read our [README](https://github.com/GetStr
- `stream-chat-android-client`: Holds all the code connected to the **low-level-client**, used to request data from and send information to the API.
- `stream-chat-android-offline`: As an addition to the **client** module, you can use **offline** to introduce persistence and caching to your app.
- `stream-chat-android-ui-common`: Common UI-related code and utility functions.
- `stream-chat-android-state`: Module that contains common state-related API and functionality, such as syncing and persisting state and various messages.

- `stream-chat-android-compose-sample`: The main sample app featuring the Compose SDK.
- `stream-chat-android-compose`: Our Compose SDK that features channels and messages components, as well as other utilities.
Expand Down
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ streamProject {
"stream-chat-android-core",
"stream-chat-android-markdown-transformer",
"stream-chat-android-offline",
"stream-chat-android-state",
"stream-chat-android-ui-common",
)
}
Expand Down
4 changes: 2 additions & 2 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,10 @@ end

private_lane :sources_matrix do
{
unit: ['stream-chat-android-test', 'stream-chat-android-client', 'stream-chat-android-compose/', 'stream-chat-android-core', 'stream-chat-android-markdown-transformer', 'stream-chat-android-offline', 'stream-chat-android-state', 'stream-chat-android-ui-common', 'stream-chat-android-ui-components/'],
unit: ['stream-chat-android-test', 'stream-chat-android-client', 'stream-chat-android-compose/', 'stream-chat-android-core', 'stream-chat-android-markdown-transformer', 'stream-chat-android-offline', 'stream-chat-android-ui-common', 'stream-chat-android-ui-components/'],
ui: ['stream-chat-android-ui', '.github/workflows/snapshot-test'],
e2e: ['buildSrc', 'stream-chat-android', '.github/workflows/e2e-test'],
sonar: ['stream-chat-android-client/', 'stream-chat-android-compose/', 'stream-chat-android-core/', 'stream-chat-android-markdown-transformer/', 'stream-chat-android-offline/', 'stream-chat-android-state/', 'stream-chat-android-ui-common/', 'stream-chat-android-ui-components/'],
sonar: ['stream-chat-android-client/', 'stream-chat-android-compose/', 'stream-chat-android-core/', 'stream-chat-android-markdown-transformer/', 'stream-chat-android-offline/', 'stream-chat-android-ui-common/', 'stream-chat-android-ui-components/'],
ruby: ['fastlane', 'Gemfile', 'Gemfile.lock']
}
end
Expand Down
5 changes: 2 additions & 3 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ plugins {
id("com.gradle.enterprise") version "3.7"
}
include (
":stream-chat-android-ui-common",
":stream-chat-android-ui-common",
":stream-chat-android-ui-components",
":stream-chat-android-ui-components-sample",
":stream-chat-android-ui-guides",
":stream-chat-android-state",
":stream-chat-android-offline",
":stream-chat-android-offline",
":stream-chat-android-client",
":stream-chat-android-client-test",
":stream-chat-android-core",
Expand Down
255 changes: 254 additions & 1 deletion stream-chat-android-client/api/stream-chat-android-client.api

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions stream-chat-android-client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,14 @@ dependencies {
testImplementation(project(":stream-chat-android-client-test"))
testImplementation(testFixtures(project(":stream-chat-android-core")))
testImplementation(libs.stream.result)
testImplementation(libs.androidx.core.testing)
testImplementation(libs.androidx.test.core)
testImplementation(libs.androidx.test.junit)
testImplementation(libs.androidx.lifecycle.runtime.testing)
testImplementation(libs.androidx.work.testing)
testImplementation(libs.junit.jupiter.api)
testImplementation(libs.junit.jupiter.params)
testImplementation(libs.moshi.kotlin)
testImplementation(libs.turbine)
testRuntimeOnly(libs.junit.jupiter.engine)
testRuntimeOnly(libs.junit.vintage.engine)
Expand All @@ -125,6 +128,7 @@ dependencies {

// Instrumentation tests
androidTestImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.core)
androidTestImplementation(libs.androidx.test.espresso.core)
androidTestImplementation(libs.androidx.test.junit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import io.getstream.chat.android.client.ChatClient.Companion.MAX_COOLDOWN_TIME_S
import io.getstream.chat.android.client.api.ChatApi
import io.getstream.chat.android.client.api.ChatClientConfig
import io.getstream.chat.android.client.api.ErrorCall
import io.getstream.chat.android.client.api.StateConfig
import io.getstream.chat.android.client.api.models.GetThreadOptions
import io.getstream.chat.android.client.api.models.PinnedMessagesPagination
import io.getstream.chat.android.client.api.models.QueryChannelRequest
Expand Down Expand Up @@ -108,6 +109,7 @@ import io.getstream.chat.android.client.helpers.CallPostponeHelper
import io.getstream.chat.android.client.interceptor.SendMessageInterceptor
import io.getstream.chat.android.client.interceptor.message.internal.PrepareMessageLogicImpl
import io.getstream.chat.android.client.internal.file.StreamFileManager
import io.getstream.chat.android.client.internal.state.plugin.factory.StreamStatePluginFactory
import io.getstream.chat.android.client.logger.ChatLogLevel
import io.getstream.chat.android.client.logger.ChatLoggerConfigImpl
import io.getstream.chat.android.client.logger.ChatLoggerHandler
Expand Down Expand Up @@ -4697,6 +4699,8 @@ internal constructor(
private var retryPolicy: RetryPolicy = NoRetryPolicy()
private var distinctApiCalls: Boolean = true
private var debugRequests: Boolean = false
private var pluginFactories: List<PluginFactory> = emptyList()
private var stateConfig: StateConfig = StateConfig()
private var repositoryFactoryProvider: RepositoryFactory.Provider? = null
private var uploadAttachmentsNetworkType = UploadAttachmentsNetworkType.CONNECTED
private var fileTransformer: FileTransformer = NoOpFileTransformer
Expand Down Expand Up @@ -4931,7 +4935,16 @@ internal constructor(
* @param pluginFactories The factories to be added.
*/
public fun withPlugins(vararg pluginFactories: PluginFactory): Builder = apply {
this.pluginFactories.addAll(pluginFactories)
this.pluginFactories = pluginFactories.asList()
}

/**
* Specifies the state management configuration.
*
* @param config The state configuration to be used.
*/
public fun stateConfig(config: StateConfig): Builder = apply {
stateConfig = config
}

/**
Expand Down Expand Up @@ -5074,6 +5087,11 @@ internal constructor(
val database = ChatClientDatabase.build(appContext)
val repository = ChatClientRepository.from(database)

val allPluginFactories = setupPluginFactories(
userProvided = pluginFactories,
stateConfig = stateConfig,
)

return ChatClient(
config = config,
api = api,
Expand All @@ -5088,9 +5106,9 @@ internal constructor(
retryPolicy = retryPolicy,
appSettingsManager = appSettingsManager,
chatSocket = module.chatSocket,
pluginFactories = pluginFactories,
pluginFactories = allPluginFactories,
repositoryFactoryProvider = repositoryFactoryProvider
?: pluginFactories
?: allPluginFactories
.filterIsInstance<RepositoryFactory.Provider>()
.firstOrNull()
?: NoOpRepositoryFactory.Provider,
Expand Down Expand Up @@ -5119,6 +5137,21 @@ internal constructor(
}
}

private fun setupPluginFactories(
userProvided: List<PluginFactory>,
stateConfig: StateConfig,
): List<PluginFactory> {
return buildList {
// Mandatory plugins first
add(ThrottlingPluginFactory)
add(MessageDeliveredPluginFactory)
// Then user provided plugins
addAll(userProvided)
// Finally state plugin
add(StreamStatePluginFactory(stateConfig, appContext))
}
}

private fun setupStreamLog() {
if (!StreamLog.isInstalled && logLevel != ChatLogLevel.NOTHING) {
StreamLog.setValidator(StreamLogLevelValidator(logLevel))
Expand Down Expand Up @@ -5147,16 +5180,6 @@ internal constructor(
}

public abstract class ChatClientBuilder @InternalStreamChatApi public constructor() {
/**
* Factories of plugins that will be added to the SDK.
*
* @see [Plugin]
* @see [PluginFactory]
*/
protected val pluginFactories: MutableList<PluginFactory> = mutableListOf(
ThrottlingPluginFactory,
MessageDeliveredPluginFactory,
)

/**
* Create a [ChatClient] instance based on the current configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@
* limitations under the License.
*/

package io.getstream.chat.android.state.plugin.config
package io.getstream.chat.android.client.api

import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.client.setup.state.ClientState
import io.getstream.chat.android.models.TimeDuration
import io.getstream.chat.android.state.extensions.queryChannelsAsState
import io.getstream.chat.android.state.extensions.watchChannelAsState
import io.getstream.chat.android.state.plugin.internal.StatePlugin

/**
* Provides a configuration for [io.getstream.chat.android.state.plugin.internal.StatePlugin].
Expand Down Expand Up @@ -79,7 +76,7 @@ import io.getstream.chat.android.state.plugin.internal.StatePlugin
* By default, no limits are applied, meaning all messages are kept in memory. See [MessageLimitConfig] and
* [ChannelMessageLimit] for configuration details.
*/
public data class StatePluginConfig @JvmOverloads constructor(
public data class StateConfig @JvmOverloads constructor(
@Deprecated(
"The background sync on push notification is no longer needed to keep the state in sync and " +
"will be removed in the future. If you are using the default UI components, or building your own UI " +
Expand All @@ -89,7 +86,7 @@ public data class StatePluginConfig @JvmOverloads constructor(
public val backgroundSyncEnabled: Boolean = true,
public val userPresence: Boolean = true,
public val isAutomaticSyncOnReconnectEnabled: Boolean = true,
public val syncMaxThreshold: TimeDuration = TimeDuration.hours(12),
public val syncMaxThreshold: TimeDuration = TimeDuration.hours(hours = 12),
public val now: () -> Long = { System.currentTimeMillis() },
public val messageLimitConfig: MessageLimitConfig = MessageLimitConfig(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package io.getstream.chat.android.state.event.handler.chat
package io.getstream.chat.android.client.api.event

import io.getstream.chat.android.client.events.ChannelDeletedEvent
import io.getstream.chat.android.client.events.ChannelHiddenEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@
* limitations under the License.
*/

package io.getstream.chat.android.state.event.handler.chat.factory
package io.getstream.chat.android.client.api.event

import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.client.setup.state.ClientState
import io.getstream.chat.android.models.Channel
import io.getstream.chat.android.state.event.handler.chat.ChatEventHandler
import io.getstream.chat.android.state.event.handler.chat.DefaultChatEventHandler
import kotlinx.coroutines.flow.StateFlow

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package io.getstream.chat.android.state.event.handler.chat
package io.getstream.chat.android.client.api.event

import io.getstream.chat.android.client.events.ChatEvent
import io.getstream.chat.android.client.events.CidEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package io.getstream.chat.android.state.plugin.state.querychannels
package io.getstream.chat.android.client.api.state

import io.getstream.chat.android.models.Channel

Expand All @@ -37,7 +37,9 @@ public sealed class ChannelsStateData {
override fun toString(): String = "ChannelsStateData.Loading"
}

/** If we are offline and don't have channels stored in offline storage, typically displayed as an error condition. */
/**
* If we are offline and don't have channels stored in offline storage, typically displayed as an error condition.
*/
public object OfflineNoResults : ChannelsStateData() {
override fun toString(): String = "ChannelsStateData.OfflineNoResults"
}
Expand Down
Loading
Loading