Skip to main content
The UI Kit is split into three modules that follow Clean Architecture principles. chatuikit-core holds all business logic, data access, and state management. The UI modules (chatuikit-jetpack and chatuikit-kotlin) provide platform-specific rendering on top of the shared core.

Module Structure

4-Layer Architecture

Every feature follows the same layered flow: View → ViewModel → Repository → DataSource. The ViewModel lives in chatuikit-core and is shared by both UI modules. This means the same CometChatConversationsViewModel drives both the XML View and the Composable — only the rendering layer differs.

Clean Architecture Layers (chatuikit-core)

Data Layer

The data layer wraps the CometChat SDK behind interfaces, making it swappable and testable. DataSource — defines the contract for raw SDK operations:
Every feature has a DataSource pair: ConversationsDataSource / ConversationsDataSourceImpl, UsersDataSource / UsersDataSourceImpl, etc. Repository Implementation — coordinates data sources and handles error wrapping:
Repositories wrap raw SDK exceptions into Kotlin Result types, track pagination state, and coordinate between data sources.

Domain Layer

The domain layer defines contracts and single-purpose use cases. It has no dependency on the SDK or Android framework. Repository Interfaces — contracts that the data layer implements:
Use Cases — encapsulate a single business action:
Use cases are open so they can be overridden for testing or custom behavior. Each use case does one thing:

ViewModel Layer

ViewModels receive use cases via constructor injection and expose StateFlow / sealed UIState classes to the UI:

State Management (StateFlow + Sealed Classes)

Each feature has a dedicated sealed UIState class. All state is exposed via StateFlow — not LiveData:
Feature-specific states include additional fields:

ListOperations Interface

List-based ViewModels implement the ListOperations interface, which provides a standard contract for manipulating list data:
This ensures consistent list manipulation across Conversations, Users, Groups, Group Members, and Call Logs.

Dependency Injection via Factories

ViewModels are created through ViewModelProvider.Factory classes that wire up the dependency chain:
Default implementations are provided, but you can inject custom repositories:

Data Flow: End to End

Fetching Conversations

Real-Time Updates

User Action (Delete Conversation)

Component ↔ Core Mapping

Events (Cross-Component Communication)

The CometChatEvents singleton in chatuikit-core provides a typed event bus using Kotlin SharedFlow for communication between components that don’t share a ViewModel: See the Events reference for sealed class types and subscription examples.

Component-Level Overrides

Every layer in the architecture is designed to be replaceable. You can override at the level that makes sense for your use case — from swapping the entire data source to just tweaking a single use case.

Override Points

1. Custom Repository

The most common override. Implement the repository interface and pass it to the factory.
Wire it in:

2. Custom DataSource

Override at the lowest level to change how SDK calls are made — useful for caching, offline support, or wrapping a different backend.
Then wrap it in the default repository implementation:

3. Custom Use Cases

Use cases are open classes, so you can subclass them to add validation, logging, or transformation:

4. Passing a Custom ViewModel to the UI Component

Both chatuikit-jetpack (Compose) and chatuikit-kotlin (XML Views) accept a pre-built ViewModel. This is the entry point for all overrides.

5. Disabling Listeners for Previews and Testing

Every factory accepts enableListeners = false. When disabled, the ViewModel won’t register SDK listeners or UIKit event subscriptions — useful for Compose previews, unit tests, or showcase screens:

Override Summary by Component

  • Events — Cross-component communication via CometChatEvents SharedFlow
  • Methods — UI Kit wrapper methods for init, auth, and messaging