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 inchatuikit-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:ConversationsDataSource / ConversationsDataSourceImpl, UsersDataSource / UsersDataSourceImpl, etc.
Repository Implementation — coordinates data sources and handles error wrapping:
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: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 exposeStateFlow / sealed UIState classes to the UI:
State Management (StateFlow + Sealed Classes)
Each feature has a dedicated sealed UIState class. All state is exposed viaStateFlow — not LiveData:
ListOperations Interface
List-based ViewModels implement theListOperations interface, which provides a standard contract for manipulating list data:
Dependency Injection via Factories
ViewModels are created throughViewModelProvider.Factory classes that wire up the dependency chain:
Data Flow: End to End
Fetching Conversations
Real-Time Updates
User Action (Delete Conversation)
Component ↔ Core Mapping
Events (Cross-Component Communication)
TheCometChatEvents 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.- Kotlin (XML Views)
- Jetpack Compose
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.3. Custom Use Cases
Use cases areopen classes, so you can subclass them to add validation, logging, or transformation:
4. Passing a Custom ViewModel to the UI Component
Bothchatuikit-jetpack (Compose) and chatuikit-kotlin (XML Views) accept a pre-built ViewModel. This is the entry point for all overrides.
- Kotlin (XML Views)
- Jetpack Compose
5. Disabling Listeners for Previews and Testing
Every factory acceptsenableListeners = false. When disabled, the ViewModel won’t register SDK listeners or UIKit event subscriptions — useful for Compose previews, unit tests, or showcase screens: