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.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: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:
| Use Case | Action |
|---|---|
GetConversationsUseCase | Fetch paginated conversations |
DeleteConversationUseCase | Delete a conversation |
RefreshConversationsUseCase | Clear and re-fetch |
FetchUsersUseCase / SearchUsersUseCase | Fetch or search users |
FetchGroupsUseCase | Fetch groups |
FetchGroupMembersUseCase / SearchGroupMembersUseCase | Fetch or search group members |
BanGroupMemberUseCase / KickGroupMemberUseCase | Member moderation |
ChangeMemberScopeUseCase | Change member role |
SendTextMessageUseCase / SendMediaMessageUseCase / SendCustomMessageUseCase | Send messages |
EditMessageUseCase | Edit a sent message |
FetchCallLogsUseCase | Fetch call history |
InitiateCallUseCase / InitiateUserCallUseCase / StartGroupCallUseCase | Start calls |
FetchReactionsUseCase / RemoveReactionUseCase | Reaction management |
CreatePollUseCase | Create a poll |
GetStickersUseCase | Fetch sticker sets |
JoinGroupUseCase / GetGroupUseCase / GetUserUseCase | Entity lookups |
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:
| State Class | Feature | Extra Fields |
|---|---|---|
ConversationStarterUIState | Conversation list | — |
MessageListUIState | Message list | scroll position, reply state |
MessageComposerUIState | Composer | attachment state, edit mode |
MessageHeaderUIState | Header | typing indicator, user status |
GroupsUIState | Groups | — |
UsersUIState | Users | — |
GroupMembersUIState | Group members | scope change state |
CallLogsUIState | Call logs | — |
CallButtonsUIState | Call buttons | call initiation state |
IncomingCallUIState / OutgoingCallUIState / OngoingCallUIState | Calls | call session state |
ReactionListUIState | Reactions | — |
CreatePollUIState | Polls | form validation state |
StickerKeyboardUIState | Stickers | sticker sets |
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
| UI Component | Core ViewModel | Use Cases | Repository | DataSource |
|---|---|---|---|---|
| Conversation List | CometChatConversationsViewModel | Get, Delete, Refresh | ConversationsRepository | ConversationsDataSource |
| Message List | CometChatMessageListViewModel | (message fetching) | MessageListRepository | MessageListDataSource |
| Message Composer | CometChatMessageComposerViewModel | SendText, SendMedia, SendCustom, Edit | MessageComposerRepository | MessageComposerDataSource |
| Message Header | CometChatMessageHeaderViewModel | — | MessageHeaderRepository | MessageHeaderDataSource |
| Users | CometChatUsersViewModel | FetchUsers, SearchUsers | UsersRepository | UsersDataSource |
| Groups | CometChatGroupsViewModel | FetchGroups, JoinGroup | GroupsRepository | GroupsDataSource |
| Group Members | CometChatGroupMembersViewModel | FetchMembers, Search, Ban, Kick, ChangeScope | GroupMembersRepository | GroupMembersDataSource |
| Call Logs | CometChatCallLogsViewModel | FetchCallLogs | CallLogsRepository | CallLogsDataSource |
| Call Buttons | CometChatCallButtonsViewModel | InitiateCall, StartGroupCall | CallButtonsRepository | CallButtonsDataSource |
| Reactions | CometChatReactionListViewModel | FetchReactions, RemoveReaction | ReactionListRepository | ReactionListDataSource |
| Message Info | CometChatMessageInformationViewModel | — | MessageInformationRepository | MessageInformationDataSource |
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:
| Event Flow | Emitted When |
|---|---|
CometChatEvents.messageEvents | Message sent, edited, deleted, reacted |
CometChatEvents.conversationEvents | Conversation deleted |
CometChatEvents.groupEvents | Group created, member added/removed/banned |
CometChatEvents.userEvents | User blocked/unblocked |
CometChatEvents.callEvents | Call initiated, accepted, rejected |
CometChatEvents.uiEvents | UI-level events (show dialog, navigate) |
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:
Override Summary by Component
| Component | Factory Class | Repository Interface | Key Use Cases |
|---|---|---|---|
| Conversation List | CometChatConversationsViewModelFactory | ConversationsRepository | Get, Delete, Refresh |
| Users | CometChatUsersViewModelFactory | UsersRepository | FetchUsers, SearchUsers |
| Groups | CometChatGroupsViewModelFactory | GroupsRepository | FetchGroups, JoinGroup |
| Group Members | CometChatGroupMembersViewModelFactory | GroupMembersRepository | FetchMembers, Search, Ban, Kick, ChangeScope |
| Message List | CometChatMessageListViewModelFactory | MessageListRepository | (message fetching) |
| Message Composer | CometChatMessageComposerViewModelFactory | MessageComposerRepository | SendText, SendMedia, SendCustom, Edit |
| Call Logs | CometChatCallLogsViewModelFactory | CallLogsRepository | FetchCallLogs |
| Call Buttons | CometChatCallButtonsViewModelFactory | CallButtonsRepository | InitiateCall, StartGroupCall |
| Reactions | CometChatReactionListViewModelFactory | ReactionListRepository | FetchReactions, RemoveReaction |