Skip to main content
Every component in the UI Kit follows a layered architecture. Understanding these layers is the key to deep customization without rebuilding components from scratch.

Architecture Layers

Each component is built from four layers, from outermost (UI) to innermost (data):
LayerRoleExample
ViewRenders UI, handles user interaction, exposes setter methodsCometChatConversations, CometChatMessageList
ViewModelManages state, business logic, list operations, and SDK listenersCometChatConversationsViewModel, CometChatMessageListViewModel
RepositoryAbstracts data fetching — can be swapped for custom implementationsConversationsRepository, MessageListRepository
DataSourceDirect SDK calls — the lowest layer that talks to CometChat serversConversationsDataSourceImpl, MessageListDataSourceImpl
┌─────────────────────────────────────────┐
│              View Layer                  │
│  (CometChatConversations / Compose)  │
│  UI rendering, styles, callbacks        │
├─────────────────────────────────────────┤
│           ViewModel Layer               │
│  (CometChatConversationsViewModel)   │
│  State, ListOperations, SDK listeners   │
├─────────────────────────────────────────┤
│          Repository Layer               │
│  (ConversationsRepository)           │
│  Data abstraction — swappable           │
├─────────────────────────────────────────┤
│          DataSource Layer               │
│  (ConversationsDataSourceImpl)       │
│  Direct CometChat SDK calls             │
└─────────────────────────────────────────┘
The ViewModel lives in chatuikit-core and is shared by both Kotlin XML Views and Jetpack Compose. The View layer is module-specific.

Overriding the ViewModel

Every component accepts an external ViewModel. This lets you subclass the default ViewModel to override behavior, or provide a completely custom one.
// 1. Subclass the ViewModel to override behavior
class MyConversationsViewModel(
    getConversationsUseCase: GetConversationsUseCase,
    deleteConversationUseCase: DeleteConversationUseCase,
    refreshConversationsUseCase: RefreshConversationsUseCase
) : CometChatConversationsViewModel(
    getConversationsUseCase,
    deleteConversationUseCase,
    refreshConversationsUseCase
) {
    // Override any behavior here
}

// 2. Create a factory with optional custom repository
val factory = CometChatConversationsViewModelFactory(
    repository = MyCustomRepository() // or use default
)

// 3. Create the ViewModel via ViewModelProvider
val viewModel = ViewModelProvider(this, factory)
    .get(MyConversationsViewModel::class.java)

// 4. Inject into the component
val conversations = findViewById<CometChatConversations>(R.id.conversations)
conversations.setViewModel(viewModel)

Overriding the Repository

Each ViewModel is created via a Factory that accepts a custom Repository. Implement the repository interface to change how data is fetched.
// 1. Implement the repository interface
class MyConversationsRepository : ConversationsRepository {
    override suspend fun fetchConversations(request: ConversationsRequest): List<Conversation> {
        // Custom data fetching logic — local DB, filtered API call, etc.
    }
    // ... implement other methods
}

// 2. Create a factory with your custom repository
val factory = CometChatConversationsViewModelFactory(
    repository = MyConversationsRepository()
)

// 3. Create the ViewModel using the factory
val viewModel = ViewModelProvider(this, factory)
    .get(CometChatConversationsViewModel::class.java)

// 4. Set it on the component
conversations.setViewModel(viewModel)
Available repository interfaces in chatuikit-core:
RepositoryUsed by
ConversationsRepositoryCometChatConversationsViewModel
MessageListRepositoryCometChatMessageListViewModel
MessageComposerRepositoryCometChatMessageComposerViewModel
MessageHeaderRepositoryCometChatMessageHeaderViewModel
UsersRepositoryCometChatUsersViewModel
GroupsRepositoryCometChatGroupsViewModel
GroupMembersRepositoryCometChatGroupMembersViewModel
CallLogsRepositoryCometChatCallLogsViewModel
CallButtonsRepositoryCometChatCallButtonsViewModel
ReactionListRepositoryCometChatReactionListViewModel
MessageInformationRepositoryCometChatMessageInformationViewModel
StickerRepositoryCometChatStickerKeyboardViewModel
PollRepositoryCometChatCreatePollViewModel

ListOperations API

All list-based ViewModels implement the ListOperations<T> interface, giving you a consistent API to manipulate list data programmatically.

Available Operations

MethodDescription
addItem(item)Appends an item to the list
addItems(items)Appends multiple items
removeItem(item)Removes the first matching item
removeItemAt(index)Removes item at index
updateItem(item, predicate)Replaces the first item matching the predicate
clearItems()Removes all items
getItems()Returns a copy of all items
getItemAt(index)Returns item at index (or null)
getItemCount()Returns the item count
moveItemToTop(item)Moves an item to index 0 (or adds it there)
batch { }Performs multiple operations in a single emission

Example

// Batch operations — emits only once for all changes
viewModel.batch {
    add(newConversation1)
    add(newConversation2)
    remove(oldConversation)
    moveToTop(pinnedConversation)
}
Batch operations are critical for performance when handling rapid updates (e.g., multiple messages arriving simultaneously).

SDK Listeners vs UIKit Events

ViewModels use two event systems for real-time updates:
AspectSDK ListenersUIKit Events
SourceCometChat serverUIKit components
DirectionServer → ClientComponent → Component
RegistrationCometChat.add*Listener()CometChatEvents.*Events.collect {}
PurposeIncoming messages, calls, presenceUI-initiated actions (message sent, call accepted)
Both are needed for full functionality. SDK listeners handle server-pushed events, UIKit events handle inter-component communication.

Customization Categories

View Slots

Replace specific regions of a component’s UI (leading view, title, subtitle, trailing view).

Styles

Customize visual appearance using XML theme attributes or Compose style data classes.

ViewModel & Data

Configure data fetching, observe state flows, and call mutation methods on the ViewModel.

Events & Callbacks

Handle click events, selection mode, and global UI Kit events.

State Views

Replace or restyle the default empty, error, and loading state views.

Text Formatters

Create custom text processors for hashtags, mentions, links, or any pattern.

Menu & Options

Add, replace, or extend context menu actions and composer attachment options.

What’s Next

Start with Styles for quick visual changes, or ViewModel & Data for behavior customization.