diff --git a/.gitignore b/.gitignore
index 96adadbc8..fcf7bc15b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,10 @@
.DS_Store
.kiro/
+
+# IDE files
+.idea/
+
+# Python caches
+__pycache__/
+*.pyc
diff --git a/ui-kit/android/ai-assistant-chat-history.mdx b/ui-kit/android/ai-assistant-chat-history.mdx
index d692600a1..d988e7b32 100644
--- a/ui-kit/android/ai-assistant-chat-history.mdx
+++ b/ui-kit/android/ai-assistant-chat-history.mdx
@@ -2,43 +2,42 @@
title: "AI Assistant Chat History"
---
-## Overview
+`CometChatAIAssistantChatHistory` displays the conversation history between users and an AI assistant, providing a structured view of past interactions for easy review.
-The `AI Assistant Chat History` component is a pre-built user interface element designed to display the conversation history between users and an AI assistant within a chat application. It provides a structured and visually appealing way to present past interactions, making it easy for users to review previous messages and context.
+## When to use this
-
-
-
-
-***
+- You need to display a list of past conversations between a user and an AI assistant.
+- You want users to review previous messages and context from AI assistant interactions.
+- You need tap and long-press actions on chat history items (open a chat, perform additional actions).
+- You want to provide a "new chat" button to start a new conversation with the AI assistant.
+- You need to customize the appearance of the chat history list with styles.
-## Usage
+## Prerequisites
-### Integration
+- CometChat SDK initialized with `CometChatUIKit.init()` and a user logged in.
+- The `cometchat-chat-uikit-android` dependency added to your project.
+- A valid layout XML or Activity/Fragment where you will place the component.
+- The user's role must be set to `@agentic` to use AI Assistant features.
-`AIAssistantChatHistory`, as a Composite Component, offers flexible integration options, allowing it to be launched directly via button clicks or any user-triggered action.
+## Quick start
-The following code snippet exemplifies how you can seamlessly integrate the GroupMembers component into your application.
+1. Open your layout XML file.
+2. Add the `CometChatAIAssistantChatHistory` XML element:
-
-
-```xml
-
+```xml lines
+
```
-
+> **What this does:** Adds the `CometChatAIAssistantChatHistory` component to your layout. It fills the available width and height and renders the AI assistant chat history list.
-
-
-If you're defining the Group members within the XML code, you'll need to extract them and set them on the Group object using the appropriate method.
+3. In your Activity or Fragment, create a `User` object with the role set to `@agentic` and pass it to the component:
-```java
-
+```java lines
User user = new User();
user.setUid("userId");
user.setName("User Name");
@@ -50,8 +49,7 @@ binding.cometChatAiAssistantChatHistory.setUser(user);
-```kotlin
-
+```kotlin lines
val user = User()
user.uid = "userId"
user.name = "User Name"
@@ -64,20 +62,40 @@ binding.cometChatAiAssistantChatHistory.setUser(user)
-***
+> **What this does:** Creates a `User` object with the `@agentic` role and sets it on the `CometChatAIAssistantChatHistory` component. This is required for the component to fetch and display the AI assistant chat histories for that user.
+
+4. Build and run your app.
+5. Verify that the AI assistant chat history list appears with past conversation items.
+
+
+
+
+
+## Core concepts
+
+- **`CometChatAIAssistantChatHistory`**: The main component class that renders the AI assistant chat history list. It is a Composite Component that can be launched via button clicks or any user-triggered action.
+- **Actions**: Callbacks such as `setOnItemClickListener`, `setOnItemLongClickListener`, `setOnNewChatClickListener`, and `setOnCloseClickListener` that let you respond to user interactions.
+- **Style**: XML theme styles applied via `setStyle()` to customize colors, fonts, and visual appearance of the chat history.
+- **Functionality**: Methods like `setUser`, `setErrorStateVisibility`, and `setEmptyStateVisibility` that configure the component's behavior and state visibility.
+
+## Implementation
### Actions
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+What you're changing: How the component responds to user interactions such as taps, long-presses, new chat clicks, and close clicks.
+
+- **Where**: Activity or Fragment where you hold a reference to `CometChatAIAssistantChatHistory`.
+- **Applies to**: `CometChatAIAssistantChatHistory`.
+- **Default behavior**: Predefined actions execute automatically when the user interacts with the component.
+- **Override**: Call the corresponding setter method to replace the default behavior with your own logic.
-##### setOnItemClickListener
+#### `setOnItemClickListener`
-Function invoked when a chat history item is clicked, typically used to open an ai assistant chat screen.
+Function invoked when a chat history item is clicked, used to open an AI assistant chat screen.
-```java YourActivity.java
-
+```java YourActivity.java lines
binding.cometchatAiAssistantChatHistory.setOnItemClickListener((view, position, message) -> {
});
@@ -86,7 +104,7 @@ binding.cometchatAiAssistantChatHistory.setOnItemClickListener((view, position,
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
binding.cometchatAiAssistantChatHistory.setOnItemClickListener { view, position, message ->
}
@@ -96,15 +114,15 @@ binding.cometchatAiAssistantChatHistory.setOnItemClickListener { view, position,
-***
+> **What this does:** Replaces the default item-click behavior. When a user taps a chat history item, your custom lambda executes instead of the built-in navigation.
-##### setOnItemLongClick
+#### `setOnItemLongClickListener`
-Function executed when a user item is long-pressed, allowing additional actions like delete or block.
+Function executed when a chat history item is long-pressed, allowing additional actions like delete or block.
-```java YourActivity.java
+```java YourActivity.java lines
binding.cometchatAiAssistantChatHistory.setOnItemLongClickListener((view, position, message) -> {
});
@@ -113,7 +131,7 @@ binding.cometchatAiAssistantChatHistory.setOnItemLongClickListener((view, positi
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
binding.cometchatAiAssistantChatHistory.setOnItemLongClickListener { view, position, message ->
}
@@ -123,15 +141,15 @@ binding.cometchatAiAssistantChatHistory.setOnItemLongClickListener { view, posit
-***
+> **What this does:** Replaces the default long-press behavior. When a user long-presses a chat history item, your custom lambda executes.
-##### setOnNewChatClickListener
+#### `setOnNewChatClickListener`
-Function triggered when the new chat button is clicked, typically used to start a new conversation with the AI assistant.
+Function triggered when the new chat button is clicked, used to start a new conversation with the AI assistant.
-```java YourActivity.java
+```java YourActivity.java lines
binding.cometchatAiAssistantChatHistory.setOnNewChatClickListener(() -> {
});
@@ -140,7 +158,7 @@ binding.cometchatAiAssistantChatHistory.setOnNewChatClickListener(() -> {
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
binding.cometchatAiAssistantChatHistory.setOnNewChatClickListener {
}
@@ -150,15 +168,15 @@ binding.cometchatAiAssistantChatHistory.setOnNewChatClickListener {
-***
+> **What this does:** Replaces the default new-chat-click behavior. When the user taps the new chat button, your custom logic runs instead of the built-in action.
-##### setOnCloseClickListener
+#### `setOnCloseClickListener`
-Function activated when the close button is clicked, usually to exit the chat history view.
+Function activated when the close button is clicked, used to exit the chat history view.
-```java YourActivity.java
+```java YourActivity.java lines
binding.cometchatAiAssistantChatHistory.setOnCloseClickListener(() -> {
});
@@ -167,7 +185,7 @@ binding.cometchatAiAssistantChatHistory.setOnCloseClickListener(() -> {
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
binding.cometchatAiAssistantChatHistory.setOnCloseClickListener {
}
@@ -177,50 +195,59 @@ binding.cometchatAiAssistantChatHistory.setOnCloseClickListener {
-## Customization
+> **What this does:** Replaces the default close-click behavior. When the user taps the close button, your custom logic runs instead of the built-in exit action.
-The `AIAssistantChatHistory` component offers a variety of customization options to tailor its appearance and functionality to better fit your application's needs. These customizations are categorized into three main areas: Style, Functionality, and Advanced.
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap, long-press, new chat, close) and confirm your custom logic executes instead of the default behavior.
### Style
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
+What you're changing: The visual appearance of the AI Assistant Chat History component using XML theme styles.
+
+- **Where**: `themes.xml` for style definitions, and your Activity/Fragment for applying the style.
+- **Applies to**: `CometChatAIAssistantChatHistory`.
+- **Default behavior**: The component uses its default style.
+- **Override**: Define a custom style in `themes.xml`, then call `setStyle()` on the component.
-```xml themes.xml
-
-
-
+- **Code**:
+
+```xml themes.xml lines
+
+
+
```
+> **What this does:** Defines a custom style `CustomAIAssistantChatHistoryStyle` that sets the background color to `#FFFAF6` for the component, header, new chat area, date separator, and items. It applies a Times New Roman font to the header, new chat text, date separator, and item text. A helper style `textStyleTimesNewRoman` defines the font family.
+
-```java
+```java lines
binding.cometchatAiAssistantChatHistory.setStyle(R.style.CustomAIAssistantChatHistoryStyle);
```
-```kotlin
+```kotlin lines
binding.cometchatAiAssistantChatHistory.setStyle(R.style.CustomAIAssistantChatHistoryStyle);
```
@@ -228,18 +255,78 @@ binding.cometchatAiAssistantChatHistory.setStyle(R.style.CustomAIAssistantChatHi
-***
+> **What this does:** Applies the `CustomAIAssistantChatHistoryStyle` theme to the `CometChatAIAssistantChatHistory` component, changing the background colors and fonts.
To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_ai_assistant_chat_history.xml).
-### Functionality
-
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can toggle the visibility of UI elements.
+- **Verify**: The chat history component displays with the `#FFFAF6` background color and Times New Roman font for header text, new chat text, date separator text, and item text.
-Below is a list of customizations along with corresponding code snippets
+### Functionality
-| Methods | Description | Code |
-| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
-| setUser | Sets the user whose chat histories with the ai assistant need to be fetched. This is a required property for the component to function properly. | `.setUser(user);` |
-| setErrorStateVisibility | Used to toggle the visibility of the error state of the component | `.setErrorStateVisibility(View.GONE);` |
-| setEmptyStateVisibility | Used to toggle the visibility of the empty state of the component | `.setEmptyStateVisibility(View.GONE);` |
+What you're changing: Small functional customizations such as setting the user and toggling visibility of UI states.
+
+- **Where**: Activity or Fragment where you hold a reference to `CometChatAIAssistantChatHistory`.
+- **Applies to**: `CometChatAIAssistantChatHistory`.
+- **Default behavior**: All UI states are visible with default settings.
+- **Override**: Call the corresponding method on the component instance.
+
+| Methods | Description | Code |
+| --- | --- | --- |
+| `setUser` | Sets the user whose chat histories with the AI assistant need to be fetched. This is a required property for the component to function. The user's role must be `@agentic`. | `.setUser(user);` |
+| `setErrorStateVisibility` | Toggles the visibility of the error state of the component | `.setErrorStateVisibility(View.GONE);` |
+| `setEmptyStateVisibility` | Toggles the visibility of the empty state of the component | `.setEmptyStateVisibility(View.GONE);` |
+
+- **Verify**: After calling `setUser(user)`, confirm the component fetches and displays the AI assistant chat histories for that user. After calling a visibility method, confirm the corresponding UI state is shown or hidden.
+
+## Customization matrix
+
+| What you want to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Component background color | `themes.xml` | `cometChatAIAssistantChatHistoryBackgroundColor` | `#FFFAF6` |
+| Header background color | `themes.xml` | `cometChatAIAssistantChatHistoryHeaderBackgroundColor` | `#FFFAF6` |
+| Header text color | `themes.xml` | `cometChatAIAssistantChatHistoryHeaderTextColor` | `?attr/cometchatTextColorPrimary` |
+| Header text appearance | `themes.xml` | `cometChatAIAssistantChatHistoryHeaderTextAppearance` | `@style/textStyleTimesNewRoman` |
+| New chat background color | `themes.xml` | `cometChatAIAssistantChatHistoryNewChatBackgroundColor` | `#FFFAF6` |
+| New chat text color | `themes.xml` | `cometChatAIAssistantChatHistoryNewChatTextColor` | `?attr/cometchatTextColorPrimary` |
+| New chat text appearance | `themes.xml` | `cometChatAIAssistantChatHistoryNewChatTextAppearance` | `@style/textStyleTimesNewRoman` |
+| Date separator text appearance | `themes.xml` | `cometChatAIAssistantChatHistoryDateSeparatorTextAppearance` | `@style/textStyleTimesNewRoman` |
+| Date separator text color | `themes.xml` | `cometChatAIAssistantChatHistoryDateSeparatorTextColor` | `?attr/cometchatTextColorTertiary` |
+| Date separator background color | `themes.xml` | `cometChatAIAssistantChatHistoryDateSeparatorBackgroundColor` | `#FFFAF6` |
+| Item background color | `themes.xml` | `cometChatAIAssistantChatHistoryItemBackgroundColor` | `#FFFAF6` |
+| Item text appearance | `themes.xml` | `cometChatAIAssistantChatHistoryItemTextAppearance` | `@style/textStyleTimesNewRoman` |
+| Item text color | `themes.xml` | `cometChatAIAssistantChatHistoryItemTextColor` | `?attr/cometchatTextColorPrimary` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `binding.cometchatAiAssistantChatHistory.setStyle(R.style.CustomAIAssistantChatHistoryStyle);` |
+| Set the user for fetching history | Activity/Fragment | `setUser(User)` | `.setUser(user);` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE);` |
+| Empty state visibility | Activity/Fragment | `setEmptyStateVisibility(int)` | `.setEmptyStateVisibility(View.GONE);` |
+
+## Common pitfalls & fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Chat history list is empty | Verify that `setUser(user)` is called with a valid `User` object before the component attempts to fetch data. The user is a required property. |
+| AI Assistant features not working | Ensure the user's role is set to `@agentic` using `user.setRole("@agentic")` (Java) or `user.role = "@agentic"` (Kotlin). If the role is not `@agentic`, AI Assistant features will not be available. |
+| Custom style not visible | Verify that you call `setStyle(R.style.YourStyle)` on the component instance and that the style attributes use the correct `cometChatAIAssistantChatHistory*` prefix. |
+| `setOnItemClickListener` not firing | Ensure you are calling `setOnItemClickListener` on the correct `CometChatAIAssistantChatHistory` instance referenced by your binding or `findViewById`. |
+| Error state or empty state still visible after hiding | Ensure you call `setErrorStateVisibility(View.GONE)` or `setEmptyStateVisibility(View.GONE)` on the correct component instance before the component loads data. |
+
+## FAQ
+
+**Q: What is the `@agentic` role and why is it required?**
+**A:** The `@agentic` role is set on the `User` object via `user.setRole("@agentic")`. It must be set to use AI Assistant features. If the role is not `@agentic`, the component will not function for AI assistant chat history.
+
+**Q: How do I start a new AI assistant conversation from the chat history?**
+**A:** Use `setOnNewChatClickListener` to define custom logic that runs when the user taps the new chat button. Implement your navigation or conversation creation logic inside the callback.
+
+**Q: Can I customize the fonts and colors of the chat history?**
+**A:** Yes. Define a custom style in `themes.xml` using the `cometChatAIAssistantChatHistory*` attributes (e.g., `cometChatAIAssistantChatHistoryHeaderTextAppearance`, `cometChatAIAssistantChatHistoryItemTextColor`) and apply it with `setStyle()`.
+
+**Q: How do I handle the close button action?**
+**A:** Use `setOnCloseClickListener` to provide custom logic that runs when the user taps the close button. Implement your navigation or dismissal logic inside the callback.
+
+## Next steps
+
+- [Message List component](/ui-kit/android/message-list)
+- [Conversations component](/ui-kit/android/conversations)
+- [Users component](/ui-kit/android/users)
diff --git a/ui-kit/android/ai-features.mdx b/ui-kit/android/ai-features.mdx
index fa995487c..efe016cc3 100644
--- a/ui-kit/android/ai-features.mdx
+++ b/ui-kit/android/ai-features.mdx
@@ -1,20 +1,20 @@
---
-title: "AI"
+title: "Smart Chat Features"
---
## Overview
-CometChat's AI capabilities greatly enhance user interaction and engagement in your application. Let's understand how the Android UI Kit achieves these features.
+CometChat's AI capabilities greatly enhance user interaction and engagement in your application. Here's how the Android UI Kit integrates these features.
-## Conversation Starters
+## Conversation Starter
-When a user initiates a new chat, the UI kit displays a list of suggested opening lines that users can select, making it easier for them to start a conversation. These suggestions are powered by CometChat's AI, which predicts contextually relevant conversation starters.
+When a user initiates a new chat, the UI kit displays a list of suggested opening lines that users can select, making it easier for them to start a conversation. These suggestions are powered by CometChat's AI, which predicts contextually relevant conversation starter options.
-For a comprehensive understanding and guide on implementing and using the Conversation Starters, refer to our specific guide on the [Conversation Starter](/fundamentals/ai-user-copilot/conversation-starter).
+For a comprehensive understanding and guide on implementing and using the Conversation Starter, refer to our specific guide on the [Conversation Starter](/fundamentals/ai-user-copilot/conversation-starter).
Once you have successfully activated the [Conversation Starter](/fundamentals/ai-user-copilot/conversation-starter) from your CometChat Dashboard, the feature will automatically be incorporated into the [MessageList](/ui-kit/android/message-list) Component of UI Kits.
@@ -40,7 +40,7 @@ The Conversation Summary feature provides concise summaries of long conversation
For a comprehensive understanding and guide on implementing and using the Conversation Summary, refer to our specific guide on the [Conversation Summary](/fundamentals/ai-user-copilot/conversation-summary).
-Once you have successfully activated the [Smart Replies](/fundamentals/ai-user-copilot/smart-replies) from your CometChat Dashboard, the feature will automatically be incorporated into the Action sheet of [MessageComposer](/ui-kit/android/message-composer) Component of UI Kits.
+Once you have successfully activated the [Conversation Summary](/fundamentals/ai-user-copilot/conversation-summary) from your CometChat Dashboard, the feature will automatically be incorporated into the Action sheet of [MessageComposer](/ui-kit/android/message-composer) Component of UI Kits.
diff --git a/ui-kit/android/android-conversation.mdx b/ui-kit/android/android-conversation.mdx
index 4bebefe49..b1b1ec2d2 100644
--- a/ui-kit/android/android-conversation.mdx
+++ b/ui-kit/android/android-conversation.mdx
@@ -3,9 +3,9 @@ title: "Building A Conversation List + Message View"
sidebarTitle: "Conversation List + Message View"
---
-The **Conversation List + Message View** layout offers a seamless **two-panel chat interface**, commonly used in modern messaging applications like **WhatsApp Web, Slack, and Microsoft Teams**.
+The **Conversation List + Message View** layout provides a **sequential navigation pattern** for Android messaging applications, similar to **WhatsApp, Slack, and Telegram**.
-This design enables users to switch between conversations effortlessly while keeping the chat window open, ensuring a **smooth, real-time messaging experience**.
+This design allows users to view their conversation list and tap on any conversation to open a full-screen message view, providing a **familiar mobile real-time messaging experience**.
***
@@ -17,21 +17,31 @@ This design enables users to switch between conversations effortlessly while kee
### **Key Components**
-1. **Chat Header** – Displays user/group name, profile image, and status.
-2. **Message List** – Shows chat history and new messages.
-3. **Message Composer** – Allows users to send messages, media, and reactions.
+1. **Message Header** – Displays user/group name, avatar, and status.
+2. **Message List** – Shows chat history with real-time message updates.
+3. **Message Composer** – Provides input field for sending text messages, media, and attachments.
***
## **Step-by-Step Guide**
+### **Navigation Flow**
+
+This implementation follows Android's standard Activity navigation pattern:
+
+1. **ConversationActivity** displays the list of conversations
+2. User taps a conversation item
+3. **MessageActivity** launches with the selected user/group data passed via Intent extras
+
+***
+
### **Step 1: Set Up Conversation Activity**
-Create an Activity - `ConversationActivity.kt` to manage and display the chat UI.
+Create a new Activity called `ConversationActivity` to display the list of conversations.
#### **Layout**
-Define the layout using the `CometChatConversations` component:
+Define the layout using the `CometChatConversations` component in `activity_conversations.xml`:
-```xml activity_conversations.xml
+```xml activity_conversations.xml lines
-```kotlin ConversationActivity.kt
+```kotlin ConversationActivity.kt lines
import android.content.Intent
import android.os.Bundle
@@ -117,7 +127,7 @@ class ConversationActivity : AppCompatActivity() {
-```java ConversationActivity.java
+```java ConversationActivity.java lines
import android.content.Intent;
import android.os.Bundle;
@@ -189,11 +199,13 @@ This is necessary to properly manage the **UI Kit's lifecycle events**.
***
### **Step 2: Set Up Message Activity**
-Create an Activity - `MessageActivity.kt` to manage and display the chat UI.
+Create a new Activity - `MessageActivity` to display the chat interface.
#### **Layout**
-```xml activity_message.xml
+Define the layout with `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` in `activity_message.xml`:
+
+```xml activity_message.xml lines
-```kotlin MessageActivity.kt
+```kotlin MessageActivity.kt lines
import android.os.Bundle
import android.util.Log
import android.widget.Toast
@@ -344,7 +356,7 @@ class MessageActivity : AppCompatActivity() {
-```java MessageActivity.java
+```java MessageActivity.java lines
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
@@ -458,11 +470,12 @@ public class MessageActivity extends AppCompatActivity {
### **Step 3: Update MainActivity**
-Update the `MainActivity` to navigate to the `MessageActivity`:
+Update your `MainActivity` to launch `ConversationActivity` after successful login:
-```kotlin MainActivity.kt
+```kotlin MainActivity.kt highlight={15-17, 46-47} lines
+import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
@@ -524,7 +537,7 @@ class MainActivity : ComponentActivity() {
-```java MainActivity.java
+```java MainActivity.java highlight={15-17, 51-52} lines
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -595,15 +608,21 @@ public class MainActivity extends ComponentActivity {
***
-## **Running the Project**
+## **Running the Application**
-Once the components are configured, build and run the app:
+Once you've completed the setup, build and run your Android application:
-```sh
-gradle build
-```
-Ensure you've added the necessary permissions and initialized CometChat in your `Application` class.
+
+**Required Permissions**
+
+Ensure you've added the necessary permissions in your `AndroidManifest.xml`:
+
+```xml lines
+
+
+```
+
***
@@ -611,6 +630,8 @@ Ensure you've added the necessary permissions and initialized CometChat in your
### **Enhance the User Experience**
+* **[Components Overview](/ui-kit/android/components-overview)** – Explore all available UI Kit components and their customization options.
* **[Advanced Customizations](/ui-kit/android/theme-introduction)** – Personalize the chat UI to align with your brand.
+* **[Feature Guides](/ui-kit/android/guide-overview)** – Add capabilities like threaded messages, blocking, and group management.
***
diff --git a/ui-kit/android/android-one-to-one-chat.mdx b/ui-kit/android/android-one-to-one-chat.mdx
index 4308e76e4..c6338ff8f 100644
--- a/ui-kit/android/android-one-to-one-chat.mdx
+++ b/ui-kit/android/android-one-to-one-chat.mdx
@@ -3,7 +3,7 @@ title: "Building A One To One/Group Chat Experience"
sidebarTitle: "One To One/Group Chat"
---
-The **One-to-One Chat** feature provides a streamlined **direct messaging interface**, making it ideal for **support chats, dating apps, and private messaging platforms**. This setup eliminates distractions by focusing solely on a **dedicated chat window**.
+The **One-to-One Chat** feature provides a **direct messaging interface** for Android applications, ideal for **support chats, dating apps, and private messaging **. This implementation launches directly into a specific chat conversation without showing a conversation list, providing a **focused messaging experience**.
***
@@ -15,22 +15,34 @@ The **One-to-One Chat** feature provides a streamlined **direct messaging interf
### **Key Components**
-1. **Chat Header** – Displays user/group name, profile image, and status.
-2. **Message List** – Shows chat history and new messages.
-3. **Message Composer** – Allows users to send messages, media, and reactions.
+1. **Message Header** – Displays user/group name, avatar, and status.
+2. **Message List** – Shows chat history with real-time message updates.
+3. **Message Composer** – Provides input field for sending text messages, media, and attachments.
***
## **Step-by-Step Guide**
+### **Use Case**
+
+This pattern is ideal when you want to:
+- Launch a chat directly from a user profile or contact card
+- Open a support chat from a help button
+- Start a conversation from a notification
+- Navigate to a specific chat without showing the conversation list
+
+The user or group ID is passed via Intent extras when launching the Activity.
+
+***
+
### **Step 1: Set Up Message Activity**
-Create an Activity - `MessageActivity.kt` to manage and display the chat UI.
+Create an Activity - `MessageActivity` to display the full-screen chat interface.
#### **Layout**
-Define the layout using CometChat UI Kit components:
+Define the layout with `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` in `activity_message.xml`:
-```xml activity_message.xml
+```xml activity_message.xml lines
-```kotlin MessageActivity.kt
+```kotlin MessageActivity.kt lines
import android.os.Bundle
import android.util.Log
import android.widget.Toast
@@ -179,7 +193,7 @@ class MessageActivity : AppCompatActivity() {
-```java MessageActivity.java
+```java MessageActivity.java lines
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
@@ -303,13 +317,24 @@ This is necessary to properly manage the **UI Kit's lifecycle events**.
***
-### **Step 2: Update MainActivity**
+### **Step 2: Launch MessageActivity from Your App**
+
+Update your `MainActivity` (or any other Activity) to launch `MessageActivity` with the appropriate user or group ID:
-Update the `MainActivity` to navigate to the `MessageActivity`:
+
+**Passing Data via Intent**
+
+You can pass either:
+- `uid` (String) - for one-to-one chats
+- `guid` (String) - for group chats
+
+The `MessageActivity` will automatically detect which type of chat to display based on the Intent extras.
+
-```kotlin MainActivity.kt
+```kotlin MainActivity.kt highlight={15-17, 19-20, 49-52} lines
+import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
@@ -328,6 +353,9 @@ class MainActivity : ComponentActivity() {
private val region = "REGION" // Replace with your App Region
private val authKey = "AUTH_KEY" // Replace with your Auth Key or leave blank if you are authenticating using Auth Token
+ private val uid = "cometchat-uid-1" // Replace with the UID of the user you want to chat with
+ private val target_uid = "cometchat-uid-2" // Replace with the UID of the user you want to chat with
+
private val uiKitSettings = UIKitSettings.UIKitSettingsBuilder()
.setRegion(region)
.setAppId(appID)
@@ -352,12 +380,12 @@ class MainActivity : ComponentActivity() {
}
private fun loginUser() {
- CometChatUIKit.login("cometchat-uid-1", object : CometChat.CallbackListener() {
+ CometChatUIKit.login(uid, object : CometChat.CallbackListener() {
override fun onSuccess(user: User) {
// Launch One-to-One or Group Chat Screen
val intent = Intent(this@MainActivity, MessageActivity::class.java)
- intent.putExtra("uid", "cometchat-uid-1")
+ intent.putExtra("uid", target_uid) // Pass the UID of the user you want to chat with
startActivity(intent)
}
@@ -373,7 +401,7 @@ class MainActivity : ComponentActivity() {
-```java MainActivity.java
+```java MainActivity.java highlight={15-17, 19-20, 54-57} lines
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -392,6 +420,9 @@ public class MainActivity extends ComponentActivity {
private final String region = "REGION"; // Replace with your App Region
private final String authKey = "AUTH_KEY"; // Replace with your Auth Key
+ private final String uid = "cometchat-uid-1"; // Replace with the UID of the user you want to chat with
+ private final String target_uid = "cometchat-uid-2"; // Replace with the UID of the user you want to chat with
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -419,14 +450,14 @@ public class MainActivity extends ComponentActivity {
}
private void loginUser() {
- CometChatUIKit.login("cometchat-uid-1", new CometChat.CallbackListener() {
+ CometChatUIKit.login(uid, new CometChat.CallbackListener() {
@Override
public void onSuccess(User user) {
Log.d(TAG, "Login successful for user: " + user.getUid());
// Launch One-to-One or Group Chat Screen
Intent intent = new Intent(MainActivity.this, MessageActivity.class);
- intent.putExtra("uid", "cometchat-uid-1");
+ intent.putExtra("uid", target_uid);
startActivity(intent);
}
@@ -447,13 +478,23 @@ public class MainActivity extends ComponentActivity {
## **Running the Project**
-Once the components are configured, build and run the app:
+Once you've completed the setup, build and run the app:
-```sh
+```sh lines
gradle build
```
-Ensure you've added the necessary permissions and initialized CometChat in your `Application` class.
+
+**Required Permissions**
+
+Ensure you've added the necessary permissions in your `AndroidManifest.xml` and initialized CometChat in your `Application` class.
+:
+
+```xml lines
+
+
+```
+
***
@@ -461,6 +502,8 @@ Ensure you've added the necessary permissions and initialized CometChat in your
### **Enhance the User Experience**
+* **[Components Overview](/ui-kit/android/components-overview)** – Explore all available UI Kit components and their customization options.
* **[Advanced Customizations](/ui-kit/android/theme-introduction)** – Personalize the chat UI to align with your brand.
+* **[Feature Guides](/ui-kit/android/guide-overview)** – Add capabilities like threaded messages, blocking, and group management.
***
diff --git a/ui-kit/android/android-tab-based-chat.mdx b/ui-kit/android/android-tab-based-chat.mdx
index 87ad56890..4a7901646 100644
--- a/ui-kit/android/android-tab-based-chat.mdx
+++ b/ui-kit/android/android-tab-based-chat.mdx
@@ -1,9 +1,9 @@
---
-title: "Building A Messaging UI With Tabs, Sidebar, And Message View"
+title: "Building A Tab-Based Messaging UI"
sidebarTitle: "Tab Based Chat Experience"
---
-This guide walks you through creating a **tab-based messaging UI** using **React** and **CometChat UIKit**. The UI will include different sections for **Chats, Calls, Users, and Groups**, allowing seamless navigation.
+This guide walks you through creating a **tab-based messaging UI** using **Android** and **CometChat UIKit**. The UI uses **BottomNavigationView** with different sections for **Chats, Calls, Users, and Groups**, allowing seamless navigation.
***
@@ -15,29 +15,41 @@ This guide walks you through creating a **tab-based messaging UI** using **React
This layout consists of:
-1. **Sidebar (Conversation List)** – Displays recent conversations with active users and groups.
-2. **Message View** – Shows the selected chat with real-time messages.
-3. **Message Input Box** – Allows users to send messages seamlessly.
+1. **Bottom Navigation Bar** – Provides quick access to main sections (Chats, Calls, Users, Groups).
+2. **Fragment Container** – Displays the selected section's content using Android Fragments.
+3. **Dynamic Content** – Each tab loads its respective Fragment with CometChat UI components.
***
## **Step-by-Step Guide**
-### **Step 1: Create a Tab Component**
+### **Navigation Pattern**
-To manage navigation, let's build a **`CometChatTabs`** component. This component will render different tabs and allow switching between sections dynamically.
+This implementation uses Android's **BottomNavigationView** pattern:
-#### **Folder Structure**
+1. **TabbedActivity** hosts the bottom navigation and fragment container
+2. User taps a tab in the bottom navigation
+3. The corresponding Fragment is loaded into the container
+4. Each Fragment displays its CometChat UI component (Conversations, CallLogs, Users, or Groups)
-Create a `TabbedActivity` inside your `src` directory and add the following files:
+This is the standard Android pattern for apps with multiple top-level destinations.
-```txt
+***
+
+### **Step 1: Set Up Tabbed Activity**
+Create a new Activity called `TabbedActivity` with **BottomNavigationView** to manage tab navigation.
+
+#### **Project Structure**
+
+Create the following files in your Android project:
+
+```txt lines
src/main/java/your-package-name/
-├── TabbedActivity.kt
-├── ChatsFragment.kt
-├── CallLogsFragment.kt
-├── UsersFragment.kt
-├── GroupsFragment.kt
+├── TabbedActivity.kt (or .java)
+├── ChatsFragment.kt (or .java)
+├── CallLogsFragment.kt (or .java)
+├── UsersFragment.kt (or .java)
+└── GroupsFragment.kt (or .java)
src/main/java/your-package-name/
├── res/
@@ -51,16 +63,19 @@ src/main/java/your-package-name/
│ └── bottom_nav_menu.xml
```
-#### **Download the Icons**
+#### **Vector Drawable Icons**
+
+Download the navigation icons from the **CometChat UI Kit repository**:
-These icons are available in the **CometChat UI Kit res folder**. You can find them at:\
-🔗 [GitHub Assets Folder](https://github.com/cometchat/cometchat-uikit-android/tree/v5/sample-app-java/src/main/res/drawable)
+🔗 [GitHub Drawable Resources](https://github.com/cometchat/cometchat-uikit-android/tree/v5/sample-app-java/src/main/res/drawable)
+
+Place the icon files (`ic_chats.xml`, `ic_calls.xml`, `ic_user.xml`, `ic_group.xml`) in your `res/drawable/` directory.
#### **Implementation**
-```kotlin TabbedActivity.kt
+```kotlin TabbedActivity.kt highlight={} lines
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
@@ -131,7 +146,7 @@ class TabbedActivity : AppCompatActivity() {
-```java TabbedActivity.java
+```java TabbedActivity.java lines
import android.os.Bundle;
import android.view.View;
import android.view.WindowInsets;
@@ -217,7 +232,7 @@ public class TabbedActivity extends AppCompatActivity {
-```xml activity_tabbed.xml
+```xml activity_tabbed.xml lines
```
-```xml res/menu/bottom_nav_menu.xml
+```xml res/menu/bottom_nav_menu.xml lines
-
```
-In the method `setLeadingView` you need to inflate the XML and initialize the views using the conversation objects.
+Inflate and bind with typing indicator tracking:
-
-```java
-HashMap typingIndicatorHashMap = new HashMap<>();
-CometChat.addMessageListener(System.currentTimeMillis() + "", new CometChat.MessageListener() {
- @Override
- public void onTypingStarted(TypingIndicator typingIndicator) {
- if (typingIndicator.getReceiverType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
- if (typingIndicatorHashMap.containsKey(typingIndicator.getSender().getUid())) {
- return;
- }
- Log.e(TAG, "bindView: " + typingIndicator.getSender().getUid());
- typingIndicatorHashMap.put(typingIndicator.getSender().getUid(), true);
- } else {
- if (typingIndicatorHashMap.containsKey(typingIndicator.getReceiverId())) {
- return;
- }
- typingIndicatorHashMap.put(typingIndicator.getReceiverId(), true);
- }
- }
-
- @Override
- public void onTypingEnded(TypingIndicator typingIndicator) {
- if (typingIndicator.getReceiverType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
- typingIndicatorHashMap.remove(typingIndicator.getSender().getUid());
- } else {
- typingIndicatorHashMap.remove(typingIndicator.getReceiverId());
- }
- }
- });
-
-cometchatConversations.setLeadingView(new ConversationsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.leading_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- Conversation conversation,
- RecyclerView.ViewHolder holder,
- List conversationList,
- int position) {
-
- ImageView imageView = createdView.findViewById(R.id.leading_iv);
- ConstraintLayout constraintLayout = createdView.findViewById(R.id.leading_view);
- CometChatAvatar avatar = createdView.findViewById(R.id.conversations_avatar);
- CometChatStatusIndicator statusIndicator = createdView.findViewById(R.id.status_and_type_indicator);
-
-
- avatar.setAvatar(ConversationsUtils.getConversationTitle(conversation), ConversationsUtils.getConversationAvatar(conversation));
-
-
- if (conversation.getConversationType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
- if (((User) conversation.getConversationWith()).getStatus().equalsIgnoreCase(CometChatConstants.USER_STATUS_ONLINE)) {
- if (!Utils.isBlocked(((User) conversation.getConversationWith()))) {
- statusIndicator.setStatusIndicator(StatusIndicator.ONLINE);
- } else {
- statusIndicator.setStatusIndicator(StatusIndicator.OFFLINE);
- }
- } else {
- statusIndicator.setStatusIndicator(StatusIndicator.OFFLINE);
- }
- if (typingIndicatorHashMap.containsKey(((User) conversation.getConversationWith()).getUid())) {
- imageView.setVisibility(View.VISIBLE);
- constraintLayout.setVisibility(GONE);
- } else {
- imageView.setVisibility(GONE);
- constraintLayout.setVisibility(View.VISIBLE);
- }
- } else {
- if (typingIndicatorHashMap.containsKey(((Group) conversation.getConversationWith()).getGuid())) {
- imageView.setVisibility(View.VISIBLE);
- constraintLayout.setVisibility(GONE);
- } else {
- imageView.setVisibility(GONE);
- constraintLayout.setVisibility(View.VISIBLE);
- }
- }
-
- }
- });
-```
-
-
-
-```kotlin
+```kotlin lines
val typingIndicatorHashMap = HashMap()
CometChat.addMessageListener(System.currentTimeMillis().toString() + "", object : MessageListener() {
override fun onTypingStarted(typingIndicator: TypingIndicator) {
@@ -1157,10 +849,8 @@ cometchatConversations.setLeadingView(new ConversationsViewHolderListener() {
val avatar = createdView.findViewById(R.id.conversations_avatar)
val statusIndicator = createdView.findViewById(R.id.status_and_type_indicator)
-
avatar.setAvatar(ConversationsUtils.getConversationTitle(conversation), ConversationsUtils.getConversationAvatar(conversation))
-
if (conversation.conversationType == CometChatConstants.RECEIVER_TYPE_USER) {
if ((conversation.conversationWith as User).status.equals(CometChatConstants.USER_STATUS_ONLINE, ignoreCase = true)) {
if (!Utils.isBlocked((conversation.conversationWith as User))) {
@@ -1190,133 +880,41 @@ cometchatConversations.setLeadingView(new ConversationsViewHolderListener() {
}
})
```
-
-
-
-***
-
-#### setTitleView
-
-Overrides the default title view in the conversation list with a custom layout. This is useful for branding or modifying how conversation names and details are displayed.
-
-Examples:
-
-* Displaying conversation titles with additional metadata (e.g., last seen time)
-* Custom fonts or text styles for conversation names
-* Adding icons or indicators next to titles
-
-
-```java
- cometchatConversations.setTitleView(new ConversationsViewHolderListener() {
+```java lines
+HashMap typingIndicatorHashMap = new HashMap<>();
+CometChat.addMessageListener(System.currentTimeMillis() + "", new CometChat.MessageListener() {
@Override
- public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
- return null;
+ public void onTypingStarted(TypingIndicator typingIndicator) {
+ if (typingIndicator.getReceiverType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
+ if (typingIndicatorHashMap.containsKey(typingIndicator.getSender().getUid())) {
+ return;
+ }
+ typingIndicatorHashMap.put(typingIndicator.getSender().getUid(), true);
+ } else {
+ if (typingIndicatorHashMap.containsKey(typingIndicator.getReceiverId())) {
+ return;
+ }
+ typingIndicatorHashMap.put(typingIndicator.getReceiverId(), true);
+ }
}
@Override
- public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
-
+ public void onTypingEnded(TypingIndicator typingIndicator) {
+ if (typingIndicator.getReceiverType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
+ typingIndicatorHashMap.remove(typingIndicator.getSender().getUid());
+ } else {
+ typingIndicatorHashMap.remove(typingIndicator.getReceiverId());
+ }
}
});
-```
-
-
-
-
-```kotlin
- cometchatConversations.setTitleView(object :
- ConversationsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatConversationsListItemsBinding?
- ): View? {
- return null
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- conversation: Conversation,
- holder: RecyclerView.ViewHolder,
- conversationList: List,
- position: Int
- ) {
- }
- })
-```
-
-
-
-
-
-Demonstration
-
-
-
-
-
-You can create an `custom_title_view.xml` as a custom layout file. Which we will inflate in `setTitleView()`
-
-```html
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-In the method `setTitleView` you need to inflate the XML and initialize the views using the conversation objects.
-
-
-
-```java
-cometchatConversations.setTitleView(new ConversationsViewHolderListener() {
+cometchatConversations.setLeadingView(new ConversationsViewHolderListener() {
@Override
public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null);
+ return LayoutInflater.from(context).inflate(R.layout.leading_view, null);
}
@Override
@@ -1327,70 +925,96 @@ cometchatConversations.setTitleView(new ConversationsViewHolderListener() {
List conversationList,
int position) {
- TextView name = createdView.findViewById(R.id.name);
- TextView status = createdView.findViewById(R.id.status);
+ ImageView imageView = createdView.findViewById(R.id.leading_iv);
+ ConstraintLayout constraintLayout = createdView.findViewById(R.id.leading_view);
+ CometChatAvatar avatar = createdView.findViewById(R.id.conversations_avatar);
+ CometChatStatusIndicator statusIndicator = createdView.findViewById(R.id.status_and_type_indicator);
+
+ avatar.setAvatar(ConversationsUtils.getConversationTitle(conversation), ConversationsUtils.getConversationAvatar(conversation));
- name.setText(ConversationsUtils.getConversationTitle(conversation));
if (conversation.getConversationType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
- status.setVisibility(View.VISIBLE);
- status.setText("• " + ((User) conversation.getConversationWith()).getStatusMessage());
+ if (((User) conversation.getConversationWith()).getStatus().equalsIgnoreCase(CometChatConstants.USER_STATUS_ONLINE)) {
+ if (!Utils.isBlocked(((User) conversation.getConversationWith()))) {
+ statusIndicator.setStatusIndicator(StatusIndicator.ONLINE);
+ } else {
+ statusIndicator.setStatusIndicator(StatusIndicator.OFFLINE);
+ }
+ } else {
+ statusIndicator.setStatusIndicator(StatusIndicator.OFFLINE);
+ }
+ if (typingIndicatorHashMap.containsKey(((User) conversation.getConversationWith()).getUid())) {
+ imageView.setVisibility(View.VISIBLE);
+ constraintLayout.setVisibility(GONE);
+ } else {
+ imageView.setVisibility(GONE);
+ constraintLayout.setVisibility(View.VISIBLE);
+ }
} else {
- status.setVisibility(View.GONE);
+ if (typingIndicatorHashMap.containsKey(((Group) conversation.getConversationWith()).getGuid())) {
+ imageView.setVisibility(View.VISIBLE);
+ constraintLayout.setVisibility(GONE);
+ } else {
+ imageView.setVisibility(GONE);
+ constraintLayout.setVisibility(View.VISIBLE);
+ }
}
}
});
```
-
+
-
-```kotlin
-cometchatConversations.setTitleView(object : ConversationsViewHolderListener() {
- override fun createView(context: Context?, listItem: CometchatConversationsListItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null)
- }
+### `setTrailingView`
- override fun bindView(
- context: Context,
- createdView: View,
- conversation: Conversation,
- holder: RecyclerView.ViewHolder,
- conversationList: List,
- position: Int
- ) {
- val name = createdView.findViewById(R.id.name)
- val status = createdView.findViewById(R.id.status)
+Replace the timestamp / badge / right section.
- name.text = ConversationsUtils.getConversationTitle(conversation)
- if (conversation.conversationType == CometChatConstants.RECEIVER_TYPE_USER) {
- status.visibility = View.VISIBLE
- status.text = "• " + (conversation.conversationWith as User).statusMessage
- } else {
- status.visibility = View.GONE
- }
- }
- })
-```
+
+
+```kotlin lines
+cometchatConversations.setTrailingView(object :
+ ConversationsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatConversationsListItemsBinding?
+ ): View? {
+ return null
+ }
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ conversation: Conversation,
+ holder: RecyclerView.ViewHolder,
+ conversationList: List,
+ position: Int
+ ) {
+ }
+})
+```
-
-
-***
-
-#### setTrailingView
+
+```java lines
+cometchatConversations.setTrailingView(new ConversationsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
+ return null;
+ }
-Customizes the trailing (end) view of a conversation item, which is typically used for action buttons or additional information.
+ @Override
+ public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
-Examples:
+ }
+});
+```
+
+
-* Adding a mute/unmute button for each conversation
-* Displaying the last message time in a custom format
-* Showing unread message counts or notification badges
+Relative time badge example:
-You can create an `custom_tail_view.xml` as a custom layout file. Which we will inflate in `setTrailingView()`
+Create a `custom_tail_view.xml` custom layout file:
-```html
+```html lines
```
-In the method `setTrailingView` you need to inflate the XML and initialize the views using the conversation objects.
+> **What this does:** Defines a custom trailing view layout with a `MaterialCardView` containing two `TextView` elements for displaying the time value and unit (e.g., "5" and "Min ago").
+
+Inflate and bind with color-coded time badges:
+
+```kotlin lines
+cometchatConversations.setTrailingView(object : ConversationsViewHolderListener() {
+ override fun createView(context: Context?, listItem: CometchatConversationsListItemsBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null)
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ conversation: Conversation,
+ holder: RecyclerView.ViewHolder,
+ conversationList: List,
+ position: Int
+ ) {
+ val card = createdView.findViewById(R.id.card)
+ val tvHours = createdView.findViewById(R.id.hours)
+ val tvMessage = createdView.findViewById(R.id.time_title)
+
+ var timestamp = conversation.updatedAt * 1000
+
+ if (timestamp.toString().length == 10) {
+ timestamp *= 1000
+ }
+
+ val now = Calendar.getInstance()
+ val lastSeen = Calendar.getInstance()
+ lastSeen.timeInMillis = timestamp
+
+ val diffInMillis = now.timeInMillis - lastSeen.timeInMillis
+ val diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis)
+ val diffInHours = TimeUnit.MILLISECONDS.toHours(diffInMillis)
+
+ if (diffInMinutes == 0L) {
+ tvHours.text = "1"
+ tvMessage.text = "Min ago"
+ card.setCardBackgroundColor(Utils.applyColorWithAlphaValue(Color.parseColor("#6852D6"), 40))
+ tvMessage.setTextColor(Color.parseColor("#6852D6"))
+ tvHours.setTextColor(Color.parseColor("#6852D6"))
+ } else if (diffInMinutes < 60) {
+ tvHours.text = diffInMinutes.toString()
+ tvMessage.text = "Min ago"
+ card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#6852D6"), 40))
+ tvMessage.setTextColor(Color.parseColor("#6852D6"))
+ tvHours.setTextColor(Color.parseColor("#6852D6"))
+ } else if (diffInHours < 10) {
+ tvHours.text = diffInHours.toString()
+ tvMessage.text = "Hr ago"
+ tvMessage.setTextColor(Color.parseColor("#FFAB00"))
+ tvHours.setTextColor(Color.parseColor("#FFAB00"))
+ card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#FFAB00"), 40))
+ } else if (diffInHours < 1000) {
+ tvHours.text = diffInHours.toString()
+ tvMessage.text = "Hr ago"
+ tvMessage.setTextColor(Color.parseColor("#F44649"))
+ tvHours.setTextColor(Color.parseColor("#F44649"))
+ card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#F44649"), 40))
+ }
+ }
+ })
+```
+
+
-```java
+```java lines
cometchatConversations.setTrailingView(new ConversationsViewHolderListener() {
@Override
public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
@@ -1457,7 +1146,6 @@ cometchatConversations.setTrailingView(new ConversationsViewHolderListener() {
long timestamp = conversation.getUpdatedAt() * 1000;
if (String.valueOf(timestamp).length() == 10) {
- // Convert seconds to milliseconds
timestamp *= 1000;
}
@@ -1469,32 +1157,24 @@ cometchatConversations.setTrailingView(new ConversationsViewHolderListener() {
long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis);
long diffInHours = TimeUnit.MILLISECONDS.toHours(diffInMillis);
- // Check if the timestamp is within the last hour
if (diffInMinutes == 0) {
tvHours.setText("1");
tvMessage.setText("Min ago");
card.setCardBackgroundColor(Utils.applyColorWithAlphaValue(Color.parseColor("#6852D6"), 40));
tvMessage.setTextColor(Color.parseColor("#6852D6"));
tvHours.setTextColor(Color.parseColor("#6852D6"));
- return;
-
} else if (diffInMinutes < 60) {
tvHours.setText(diffInMinutes + "");
tvMessage.setText("Min ago");
card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#6852D6"), 40));
tvMessage.setTextColor(Color.parseColor("#6852D6"));
tvHours.setTextColor(Color.parseColor("#6852D6"));
- return;
- }
-
- // Check if the timestamp is within the last 24 hours
- if (diffInHours < 10) {
+ } else if (diffInHours < 10) {
tvHours.setText(diffInHours + "");
tvMessage.setText("Hr ago");
tvMessage.setTextColor(Color.parseColor("#FFAB00"));
tvHours.setTextColor(Color.parseColor("#FFAB00"));
card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#FFAB00"), 40));
-
} else if (diffInHours < 1000) {
tvHours.setText(diffInHours + "");
tvMessage.setText("Hr ago");
@@ -1505,14 +1185,101 @@ cometchatConversations.setTrailingView(new ConversationsViewHolderListener() {
}
});
```
+
+
+
+
+
+
+
+### `setTitleView`
+
+Replace the name / title text.
+
+
+
+```kotlin lines
+cometchatConversations.setTitleView(object :
+ ConversationsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatConversationsListItemsBinding?
+ ): View? {
+ return null
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ conversation: Conversation,
+ holder: RecyclerView.ViewHolder,
+ conversationList: List,
+ position: Int
+ ) {
+ }
+})
+```
+
+
+
+```java lines
+cometchatConversations.setTitleView(new ConversationsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
+ return null;
+ }
+ @Override
+ public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
+
+ }
+});
+```
+
+
+Inline user status example:
+
+Create a `custom_title_view.xml` layout:
+
+```xml custom_title_view.xml lines
+
+
+
+
+
+
+
+```
+
+> **What this does:** Defines a custom title layout with the conversation name and an inline user status message.
+
+
-```kotlin
-cometchatConversations.setTrailingView(object : ConversationsViewHolderListener() {
+```kotlin lines
+cometchatConversations.setTitleView(object : ConversationsViewHolderListener() {
override fun createView(context: Context?, listItem: CometchatConversationsListItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null)
+ return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null)
}
override fun bindView(
@@ -1523,97 +1290,117 @@ cometchatConversations.setTrailingView(object : ConversationsViewHolderListener(
conversationList: List,
position: Int
) {
- val card = createdView.findViewById(R.id.card)
- val tvHours = createdView.findViewById(R.id.hours)
- val tvMessage = createdView.findViewById(R.id.time_title)
-
- var timestamp = conversation.updatedAt * 1000
+ val name = createdView.findViewById(R.id.name)
+ val status = createdView.findViewById(R.id.status)
- if (timestamp.toString().length == 10) {
- // Convert seconds to milliseconds
- timestamp *= 1000
+ name.text = ConversationsUtils.getConversationTitle(conversation)
+ if (conversation.conversationType == CometChatConstants.RECEIVER_TYPE_USER) {
+ status.visibility = View.VISIBLE
+ status.text = "• " + (conversation.conversationWith as User).statusMessage
+ } else {
+ status.visibility = View.GONE
}
+ }
+ })
+```
+
- val now = Calendar.getInstance()
- val lastSeen = Calendar.getInstance()
- lastSeen.timeInMillis = timestamp
+
+```java lines
+cometchatConversations.setTitleView(new ConversationsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null);
+ }
- val diffInMillis = now.timeInMillis - lastSeen.timeInMillis
- val diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis)
- val diffInHours = TimeUnit.MILLISECONDS.toHours(diffInMillis)
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ Conversation conversation,
+ RecyclerView.ViewHolder holder,
+ List conversationList,
+ int position) {
- // Check if the timestamp is within the last hour
- if (diffInMinutes == 0L) {
- tvHours.text = "1"
- tvMessage.text = "Min ago"
- card.setCardBackgroundColor(Utils.applyColorWithAlphaValue(Color.parseColor("#6852D6"), 40))
- tvMessage.setTextColor(Color.parseColor("#6852D6"))
- tvHours.setTextColor(Color.parseColor("#6852D6"))
- return
- } else if (diffInMinutes < 60) {
- tvHours.text = diffInMinutes.toString() + ""
- tvMessage.text = "Min ago"
- card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#6852D6"), 40))
- tvMessage.setTextColor(Color.parseColor("#6852D6"))
- tvHours.setTextColor(Color.parseColor("#6852D6"))
- return
- }
+ TextView name = createdView.findViewById(R.id.name);
+ TextView status = createdView.findViewById(R.id.status);
- // Check if the timestamp is within the last 24 hours
- if (diffInHours < 10) {
- tvHours.text = diffInHours.toString() + ""
- tvMessage.text = "Hr ago"
- tvMessage.setTextColor(Color.parseColor("#FFAB00"))
- tvHours.setTextColor(Color.parseColor("#FFAB00"))
- card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#FFAB00"), 40))
- } else if (diffInHours < 1000) {
- tvHours.text = diffInHours.toString() + ""
- tvMessage.text = "Hr ago"
- tvMessage.setTextColor(Color.parseColor("#F44649"))
- tvHours.setTextColor(Color.parseColor("#F44649"))
- card.setCardBackgroundColor(Utils.multiplyColorAlpha(Color.parseColor("#F44649"), 40))
+ name.setText(ConversationsUtils.getConversationTitle(conversation));
+ if (conversation.getConversationType().equals(CometChatConstants.RECEIVER_TYPE_USER)) {
+ status.setVisibility(View.VISIBLE);
+ status.setText("• " + ((User) conversation.getConversationWith()).getStatusMessage());
+ } else {
+ status.setVisibility(View.GONE);
}
}
- })
+ });
+```
+
+
+
+> **What this does:** Registers a `ConversationsViewHolderListener` that provides a custom title view for each conversation item. The example inflates a layout with the conversation name and an inline user status message. For group conversations, the status is hidden.
+
+### `setSubtitleView`
+
+Replace the last message preview text.
+
+
+
+```kotlin lines
+cometchatConversations.setSubtitleView(object :
+ ConversationsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatConversationsListItemsBinding?
+ ): View? {
+ return null
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ conversation: Conversation,
+ holder: RecyclerView.ViewHolder,
+ conversationList: List,
+ position: Int
+ ) {
+ }
+})
```
+
+
+
+```java lines
+cometchatConversations.setSubtitleView(new ConversationsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
+ return null;
+ }
-
+ @Override
+ public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
+ }
+});
+```
+
-Demonstration
+Example with last-active timestamp:
-
+
-
-```java
- cometchatConversations.setTrailingView(new ConversationsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
-
- }
- });
-```
-
-
-
-```kotlin
- cometchatConversations.setTrailingView(object :
+```kotlin lines
+ cometchatConversations.setSubtitleView(object :
ConversationsViewHolderListener() {
override fun createView(
context: Context?,
listItem: CometchatConversationsListItemsBinding?
- ): View? {
- return null
+ ): View {
+ return TextView(context)
}
override fun bindView(
@@ -1624,87 +1411,99 @@ Demonstration
conversationList: List,
position: Int
) {
+ val tvSubtitle = createdView as TextView
+ tvSubtitle.text =
+ "Last Active at: " + SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(
+ conversation.updatedAt * 1000
+ )
+ tvSubtitle.setTextColor(Color.BLACK)
}
})
```
-
-
-
-***
-
-#### setItemView
-
-This function allows developers to assign a completely custom list item design to the Conversations Component, replacing the default layout.
-
-Use cases:
-
-* Implementing a unique conversation list design with custom styling
-* Adding extra elements like swipe gestures, priority indicators, or group labels
-* Fully customizing how messages are displayed in the list
-
-
-```java
- cometchatConversations.setItemView(new ConversationsViewHolderListener() {
+```java YourActivity.java lines
+ cometchatConversations.setSubtitleView(new ConversationsViewHolderListener() {
@Override
public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
- return null;
+ return new TextView(context);
}
@Override
public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
-
+ TextView tvSubtitle = (TextView) createdView;
+ tvSubtitle.setText("Last Active at: "+new SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(conversation.getUpdatedAt() * 1000));
+ tvSubtitle.setTextColor(Color.BLACK);
}
});
```
-
+
+
+> **What this does:** Registers a `ConversationsViewHolderListener` that provides a custom subtitle view for each conversation item. The example creates a `TextView` showing the last active timestamp formatted as "dd/MM/yyyy, HH:mm:ss".
+### `setItemView`
+
+Replace the entire list item row.
+
+
-```kotlin
- cometchatConversations.setItemView(object :
- ConversationsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatConversationsListItemsBinding?
- ): View? {
- return null
- }
+```kotlin lines
+cometchatConversations.setItemView(object :
+ ConversationsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatConversationsListItemsBinding?
+ ): View? {
+ return null
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- conversation: Conversation,
- holder: RecyclerView.ViewHolder,
- conversationList: List,
- position: Int
- ) {
- }
- })
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ conversation: Conversation,
+ holder: RecyclerView.ViewHolder,
+ conversationList: List,
+ position: Int
+ ) {
+ }
+})
```
-
+
+```java lines
+cometchatConversations.setItemView(new ConversationsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
+
+ }
+});
+```
+
-Demonstration
+Example with compact layout:
-You can create an `item_converation_list.xml` as a custom layout file. Which we will inflate in `setListItemView()`
+Create an `item_converation_list.xml` custom layout file:
-```html
+```html lines
+ android:orientation="vertical">
-
-
-
+
-
+
+
+
+```
+
+> **What this does:** Defines a custom list item layout with a `CometChatAvatar`, status indicator, conversation name, and date — providing a compact, single-line conversation item design.
+
+Inflate the XML and bind:
+
+
+
+```kotlin lines
+ cometchatConversations.setItemView(object :
+ ConversationsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatConversationsListItemsBinding?
+ ): View {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.custom_list_item_view, null, false)
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ conversation: Conversation,
+ holder: RecyclerView.ViewHolder,
+ conversationList: List,
+ position: Int
+ ) {
+ val avatar = createdView.findViewById(R.id.custom_avatar)
+ val title = createdView.findViewById(R.id.tvName)
+ val tvDate = createdView.findViewById(R.id.tvDate)
+
+ val name = ConversationsUtils.getConversationTitle(conversation)
+ title.text = name
+ avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle)
+ avatar.avatarPlaceHolderTextAppearance =
+ com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold
+ avatar.setAvatar(name, ConversationsUtils.getConversationAvatar(conversation))
+ val simpleDateFormat = SimpleDateFormat("hh:mm a")
+ val date = simpleDateFormat.format(conversation.updatedAt * 1000)
+ tvDate.text = date
+ }
+ })
+```
+
+
+
+```java YourActivity.java lines
+ cometchatConversations.setItemView(new ConversationsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_list_item_view, null, false);
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
+ CometChatAvatar avatar = createdView.findViewById(R.id.custom_avatar);
+ TextView title = createdView.findViewById(R.id.tvName);
+ TextView tvDate = createdView.findViewById(R.id.tvDate);
+
+ String name = ConversationsUtils.getConversationTitle(conversation);
+ title.setText(name);
+ avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle);
+ avatar.setAvatarPlaceHolderTextAppearance(com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold);
+ avatar.setAvatar(name, ConversationsUtils.getConversationAvatar(conversation));
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm a");
+ String date = simpleDateFormat.format(conversation.getUpdatedAt() * 1000);
+ tvDate.setText(date);
+ }
+ });
+```
+
+
+
+> **What this does:** Registers a `ConversationsViewHolderListener` that replaces the entire list item row. The example inflates a compact layout with an avatar, name, and date — replacing the default multi-line conversation item.
+
+### `setDateTimeFormatter`
+
+Custom date/time formatting for conversation timestamps. Implement the `DateTimeFormatterCallback` interface to control how each time range is displayed:
+
+| Method | Called when |
+| --- | --- |
+| `time(long timestamp)` | Custom full timestamp format |
+| `today(long timestamp)` | Message is from today |
+| `yesterday(long timestamp)` | Message is from yesterday |
+| `lastWeek(long timestamp)` | Message is from the past week |
+| `otherDays(long timestamp)` | Message is older than a week |
+| `minute(long timestamp)` | Exactly 1 minute ago |
+| `minutes(long diffInMinutesFromNow, long timestamp)` | Multiple minutes ago (e.g., "5 minutes ago") |
+| `hour(long timestamp)` | Exactly 1 hour ago |
+| `hours(long diffInHourFromNow, long timestamp)` | Multiple hours ago (e.g., "2 hours ago") |
+
+
+
+```kotlin lines
+cometchatConversations.setDateTimeFormatter(object : DateTimeFormatterCallback {
+
+ private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
+ private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
+
+ override fun time(timestamp: Long): String {
+ return fullTimeFormatter.format(Date(timestamp))
+ }
+
+ override fun today(timestamp: Long): String {
+ return "Today"
+ }
+
+ override fun yesterday(timestamp: Long): String {
+ return "Yesterday"
+ }
+
+ override fun lastWeek(timestamp: Long): String {
+ return "Last Week"
+ }
+
+ override fun otherDays(timestamp: Long): String {
+ return dateFormatter.format(Date(timestamp))
+ }
+
+ override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String {
+ return "$diffInMinutesFromNow mins ago"
+ }
+
+ override fun hours(diffInHourFromNow: Long, timestamp: Long): String {
+ return "$diffInHourFromNow hrs ago"
+ }
+ })
+```
+
+
+
+```java lines
+cometchatConversations.setDateTimeFormatter(new DateTimeFormatterCallback() {
+
+ private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault());
+ private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault());
+
+ @Override
+ public String time(long timestamp) {
+ return fullTimeFormatter.format(new Date(timestamp));
+ }
+
+ @Override
+ public String today(long timestamp) {
+ return "Today";
+ }
+
+ @Override
+ public String yesterday(long timestamp) {
+ return "Yesterday";
+ }
+
+ @Override
+ public String lastWeek(long timestamp) {
+ return "Last Week";
+ }
+
+ @Override
+ public String otherDays(long timestamp) {
+ return dateFormatter.format(new Date(timestamp));
+ }
+
+ @Override
+ public String minutes(long diffInMinutesFromNow, long timestamp) {
+ return diffInMinutesFromNow + " mins ago";
+ }
+
+ @Override
+ public String hours(long diffInHourFromNow, long timestamp) {
+ return diffInHourFromNow + " hrs ago";
+ }
+ });
+```
+
+
+
+### `setOptions`
-
-```
+Replace the long-press context menu entirely.
-In the method `setItemView` you need to inflate the XML and initialize the views using the conversation objects.
+Generic signature:
+
+```kotlin lines
+cometchatConversations.setOptions { context, conversation -> emptyList() }
+```
+
+
-```java YourActivity.java
- cometchatConversations.setItemView(new ConversationsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_list_item_view, null, false);
- }
+```java lines
+cometchatConversations.setOptions((context, conversation) -> Collections.emptyList());
+```
+
+
- @Override
- public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
- CometChatAvatar avatar = createdView.findViewById(R.id.custom_avatar);
- TextView title = createdView.findViewById(R.id.tvName);
- TextView tvDate = createdView.findViewById(R.id.tvDate);
+Example with a custom delete option:
- String name = ConversationsUtils.getConversationTitle(conversation);
- title.setText(name);
- avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle);
- avatar.setAvatarPlaceHolderTextAppearance(com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold);
- avatar.setAvatar(name, ConversationsUtils.getConversationAvatar(conversation));
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm a");
- String date = simpleDateFormat.format(conversation.getUpdatedAt() * 1000);
- tvDate.setText(date);
- }
- });
+
+
+
+
+
+
+```kotlin lines
+cometchatConversations.setOptions { context, conversation ->
+ val optionsArrayList: MutableList =
+ ArrayList()
+ optionsArrayList.add(
+ CometChatPopupMenu.MenuItem(
+ UIKitConstants.ConversationOption.DELETE,
+ "Delete",
+ ResourcesCompat. getDrawable(resources,com.cometchat.chatuikit.R.drawable.cometchat_ic_delete, getContext()?.theme),
+ null,
+ CometChatTheme.getErrorColor(context),
+ 0,
+ CometChatTheme.getErrorColor(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context)
+ ) {
+ Toast.makeText(context, "Delete", Toast.LENGTH_SHORT).show()
+ }
+ )
+ optionsArrayList
+ }
```
+
+
+```java lines
+cometchatConversations.setOptions((context, conversation) -> {
+List optionsArrayList = new ArrayList<>();
+optionsArrayList.add(new CometChatPopupMenu.MenuItem(UIKitConstants.ConversationOption.DELETE,
+ "Delete",
+ getResources().getDrawable(com.cometchat.chatuikit.R.drawable.cometchat_ic_delete),
+ null,
+ CometChatTheme.getErrorColor(context),
+ 0,
+ CometChatTheme.getErrorColor(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context),
+ () -> {
+ Toast.makeText(context, "Delete", Toast.LENGTH_SHORT).show();
+ }));
+ return optionsArrayList;
+ });
+```
+
-
-```kotlin
- cometchatConversations.setItemView(object :
- ConversationsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatConversationsListItemsBinding?
- ): View {
- return LayoutInflater.from(context)
- .inflate(R.layout.custom_list_item_view, null, false)
- }
+### `addOptions`
- override fun bindView(
- context: Context,
- createdView: View,
- conversation: Conversation,
- holder: RecyclerView.ViewHolder,
- conversationList: List,
- position: Int
- ) {
- val avatar = createdView.findViewById(R.id.custom_avatar)
- val title = createdView.findViewById(R.id.tvName)
- val tvDate = createdView.findViewById(R.id.tvDate)
+Append to the long-press context menu without removing defaults.
- val name = ConversationsUtils.getConversationTitle(conversation)
- title.text = name
- avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle)
- avatar.avatarPlaceHolderTextAppearance =
- com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold
- avatar.setAvatar(name, ConversationsUtils.getConversationAvatar(conversation))
- val simpleDateFormat = SimpleDateFormat("hh:mm a")
- val date = simpleDateFormat.format(conversation.updatedAt * 1000)
- tvDate.text = date
- }
- })
-```
+Generic signature:
+
+
+```kotlin lines
+cometchatConversations.addOptions { context, conversation -> emptyList() }
+```
+
+```java lines
+cometchatConversations.addOptions((context, conversation) -> Collections.emptyList());
+```
+
-***
+Example with archive, pin, and mark-as-read options:
-#### setTextFormatters
+
+
+
-This method enables developers to define and apply text formatters that dynamically modify or transform message content before rendering it in the UI. Text formatters can be used for purposes such as:
+
+
+```kotlin lines
+cometchatConversations.addOptions { context, conversation ->
+ val optionsArrayList: MutableList = ArrayList()
+ optionsArrayList.add(
+ CometChatPopupMenu.MenuItem(
+ "ARCHIVE", "Archive",
+ resources.getDrawable(R.drawable.archive), null,
+ CometChatTheme.getTextColorPrimary(context), 0,
+ CometChatTheme.getTextColorPrimary(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context)
+ ) { Toast.makeText(context, "Archive", Toast.LENGTH_SHORT).show() }
+ )
+ optionsArrayList.add(
+ CometChatPopupMenu.MenuItem(
+ "PIN", "Pin",
+ resources.getDrawable(R.drawable.pin), null,
+ CometChatTheme.getTextColorPrimary(context), 0,
+ CometChatTheme.getTextColorPrimary(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context)
+ ) { Toast.makeText(context, "Pin", Toast.LENGTH_SHORT).show() }
+ )
+ optionsArrayList.add(
+ CometChatPopupMenu.MenuItem(
+ "MARKASREAD", "Mark as read",
+ resources.getDrawable(R.drawable.mark_as_read), null,
+ CometChatTheme.getTextColorPrimary(context), 0,
+ CometChatTheme.getTextColorPrimary(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context)
+ ) { Toast.makeText(context, "Mark as read", Toast.LENGTH_SHORT).show() }
+ )
+ optionsArrayList
+ }
+```
+
-* Automatically converting URLs into clickable links
-* Applying Markdown or rich text styling
-* Replacing certain words or patterns with emojis or predefined text
-* Censoring specific words for moderation
+
+```java lines
+cometchatConversations.addOptions((context, conversation) -> {
+ List optionsArrayList = new ArrayList<>();
+ optionsArrayList.add(new CometChatPopupMenu.MenuItem("ARCHIVE",
+ "Archive",
+ getResources().getDrawable(R.drawable.archive),
+ null,
+ CometChatTheme.getTextColorPrimary(context),
+ 0,
+ CometChatTheme.getTextColorPrimary(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context),
+ () -> Toast.makeText(context, "Archive", Toast.LENGTH_SHORT).show()));
+ optionsArrayList.add(new CometChatPopupMenu.MenuItem("PIN",
+ "Pin",
+ getResources().getDrawable(R.drawable.pin),
+ null,
+ CometChatTheme.getTextColorPrimary(context),
+ 0,
+ CometChatTheme.getTextColorPrimary(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context),
+ () -> Toast.makeText(context, "Pin", Toast.LENGTH_SHORT).show()));
+ optionsArrayList.add(new CometChatPopupMenu.MenuItem("MARKASREAD",
+ "Mark as read",
+ getResources().getDrawable(R.drawable.mark_as_read),
+ null,
+ CometChatTheme.getTextColorPrimary(context),
+ 0,
+ CometChatTheme.getTextColorPrimary(context),
+ CometChatTheme.getTextAppearanceBodyRegular(context),
+ () -> Toast.makeText(context, "Mark as read", Toast.LENGTH_SHORT).show()));
+ return optionsArrayList;
+ });
+```
+
+
-By utilizing this method, developers can enhance readability, usability, and compliance with content guidelines. [MentionsFormatter Guide](/ui-kit/android/mentions-formatter-guide)
+### `setTextFormatters`
-**Example**
+Custom text formatters for the conversation subtitle. See the [MentionsFormatter Guide](/ui-kit/android/mentions-formatter-guide) for details.
-```xml themes.xml
+```xml themes.xml lines
- @Override
- public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
- TextView tvSubtitle = (TextView) createdView;
- tvSubtitle.setText("Last Active at: "+new SimpleDateFormat("dd/mm/yyyy, HH:MM:SS").format(conversation.getUpdatedAt() * 1000));
- tvSubtitle.setTextColor(Color.BLACK);
- }
- });
-```
+
-
+
+```
+
-```kotlin
- cometchatConversations.setSubtitleView(object :
- ConversationsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatConversationsListItemsBinding?
- ): View {
- return TextView(context)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- conversation: Conversation,
- holder: RecyclerView.ViewHolder,
- conversationList: List,
- position: Int
- ) {
- val tvSubtitle = createdView as TextView
- tvSubtitle.text =
- "Last Active at: " + SimpleDateFormat("dd/mm/yyyy, HH:MM:SS").format(
- conversation.updatedAt * 1000
- )
- tvSubtitle.setTextColor(Color.BLACK)
- }
- })
+```kotlin lines
+cometChatConversations.setStyle(R.style.CustomConversationsStyle)
```
-
+
+```java lines
+cometChatConversations.setStyle(R.style.CustomConversationsStyle);
+```
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_conversations.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon |
+| `setBackIcon` | `Drawable` | Custom back icon drawable |
+| `setTitleTextColor` | `@ColorInt int` | Title text color in the toolbar |
+| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance in the toolbar |
+| `setItemTitleTextColor` | `@ColorInt int` | Text color for conversation item titles |
+| `setItemTitleTextAppearance` | `@StyleRes int` | Text appearance for conversation item titles |
+| `setItemSubtitleTextColor` | `@ColorInt int` | Text color for conversation item subtitles |
+| `setItemSubtitleTextAppearance` | `@StyleRes int` | Text appearance for conversation item subtitles |
+| `setItemMessageTypeIconTint` | `@ColorInt int` | Tint for message type icons in subtitles |
+| `setSeparatorColor` | `@ColorInt int` | Color of list item separators |
+| `setSeparatorHeight` | `@Dimension int` | Height of list item separators |
+| `setStrokeColor` | `@ColorInt int` | Stroke color of the component border |
+| `setStrokeWidth` | `@Dimension int` | Stroke width of the component border |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component |
+| `setEmptyStateTitleTextColor` | `@ColorInt int` | Title text color for the empty state |
+| `setEmptyStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the empty state |
+| `setEmptyStateTextTitleAppearance` | `@StyleRes int` | Title text appearance for the empty state |
+| `setEmptyStateTextSubtitleAppearance` | `@StyleRes int` | Subtitle text appearance for the empty state |
+| `setErrorStateTitleTextColor` | `@ColorInt int` | Title text color for the error state |
+| `setErrorStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the error state |
+| `setErrorStateTextTitleAppearance` | `@StyleRes int` | Title text appearance for the error state |
+| `setErrorStateTextSubtitleAppearance` | `@StyleRes int` | Subtitle text appearance for the error state |
+| `setDeleteOptionIcon` | `Drawable` | Icon for the delete option in the context menu |
+| `setDeleteOptionIconTint` | `int` | Tint for the delete option icon |
+| `setDeleteOptionTextColor` | `int` | Text color for the delete option |
+| `setDeleteOptionTextAppearance` | `int` | Text appearance for the delete option |
+| `setAvatarStyle` | `@StyleRes int` | Style for conversation avatars |
+| `setStatusIndicatorStyle` | `@StyleRes int` | Style for online/offline status indicators |
+| `setBadgeStyle` | `@StyleRes int` | Style for unread badge counts |
+| `setReceiptStyle` | `@StyleRes int` | Style for read/delivered receipt icons |
+| `setTypingIndicatorStyle` | `@StyleRes int` | Style for typing indicator text |
+| `setMentionsStyle` | `@StyleRes int` | Style for @mention text in subtitles |
+| `setItemBackgroundColor` | `@ColorInt int` | Background color for list items |
+| `setItemSelectedBackgroundColor` | `@ColorInt int` | Background color for selected list items |
+
+### Checkbox Style Properties (Selection Mode)
+
+When using `SINGLE` or `MULTIPLE` selection mode, checkboxes appear on each item:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setCheckBoxStrokeWidth` | `@Dimension int` | Stroke width of the checkbox border |
+| `setCheckBoxCornerRadius` | `@Dimension int` | Corner radius of the checkbox |
+| `setCheckBoxStrokeColor` | `@ColorInt int` | Stroke color of the checkbox border |
+| `setCheckBoxBackgroundColor` | `@ColorInt int` | Background color of unchecked checkbox |
+| `setCheckBoxCheckedBackgroundColor` | `@ColorInt int` | Background color of checked checkbox |
+| `setCheckBoxSelectIcon` | `Drawable` | Icon shown when checkbox is checked |
+| `setCheckBoxSelectIconTint` | `@ColorInt int` | Tint for the checkbox select icon |
+| `setDiscardSelectionIcon` | `Drawable` | Icon for the discard selection button |
+| `setDiscardSelectionIconTint` | `@ColorInt int` | Tint for the discard selection icon |
+| `setSubmitSelectionIcon` | `Drawable` | Icon for the submit selection button |
+| `setSubmitSelectionIconTint` | `@ColorInt int` | Tint for the submit selection icon |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override behavior on user interaction | Activity/Fragment | `setOn` callbacks | `setOnItemClick((v, pos, c) -> { ... })` |
+| Filter which conversations appear | Activity/Fragment | `setConversationsRequestBuilder` | `setConversationsRequestBuilder(builder)` |
+| Toggle visibility of UI elements | Activity/Fragment | `setVisibility(int)` | `setReceiptsVisibility(View.GONE)` |
+| Replace a section of the list item | Activity/Fragment | `setView` | `setLeadingView(listener)` |
+| Change colors, fonts, spacing | `themes.xml` | `CometChatConversationsStyle` | `@style/...` |
+| Avatar style (corner radius, background) | `themes.xml` | `cometchatConversationsAvatarStyle` | `8dp` |
+| Badge count style (background, text color) | `themes.xml` | `cometchatConversationsBadgeStyle` | `#F76808` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometChatConversations.setStyle(R.style.CustomConversationsStyle);` |
+| Back button visibility | Activity/Fragment | `setBackIconVisibility(int)` | `.setBackIconVisibility(View.VISIBLE);` |
+| Toolbar visibility | Activity/Fragment | `setToolbarVisibility(int)` | `.setToolbarVisibility(View.GONE);` |
+| Loading state visibility | Activity/Fragment | `setLoadingStateVisibility(int)` | `.setLoadingStateVisibility(View.GONE);` |
+| Delete option visibility on long press | Activity/Fragment | `setDeleteConversationOptionVisibility(int)` | `.setDeleteConversationOptionVisibility(View.GONE);` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE);` |
+| Empty state visibility | Activity/Fragment | `setEmptyStateVisibility(int)` | `.setEmptyStateVisibility(View.GONE);` |
+| Separator visibility | Activity/Fragment | `setSeparatorVisibility(int)` | `.setSeparatorVisibility(View.GONE);` |
+| User online status visibility | Activity/Fragment | `setUserStatusVisibility(int)` | `.setUserStatusVisibility(View.GONE);` |
+| Group type indicator visibility | Activity/Fragment | `setGroupTypeVisibility(int)` | `.setGroupTypeVisibility(View.GONE);` |
+| Read/delivered receipts visibility | Activity/Fragment | `setReceiptsVisibility(int)` | `.setReceiptsVisibility(View.GONE);` |
+| Incoming message sound | Activity/Fragment | `disableSoundForMessages(boolean)` | `.disableSoundForMessages(true);` |
+| Custom message sound | Activity/Fragment | `setCustomSoundForMessages(int)` | `.setCustomSoundForMessages(R.raw.cometchat_beep2);` |
+| Selection mode (single/multiple) | Activity/Fragment | `setSelectionMode(SelectionMode)` | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| Date/time formatting | Activity/Fragment | `setDateTimeFormatter(DateTimeFormatterCallback)` | See `setDateTimeFormatter` code above |
+| Date format | Activity/Fragment | `setDateFormat(SimpleDateFormat)` | `.setDateFormat(new SimpleDateFormat("dd MMM, hh:mm a", Locale.getDefault()));` |
+| Long-press options (replace) | Activity/Fragment | `setOptions(Function2)` | See `setOptions` code above |
+| Long-press options (append) | Activity/Fragment | `addOptions(Function2)` | See `addOptions` code above |
+| Loading view | Activity/Fragment | `setLoadingView(int)` | `.setLoadingView(R.layout.your_loading_view);` |
+| Empty view | Activity/Fragment | `setEmptyView(int)` | `.setEmptyView(R.layout.your_empty_view);` |
+| Error view | Activity/Fragment | `setErrorView(int)` | `.setErrorView(R.layout.your_error_view);` |
+| Leading view (avatar area) | Activity/Fragment | `setLeadingView(ConversationsViewHolderListener)` | See `setLeadingView` code above |
+| Title view | Activity/Fragment | `setTitleView(ConversationsViewHolderListener)` | See `setTitleView` code above |
+| Trailing view | Activity/Fragment | `setTrailingView(ConversationsViewHolderListener)` | See `setTrailingView` code above |
+| Entire list item | Activity/Fragment | `setItemView(ConversationsViewHolderListener)` | See `setItemView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(ConversationsViewHolderListener)` | See `setSubtitleView` code above |
+| Text formatters (mentions) | Activity/Fragment | `setTextFormatters(List)` | See `setTextFormatters` code above |
+| Overflow menu | Activity/Fragment | `setOverflowMenu(View)` | `cometChatConversations.setOverflowMenu(view);` |
+| Filter conversations | Activity/Fragment | `setConversationsRequestBuilder(ConversationsRequestBuilder)` | See Filters code above |
+| Search box visibility | Activity/Fragment | `setSearchBoxVisibility(int)` | `.setSearchBoxVisibility(View.GONE);` |
+| Search input text | Activity/Fragment | `setSearchInputText(String)` | `.setSearchInputText("search term");` |
+| Search placeholder text | Activity/Fragment | `setSearchPlaceholderText(String)` | `.setSearchPlaceholderText("Search...");` |
+| Search input colors | Activity/Fragment | `setSearchInputTextColor`, `setSearchInputBackgroundColor` | `.setSearchInputTextColor(Color.BLACK);` |
+| Search input icons | Activity/Fragment | `setSearchInputStartIcon`, `setSearchInputEndIcon` | `.setSearchInputStartIcon(drawable);` |
+| Hide receipts (adapter) | Activity/Fragment | `hideReceipts(boolean)` | `.hideReceipts(true);` |
+| Programmatic selection | Activity/Fragment | `selectConversation(Conversation, SelectionMode)` | `.selectConversation(conv, SelectionMode.SINGLE);` |
+| Clear selection | Activity/Fragment | `clearSelection()` | `.clearSelection();` |
+| Selected conversations strip | Activity/Fragment | `setSelectedConversationsListVisibility(int)` | `.setSelectedConversationsListVisibility(View.VISIBLE);` |
+| Selected conversation avatar style | Activity/Fragment | `setSelectedConversationAvatarStyle(int)` | `.setSelectedConversationAvatarStyle(R.style.CustomAvatarStyle);` |
+| Internal adapter access | Activity/Fragment | `getConversationsAdapter()` / `setAdapter()` | Advanced use only |
+| Internal ViewModel access | Activity/Fragment | `getViewModel()` | Advanced use only |
+| Mention-all label | Activity/Fragment | `setMentionAllLabelId(String, String)` | `.setMentionAllLabelId("all", "Everyone");` |
+
+## Accessibility
+
+The component renders a scrollable `RecyclerView` of interactive conversation items. Each conversation row responds to tap and long-press gestures. The unread badge count is rendered as a `TextView` with the count as text content, accessible to TalkBack. Avatar images include the conversation name as content description.
+
+For custom views provided via `setLeadingView`, `setTitleView`, `setTrailingView`, or `setItemView`, ensure you set `android:contentDescription` on visual-only elements (status indicators, icons) so TalkBack can announce them. The default views handle this automatically.
+
+Group type indicators and online/offline status dots are visual-only by default. If screen reader descriptions are needed for these, provide them via a custom view with appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Conversation list is empty despite having conversations | Verify that a user is logged in with `CometChatUIKit.login()` before displaying the component. The component fetches conversations for the logged-in user only. |
+| Filters not applied | Ensure you call `setConversationsRequestBuilder(builder)` on the `CometChatConversations` instance after creating and configuring the builder. |
+| Custom style not visible | Verify the style parent is `CometChatConversationsStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| `setOnItemClick` not firing | If you set `setSelectionMode` to `MULTIPLE`, item clicks may be consumed by the selection logic. Set the selection mode to `NONE` if you need standard click behavior. |
+| Event listener not receiving events | Ensure you call `CometChatConversationEvents.addListener` with a unique tag. If you use the same tag as another listener, the previous one is replaced. |
+| Typing indicator not showing in custom leading view | Ensure you add a `CometChat.MessageListener` to track typing events and update the `typingIndicatorHashMap` before calling `setLeadingView`. |
+| Custom view returns null in `createView` | If `createView` returns `null`, the default view is used. Return a valid inflated `View` to replace the default. |
+| Sound still plays after `disableSoundForMessages(true)` | Ensure you call `disableSoundForMessages(true)` before the component starts loading. If called after data is already loaded, it may not take effect for existing notifications. |
+| Delete option still visible after hiding | Ensure you call `setDeleteConversationOptionVisibility(View.GONE)` on the correct `CometChatConversations` instance. |
+
+## FAQ
+
+**Q: How do I show only user conversations (no groups)?**
+**A:** Create a `ConversationsRequest.ConversationsRequestBuilder`, call `setConversationType(CometChatConstants.CONVERSATION_TYPE_USER)`, and pass it to `setConversationsRequestBuilder`.
+
+**Q: Can I use `CometChatConversations` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, call `setContentView(new CometChatConversations(this))`. In a Fragment, return `new CometChatConversations(getContext())` from `onCreateView`.
+
+**Q: How do I listen for conversation deletion events outside the component?**
+**A:** Use `CometChatConversationEvents.addListener("YOUR_TAG", ...)` and override `ccConversationDeleted`. Call `CometChatConversationEvents.removeListener("YOUR_TAG")` to unsubscribe.
+
+**Q: How do I customize the avatar and badge styles?**
+**A:** Define custom styles with parents `CometChatAvatarStyle` and `CometChatBadgeStyle` in `themes.xml`, reference them in a `CometChatConversationsStyle`, and apply with `setStyle()`.
+
+**Q: How do I add custom long-press options without removing the defaults?**
+**A:** Use `addOptions` instead of `setOptions`. `addOptions` appends your custom `MenuItem` objects to the existing default options.
+
+
+## Next Steps
+
+- [Groups component](/ui-kit/android/groups)
+- [Message list component](/ui-kit/android/message-list)
+- [Message composer component](/ui-kit/android/message-composer)
diff --git a/ui-kit/android/core-features.mdx b/ui-kit/android/core-features.mdx
index ecc7e1470..44a26ed5d 100644
--- a/ui-kit/android/core-features.mdx
+++ b/ui-kit/android/core-features.mdx
@@ -53,7 +53,7 @@ CometChat's Read Receipts feature provides visibility into the message status, l
| [MessageList](/ui-kit/android/message-list) | [MessageList](/ui-kit/android/message-list) is a Component that renders different types of Message bubbles, Read Recept status is an integral part of all message bubbles, no matter the type, and provides real-time updates about the status of the message. |
| [MessageInformation](/ui-kit/android/component-styling#message-information) | [MessageInformation](/ui-kit/android/component-styling#message-information) component provides transparency into the status of each sent message, giving the sender insights into whether their message has been delivered and read. |
-## Mark As Unread
+## Mark as Unread
Mark as Unread feature allows users to manually mark messages as unread, helping them keep track of important conversations they want to revisit later. When enabled, the message list can automatically start from the first unread message, making it easier to pick up where you left off.
@@ -66,9 +66,9 @@ Mark as Unread feature allows users to manually mark messages as unread, helping
| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) provides the "Mark as unread" option in message actions and supports starting from the first unread message when enabled. |
| [Conversations](/ui-kit/android/conversations) | [Conversations](/ui-kit/android/conversations) component listens to conversation updates and reflects the updated unread count in real-time. |
-## Typing Indicator
+## Typing Indicators
-The Typing Indicator feature in CometChat shows when a user is typing a response in real-time, fostering a more interactive and engaging chat environment. This feature enhances the real-time communication experience, making conversations feel more natural and fluid.
+Typing Indicators in CometChat show when a user is typing a response in real-time, fostering a more interactive and engaging chat environment. This feature enhances the real-time communication experience, making conversations feel more natural and fluid.
@@ -91,7 +91,7 @@ CometChat's User Presence feature allows users to see whether their contacts are
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Conversations](/ui-kit/android/conversations) | [Conversations](/ui-kit/android/conversations) is a Component that renders Conversations item List, Conversations item also shows user presence information. |
| [Message Header](/ui-kit/android/message-header) | [Message Header](/ui-kit/android/message-header) that renders details of User or Groups in ToolBar. The MessageHeader also handles user Presence information. |
-| [Users](/ui-kit/android/users) | [Users](/ui-kit/android/users) renders list of users available in your app.It also responsible to render users Presence information. |
+| [Users](/ui-kit/android/users) | [Users](/ui-kit/android/users) renders a list of users available in your app. It is also responsible for rendering user presence information. |
| [Group Members](/ui-kit/android/group-members) | [Group Members](/ui-kit/android/group-members) renders list of users available in the group. The Group Members component also handles user Presence information. |
## Reactions
@@ -117,12 +117,26 @@ Mentions is a robust feature provided by CometChat that enhances the interactivi
| Components | Functionality |
| -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Conversations](/ui-kit/android/conversations) | [Conversations](/ui-kit/android/conversations) component provides an enhanced user experience by integrating the Mentions feature. This means that from the conversation list itself, users can see where they or someone else have been specifically mentioned. |
-| [MessageComposer](/ui-kit/android/message-composer) | [MessageComposer](/ui-kit/android/message-composer)is a component that allows users to craft and send various types of messages, including the usage of the Mentions feature for direct addressing within the conversation. |
+| [MessageComposer](/ui-kit/android/message-composer) | [MessageComposer](/ui-kit/android/message-composer) is a component that allows users to craft and send various types of messages, including the usage of the Mentions feature for direct addressing within the conversation. |
| [MessageList](/ui-kit/android/message-list) | [MessageList](/ui-kit/android/message-list) is a component that displays a list of sent and received messages. It also supports the rendering of Mentions, enhancing the readability and interactivity of conversations. |
-## Quoted Reply
+## Threaded Conversations
+
+The Threaded Conversations feature enables users to respond directly to a specific message in a chat. This keeps conversations organized and enhances the user experience by maintaining context, especially in group chats.
+
+
+
+
+
+| Components | Functionality |
+| ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Threaded Header](/ui-kit/android/threaded-messages-header) | [Threaded Header](/ui-kit/android/threaded-messages-header) that displays all replies made to a particular message in a conversation. |
+| [MessageComposer](/ui-kit/android/message-composer) | [MessageComposer](/ui-kit/android/message-composer) is a component that allows users to craft and send various types of messages, including the usage of the Mentions feature for direct addressing within the conversation. |
+| [MessageList](/ui-kit/android/message-list) | [MessageList](/ui-kit/android/message-list) is a component that displays a list of sent and received messages. It also supports the rendering of Mentions, enhancing the readability and interactivity of conversations. |
+
+## Quoted Replies
-Quoted Reply is a robust feature provided by CometChat that enables users to quickly reply to specific messages by selecting the "Reply" option from a message's action menu. This enhances context, keeps conversations organized, and improves overall chat experience in both 1-1 and group chats.
+Quoted Replies are a robust feature provided by CometChat that enables users to quickly reply to specific messages by selecting the "Reply" option from a message's action menu. This enhances context, keeps conversations organized, and improves overall chat experience in both 1-1 and group chats.
@@ -133,20 +147,15 @@ Quoted Reply is a robust feature provided by CometChat that enables users to qui
| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) supports replying to messages via the "Reply" option. Users can select "Reply" on a message to open the composer with the quoted reply pre-filled, maintaining context. |
| [Message Composer](/ui-kit/android/message-composer) | [Message Composer](/ui-kit/android/message-composer) works seamlessly with Quoted Message by showing the quoted reply above the input field, letting users compose their response in proper context. |
-## Conversation and Advanced Search
+## Group Chats
-Conversation and Advanced Search is a powerful feature provided by CometChat that enables users to quickly find conversations, messages, and media across chats in real time. It supports filters, scopes, and custom actions, allowing users to locate content efficiently while keeping the chat experience smooth and intuitive.
+CometChat facilitates Group Chats, allowing users to have conversations with multiple participants simultaneously. This feature is crucial for team collaborations, group discussions, social communities, and more.
-
+
-| Components | Functionality |
-| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Search](/ui-kit/android/search) | [Search](/ui-kit/android/search) allows users to search across conversations and messages in real time. Users can click on a result to open the conversation or jump directly to a specific message. |
-| [Message Header](/ui-kit/android/message-header) | [Message Header](/ui-kit/android/message-header) shows the search button in the chat header, allowing users to search within a conversation. |
-| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) shows the selected message when clicked from search results and highlights it in the message list. |
-| [Conversations](/ui-kit/android/conversations) | [Conversations](/ui-kit/android/conversations) displays the search input. |
+For a comprehensive understanding and guide on implementing and using the Groups feature in CometChat, you should refer to our detailed guide on [Groups](/ui-kit/android/groups).
## Moderation
@@ -182,26 +191,17 @@ Learn more about how flagged messages are handled, reviewed, and moderated in th
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. |
-## Threaded Conversations
-
-The Threaded Conversations feature enables users to respond directly to a specific message in a chat. This keeps conversations organized and enhances the user experience by maintaining context, especially in group chats.
-
-
-
-
-
-| Components | Functionality |
-| ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Threaded Header](/ui-kit/android/threaded-messages-header) | [Threaded Header](/ui-kit/android/threaded-messages-header) that displays all replies made to a particular message in a conversation. |
-| [MessageComposer](/ui-kit/android/message-composer) | [MessageComposer](/ui-kit/android/message-composer)is a component that allows users to craft and send various types of messages, including the usage of the Mentions feature for direct addressing within the conversation. |
-| [MessageList](/ui-kit/android/message-list) | [MessageList](/ui-kit/android/message-list) is a component that displays a list of sent and received messages. It also supports the rendering of Mentions, enhancing the readability and interactivity of conversations. |
-
-## Group Chat
+## Conversation and Advanced Search
-CometChat facilitates Group Chats, allowing users to have conversations with multiple participants simultaneously. This feature is crucial for team collaborations, group discussions, social communities, and more.
+Conversation and Advanced Search is a powerful feature provided by CometChat that enables users to quickly find conversations, messages, and media across chats in real time. It supports filters, scopes, and custom actions, allowing users to locate content efficiently while keeping the chat experience smooth and intuitive.
-
+
-For a comprehensive understanding and guide on implementing and using the Groups feature in CometChat, you should refer to our detailed guide on [Groups](/ui-kit/android/groups).
+| Components | Functionality |
+| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Search](/ui-kit/android/search) | [Search](/ui-kit/android/search) allows users to search across conversations and messages in real time. Users can click on a result to open the conversation or jump directly to a specific message. |
+| [Message Header](/ui-kit/android/message-header) | [Message Header](/ui-kit/android/message-header) shows the search button in the chat header, allowing users to search within a conversation. |
+| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) shows the selected message when clicked from search results and highlights it in the message list. |
+| [Conversations](/ui-kit/android/conversations) | [Conversations](/ui-kit/android/conversations) displays the search input. |
diff --git a/ui-kit/android/events.mdx b/ui-kit/android/events.mdx
index 61c3696eb..6d34ebd62 100644
--- a/ui-kit/android/events.mdx
+++ b/ui-kit/android/events.mdx
@@ -2,22 +2,54 @@
title: "Events"
---
-## Overview
+Events enable a decoupled, flexible architecture in the CometChat UI Kit. Components and Composite Components emit events in response to user interactions or state changes, allowing other parts of your application to react without direct references between components.
-Events allow for a decoupled, flexible architecture where different parts of the application can interact without having to directly reference each other. This makes it easier to create complex, interactive experiences, as well as to extend and customize the functionality provided by the CometChat UI Kit.
+## When to use this
-Both Components and Composite Components have the ability to emit events. These events are dispatched in response to certain changes or user interactions within the component. By emitting events, these components allow other parts of the application to react to changes or interactions, thus enabling dynamic and interactive behavior within the application.
+- You need to update your UI when a user is blocked or unblocked.
+- You need to respond to group actions such as member joins, kicks, bans, or ownership transfers.
+- You need to track conversation deletions or updates in real time.
+- You need to react to messages being sent, edited, deleted, or read.
+- You need to handle call lifecycle events (outgoing, accepted, rejected, ended).
+- You need to respond to UI-level events such as panel visibility changes or active chat changes.
+
+## Prerequisites
+
+- The `cometchat-chat-uikit-android` dependency added to your project.
+- `CometChatUIKit.init()` called and completed successfully.
+- A logged-in CometChat user (call `CometChatUIKit.login()` before registering listeners).
+
+## API reference
### User Events
-`UserEvents` emit events when the logged-in user executes actions on another user. This class provides methods to add and remove listeners for user events, as well as methods to handle specific user actions such as blocking and unblocking users.
+`CometChatUserEvents` emits events when the logged-in user executes actions on another user. This class provides methods to add and remove listeners for user events, as well as methods to handle specific user actions such as blocking and unblocking users.
+
+**Events:**
-1. `ccUserBlocked`: Triggered when the logged-in user blocks another user.
-2. `ccUserUnblocked`: Triggered when the logged-in user unblocks another user.
+| Event | Description |
+| ----- | ----------- |
+| `ccUserBlocked` | Triggered when the logged-in user blocks another user. |
+| `ccUserUnblocked` | Triggered when the logged-in user unblocks another user. |
+
+**Listener registration:**
+
+```kotlin lines
+CometChatUserEvents.addUserListener(LISTENERS_TAG, object : CometChatUserEvents() {
+ override fun ccUserBlocked(user: User) {
+ // Perform action when user is blocked
+ }
+
+ override fun ccUserUnblocked(user: User) {
+ // Perform action when user is unblocked
+ }
+})
+```
+
-```java
+```java lines
CometChatUserEvents.addUserListener(LISTENERS_TAG, new CometChatUserEvents() {
@Override
public void ccUserBlocked(User user) {
@@ -30,46 +62,82 @@ CometChatUserEvents.addUserListener(LISTENERS_TAG, new CometChatUserEvents() {
}
});
```
-
+
+
+> **What this does:** Registers a listener on `CometChatUserEvents` using a unique `LISTENERS_TAG`. The `ccUserBlocked` callback fires when the logged-in user blocks another user, and `ccUserUnblocked` fires when the logged-in user unblocks another user.
+
+---
+
+### Group Events
+
+`CometChatGroupEvents` emits events when the logged-in user performs actions related to groups. This class provides methods to listen to various group-related events and handle them.
+**Events:**
+
+| Event | Description |
+| ----- | ----------- |
+| `ccGroupCreated` | Triggered when the logged-in user creates a group. |
+| `ccGroupDeleted` | Triggered when the logged-in user deletes a group. |
+| `ccGroupLeft` | Triggered when the logged-in user leaves a group. Provides the action message, the user who left, and the group. |
+| `ccGroupMemberScopeChanged` | Triggered when the logged-in user changes the scope of another group member. Provides the action message, updated user, new scope, previous scope, and group. |
+| `ccGroupMemberBanned` | Triggered when the logged-in user bans a group member from the group. Provides the action message, banned user, who banned them, and the group. |
+| `ccGroupMemberKicked` | Triggered when the logged-in user kicks another group member from the group. Provides the action message, kicked user, who kicked them, and the group. |
+| `ccGroupMemberUnBanned` | Triggered when the logged-in user unbans a user banned from the group. Provides the action message, unbanned user, who unbanned them, and the group. |
+| `ccGroupMemberJoined` | Triggered when the logged-in user joins a group. Provides the joined user and the group. |
+| `ccGroupMemberAdded` | Triggered when the logged-in user adds new members to the group. Provides action messages, added users, the group, and who added them. |
+| `ccOwnershipChanged` | Triggered when the logged-in user transfers the ownership of their group to some other member. Provides the group and the new owner (as `GroupMember`). |
+
+**Listener registration:**
+
+
-```kotlin
-CometChatUserEvents.addUserListener(LISTENERS_TAG, object : CometChatUserEvents() {
- override fun ccUserBlocked(user: User) {
- // Perform action when user is blocked
+```kotlin lines
+CometChatGroupEvents.addGroupListener(LISTENERS_TAG, object : CometChatGroupEvents() {
+ override fun ccGroupCreated(group: Group) {
+ // Perform action when group is created
}
- override fun ccUserUnblocked(user: User) {
- // Perform action when user is unblocked
+ override fun ccGroupDeleted(group: Group) {
+ // Perform action when group is deleted
}
-})
-```
-
+ override fun ccGroupLeft(actionMessage: Action, leftUser: User, leftGroup: Group) {
+ // Perform action when user leaves group
+ }
-
+ override fun ccGroupMemberScopeChanged(actionMessage: Action, updatedUser: User, scopeChangedTo: String, scopeChangedFrom: String, group: Group) {
+ // Perform action when group member scope is changed
+ }
-### Group Events
+ override fun ccGroupMemberBanned(actionMessage: Action, bannedUser: User, bannedBy: User, bannedFrom: Group) {
+ // Perform action when user is banned from group
+ }
-`GroupEvents` Emits events when the logged-in user performs actions related to groups. This class provides methods to listen to various group-related events and handle them accordingly.
+ override fun ccGroupMemberKicked(actionMessage: Action, kickedUser: User, kickedBy: User, kickedFrom: Group) {
+ // Perform action when user is kicked from group
+ }
-Following are all the group events
+ override fun ccGroupMemberUnBanned(actionMessage: Action, unbannedUser: User, unBannedBy: User, unBannedFrom: Group) {
+ // Perform action when user is unbanned from group
+ }
-1. `ccGroupCreated`: Triggered when the logged-in user creates a group.
-2. `ccGroupDeleted`: Triggered when the logged-in user deletes a group.
-3. `ccGroupLeft`: Triggered when the logged-in user leaves a group.
-4. `ccGroupMemberScopeChanged`: Triggered when the logged-in user changes the scope of another group member.
-5. `ccGroupMemberBanned`: Triggered when the logged-in user bans a group member from the group.
-6. `ccGroupMemberKicked`: Triggered when the logged-in user kicks another group member from the group.
-7. `ccGroupMemberUnbanned`: Triggered when the logged-in user unbans a user banned from the group.
-8. `ccGroupMemberJoined`: Triggered when the logged-in user joins a group.
-9. `ccGroupMemberAdded`: Triggered when the logged-in user adds new members to the group.
-10. `ccOwnershipChanged`: Triggered when the logged-in user transfers the ownership of their group to some other member.
+ override fun ccGroupMemberJoined(joinedUser: User, joinedGroup: Group) {
+ // Perform action when user joins group
+ }
-To listen to group events
+ override fun ccGroupMemberAdded(actionMessages: List, usersAdded: List, userAddedIn: Group, addedBy: User) {
+ // Perform action when members are added to group
+ }
-```typescript
+ override fun ccOwnershipChanged(group: Group, newOwner: GroupMember) {
+ // Perform action when group ownership is changed
+ }
+})
+```
+
+
+```java lines
CometChatGroupEvents.addGroupListener(LISTENERS_TAG, new CometChatGroupEvents() {
@Override
public void ccGroupCreated(Group group) {
@@ -82,59 +150,82 @@ CometChatGroupEvents.addGroupListener(LISTENERS_TAG, new CometChatGroupEvents()
}
@Override
- public void ccGroupLeft(Group group) {
+ public void ccGroupLeft(Action actionMessage, User leftUser, Group leftGroup) {
// Perform action when user leaves group
}
@Override
- public void ccGroupMemberScopeChanged(Group group, User user, String scope) {
+ public void ccGroupMemberScopeChanged(Action actionMessage, User updatedUser, String scopeChangedTo, String scopeChangedFrom, Group group) {
// Perform action when group member scope is changed
}
@Override
- public void ccGroupMemberBanned(Group group, User user, User bannedBy) {
+ public void ccGroupMemberBanned(Action actionMessage, User bannedUser, User bannedBy, Group bannedFrom) {
// Perform action when user is banned from group
}
@Override
- public void ccGroupMemberKicked(Group group, User kickedUser, User kickedBy) {
+ public void ccGroupMemberKicked(Action actionMessage, User kickedUser, User kickedBy, Group kickedFrom) {
// Perform action when user is kicked from group
}
@Override
- public void ccGroupMemberUnbanned(Group group, User user, User unbannedBy) {
+ public void ccGroupMemberUnBanned(Action actionMessage, User unbannedUser, User unBannedBy, Group unBannedFrom) {
// Perform action when user is unbanned from group
}
@Override
- public void ccGroupMemberJoined(Group group, User joinedUser) {
+ public void ccGroupMemberJoined(User joinedUser, Group joinedGroup) {
// Perform action when user joins group
}
@Override
- public void ccGroupMemberAdded(Group group, List addedMembers, User addedBy) {
+ public void ccGroupMemberAdded(List actionMessages, List usersAdded, Group userAddedIn, User addedBy) {
// Perform action when members are added to group
}
@Override
- public void ccOwnershipChanged(Group group, User newOwner, User oldOwner) {
+ public void ccOwnershipChanged(Group group, GroupMember newOwner) {
// Perform action when group ownership is changed
}
});
```
+
+
+
+> **What this does:** Registers a listener on `CometChatGroupEvents` using a unique `LISTENERS_TAG`. Each callback fires when the logged-in user performs the corresponding group action — creating, deleting, leaving a group, or managing members (scope change, ban, kick, unban, join, add, ownership transfer).
+
+---
### Conversation Events
-The `ConversationEvents` component emits events when the logged-in user performs actions related to conversations. This allows for the UI to be updated accordingly. Below are the events emitted by the Conversation Component:
+`CometChatConversationEvents` emits events when the logged-in user performs actions related to conversations. This allows the UI to be updated when conversations change.
-* `ccConversationDeleted`: Triggered when the logged-in user deletes a conversation.
-* `ccUpdateConversation`: Triggered when there is an update in the conversation.
+**Events:**
-To listen to conversation events and handle them in your application, you can use the following code snippets:
+| Event | Description |
+| ----- | ----------- |
+| `ccConversationDeleted` | Triggered when the logged-in user deletes a conversation. |
+| `ccUpdateConversation` | Triggered when there is an update in the conversation. |
+
+**Listener registration:**
+
+```kotlin lines
+CometChatConversationEvents.addListener("LISTENERS_TAG", object : CometChatConversationEvents() {
+ override fun ccConversationDeleted(conversation: Conversation) {
+ // Perform action when conversation is deleted
+ }
+
+ override fun ccUpdateConversation(conversation: Conversation) {
+ // Perform action when conversation is updated
+ }
+})
+```
+
-```java
+```java lines
CometChatConversationEvents.addListener("LISTENERS_TAG", new CometChatConversationEvents() {
@Override
public void ccConversationDeleted(Conversation conversation) {
@@ -142,122 +233,144 @@ CometChatConversationEvents.addListener("LISTENERS_TAG", new CometChatConversati
}
@Override
- public void ccUpdateConversation(Conversation conversation) {
- // Perform action when conversation is updated
- }
+ public void ccUpdateConversation(Conversation conversation) {
+ // Perform action when conversation is updated
+ }
});
```
-
+
-
-```kotlin
-CometChatConversationEvents.addListener("LISTENERS_TAG", object : CometChatConversationEvents() {
- override fun ccConversationDeleted(conversation: Conversation) {
- // Perform action when conversation is deleted
- }
-})
-```
+> **What this does:** Registers a listener on `CometChatConversationEvents` using a unique listener tag. The `ccConversationDeleted` callback fires when the logged-in user deletes a conversation, and `ccUpdateConversation` fires when a conversation is updated.
-
-
-
+---
### Message Events
-`MessageEvents` emits events when various actions are performed on messages within the application. These events facilitate updating the UI accordingly. Below are the events emitted by the MessageEvents component:
+`CometChatMessageEvents` emits events when various actions are performed on messages within the application. These events facilitate updating the UI when messages change.
-* `ccMessageSent`: Triggered whenever a loggedIn user sends any message. It can have two states: `inProgress` and `sent`.
-* `ccMessageEdited`: Triggered whenever a loggedIn user edits any message from the list of messages. It can have two states: `inProgress` and `sent`.
-* `ccMessageDeleted`: Triggered whenever a loggedIn user deletes any message from the list of messages.
-* `ccMessageRead`: Triggered whenever a loggedIn user reads any message.
-* `ccLiveReaction`: Triggered whenever a loggedIn user clicks on live reaction.
-* `onFormMessageReceived`: Triggered when a form message is received.
-* `onCardMessageReceived`: Triggered when a card message is received.
-* `onCustomInteractiveMessageReceived`: Triggered when a custom interactive message is received.
-* `onInteractionGoalCompleted`: Triggered when an interaction goal is completed.
-* `onSchedulerMessageReceived`: Triggered when a scheduler message is received.
+**Events:**
-To listen to message events and handle them in your application, you can use the following code snippets:
+| Event | Description |
+| ----- | ----------- |
+| `ccMessageSent` | Triggered whenever a logged-in user sends any message. It can have two states: `inProgress` and `sent`. |
+| `ccMessageEdited` | Triggered whenever a logged-in user edits any message from the list of messages. It can have two states: `inProgress` and `sent`. |
+| `ccMessageDeleted` | Triggered whenever a logged-in user deletes any message from the list of messages. |
+| `ccMessageRead` | Triggered whenever a logged-in user reads any message. |
+| `ccLiveReaction` | Triggered whenever a logged-in user clicks on live reaction. |
+| `onFormMessageReceived` | Triggered when a form message is received. |
+| `onCardMessageReceived` | Triggered when a card message is received. |
+| `onCustomInteractiveMessageReceived` | Triggered when a custom interactive message is received. |
+| `onInteractionGoalCompleted` | Triggered when an interaction goal is completed. |
+| `onSchedulerMessageReceived` | Triggered when a scheduler message is received. |
+
+**Listener registration:**
-
-```java
-CometChatMessageEvents.addListener("UNIQUE_ID", new CometChatMessageEvents() {
- @Override
- public void ccMessageSent(BaseMessage baseMessage, int status) {
+
+```kotlin lines
+CometChatMessageEvents.addListener("UNIQUE_ID", object : CometChatMessageEvents() {
+ override fun ccMessageSent(baseMessage: BaseMessage?, status: Int) {
// Perform action when message is sent
}
- @Override
- public void ccMessageEdited(BaseMessage baseMessage, int status) {
+ override fun ccMessageEdited(baseMessage: BaseMessage?, status: Int) {
// Perform action when message is edited
}
- @Override
- public void ccMessageDeleted(BaseMessage baseMessage) {
+ override fun ccMessageDeleted(baseMessage: BaseMessage?) {
// Perform action when message is deleted
}
- @Override
- public void ccMessageRead(BaseMessage baseMessage) {
+ override fun ccMessageRead(baseMessage: BaseMessage?) {
// Perform action when message is read
}
- @Override
- public void ccLiveReaction(int icon) {
+ override fun ccLiveReaction(icon: Int) {
// Perform action on live reaction
}
// Other overridden methods for handling specific message types and actions
-});
+})
```
-
-
-
-```kotlin
-CometChatMessageEvents.addListener("UNIQUE_ID", object : CometChatMessageEvents() {
- override fun ccMessageSent(baseMessage: BaseMessage?, status: Int) {
+
+```java lines
+CometChatMessageEvents.addListener("UNIQUE_ID", new CometChatMessageEvents() {
+ @Override
+ public void ccMessageSent(BaseMessage baseMessage, int status) {
// Perform action when message is sent
}
- override fun ccMessageEdited(baseMessage: BaseMessage?, status: Int) {
+ @Override
+ public void ccMessageEdited(BaseMessage baseMessage, int status) {
// Perform action when message is edited
}
- override fun ccMessageDeleted(baseMessage: BaseMessage?) {
+ @Override
+ public void ccMessageDeleted(BaseMessage baseMessage) {
// Perform action when message is deleted
}
- override fun ccMessageRead(baseMessage: BaseMessage?) {
+ @Override
+ public void ccMessageRead(BaseMessage baseMessage) {
// Perform action when message is read
}
- override fun ccLiveReaction(icon: Int) {
+ @Override
+ public void ccLiveReaction(int icon) {
// Perform action on live reaction
}
// Other overridden methods for handling specific message types and actions
-})
+});
```
-
-
+> **What this does:** Registers a listener on `CometChatMessageEvents` using a unique ID string. The callbacks fire for message lifecycle events — sending, editing, deleting, reading messages, and reacting with live reactions. Additional overrides handle interactive message types (`onFormMessageReceived`, `onCardMessageReceived`, `onCustomInteractiveMessageReceived`, `onInteractionGoalCompleted`, `onSchedulerMessageReceived`).
+
+---
+
### Call Events
-`Call Events` emits events related to calls within the application. This class provides methods to listen to call-related events and handle them accordingly.
+`CometChatCallEvents` emits events related to calls within the application. This class provides methods to listen to call-related events and handle them.
+
+**Events:**
+
+| Event | Description |
+| ----- | ----------- |
+| `ccOutgoingCall` | Triggered when the logged-in user initiates an outgoing call. |
+| `ccCallAccepted` | Triggered when a call is accepted. |
+| `ccCallRejected` | Triggered when a call is rejected. |
+| `ccCallEnded` | Triggered when a call is ended. |
+
+**Listener registration:**
-* `ccOutgoingCall`: Triggered when the logged-in user initiates an outgoing call.
-* `ccCallAccepted`: Triggered when a call is accepted.
-* `ccCallRejected`: Triggered when a call is rejected.
-* `ccCallEnded`: Triggered when a call is ended.
+
+
+```kotlin lines
+CometChatCallEvents.addListener("ListenerID", object : CometChatCallEvents() {
+ override fun ccOutgoingCall(call: Call) {
+ // Perform action when outgoing call is initiated
+ }
-To listen to call events and handle them in your application, you can use the following code snippet:
+ override fun ccCallAccepted(call: Call) {
+ // Perform action when call is accepted
+ }
-```typescript
+ override fun ccCallRejected(call: Call) {
+ // Perform action when call is rejected
+ }
+
+ override fun ccCallEnded(call: Call) {
+ // Perform action when call is ended
+ }
+})
+```
+
+
+```java lines
CometChatCallEvents.addListener("ListenerID", new CometChatCallEvents() {
@Override
public void ccOutgoingCall(Call call) {
@@ -280,21 +393,52 @@ CometChatCallEvents.addListener("ListenerID", new CometChatCallEvents() {
}
});
```
+
+
+
+> **What this does:** Registers a listener on `CometChatCallEvents` using a unique `"ListenerID"`. The callbacks fire for each stage of the call lifecycle — initiating an outgoing call, accepting, rejecting, and ending a call.
+
+---
### UI Events
-`UIEvents` emits events related to UI components within the CometChat UI. This class provides methods to listen to UI-related events and handle them accordingly.
+`CometChatUIEvents` emits events related to UI components within the CometChat UI Kit. This class provides methods to listen to UI-related events and handle them.
+
+**Events:**
+
+| Event | Description |
+| ----- | ----------- |
+| `showPanel` | Triggered to show an additional UI panel with custom elements. |
+| `hidePanel` | Triggered to hide a previously shown UI panel. |
+| `ccActiveChatChanged` | Triggered when the active chat changes, providing information about the current message, user, and group. |
+| `ccOpenChat` | Triggered to open a chat with a specific user or group. |
-Following are the UI events
+**Listener registration:**
+
+
+
+```kotlin lines
+CometChatUIEvents.addListener("UNIQUE_ID", object : CometChatUIEvents() {
+ override fun showPanel(id: HashMap, alignment: UIKitConstants.CustomUIPosition, view: Function1) {
+ // Perform action to show UI panel with custom elements
+ }
-* `showPanel`: Triggered to show an additional UI panel with custom elements.
-* `hidePanel`: Triggered to hide a previously shown UI panel.
-* `ccActiveChatChanged`: Triggered when the active chat changes, providing information about the current message, user, and group.
-* `ccOpenChat`: Triggered to open a chat with a specific user or group.
+ override fun hidePanel(id: HashMap, alignment: UIKitConstants.CustomUIPosition) {
+ // Perform action to hide UI panel
+ }
-To listen to UI events and handle them in your application, you can use the following code snippet:
+ override fun ccActiveChatChanged(id: HashMap, message: BaseMessage, user: User, group: Group) {
+ // Perform action when active chat changes
+ }
-```typescript
+ override fun ccOpenChat(user: User, group: Group) {
+ // Perform action to open a chat with a specific user or group
+ }
+})
+```
+
+
+```java lines
CometChatUIEvents.addListener("UNIQUE_ID", new CometChatUIEvents() {
@Override
public void showPanel(HashMap id, UIKitConstants.CustomUIPosition alignment, Function1 view) {
@@ -317,3 +461,46 @@ CometChatUIEvents.addListener("UNIQUE_ID", new CometChatUIEvents() {
}
});
```
+
+
+
+> **What this does:** Registers a listener on `CometChatUIEvents` using a unique ID string. The callbacks fire for UI-level actions — showing or hiding custom panels, reacting to active chat changes, and opening a chat with a specific user or group.
+
+---
+
+## Removing event listeners
+
+Each event listener class provides methods to add and remove listeners. If you register a listener, remove it when the component or activity is destroyed to prevent memory leaks. Use the same tag or ID string you passed during registration.
+
+---
+
+## Common pitfalls and fixes
+
+| Pitfall | Fix |
+| ------- | --- |
+| Forgetting to remove event listeners when an activity or fragment is destroyed, causing memory leaks and duplicate callbacks. | Remove your event listeners in your `onDestroy()` or `onDestroyView()` lifecycle callback, using the same tag you passed during registration. |
+| Using a non-unique or hardcoded listener tag, causing one listener to overwrite another. | Use a unique string for each listener registration (for example, the class name or a UUID). If two registrations share the same tag, only the last one receives callbacks. |
+| Registering a listener after the event has already fired, so the callback is never triggered. | Register your event listeners early in the component lifecycle (for example, in `onCreate()` or `onViewCreated()`), before any user interaction that could trigger the event. |
+| Expecting Kotlin-style nullable parameters in Java callbacks (or vice versa). | Match the parameter types to the language you are using. In Kotlin, message event callbacks use nullable types (for example, `BaseMessage?`), while Java callbacks use non-nullable types (for example, `BaseMessage`). |
+| Not handling all relevant callbacks in a listener, causing missed events. | Override every callback method you need. If you register a `CometChatGroupEvents` listener but only override `ccGroupCreated`, you will not receive `ccGroupMemberJoined` or other group events. |
+| Assuming events fire on the main thread and updating UI directly without checking. | Wrap UI updates inside `runOnUiThread {}` (Kotlin) or `runOnUiThread(() -> { })` (Java) to ensure thread safety when handling event callbacks. |
+
+## FAQ
+
+**How do I listen for multiple event types at the same time?**
+Register separate listeners for each event class. For example, register a `CometChatUserEvents` listener and a `CometChatMessageEvents` listener independently, each with its own unique tag or ID. There is no single listener that covers all event categories.
+
+**What is the difference between UI Kit events and SDK-level listeners?**
+UI Kit events (for example, `CometChatMessageEvents`, `CometChatUserEvents`) are emitted by UI Kit components when the logged-in user performs actions through the UI. SDK-level listeners (from the core CometChat SDK) handle real-time events from the server, such as incoming messages from other users. Use UI Kit events to keep your UI in sync with user-initiated actions, and SDK-level listeners for server-pushed updates.
+
+**Do I need to remove listeners if my activity is finishing?**
+Yes. If you do not remove listeners in `onDestroy()` or `onDestroyView()`, the listener reference persists and can cause memory leaks or duplicate callback invocations when the activity or fragment is recreated.
+
+**Can I register the same listener tag twice?**
+If you call `addListener` or `addUserListener`/`addGroupListener` with the same tag, the second registration replaces the first. Only the most recently registered listener for that tag receives callbacks.
+
+## Next steps
+
+- [Methods reference](/ui-kit/android/methods) — UI Kit wrapper methods for initialization, authentication, and sending messages.
+- [Conversations component](/ui-kit/android/conversations) — Display and manage the conversation list, which reacts to conversation events.
+- [Message List component](/ui-kit/android/message-list) — Display messages in a chat, which reacts to message events.
diff --git a/ui-kit/android/extensions.mdx b/ui-kit/android/extensions.mdx
index 6333a9633..15181ee97 100644
--- a/ui-kit/android/extensions.mdx
+++ b/ui-kit/android/extensions.mdx
@@ -6,11 +6,11 @@ title: "Extensions"
CometChat’s UI Kit comes with built-in support for a wide variety of extensions that provide additional functionality. These extensions enhance the chatting experience, making it more interactive, secure, and efficient.
-Activating any of the extensions in CometChat is a simple process done through your application's dashboard. Refer to our guide For detailed information on [Extensions](/fundamentals/extensions-overview)
+Activating any of the extensions in CometChat is a simple process done through your application's dashboard. Refer to our guide for detailed information on [Extensions](/fundamentals/extensions-overview).
-Once you have successfully enabled the desired extension in your dashboard, it will be reflected in your CometChat application upon initialization and successful login. Please note, that the extension features will only be available if they are supported by CometChat UI Kit.
+Once you have successfully enabled the desired extension in your dashboard, it will be reflected in your CometChat application upon initialization and successful login. Please note that extension features will only be available if they are supported by the CometChat UI Kit.
-CometChat’s UI Kit offers built-in support for 12 powerful extensions. This seamless integration makes it easy for you to enhance your chat application with engaging features without any extra coding effort. Just enable the desired extensions from the CometChat Dashboard, and they will be automatically reflected in the relevant components of your application, providing a richer and more engaging experience for your users.
+CometChat’s UI Kit offers built-in support for 8 extensions. This seamless integration makes it easy for you to enhance your chat application with engaging features without any extra coding effort. Just enable the desired extensions from the CometChat Dashboard, and they will be automatically reflected in the relevant components of your application, providing a richer and more engaging experience for your users.
## Built-in Extensions
@@ -76,12 +76,6 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/
-### Profanity Filter
-
-The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions).
-
-Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits.
-
### Thumbnail Generation
The Thumbnail Generation extension automatically creates a smaller preview image whenever a larger image is shared, helping to reduce the upload/download time and bandwidth usage. For a comprehensive understanding and guide on implementing and using the Thumbnail Generation Extension, refer to our specific guide on the [Thumbnail Generation Extension](/fundamentals/thumbnail-generation).
@@ -91,3 +85,9 @@ Once you have successfully activated the [Thumbnail Generation Extension](/funda
+
+### Profanity Filter
+
+The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions).
+
+Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits.
diff --git a/ui-kit/android/getting-started.mdx b/ui-kit/android/getting-started.mdx
index 20f734f15..5b5d59204 100644
--- a/ui-kit/android/getting-started.mdx
+++ b/ui-kit/android/getting-started.mdx
@@ -72,7 +72,7 @@ Ensure your system meets the following **prerequisites** before proceeding with
**System Requirements:**
* **Android Studio** installed on your machine.
-* An **Android emulator or physical device** running Android 6.0 or higher.
+* An **Android emulator or physical device** running Android 7.0 (API 24) or higher.
* **Java 8 or higher** installed.
* **Gradle plugin 4.0.1 or later** installed.
@@ -85,7 +85,7 @@ Ensure your system meets the following **prerequisites** before proceeding with
1. Open **Android Studio** and start a **new project**.
2. Choose **Empty Activity** as the project template.
3. Enter a project name and choose **Java** or **Kotlin** as the language.
-4. Set **minimum API level** to **21 or higher**.
+4. Set **minimum API level** to **24 or higher**.
***
@@ -100,7 +100,7 @@ To integrate CometChat into your Android project, you need to add the CometChat
-```gradle settings.gradle.kts
+```gradle settings.gradle.kts lines
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
@@ -115,7 +115,7 @@ dependencyResolutionManagement {
-```gradle settings.gradle
+```gradle settings.gradle lines
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
@@ -138,15 +138,15 @@ dependencyResolutionManagement {
Inside `libs.versions.toml`, add the CometChat Chat UI Kit version under the `[versions]` section:
-```toml libs.versions.toml
+```toml libs.versions.toml lines
[versions]
-cometchat-ui-kit = "5.2.7"
+cometchat-ui-kit = "5.2.9"
cometchat-calls-sdk = "4.3.3"
```
Under the `[libraries]` section, define the library and reference the version:
-```toml libs.versions.toml
+```toml libs.versions.toml lines
[libraries]
cometchat-ui-kit = { module = "com.cometchat:chat-uikit-android", version.ref = "cometchat-ui-kit" }
cometchat-calls-sdk = { module = "com.cometchat:calls-sdk-android", version.ref = "cometchat-calls-sdk" }
@@ -154,7 +154,7 @@ cometchat-calls-sdk = { module = "com.cometchat:calls-sdk-android", version.ref
Now, in your app-level `build.gradle.kts` file, add the dependency using libs from Version Catalogs:
-```gradle build.gradle.kts
+```gradle build.gradle.kts lines
dependencies {
implementation(libs.cometchat.ui.kit)
@@ -168,10 +168,10 @@ dependencies {
Open the **app level** `build.gradle` file and add the following dependency to fetch the chat UI kit into your project.
-```gradle build.gradle
+```gradle build.gradle lines
dependencies {
// CometChat UIKit
- implementation 'com.cometchat:chat-uikit-android:5.2.7'
+ implementation 'com.cometchat:chat-uikit-android:5.2.9'
// (Optional) Include this if your app uses voice/video calling features
implementation 'com.cometchat:calls-sdk-android:4.3.3'
@@ -188,7 +188,7 @@ The Jetifier tool helps migrate legacy support libraries to AndroidX.
Open the gradle.properties file and verify if the specified line is present. If not, add it accordingly.
-```gradle gradle.properties
+```gradle gradle.properties lines
android.enableJetifier=true
```
@@ -234,7 +234,7 @@ For secure authentication, use the [`Auth Token`](/ui-kit/android/methods#login-
-```kotlin MainActivity.kt
+```kotlin MainActivity.kt highlight={15-17, 46-55} lines
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
@@ -304,7 +304,7 @@ class MainActivity : ComponentActivity() {
-```java MainActivity.java
+```java MainActivity.java highlight={15-17, 51-60} lines
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -404,11 +404,11 @@ Use the `CometChatTheme.DayNight` style, which is built on `Theme.MaterialCompon
Set `CometChatTheme.DayNight` as the parent theme for your application in the `themes.xml` file.
-```xml themes.xml
+```xml themes.xml lines
```
-```xml AndroidManifest.xml
+```xml AndroidManifest.xml lines
+
+```json
+{
+ "component": "CometChatGroupMembers",
+ "package": "com.cometchat.chatuikit.groupmembers",
+ "xmlElement": "",
+ "description": "Scrollable list of all members in a group with search, avatars, names, scope badges, and online/offline status indicators. Requires a Group object to be set via setGroup().",
+ "primaryOutput": {
+ "method": "setOnItemClick",
+ "type": "OnItemClick"
+ },
+ "methods": {
+ "data": {
+ "setGroup": {
+ "type": "Group",
+ "required": true,
+ "note": "Must be called before the component can load data"
+ },
+ "setGroupMembersRequestBuilder": {
+ "type": "GroupMembersRequest.GroupMembersRequestBuilder",
+ "default": "SDK default",
+ "note": "Pass the builder, not the result of .build()"
+ },
+ "setSearchRequestBuilder": {
+ "type": "GroupMembersRequest.GroupMembersRequestBuilder",
+ "default": "Same as main builder",
+ "note": "Separate builder for search results"
+ }
+ },
+ "callbacks": {
+ "setOnItemClick": "OnItemClick",
+ "setOnItemLongClick": "OnItemLongClick",
+ "setOnBackPressListener": "OnBackPress",
+ "setOnSelection": "OnSelection",
+ "setOnError": "OnError",
+ "setOnLoadMore": "OnLoad",
+ "setOnEmpty": "OnEmpty"
+ },
+ "visibility": {
+ "setBackIconVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.GONE" },
+ "setToolbarVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setLoadingStateVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setErrorStateVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setEmptyStateVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setSeparatorVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setUserStatusVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setSearchBoxVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setKickMemberOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setBanMemberOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setScopeChangeOptionVisibility": { "type": "int", "default": "View.VISIBLE" }
+ },
+ "selection": {
+ "setSelectionMode": {
+ "type": "UIKitConstants.SelectionMode",
+ "values": ["NONE", "SINGLE", "MULTIPLE"],
+ "default": "NONE"
+ }
+ },
+ "viewSlots": {
+ "setItemView": "GroupMembersViewHolderListeners — entire list item row",
+ "setLeadingView": "GroupMembersViewHolderListeners — avatar / left section",
+ "setTitleView": "GroupMembersViewHolderListeners — name / title text",
+ "setSubtitleView": "GroupMembersViewHolderListeners — subtitle text below name",
+ "setTrailingView": "GroupMembersViewHolderListeners — right section",
+ "setLoadingStateView": "@LayoutRes int — loading spinner",
+ "setEmptyStateView": "@LayoutRes int — empty state",
+ "setErrorStateView": "@LayoutRes int — error state",
+ "setOverflowMenu": "View — toolbar menu",
+ "setOptions": "Function3> — long-press context menu (replaces defaults)",
+ "addOptions": "Function3> — long-press context menu (appends to defaults)"
+ },
+ "advanced": {
+ "selectGroupMember": "GroupMember, SelectionMode — programmatic selection",
+ "clearSelection": "void — clears all selected group members",
+ "getSelectedGroupMembers": "List — returns selected items",
+ "setSearchKeyword": "String — programmatic search",
+ "setTitleText": "String — custom toolbar title",
+ "excludeOwner": "boolean — exclude group owner from list",
+ "getBinding": "CometchatGroupMembersListViewBinding — root ViewBinding",
+ "getViewModel": "GroupMembersViewModel — internal ViewModel access",
+ "getAdapter": "GroupMembersAdapter — internal adapter access",
+ "setAdapter": "GroupMembersAdapter — replace the default adapter"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatGroupMembersStyle"
+ }
+ }
+ },
+ "events": [
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberBanned",
+ "payload": "Action, User, User, Group",
+ "description": "A group member was banned from the group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberKicked",
+ "payload": "Action, User, User, Group",
+ "description": "A group member was kicked from the group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberScopeChanged",
+ "payload": "Action, User, String, String, Group",
+ "description": "A group member's scope was changed"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberAdded",
+ "payload": "List, List, Group, User",
+ "description": "Members were added to the group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberUnBanned",
+ "payload": "Action, User, User, Group",
+ "description": "A group member was unbanned"
+ },
+ {
+ "name": "CometChatGroupEvents.ccOwnershipChanged",
+ "payload": "Group, GroupMember",
+ "description": "Group ownership was transferred"
+ }
+ ],
+ "sdkListeners": [
+ "onGroupMemberJoined",
+ "onGroupMemberLeft",
+ "onGroupMemberKicked",
+ "onGroupMemberBanned",
+ "onGroupMemberScopeChanged",
+ "onMemberAddedToGroup",
+ "onUserOnline",
+ "onUserOffline"
+ ]
+}
+```
-`CometChatGroupMembers` is a versatile [Component](/ui-kit/android/components-overview#components) designed to showcase all users who are either added to or invited to a group, thereby enabling them to participate in group discussions, access shared content, and engage in collaborative activities. Group members have the capability to communicate in real-time through messaging, voice and video calls, and various other interactions. Additionally, they can interact with each other, share files, and join calls based on the permissions established by the group administrator or owner.
+
-
-
-
+## Where It Fits
-***
+`CometChatGroupMembers` is a list component. It renders all members of a specific group and emits the selected `GroupMember` via `setOnItemClick`. It requires a `Group` object set via `setGroup()` before it can load data. Wire it to `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to build a group messaging layout.
-## Usage
+
+
+```kotlin GroupChatActivity.kt lines
+class GroupChatActivity : AppCompatActivity() {
+
+ private lateinit var groupMembers: CometChatGroupMembers
+ private lateinit var messageHeader: CometChatMessageHeader
+ private lateinit var messageList: CometChatMessageList
+ private lateinit var messageComposer: CometChatMessageComposer
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_group_chat)
+
+ groupMembers = findViewById(R.id.group_members)
+ messageHeader = findViewById(R.id.message_header)
+ messageList = findViewById(R.id.message_list)
+ messageComposer = findViewById(R.id.message_composer)
+
+ val group = Group().apply {
+ guid = "GROUP_ID"
+ name = "GROUP_NAME"
+ }
+ groupMembers.setGroup(group)
-### Integration
+ groupMembers.setOnItemClick { view, position, groupMember ->
+ messageHeader.setUser(groupMember)
+ messageList.setUser(groupMember)
+ messageComposer.setUser(groupMember)
+ }
+ }
+}
+```
+
-`CometChatGroupMembers`, as a Composite Component, offers flexible integration options, allowing it to be launched directly via button clicks or any user-triggered action. Additionally, it seamlessly integrates into tab view controllers. With group members, users gain access to a wide range of parameters and methods for effortless customization of its user interface.
+
+```java GroupChatActivity.java lines
+public class GroupChatActivity extends AppCompatActivity {
-The following code snippet exemplifies how you can seamlessly integrate the GroupMembers component into your application.
+ private CometChatGroupMembers groupMembers;
+ private CometChatMessageHeader messageHeader;
+ private CometChatMessageList messageList;
+ private CometChatMessageComposer messageComposer;
-
-
-```xml
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_group_chat);
+
+ groupMembers = findViewById(R.id.group_members);
+ messageHeader = findViewById(R.id.message_header);
+ messageList = findViewById(R.id.message_list);
+ messageComposer = findViewById(R.id.message_composer);
+
+ Group group = new Group();
+ group.setGuid("GROUP_ID");
+ group.setName("GROUP_NAME");
+ groupMembers.setGroup(group);
+
+ groupMembers.setOnItemClick((view, position, groupMember) -> {
+ messageHeader.setUser(groupMember);
+ messageList.setUser(groupMember);
+ messageComposer.setUser(groupMember);
+ });
+ }
+}
+```
+
+
+
+## Quick Start
+
+Add the component to your layout XML:
+
+```xml layout_activity.xml lines
```
-
+
+
+
-
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, the `cometchat-chat-uikit-android` dependency added, and a valid `Group` object with a group ID (`GUID`).
-If you're defining the Group members within the XML code, you'll need to extract them and set them on the Group object using the appropriate method.
+Set the `Group` object in your Activity or Fragment:
+
+```kotlin YourActivity.kt lines
+val cometchatGroupMembers: CometChatGroupMembers = binding.groupMember
+
+val group = Group().apply {
+ guid = "GROUP_ID"
+ name = "GROUP_NAME"
+}
+
+cometchatGroupMembers.setGroup(group)
+```
+
+
-```java
+```java YourActivity.java lines
CometChatGroupMembers cometchatGroupMembers = binding.groupMember;
Group group = new Group();
@@ -46,334 +261,321 @@ group.setName("GROUP_NAME");
cometchatGroupMembers.setGroup(group);
```
-
+
-
-```kotlin
-val cometchatGroupMembers: CometChatGroupMembers = binding.groupMember
+> **What this does:** Creates a `Group` object with a group ID and name, then passes it to the `CometChatGroupMembers` component. The component fetches and displays all members of that group.
-val group: Group = Group()
-group.setGuid("GROUP_ID")
-group.setName("GROUP_NAME")
+Or add programmatically in an Activity:
-cometchatGroupMembers.setGroup(group)
+
+
+```kotlin YourActivity.kt lines
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val groupMembers = CometChatGroupMembers(this)
+ val group = Group().apply {
+ guid = "GROUP_ID"
+ name = "GROUP_NAME"
+ }
+ groupMembers.setGroup(group)
+ setContentView(groupMembers)
+}
```
-
-
-
-***
-
-### Actions
-
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
-
-##### setOnItemClick
-
-Function invoked when a user item is clicked, typically used to open a user profile or chat screen.
-
-
-```java YourActivity.java
-cometchatUsers.setOnItemClick((view1, position, user) -> {
-
- });
+```java YourActivity.java lines
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ CometChatGroupMembers groupMembers = new CometChatGroupMembers(this);
+ Group group = new Group();
+ group.setGuid("GROUP_ID");
+ group.setName("GROUP_NAME");
+ groupMembers.setGroup(group);
+ setContentView(groupMembers);
+}
```
-
+
+Or in a Fragment:
+
+
-```kotlin YourActivity.kt
-cometchatUsers.onItemClick = OnItemClick { view, position, user ->
-
+```kotlin YourFragment.kt lines
+override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ val groupMembers = CometChatGroupMembers(requireContext())
+ val group = Group().apply {
+ guid = "GROUP_ID"
+ name = "GROUP_NAME"
}
+ groupMembers.setGroup(group)
+ return groupMembers
+}
```
-
+
+```java YourFragment.java lines
+@Override
+public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ CometChatGroupMembers groupMembers = new CometChatGroupMembers(getContext());
+ Group group = new Group();
+ group.setGuid("GROUP_ID");
+ group.setName("GROUP_NAME");
+ groupMembers.setGroup(group);
+ return groupMembers;
+}
+```
+
-***
+## Filtering Group Members
-##### setOnItemLongClick
-
-Function executed when a user item is long-pressed, allowing additional actions like delete or block.
+Pass a `GroupMembersRequest.GroupMembersRequestBuilder` to `setGroupMembersRequestBuilder`. Pass the builder instance — not the result of `.build()`.
-
-```java YourActivity.java
-cometchatUsers.setOnItemLongClick((view1, position, user) -> {
-
- });
+
+```kotlin lines
+val builder = GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
+ .setLimit(10)
+cometchatGroupMembers.setGroupMembersRequestBuilder(builder)
```
-
-
-```kotlin YourActivity.kt
-cometchatUsers.onItemLongClick = OnItemLongClick({ view, position, user ->
-
- })
+
+```java lines
+GroupMembersRequest.GroupMembersRequestBuilder builder = new GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
+ .setLimit(10);
+cometchatGroupMembers.setGroupMembersRequestBuilder(builder);
```
-
-
-***
+### Filter Recipes
-##### setOnBackPressListener
+| Recipe | Code |
+| --- | --- |
+| Limit to 10 per page | `builder.setLimit(10)` |
+| Search by keyword | `builder.setSearchKeyword("john")` |
+| Filter by scopes | `builder.setScopes(Arrays.asList("admin", "moderator"))` |
+| Admins only | `builder.setScopes(Arrays.asList("admin"))` |
+| Moderators only | `builder.setScopes(Arrays.asList("moderator"))` |
+| Participants only | `builder.setScopes(Arrays.asList("participant"))` |
-`OnBackPressListener` is triggered when you press the back button in the app bar. It has a predefined behavior; when clicked, it navigates to the previous activity. However, you can override this action using the following code snippet.
+> The component uses infinite scroll — the next page loads as the user scrolls to the bottom.
-
-
-```java YourActivity.java
-cometchatUsers.setOnBackPressListener(() -> {
-
- });
-```
+### Search Request Builder
-
+Use `setSearchRequestBuilder` to customize the search list separately from the main list:
+
-```kotlin YourActivity.kt
-cometchatUsers.onBackPressListener = OnBackPress {
-
- }
+```kotlin lines
+val searchBuilder = GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
+ .setLimit(LIMIT)
+ .setSearchKeyword(SEARCH_KEYWORD)
+cometchatGroupMembers.setSearchRequestBuilder(searchBuilder)
```
-
+
+```java lines
+GroupMembersRequest.GroupMembersRequestBuilder searchBuilder = new GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
+ .setLimit(LIMIT)
+ .setSearchKeyword(SEARCH_KEYWORD);
+cometchatGroupMembers.setSearchRequestBuilder(searchBuilder);
+```
+
-***
+> **What this does:** Creates a `GroupMembersRequestBuilder` with a group ID, limit, and search keyword, then applies it as the search request builder. When the user searches, the component uses this builder to filter results.
+
+## Actions and Events
+
+### Callback Methods
-##### setOnSelect
+#### `setOnItemClick`
-Called when a item from the fetched list is selected, useful for multi-selection features.
+Fires when a group member row is tapped. Primary navigation hook — set the active member and render the message view.
-
-```java YourActivity.java
-cometchatUsers.setOnSelect(t -> {
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnItemClick { view, position, groupMember ->
- });
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatUsers.setOnSelect(object : OnSelection {
- override fun onSelection(t: MutableList?) {
-
- }
- })
-```
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnItemClick((view, position, groupMember) -> {
+});
+```
-
-***
+> **What this does:** Replaces the default item-click behavior. When a user taps a group member, your custom lambda executes instead of the built-in navigation.
-##### setOnError
+#### `setOnItemLongClick`
-This action doesn't change the behavior of the component but rather listens for any errors that occur in the Users component.
+Fires when a group member row is long-pressed. Use for additional actions like kick, ban, or change scope.
-
-```java YourActivity.java
-cometchatUsers.setOnError(cometchatException -> {
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnItemLongClick { view, position, groupMember ->
- });
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatUsers.setOnError {
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnItemLongClick((view, position, groupMember) -> {
- }
+});
```
-
-
-***
-
-##### setOnLoad
+#### `setOnBackPressListener`
-Invoked when the list is successfully fetched and loaded, helping track component readiness.
+Fires when the user presses the back button in the app bar. Default: navigates to the previous activity.
-
-```java YourActivity.java
-cometchatUsers.setOnLoad(list -> {
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnBackPressListener {
-});
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatUsers.setOnLoad(object : OnLoad {
- override fun onLoad(list: MutableList?) {
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnBackPressListener(() -> {
- }
-})
+});
```
-
-
-***
-
-##### setOnEmpty
+#### `setOnSelection`
-Called when the list is empty, enabling custom handling such as showing a placeholder message.
+Fires when a group member is checked/unchecked in multi-select mode. Requires `setSelectionMode` to be set.
-
-```java YourActivity.java
-cometchatUsers.setOnEmpty(() -> {
-
- });
-```
-
-
-
-```kotlin YourActivity.kt
-cometchatUsers.setOnEmpty{
-
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnSelection(object : OnSelection {
+ override fun onSelection(t: MutableList?) {
+
}
+})
```
-
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnSelection(t -> {
+
+});
+```
+
-***
+#### `setOnError`
-### Filters
+Fires on internal errors (network failure, auth issue, SDK exception).
-**Filters** allow you to customize the data displayed in a list within a `Component`. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using `RequestBuilders` of Chat SDK.
+
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnError {
-##### 1. GroupsRequestBuilder
+}
+```
+
-The [GroupsRequestBuilder](/sdk/android/retrieve-groups) enables you to filter and customize the group list based on available parameters in GroupsRequestBuilder. This feature allows you to create more specific and targeted queries when fetching groups. The following are the parameters available in [GroupsRequestBuilder](/sdk/android/retrieve-groups)
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnError(cometchatException -> {
-| Property | Description | Code |
-| ------------------ | ---------------------------------------------------------------------------------------------------------------- | --------------------------- |
-| **Limit** | Sets the number of group members that can be fetched in a single request, suitable for pagination. | `.setLimit(int)` |
-| **Search Keyword** | Used for fetching group members matching the passed string. | `.setSearchKeyword(String)` |
-| **Scopes** | Used for fetching group members having matching scopes which may be of participant, moderator, admin, and owner. | `.setScopes(List)` |
+});
+```
+
+
-**Example**
+#### `setOnLoadMore`
-In the example below, we are applying a filter to the Group List based on limit and scope.
+Fires when the list is successfully fetched and loaded.
-
-```java
-GroupMembersRequest.GroupMembersRequestBuilder groupMembersRequestBuilder= new GroupMembersRequest.GroupMembersRequestBuilder(GUID).setLimit(limit);
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnLoadMore(object : OnLoad {
+ override fun onLoad(list: MutableList?) {
-cometchatGroupMembers.setGroupMembersRequestBuilder(groupMembersRequestBuilder);
+ }
+})
```
-
-
-```kotlin
-val groupMembersRequestBuilder = GroupMembersRequestBuilder(GUID).setLimit(limit)
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnLoadMore(list -> {
-cometchatGroupMembers.setGroupMembersRequestBuilder(groupMembersRequestBuilder)
+});
```
-
-
-***
+#### `setOnEmpty`
-##### 2. SearchRequestBuilder
-
-The SearchRequestBuilder uses [GroupsRequestBuilder](/sdk/android/retrieve-groups) enables you to filter and customize the search list based on available parameters in GroupsRequestBuilder.
-
-This feature allows you to keep uniformity between the displayed Groups List and searched Group List.
-
-**Example**
+Fires when the list is empty, enabling custom handling such as showing a placeholder.
-
-```java
-GroupMembersRequest.GroupMembersRequestBuilder groupMembersRequestBuilder= new GroupMembersRequest.GroupMembersRequestBuilder(GUID).setLimit(LIMIT).setSearchKeyword(SEARCH_KEYWORD);
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setOnEmpty {
-cometchatGroupMembers.setSearchRequestBuilder(groupMembersRequestBuilder);
+}
```
-
-
-```kotlin
-val groupMembersRequestBuilder = GroupMembersRequestBuilder(GUID).setLimit(LIMIT).setSearchKeyword(SEARCH_KEYWORD)
+
+```java YourActivity.java lines
+cometchatGroupMembers.setOnEmpty(() -> {
-cometchatGroupMembers.setSearchRequestBuilder(groupMembersRequestBuilder)
+});
```
-
-
-***
-
-### Events
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap, long-press, back, select) and confirm your custom logic executes instead of the default behavior.
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed.
+### Global UI Events
-Events emitted by the Join Group component is as follows.
+`CometChatGroupEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed.
-| Event | Description |
-| ----------------------------- | ----------------------------------------------------------------- |
-| **ccGroupMemberBanned** | Triggers when the group member banned from the group successfully |
-| **ccGroupMemberKicked** | Triggers when the group member kicked from the group successfully |
-| **ccGroupMemberScopeChanged** | Triggers when the group member scope is changed in the group |
+| Event | Fires when | Payload |
+| --- | --- | --- |
+| `ccGroupMemberBanned` | A group member is banned from the group | `Action, User, User, Group` |
+| `ccGroupMemberKicked` | A group member is kicked from the group | `Action, User, User, Group` |
+| `ccGroupMemberScopeChanged` | A group member's scope is changed | `Action, User, String, String, Group` |
+| `ccGroupMemberAdded` | Members are added to the group | `List, List, Group, User` |
+| `ccGroupMemberUnBanned` | A group member is unbanned | `Action, User, User, Group` |
+| `ccOwnershipChanged` | Group ownership is transferred | `Group, GroupMember` |
-
-```java
-CometChatGroupEvents.addGroupListener("LISTENER_ID", new CometChatGroupEvents() {
- @Override
- public void ccGroupMemberKicked(Action actionMessage, User kickedUser, User kickedBy, Group kickedFrom) {
- super.ccGroupMemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom);
- }
-
- @Override
- public void ccGroupMemberBanned(Action actionMessage, User bannedUser, User bannedBy, Group bannedFrom) {
- super.ccGroupMemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom);
- }
-
- @Override
- public void ccGroupMemberScopeChanged(Action actionMessage, User updatedUser, String scopeChangedTo, String scopeChangedFrom, Group group) {
- super.ccGroupMemberScopeChanged(actionMessage, updatedUser, scopeChangedTo, scopeChangedFrom, group);
- }
-
-});
-```
-
-
-
-```kotlin
-CometChatGroupEvents.addGroupListener("LISTENER_ID", object : CometChatGroupEvents() {
+```kotlin Add Listener lines
+CometChatGroupEvents.addGroupListener("LISTENER_TAG", object : CometChatGroupEvents() {
override fun ccGroupMemberKicked(
actionMessage: Action,
kickedUser: User,
@@ -410,638 +612,722 @@ CometChatGroupEvents.addGroupListener("LISTENER_ID", object : CometChatGroupEven
})
```
-
+Remove Listener
-
+```
+CometChatGroupEvents.removeListener("LISTENER_TAG")
+```
+
-***
+
+```java Add Listener lines
+CometChatGroupEvents.addGroupListener("LISTENER_TAG", new CometChatGroupEvents() {
+ @Override
+ public void ccGroupMemberKicked(Action actionMessage, User kickedUser, User kickedBy, Group kickedFrom) {
+ super.ccGroupMemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom);
+ }
-Remove the added listener
+ @Override
+ public void ccGroupMemberBanned(Action actionMessage, User bannedUser, User bannedBy, Group bannedFrom) {
+ super.ccGroupMemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom);
+ }
-
-
-```java
-CometChatGroupEvents.removeListener("LISTENER_ID");
+ @Override
+ public void ccGroupMemberScopeChanged(Action actionMessage, User updatedUser, String scopeChangedTo, String scopeChangedFrom, Group group) {
+ super.ccGroupMemberScopeChanged(actionMessage, updatedUser, scopeChangedTo, scopeChangedFrom, group);
+ }
+});
```
-
+Remove Listener
-
-```kotlin
-CometChatGroupEvents.removeListener("LISTENER_ID")
```
-
+CometChatGroupEvents.removeListener("LISTENER_TAG");
+```
-
-***
-
-## Customization
+> **What this does:** Registers a global event listener tagged with `"LISTENER_TAG"`. When a group member is kicked, banned, or has their scope changed, the corresponding callback fires with the action details, affected user, and group information.
+
+### SDK Events (Real-Time, Automatic)
+
+The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.
+
+| SDK Listener | Internal behavior |
+| --- | --- |
+| `onGroupMemberJoined` | Adds the new member to the list |
+| `onGroupMemberLeft` | Removes the member from the list |
+| `onGroupMemberKicked` | Removes the kicked member from the list |
+| `onGroupMemberBanned` | Removes the banned member from the list |
+| `onGroupMemberScopeChanged` | Updates the member's scope in the list |
+| `onMemberAddedToGroup` | Adds the new member to the list |
+| `onUserOnline` | Updates online status indicator for the member |
+| `onUserOffline` | Updates offline status indicator for the member |
+
+> Automatic: group membership changes and user presence changes update the list in real time.
+
+## Functionality
+
+Small functional customizations such as toggling visibility of UI elements and configuring selection modes.
+
+| Methods | Description | Code |
+| --- | --- | --- |
+| `setGroup` | Sets the group whose members need to be fetched. Required for the component to function. | `.setGroup(group);` |
+| `setBackIconVisibility` | Toggles visibility for the back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` |
+| `setToolbarVisibility` | Toggles visibility for the toolbar in the app bar | `.setToolbarVisibility(View.GONE);` |
+| `setLoadingStateVisibility` | Hides the loading state while fetching members | `.setLoadingStateVisibility(View.GONE);` |
+| `setErrorStateVisibility` | Hides the error state on fetching members | `.setErrorStateVisibility(View.GONE);` |
+| `setEmptyStateVisibility` | Hides the empty state on fetching members | `.setEmptyStateVisibility(View.GONE);` |
+| `setSeparatorVisibility` | Controls visibility of separators in the list view | `.setSeparatorVisibility(View.GONE);` |
+| `setUserStatusVisibility` | Controls visibility of the online status indicator | `.setUserStatusVisibility(View.GONE);` |
+| `setSearchBoxVisibility` | Controls visibility of the search box in the toolbar | `.setSearchBoxVisibility(View.GONE);` |
+| `setSelectionMode` | Determines the selection mode (single or multiple) | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| `setSearchKeyword` | Programmatically triggers a search with the given keyword | `.setSearchKeyword("anything");` |
+| `setTitleText` | Sets a custom title in the toolbar | `.setTitleText("Members");` |
+| `setKickMemberOptionVisibility` | Toggles visibility for the kick member option in the long-press menu | `.setKickMemberOptionVisibility(View.GONE);` |
+| `setBanMemberOptionVisibility` | Toggles visibility for the ban member option in the long-press menu | `.setBanMemberOptionVisibility(View.GONE);` |
+| `setScopeChangeOptionVisibility` | Toggles visibility for the scope change option in the long-press menu | `.setScopeChangeOptionVisibility(View.GONE);` |
+| `excludeOwner` | When true, excludes the group owner from the member list | `.excludeOwner(true);` |
+
+- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden.
+
+## Custom View Slots
+
+Each slot replaces a section of the default UI. Slots that accept a `GroupMember` parameter receive the group member object for that row via the `GroupMembersViewHolderListeners` pattern (`createView` + `bindView`).
+
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Leading view | `setLeadingView(GroupMembersViewHolderListeners)` | Avatar / left section |
+| Title view | `setTitleView(GroupMembersViewHolderListeners)` | Name / title text |
+| Subtitle view | `setSubtitleView(GroupMembersViewHolderListeners)` | Subtitle text below name |
+| Trailing view | `setTrailingView(GroupMembersViewHolderListeners)` | Right section |
+| Item view | `setItemView(GroupMembersViewHolderListeners)` | Entire list item row |
+| Loading view | `setLoadingStateView(@LayoutRes int)` | Loading spinner |
+| Empty view | `setEmptyStateView(@LayoutRes int)` | Empty state |
+| Error view | `setErrorStateView(@LayoutRes int)` | Error state |
+| Overflow menu | `setOverflowMenu(View)` | Toolbar menu |
+| Options (replace) | `setOptions(Function3)` | Long-press context menu (replaces defaults) |
+| Options (append) | `addOptions(Function3)` | Long-press context menu (appends to defaults) |
+
+### `setLeadingView`
+
+Replace the avatar / left section.
-To fit your app's design requirements, you can customize the appearance of the Groups component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
-
-### Style
-
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
-
-
-
-
-
-```xml themes.xml
-
+
+
+```kotlin lines
+cometchatGroupMembers.setLeadingView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View? {
+ return null
+ }
-
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ }
+})
```
+
-
-```java
-cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle);
-```
+```java lines
+cometchatGroupMembers.setLeadingView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return null;
+ }
-
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
-
-```kotlin
-cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle)
+ }
+});
```
-
-
-***
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_group_members.xml).
+> **What this does:** Registers a `GroupMembersViewHolderListeners` that provides a custom view for the leading (left) area of each group member item. `createView` inflates your layout, and `bindView` populates it with group member data.
-### Functionality
+Scope badge avatar example:
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can toggle the visibility of UI elements.
+
+
+
-Below is a list of customizations along with corresponding code snippets
+Create a custom layout file named `custom_title_view.xml`:
-| Methods | Description | Code |
-| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
-| setGroup | Sets the group whose members need to be fetched. This is a required property for the component to function properly. | `.setGroup(group);` |
-| setBackIconVisibility | Used to toggle visibility for back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` |
-| setToolbarVisibility | Used to toggle visibility for back button in the app bar | `.setToolbarVisibility(View.GONE);` |
-| setErrorStateVisibility | Used to hide error state on fetching Users | `.setErrorStateVisibility(View.GONE);` |
-| setEmptyStateVisibility | Used to hide empty state on fetching Users | `.setEmptyStateVisibility(View.GONE);` |
-| setLoadingStateVisibility | Used to hide loading state while fetching Users | `.setLoadingStateVisibility(View.GONE);` |
-| setSeparatorVisibility | Used to control visibility of Separators in the list view | `.setSeparatorVisibility(View.GONE);` |
-| setUsersStatusVisibility | Used to control visibility of status indicator shown if user is online | `.setUsersStatusVisibility(View.GONE);` |
-| setSelectionMode | This method determines the selection mode for members, enabling users to select either a single or multiple members at once. | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
-| setSearchkeyword | Used for fetching members matching the passed keywords | `.setSearchkeyword("anything");` |
-| setSearchBoxVisibility | Used to hide search box shown in the tool bar | `.setSearchBoxVisibility(View.GONE);` |
-
-***
-
-### Advanced
-
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your own views, layouts, and UI elements and then incorporate those into the component.
-
-The `Group Memebers` component does not provide additional functionalities beyond this level of customization.
-
-***
-
-#### setOptions
-
-Defines a set of available actions that users can perform when they interact with a group member item.
+```xml custom_title_view.xml lines
+
+
-Use Cases:
+
-* Provide actions like "View Profile", "Send Message", "Remove from Group".
-* Restrict certain actions to admins (e.g., "Promote to Admin", "Ban User").
+
-
-
-```java
-cometchatUsers.setOptions((context, user) -> Collections.emptyList());
+
```
-
+> **What this does:** Defines a custom leading view layout with a `CometChatAvatar` and a role badge view that can display different backgrounds based on the member's scope (admin, moderator, participant).
+
-```kotlin
-cometchatUsers.options = Function2?> { context, user -> emptyList() }
-```
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setLeadingView(object : GroupMembersViewHolderListeners() {
+ override fun createView(context: Context?, listItem: CometchatGroupMemberListItemBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.header_leading_view, null, false)
+ }
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ val avatar = createdView.findViewById(R.id.avatar)
+ avatar.setAvatar(groupMember.name, groupMember.avatar)
+ val role = createdView.findViewById(R.id.batch_view)
+ if (UIKitConstants.GroupMemberScope.ADMIN == groupMember.scope) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.marketing_head, null)
+ } else if (UIKitConstants.GroupMemberScope.MODERATOR == groupMember.scope) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.sr_manager, null)
+ } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS == groupMember.scope) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.content_manager, null)
+ } else {
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.team_member, null)
+ }
+ val layoutParams = LinearLayout.LayoutParams(
+ Utils.convertDpToPx(context, 40),
+ Utils.convertDpToPx(context, 40)
+ )
+ createdView.layoutParams = layoutParams
+ }
+})
+```
-
-
-***
-
-#### addOptions
-
-Adds custom actions to the existing options available when interacting with a group member.
-
-Use Cases:
-
-* Extend functionality by adding "Block User", "Report User", or "View Activity".
-* Customize actions based on member roles.
-
-
-```java
-cometchatUsers.addOptions((context, user) -> Collections.emptyList());
-```
-
-
+```java YourActivity.java lines
+cometchatGroupMembers.setLeadingView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.header_leading_view, null, false);
+ }
-
-```kotlin
-cometchatUsers.addOptions { context, user -> emptyList() }
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+ CometChatAvatar avatar = createdView.findViewById(R.id.avatar);
+ avatar.setAvatar(groupMember.getName(), groupMember.getAvatar());
+ View role = createdView.findViewById(R.id.batch_view);
+ if (UIKitConstants.GroupMemberScope.ADMIN.equals(groupMember.getScope())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.marketing_head, null));
+ } else if (UIKitConstants.GroupMemberScope.MODERATOR.equals(groupMember.getScope())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.sr_manager, null));
+ } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS.equals(groupMember.getScope())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.content_manager, null));
+ } else {
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.team_member, null));
+ }
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(Utils.convertDpToPx(context, 40),
+ Utils.convertDpToPx(context, 40));
+ createdView.setLayoutParams(layoutParams);
+ }
+});
```
-
-
-***
+> **What this does:** Inflates a custom leading view layout and populates it with the group member's avatar and a role-based badge. If the member is an admin, the badge shows the `marketing_head` drawable; if a moderator, `sr_manager`; if a participant, `content_manager`; otherwise, `team_member`. The view is sized to 40dp × 40dp.
-#### setLoadingView
+### `setTitleView`
-Displays a custom loading view while group members are being fetched.
+Replace the name / title text.
-Use Cases:
+
+
+```kotlin lines
+cometchatGroupMembers.setTitleView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View? {
+ return null
+ }
-* Show a loading spinner with "Fetching group members...".
-* Implement a skeleton loader for a smoother UI experience.
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ }
+})
+```
+
-
-```java
-cometchatUsers.setLoadingView(R.layout.your_loading_view);
-```
+```java lines
+cometchatGroupMembers.setTitleView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return null;
+ }
-
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
-
-```kotlin
-cometchatUsers.loadingView = R.layout.your_loading_view
+ }
+});
```
-
-
-***
+Inline role badge example:
-#### setEmptyView
+
+
+
-Configures a view to be displayed when no group members are found.
+Create a custom layout file named `custom_title_view.xml`:
-Use Cases:
+```xml custom_title_view.xml lines
+
+
-* Display a message like "No members in this group yet.".
-* Show a button to Invite Members.
+
-
-
-```java
-cometchatUsers.setEmptyView(R.layout.your_empty_view);
+
+
```
-
+> **What this does:** Defines a custom title view layout with a `TextView` for the member name and a `View` for the role badge, arranged horizontally.
+
-```kotlin
-cometchatUsers.emptyView = R.layout.your_empty_view
-```
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setTitleView(object : GroupMembersViewHolderListeners() {
+ override fun createView(context: Context?, listItem: CometchatGroupMemberListItemBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null, false)
+ }
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ val layout = createdView.findViewById(R.id.user_layout)
+ val layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ layout.layoutParams = layoutParams
+ val name = createdView.findViewById(R.id.title)
+ name.text = groupMember.name
+ val role = createdView.findViewById(R.id.role)
+ if (UIKitConstants.GroupMemberScope.ADMIN == groupMember.scope) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.marketing_head, null)
+ } else if (UIKitConstants.GroupMemberScope.MODERATOR == groupMember.scope) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.sr_manager, null)
+ } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS == groupMember.scope) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.content_manager, null)
+ } else {
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.team_member, null)
+ }
+ }
+})
+```
-
-
-***
-
-#### setErrorView
-
-Defines a custom error state view when there is an issue loading group members.
-
-Use Cases:
-
-* Display a retry button with "Failed to load members. Tap to retry.".
-* Show an illustration for a better user experience.
-
-
-```java
-cometchatUsers.setErrorView(R.layout.your_empty_view);
-```
-
-
+```java YourActivity.java lines
+cometchatGroupMembers.setTitleView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null, false);
+ }
-
-```kotlin
-cometchatUsers.errorView = R.layout.your_error_view
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+ LinearLayout layout = createdView.findViewById(R.id.user_layout);
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ layout.setLayoutParams(layoutParams);
+ TextView name = createdView.findViewById(R.id.title);
+ name.setText(groupMember.getName());
+ View role = createdView.findViewById(R.id.role);
+ if (UIKitConstants.GroupMemberScope.ADMIN.equals(groupMember.getScope())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.marketing_head, null));
+ } else if (UIKitConstants.GroupMemberScope.MODERATOR.equals(groupMember.getScope())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.sr_manager, null));
+ } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS.equals(groupMember.getScope())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.content_manager, null));
+ } else {
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.team_member, null));
+ }
+ }
+});
```
-
-
-***
-
-#### setLeadingView
+> **What this does:** Inflates a custom title view layout and populates it with the group member's name and a role-based badge. The badge background changes based on the member's scope: `marketing_head` for admin, `sr_manager` for moderator, `content_manager` for participant, and `team_member` for others.
-Sets a custom leading view for each group member item, usually used for profile images or avatars.
+### `setSubtitleView`
-Use Cases:
-
-* Show a circular avatar with an online/offline indicator.
-* Add a role-based badge (Admin, Moderator, Member).
+Replace the subtitle text below the member's name.
-
-```java
-cometchatUsers.setLeadingView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-
- }
- });
-```
-
-
-
-```kotlin
-cometchatUsers.setLeadingView(object: UsersViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatGroupMembers.setSubtitleView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, user: User, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
}
})
```
-
-
-
-
-
-
-
-You can indeed create a custom layout file named `custom_title_view.xml` for more complex or unique list items.
+
+```java lines
+cometchatGroupMembers.setSubtitleView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return null;
+ }
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
+ }
+});
+```
+
+
-```xml custom_title_view.xml
-
-
+Example with join date:
-
+
+
+
-
+
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setSubtitleView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View {
+ return TextView(context)
+ }
-
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ (createdView as TextView).text =
+ "Joined at: " + SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(groupMember.joinedAt * 1000)
+ }
+})
```
+
-
-```java YourActivity.java
-cometchatGroupMembers.setTitleView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.header_leading_view, null, false);
-
-
- }
-
- @Override
- public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
- CometChatAvatar avatar = createdView.findViewById(R.id.avatar);
- avatar.setAvatar(groupMember.getName(), groupMember.getAvatar());
- View role = createdView.findViewById(R.id.batch_view);
- if (UIKitConstants.GroupMemberScope.ADMIN.equals(groupMember.getScope())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.marketing_head, null));
- } else if (UIKitConstants.GroupMemberScope.MODERATOR.equals(groupMember.getScope())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.sr_manager, null));
- } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS.equals(groupMember.getScope())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.content_manager, null));
- } else {
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.team_member, null));
- }
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(Utils.convertDpToPx(context, 40),
- Utils.convertDpToPx(context, 40));
- createdView.setLayoutParams(layoutParams);
- }
- });
-```
-
-
+```java YourActivity.java lines
+cometchatGroupMembers.setSubtitleView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return new TextView(context);
+ }
-
-```kotlin YourActivity.kt
-cometchatGroupMembers.setLeadingView(object : GroupMembersViewHolderListeners() {
- override fun createView(context: Context?, listItem: CometchatGroupMemberListItemBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.header_leading_view, null, false)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- groupMember: GroupMember,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupMemberList: List,
- position: Int
- ) {
- val avatar = createdView.findViewById(R.id.avatar)
- avatar.setAvatar(groupMember.name, groupMember.avatar)
- val role = createdView.findViewById(R.id.batch_view)
- if (UIKitConstants.GroupMemberScope.ADMIN == groupMember.scope) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.marketing_head, null)
- } else if (UIKitConstants.GroupMemberScope.MODERATOR == groupMember.scope) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.sr_manager, null)
- } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS == groupMember.scope) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.content_manager, null)
- } else {
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.team_member, null)
- }
- val layoutParams = LinearLayout.LayoutParams(
- Utils.convertDpToPx(context, 40),
- Utils.convertDpToPx(context, 40)
- )
- createdView.layoutParams = layoutParams
- }
- })
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+ ((TextView) createdView).setText("Joined at: " + new SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(groupMember.getJoinedAt() * 1000));
+ }
+});
```
-
-
-***
-
-#### setTitleView
+> **What this does:** Creates a `TextView` as the subtitle view and populates it with the group member's join date formatted as "dd/MM/yyyy, HH:mm:ss". The `joinedAt` timestamp is multiplied by 1000 to convert from seconds to milliseconds.
-Customizes the title view, typically displaying the member's name.
+### `setTrailingView`
-Use Cases:
-
-* Customize fonts, colors, or styles for usernames.
-* Add role-specific indicators like "(Group Admin)".
+Replace the right section of each group member item.
-
-```java
-cometchatUsers.setTitleView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-
- }
- });
-```
-
-
-
-```kotlin
-cometchatUsers.setTitleView(object: UsersViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatGroupMembers.setTrailingView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, user: User, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
}
})
```
-
+
+```java lines
+cometchatGroupMembers.setTrailingView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+
+ }
+});
+```
+
+Scope badge example:
+
-
+
-You can indeed create a custom layout file named `custom_title_view.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
+Create a custom layout file named `custom_tail_view.xml`:
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
-
-```xml custom_title_view.xml
+```xml custom_tail_view.xml lines
+ android:layout_height="wrap_content">
-
+ android:layout_marginStart="16dp"
+ app:cardBackgroundColor="?attr/cometchatPrimaryColor"
+ app:cardCornerRadius="@dimen/cometchat_radius_max"
+ app:cardElevation="@dimen/cometchat_0dp">
-
-
-```
+
-
-
-```java YourActivity.java
-cometchatGroupMembers.setTitleView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null, false);
-
- }
-
- @Override
- public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
- LinearLayout layout = createdView.findViewById(R.id.user_layout);
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- layout.setLayoutParams(layoutParams);
- TextView name = createdView.findViewById(R.id.title);
- name.setText(groupMember.getName());
- View role = createdView.findViewById(R.id.role);
- if (UIKitConstants.GroupMemberScope.ADMIN.equals(groupMember.getScope())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.marketing_head, null));
- } else if (UIKitConstants.GroupMemberScope.MODERATOR.equals(groupMember.getScope())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.sr_manager, null));
- } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS.equals(groupMember.getScope())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.content_manager, null));
- } else {
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.team_member, null));
-
- }
- }
- });
+
+
+
```
-
+> **What this does:** Defines a custom trailing view layout with a `MaterialCardView` containing a `TextView` that displays the member's scope as a colored badge.
+
-```kotlin YourActivity.kt
-cometchatGroupMembers.setTitleView(object : GroupMembersViewHolderListeners() {
- override fun createView(context: Context?, listItem: CometchatGroupMemberListItemBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null, false)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- groupMember: GroupMember,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupMemberList: List,
- position: Int
- ) {
- val layout = createdView.findViewById(R.id.user_layout)
- val layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- layout.layoutParams = layoutParams
- val name = createdView.findViewById(R.id.title)
- name.text = groupMember.name
- val role = createdView.findViewById(R.id.role)
- if (UIKitConstants.GroupMemberScope.ADMIN == groupMember.scope) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.marketing_head, null)
- } else if (UIKitConstants.GroupMemberScope.MODERATOR == groupMember.scope) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.sr_manager, null)
- } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS == groupMember.scope) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.content_manager, null)
- } else {
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.team_member, null)
- }
- }
- })
-```
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setTrailingView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View {
+ return View.inflate(context, R.layout.custom_tail_view, null)
+ }
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ val cardView = createdView.findViewById(R.id.scope_card)
+ val tvName = createdView.findViewById(R.id.tv_scope)
+ cardView.setCardBackgroundColor(CometChatTheme.getExtendedPrimaryColor100(context))
+ tvName.text = groupMember.scope
+ createdView.visibility =
+ if (groupMember.scope == UIKitConstants.GroupMemberScope.PARTICIPANTS) View.VISIBLE else View.GONE
+ }
+})
+```
-
-
-***
-
-#### setItemView
-
-Assigns a fully custom ListItem layout to the Group Members Component, replacing the default structure.
-
-Use Cases:
-
-* Include additional member details like joined date, bio, or status.
-* Modify layout based on user roles.
-
-
-```java
-cometchatGroupMembers.setItemView(new GroupMembersViewHolderListeners() {
+```java YourActivity.java lines
+cometchatGroupMembers.setTrailingView(new GroupMembersViewHolderListeners() {
@Override
- public View createView(Context context, CometchatGroupMemberListItemBinding cometChatListItem) {
- return null;
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return View.inflate(context, R.layout.custom_tail_view, null);
}
@Override
- public void bindView(Context context, View view, GroupMember groupMember, Group group, RecyclerView.ViewHolder viewHolder, List list, int i) {
-
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+ MaterialCardView cardView = createdView.findViewById(R.id.scope_card);
+ TextView tvName = createdView.findViewById(R.id.tv_scope);
+ cardView.setCardBackgroundColor(CometChatTheme.getExtendedPrimaryColor100(context));
+ tvName.setText(groupMember.getScope());
+ createdView.setVisibility(groupMember.getScope().equals(UIKitConstants.GroupMemberScope.PARTICIPANTS) ? View.VISIBLE : View.GONE);
}
});
```
+
+
-
+> **What this does:** Inflates a custom trailing view that displays a scope badge for each group member. The badge background uses the extended primary color, the text shows the member's scope, and the badge is only visible for participants (hidden for admins, moderators, and owners).
+
+### `setItemView`
+Replace the entire list item row.
+
+
-```kotlin
+```kotlin lines
cometchatGroupMembers.setItemView(object : GroupMembersViewHolderListeners() {
- override fun createView(context: Context, cometChatListItem: CometchatGroupMemberListItemBinding): View? {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View? {
return null
}
override fun bindView(
context: Context,
- view: View,
+ createdView: View,
groupMember: GroupMember,
group: Group,
- viewHolder: RecyclerView.ViewHolder,
- list: List,
- i: Int
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
) {
}
})
```
-
+
+```java lines
+cometchatGroupMembers.setItemView(new GroupMembersViewHolderListeners() {
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+
+ }
+});
+```
+
-**Example**
+Example with name and scope:
-You can indeed create a custom layout file named `item_list.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
+Create a custom layout file named `item_list.xml`:
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
-
-```xml item_list.xml
+```xml item_list.xml lines
-
```
+> **What this does:** Defines a custom list item layout with two `TextView` elements: one for the member name and one for the subtitle (scope), arranged vertically.
+
+
+```kotlin YourActivity.kt lines
+cometchatGroupMembers.setItemView(object : GroupMembersViewHolderListeners() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatGroupMemberListItemBinding?
+ ): View {
+ return View.inflate(context, R.layout.custom_group_list_item, null)
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ groupMember: GroupMember,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupMemberList: List,
+ position: Int
+ ) {
+ val tvName = createdView.findViewById(R.id.tvName)
+ val tvScope = createdView.findViewById(R.id.tvSubtitle)
+ tvName.text = groupMember.name
+ tvScope.text = groupMember.scope
+ }
+})
+```
+
+
-```java YourActivity.java
+```java YourActivity.java lines
cometchatGroupMembers.setItemView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
- return View.inflate(context, R.layout.custom_group_list_item, null);
- }
-
- @Override
- public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
- TextView tvName = createdView.findViewById(R.id.tvName);
- TextView tvScope = createdView.findViewById(R.id.tvSubtitle);
- tvName.setText(groupMember.getName());
- tvScope.setText(groupMember.getScope());
- }
- });
-```
+ @Override
+ public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
+ return View.inflate(context, R.layout.custom_group_list_item, null);
+ }
+ @Override
+ public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
+ TextView tvName = createdView.findViewById(R.id.tvName);
+ TextView tvScope = createdView.findViewById(R.id.tvSubtitle);
+ tvName.setText(groupMember.getName());
+ tvScope.setText(groupMember.getScope());
+ }
+});
+```
+
+> **What this does:** Inflates a custom list item layout and populates it with the group member's name and scope. Each list item shows the member name in the primary text style and their scope (admin, moderator, participant) in the secondary text style.
+
+### `setOptions`
+
+Replace the long-press context menu entirely.
+
+
-```kotlin YourActivity.kt
-cometchatGroupMembers.setItemView(object :
- GroupMembersViewHolderListeners() {
- override fun createView(
- context: Context?,
- listItem: CometchatGroupMemberListItemBinding?
- ): View {
- return View.inflate(context, R.layout.custom_group_list_item, null)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- groupMember: GroupMember,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupMemberList: List,
- position: Int
- ) {
- val tvName = createdView.findViewById(R.id.tvName)
- val tvScope = createdView.findViewById(R.id.tvSubtitle)
- tvName.text = groupMember.name
- tvScope.text = groupMember.scope
- }
- })
+```kotlin lines
+cometchatGroupMembers.setOptions { context, groupMember, group -> emptyList() }
```
-
+
+```java lines
+cometchatGroupMembers.setOptions((context, groupMember, group) -> Collections.emptyList());
+```
+
-***
+### `addOptions`
-#### setSubTitleView
+Append to the long-press context menu without removing defaults.
+
+
+
+```kotlin lines
+cometchatGroupMembers.addOptions { context, groupMember, group -> emptyList() }
+```
+
-Customizes the subtitle view for each group member, typically used for extra details.
+
+```java lines
+cometchatGroupMembers.addOptions((context, groupMember, group) -> Collections.emptyList());
+```
+
+
-Use Cases:
+### `setLoadingStateView`
-* Show "Last Active" time.
-* Display a custom status message.
+Sets a custom loading view displayed when data is being fetched.
+
+```kotlin lines
+cometchatGroupMembers.setLoadingStateView(R.layout.your_loading_view)
+```
+
+
-```java
-cometchatGroupMembers.setSubtitleView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding cometChatListItem) {
- return null;
- }
+```java lines
+cometchatGroupMembers.setLoadingStateView(R.layout.your_loading_view);
+```
+
+
- @Override
- public void bindView(Context context, View view, GroupMember groupMember, Group group, RecyclerView.ViewHolder viewHolder, List list, int i) {
+### `setEmptyStateView`
- }
-});
+Configures a custom view displayed when there are no group members in the list.
+
+
+
+```kotlin lines
+cometchatGroupMembers.setEmptyStateView(R.layout.your_empty_view)
```
+
+
+```java lines
+cometchatGroupMembers.setEmptyStateView(R.layout.your_empty_view);
+```
+
-
-```kotlin
-cometchatGroupMembers.setSubtitleView(object : GroupMembersViewHolderListeners() {
- override fun createView(context: Context, cometChatListItem: CometchatGroupMemberListItemBinding?): View? {
- return null
- }
+### `setErrorStateView`
- override fun bindView(
- context: Context,
- view: View,
- groupMember: GroupMember,
- group: Group,
- viewHolder: RecyclerView.ViewHolder,
- list: List,
- i: Int
- ) {
- }
-})
-```
+Defines a custom error state view that appears when an issue occurs while loading group members.
+
+
+```kotlin lines
+cometchatGroupMembers.setErrorStateView(R.layout.your_error_view)
+```
+
+```java lines
+cometchatGroupMembers.setErrorStateView(R.layout.your_error_view);
+```
+
-**Example**
+### `setOverflowMenu`
+
+Replace the toolbar overflow menu.
-
+
-You can indeed create a custom layout file named `subtitle_layout.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
-
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
-
-
-```java YourActivity.java
-cometchatGroupMembers.setSubtitleView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
- return new TextView(context);
- }
-
- @Override
- public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
- ((TextView) createdView).setText("Joined at: "+new SimpleDateFormat("dd/mm/yyyy").format(groupMember.getJoinedAt()*1000));
- }
- });
+
+```kotlin lines
+val addMemberIv = ImageView(this)
+addMemberIv.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_add, null))
+cometchatGroupMembers.setOverflowMenu(addMemberIv)
```
-
-
-```kotlin YourActivity.kt
-cometchatGroupMembers.setSubtitleView(object :
- GroupMembersViewHolderListeners() {
- override fun createView(
- context: Context?,
- listItem: CometchatGroupMemberListItemBinding?
- ): View {
- return TextView(context)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- groupMember: GroupMember,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupMemberList: List,
- position: Int
- ) {
- (createdView as TextView).text =
- "Joined at: " + SimpleDateFormat("dd/mm/yyyy").format(groupMember.joinedAt * 1000)
- }
- })
+
+```java lines
+ImageView addMemberIv = new ImageView(this);
+addMemberIv.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_add, null));
+cometchatGroupMembers.setOverflowMenu(addMemberIv);
```
-
-
-***
+> **What this does:** Creates an `ImageView` with an add icon and sets it as the overflow menu in the group members toolbar. This provides a quick action button for adding new members.
-#### setTrailingView
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the group member list item, and the data binding populates correctly for each member.
-Customizes the trailing (right-end) section of each member item, typically used for action buttons.
+## Common Patterns
-Use Cases:
-
-* Show quick actions like Mute, Remove, or Promote.
-* Display a "Last Active" timestamp.
+### Hide all chrome — minimal list
+
+```kotlin lines
+cometchatGroupMembers.setUserStatusVisibility(View.GONE)
+cometchatGroupMembers.setSeparatorVisibility(View.GONE)
+cometchatGroupMembers.setToolbarVisibility(View.GONE)
+```
+
+
-```java
-cometchatGroupMembers.setTrailingView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding cometChatListItem) {
- return null;
- }
+```java lines
+cometchatGroupMembers.setUserStatusVisibility(View.GONE);
+cometchatGroupMembers.setSeparatorVisibility(View.GONE);
+cometchatGroupMembers.setToolbarVisibility(View.GONE);
+```
+
+
- @Override
- public void bindView(Context context, View view, GroupMember groupMember, Group group, RecyclerView.ViewHolder viewHolder, List list, int i) {
+### Admins-only list
- }
-});
+
+
+```kotlin lines
+val builder = GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
+ .setScopes(listOf("admin"))
+cometchatGroupMembers.setGroupMembersRequestBuilder(builder)
```
-
-
-```kotlin
-cometchatGroupMembers.setTrailingView(object : GroupMembersViewHolderListeners() {
- override fun createView(context: Context, cometChatListItem: CometchatGroupMemberListItemBinding?): View? {
- return null
- }
+
+```java lines
+GroupMembersRequest.GroupMembersRequestBuilder builder = new GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
+ .setScopes(Arrays.asList("admin"));
+cometchatGroupMembers.setGroupMembersRequestBuilder(builder);
+```
+
+
- override fun bindView(
- context: Context,
- view: View,
- groupMember: GroupMember,
- group: Group,
- viewHolder: RecyclerView.ViewHolder,
- list: List,
- i: Int
- ) {
+### Exclude group owner
- }
-})
+
+
+```kotlin lines
+cometchatGroupMembers.excludeOwner(true)
```
-
+
+```java lines
+cometchatGroupMembers.excludeOwner(true);
+```
+
-**Example**
-
-
-
-
+### Hide kick/ban/scope options
-You can indeed create a custom layout file named `tail_view_layout.xml` for more complex or unique list items.
+
+
+```kotlin lines
+cometchatGroupMembers.setKickMemberOptionVisibility(View.GONE)
+cometchatGroupMembers.setBanMemberOptionVisibility(View.GONE)
+cometchatGroupMembers.setScopeChangeOptionVisibility(View.GONE)
+```
+
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
+
+```java lines
+cometchatGroupMembers.setKickMemberOptionVisibility(View.GONE);
+cometchatGroupMembers.setBanMemberOptionVisibility(View.GONE);
+cometchatGroupMembers.setScopeChangeOptionVisibility(View.GONE);
+```
+
+
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
+## Advanced Methods
-```xml custom_tail_view.xml
-
-
+### Programmatic Selection
-
+#### `selectGroupMember`
-
+Programmatically selects or deselects a group member. Works with both `SINGLE` and `MULTIPLE` selection modes.
-
+
+
+```kotlin lines
+// Select a member in single-select mode
+cometchatGroupMembers.selectGroupMember(groupMember, UIKitConstants.SelectionMode.SINGLE)
-
+// Select a member in multi-select mode
+cometchatGroupMembers.selectGroupMember(groupMember, UIKitConstants.SelectionMode.MULTIPLE)
```
+
-
-```java YourActivity.java
-cometchatGroupMembers.setTrailingView(new GroupMembersViewHolderListeners() {
- @Override
- public View createView(Context context, CometchatGroupMemberListItemBinding listItem) {
- return View.inflate(context, R.layout.custom_tail_view, null);
- }
-
- @Override
- public void bindView(Context context, View createdView, GroupMember groupMember, Group group, RecyclerView.ViewHolder holder, List groupMemberList, int position) {
- MaterialCardView cardView = createdView.findViewById(R.id.scope_card);
- TextView tvName = createdView.findViewById(R.id.tv_scope);
- cardView.setCardBackgroundColor(CometChatTheme.getExtendedPrimaryColor100(context));
- tvName.setText(groupMember.getScope());
- createdView.setVisibility(groupMember.getScope().equals(UIKitConstants.GroupMemberScope.PARTICIPANTS) ? View.VISIBLE : View.GONE);
- }
- });
-```
+```java lines
+// Select a member in single-select mode
+cometchatGroupMembers.selectGroupMember(groupMember, UIKitConstants.SelectionMode.SINGLE);
+// Select a member in multi-select mode
+cometchatGroupMembers.selectGroupMember(groupMember, UIKitConstants.SelectionMode.MULTIPLE);
+```
+
+
+> In `SINGLE` mode, selecting a new member replaces the previous selection. In `MULTIPLE` mode, calling this on an already-selected member deselects it (toggle behavior).
+
+#### `getSelectedGroupMembers`
+Returns the list of currently selected `GroupMember` objects.
+
+
-```kotlin YourActivity.kt
-cometchatGroupMembers.setTrailingView(object :
- GroupMembersViewHolderListeners() {
- override fun createView(
- context: Context?,
- listItem: CometchatGroupMemberListItemBinding?
- ): View {
- return View.inflate(context, R.layout.custom_tail_view, null)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- groupMember: GroupMember,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupMemberList: List,
- position: Int
- ) {
- val cardView = createdView.findViewById(R.id.scope_card)
- val tvName = createdView.findViewById(R.id.tv_scope)
- cardView.setCardBackgroundColor(CometChatTheme.getExtendedPrimaryColor100(context))
- tvName.text = groupMember.scope
- createdView.visibility =
- if (groupMember.scope == UIKitConstants.GroupMemberScope.PARTICIPANTS) View.VISIBLE else View.GONE
- }
- })
+```kotlin lines
+val selected = cometchatGroupMembers.selectedGroupMembers
```
-
+
+```java lines
+List selected = cometchatGroupMembers.getSelectedGroupMembers();
+```
+
-#### setOverflowMenu
+### Selected Group Members List
-Allows customization of the overflow menu (three-dot ⋮ icon) with additional options.
+When using multi-select mode, a horizontal list of selected group members can be shown above the main list.
-Use Cases:
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSelectedGroupMembersListVisibility` | `int (View.VISIBLE / View.GONE)` | Show or hide the selected members strip |
+| `setSelectedGroupMemberAvatarStyle` | `@StyleRes int` | Avatar style for selected member chips |
+| `setSelectedGroupMemberItemTextColor` | `@ColorInt int` | Text color for selected member names |
+| `setSelectedGroupMemberItemTextAppearance` | `@StyleRes int` | Text appearance for selected member names |
+| `setSelectedGroupMemberItemRemoveIcon` | `Drawable` | Icon for the remove button on each chip |
+| `setSelectedGroupMemberItemRemoveIconTint` | `@ColorInt int` | Tint color for the remove icon |
-* Add extra actions like "Report Member", "Restrict from Posting".
-* Provide group admins with moderation options.
+### Search Input Customization
-
-
-```java
-cometchatGroupMembers.setOverflowMenu(v);
-```
+The built-in search box can be customized programmatically:
-
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSearchInputTextColor` | `@ColorInt int` | Text color of the search input |
+| `setSearchInputPlaceHolderTextColor` | `@ColorInt int` | Placeholder text color |
+| `setSearchInputIcon` | `Drawable` | Leading icon in the search box |
+| `setSearchInputIconTint` | `@ColorInt int` | Tint for the leading icon |
+| `setSearchInputEndIcon` | `Drawable` | Trailing icon in the search box |
+| `setSearchInputEndIconTint` | `@ColorInt int` | Tint for the trailing icon |
+| `setSearchInputStrokeWidth` | `@Dimension int` | Stroke width of the search box border |
+| `setSearchInputStrokeColor` | `@ColorInt int` | Stroke color of the search box border |
+| `setSearchInputBackgroundColor` | `@ColorInt int` | Background color of the search box |
+| `setSearchInputCornerRadius` | `@Dimension int` | Corner radius of the search box |
+| `setSearchInputTextAppearance` | `@StyleRes int` | Text appearance of the search input |
-
-```kotlin
-cometchatGroupMembers.setOverflowMenu(v)
-```
+### Internal Access
-
+These methods provide direct access to internal components for advanced use cases.
-
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getBinding()` | `CometchatGroupMembersListViewBinding` | The ViewBinding for the component's root layout |
+| `getViewModel()` | `GroupMembersViewModel` | The ViewModel managing group member data and state |
+| `getAdapter()` | `GroupMembersAdapter` | The adapter powering the RecyclerView |
+| `setAdapter(GroupMembersAdapter)` | `void` | Replaces the default adapter with a custom one |
+| `getRecyclerView()` | `RecyclerView` | The RecyclerView displaying the member list |
+
+> Use these only when the standard API is insufficient. Directly manipulating the adapter or ViewModel may conflict with the component's internal state management.
+
+## Style
-Example:
+The component uses XML theme styles. Define a custom style with parent `CometChatGroupMembersStyle` in `themes.xml`, then apply with `setStyle()`.
-
+
-
-
-```java
-ImageView addMemberIv = new ImageView(this);
-addMemberIv.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_add, null));
-cometchatGroupMembers.setOverflowMenu(addMemberIv);
-```
+```xml themes.xml lines
+
-
+
+```
+
-```kotlin
-val addMemberIv = ImageView(this)
-addMemberIv.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_add, null))
-cometchatGroupMembers.setOverflowMenu(addMemberIv)
+```kotlin lines
+cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle)
```
-
+
+```java lines
+cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle);
+```
+
+
+> **What this does:** Applies the `CustomGroupMembersStyle` theme to the `CometChatGroupMembers` component, changing the avatar, separator, title text, and back icon appearance.
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_group_members.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon |
+| `setBackIcon` | `Drawable` | Custom back icon drawable |
+| `setTitleTextColor` | `@ColorInt int` | Title text color in the toolbar |
+| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance in the toolbar |
+| `setItemTitleTextColor` | `@ColorInt int` | Text color for member item titles |
+| `setItemTitleTextAppearance` | `@StyleRes int` | Text appearance for member item titles |
+| `setSeparatorColor` | `@ColorInt int` | Color of list item separators |
+| `setSeparatorHeight` | `@Dimension int` | Height of list item separators |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component |
+| `setEmptyStateTitleTextColor` | `@ColorInt int` | Title text color for the empty state |
+| `setEmptyStateTitleTextAppearance` | `@StyleRes int` | Title text appearance for the empty state |
+| `setEmptyStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the empty state |
+| `setEmptyStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the empty state |
+| `setErrorStateTitleTextColor` | `@ColorInt int` | Title text color for the error state |
+| `setErrorStateTitleTextAppearance` | `@StyleRes int` | Title text appearance for the error state |
+| `setErrorStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the error state |
+| `setErrorStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the error state |
+| `setAvatarStyle` | `@StyleRes int` | Style for member avatars |
+| `setStatusIndicatorStyle` | `@StyleRes int` | Style for online/offline status indicators |
+
+### Checkbox Style Properties (Selection Mode)
+
+When using `SINGLE` or `MULTIPLE` selection mode, checkboxes appear on each item:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setCheckBoxStrokeWidth` | `@Dimension int` | Stroke width of the checkbox border |
+| `setCheckBoxCornerRadius` | `@Dimension int` | Corner radius of the checkbox |
+| `setCheckBoxStrokeColor` | `@ColorInt int` | Stroke color of the checkbox border |
+| `setCheckBoxBackgroundColor` | `@ColorInt int` | Background color of unchecked checkbox |
+| `setCheckBoxCheckedBackgroundColor` | `@ColorInt int` | Background color of checked checkbox |
+| `setSelectIcon` | `Drawable` | Icon shown when checkbox is checked |
+| `setSelectIconTint` | `@ColorInt int` | Tint for the checkbox select icon |
+| `setDiscardSelectionIcon` | `Drawable` | Icon for the discard selection button |
+| `setDiscardSelectionIconTint` | `@ColorInt int` | Tint for the discard selection icon |
+| `setSubmitSelectionIcon` | `Drawable` | Icon for the submit selection button |
+| `setSubmitSelectionIconTint` | `@ColorInt int` | Tint for the submit selection icon |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override behavior on member interaction | Activity/Fragment | `setOn` callbacks | `setOnItemClick((v, pos, m) -> { ... })` |
+| Filter which members appear | Activity/Fragment | `setGroupMembersRequestBuilder` | `setGroupMembersRequestBuilder(builder)` |
+| Customize search results | Activity/Fragment | `setSearchRequestBuilder` | `setSearchRequestBuilder(builder)` |
+| Toggle visibility of UI elements | Activity/Fragment | `setVisibility(int)` | `setUserStatusVisibility(View.GONE)` |
+| Replace a section of the list item | Activity/Fragment | `setView` | `setLeadingView(listener)` |
+| Change colors, fonts, spacing | `themes.xml` | `CometChatGroupMembersStyle` | `#F76808` |
+| Avatar style (corner radius, background) | `themes.xml` | `cometchatGroupMembersAvatarStyle` | `8dp` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle);` |
+| Set the group | Activity/Fragment | `setGroup(Group)` | `.setGroup(group);` |
+| Back button visibility | Activity/Fragment | `setBackIconVisibility(int)` | `.setBackIconVisibility(View.VISIBLE);` |
+| Toolbar visibility | Activity/Fragment | `setToolbarVisibility(int)` | `.setToolbarVisibility(View.GONE);` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE);` |
+| Empty state visibility | Activity/Fragment | `setEmptyStateVisibility(int)` | `.setEmptyStateVisibility(View.GONE);` |
+| Loading state visibility | Activity/Fragment | `setLoadingStateVisibility(int)` | `.setLoadingStateVisibility(View.GONE);` |
+| Separator visibility | Activity/Fragment | `setSeparatorVisibility(int)` | `.setSeparatorVisibility(View.GONE);` |
+| User online status visibility | Activity/Fragment | `setUserStatusVisibility(int)` | `.setUserStatusVisibility(View.GONE);` |
+| Selection mode (single/multiple) | Activity/Fragment | `setSelectionMode(SelectionMode)` | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| Search keyword | Activity/Fragment | `setSearchKeyword(String)` | `.setSearchKeyword("anything");` |
+| Search box visibility | Activity/Fragment | `setSearchBoxVisibility(int)` | `.setSearchBoxVisibility(View.GONE);` |
+| Custom toolbar title | Activity/Fragment | `setTitleText(String)` | `.setTitleText("Members");` |
+| Long-press options (replace) | Activity/Fragment | `setOptions(Function3)` | See `setOptions` code above |
+| Long-press options (append) | Activity/Fragment | `addOptions(Function3)` | See `addOptions` code above |
+| Loading view | Activity/Fragment | `setLoadingStateView(int)` | `.setLoadingStateView(R.layout.your_loading_view);` |
+| Empty view | Activity/Fragment | `setEmptyStateView(int)` | `.setEmptyStateView(R.layout.your_empty_view);` |
+| Error view | Activity/Fragment | `setErrorStateView(int)` | `.setErrorStateView(R.layout.your_error_view);` |
+| Leading view (avatar area) | Activity/Fragment | `setLeadingView(GroupMembersViewHolderListeners)` | See `setLeadingView` code above |
+| Title view | Activity/Fragment | `setTitleView(GroupMembersViewHolderListeners)` | See `setTitleView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(GroupMembersViewHolderListeners)` | See `setSubtitleView` code above |
+| Trailing view | Activity/Fragment | `setTrailingView(GroupMembersViewHolderListeners)` | See `setTrailingView` code above |
+| Entire list item | Activity/Fragment | `setItemView(GroupMembersViewHolderListeners)` | See `setItemView` code above |
+| Overflow menu | Activity/Fragment | `setOverflowMenu(View)` | `cometchatGroupMembers.setOverflowMenu(view);` |
+| Kick member option visibility | Activity/Fragment | `setKickMemberOptionVisibility(int)` | `.setKickMemberOptionVisibility(View.GONE);` |
+| Ban member option visibility | Activity/Fragment | `setBanMemberOptionVisibility(int)` | `.setBanMemberOptionVisibility(View.GONE);` |
+| Scope change option visibility | Activity/Fragment | `setScopeChangeOptionVisibility(int)` | `.setScopeChangeOptionVisibility(View.GONE);` |
+| Exclude group owner | Activity/Fragment | `excludeOwner(boolean)` | `.excludeOwner(true);` |
+| Programmatic selection | Activity/Fragment | `selectGroupMember(GroupMember, SelectionMode)` | `.selectGroupMember(member, SelectionMode.SINGLE);` |
+| Selected members strip | Activity/Fragment | `setSelectedGroupMembersListVisibility(int)` | `.setSelectedGroupMembersListVisibility(View.VISIBLE);` |
+| Internal adapter access | Activity/Fragment | `getAdapter()` / `setAdapter()` | Advanced use only |
+
+## Accessibility
+
+The component renders a scrollable `RecyclerView` of interactive group member items. Each member row responds to tap and long-press gestures. Avatar images include the member name as content description.
+
+For custom views provided via `setLeadingView`, `setTitleView`, `setTrailingView`, or `setItemView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+Online/offline status dots are visual-only by default. If screen reader descriptions are needed, provide them via a custom view with appropriate `contentDescription` attributes. Scope badges (admin, moderator, participant) should also include content descriptions when using custom trailing views.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Group member list is empty despite having members | Verify that `setGroup(group)` is called with a valid `Group` object that has a correct `GUID`. The component requires a group to fetch members. |
+| `setGroup` not called | `setGroup` is a required property. If you define `CometChatGroupMembers` in XML, you must still call `setGroup()` programmatically in your Activity or Fragment. |
+| Filters not applied | Ensure you call `setGroupMembersRequestBuilder(builder)` on the `CometChatGroupMembers` instance after creating and configuring the builder. |
+| Custom style not visible | Verify the style parent is `CometChatGroupMembersStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| `setOnItemClick` not firing | If you set `setSelectionMode` to `MULTIPLE`, item clicks may be consumed by the selection logic. Set the selection mode to `NONE` if you need standard click behavior. |
+| Event listener not receiving events | Ensure you call `CometChatGroupEvents.addGroupListener` with a unique tag. If you use the same tag as another listener, the previous one is replaced. |
+| Custom view returns null in `createView` | If `createView` returns `null`, the default view is used. Return a valid inflated `View` to replace the default. |
+| Scope badge not showing for participants | In the trailing view example, the badge is only visible when `groupMember.getScope()` equals `UIKitConstants.GroupMemberScope.PARTICIPANTS`. If you want it visible for all scopes, remove the visibility condition. |
+| Search not working with custom filter | If you set a `GroupMembersRequestBuilder` via `setGroupMembersRequestBuilder`, the search may use different parameters. Use `setSearchRequestBuilder` to control search behavior separately. |
+| Online status indicator not visible | Ensure `setUserStatusVisibility` is set to `View.VISIBLE`. If set to `View.GONE`, the online/offline status indicator will not appear next to member avatars. |
+
+## FAQ
+
+**Q: How do I filter group members by scope (admin, moderator, participant)?**
+**A:** Create a `GroupMembersRequest.GroupMembersRequestBuilder`, call `setScopes(List)` with the desired scopes, and pass it to `setGroupMembersRequestBuilder`.
+
+**Q: How do I listen for member kick, ban, or scope change events outside the component?**
+**A:** Use `CometChatGroupEvents.addGroupListener("YOUR_TAG", ...)` and override `ccGroupMemberKicked`, `ccGroupMemberBanned`, or `ccGroupMemberScopeChanged`. Call `CometChatGroupEvents.removeListener("YOUR_TAG")` to unsubscribe.
+
+**Q: Can I show a custom badge for each member's role?**
+**A:** Yes. Use `setLeadingView` or `setTitleView` with a `GroupMembersViewHolderListeners` implementation. In `bindView`, check `groupMember.getScope()` against `UIKitConstants.GroupMemberScope.ADMIN`, `UIKitConstants.GroupMemberScope.MODERATOR`, and `UIKitConstants.GroupMemberScope.PARTICIPANTS` to set the appropriate badge drawable.
+
+**Q: How do I customize the avatar style in the group members list?**
+**A:** Define a custom style with parent `CometChatAvatarStyle` in `themes.xml`, reference it in a `CometChatGroupMembersStyle` using `cometchatGroupMembersAvatarStyle`, and apply with `setStyle()`.
+
+**Q: How do I add custom long-press options without removing the defaults?**
+**A:** Use `addOptions` instead of `setOptions`. `addOptions` appends your custom `MenuItem` objects to the existing default options.
+
+**Q: Can I use `CometChatGroupMembers` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, create the component and call `setContentView()`. In a Fragment, return the component from `onCreateView`. In both cases, you must call `setGroup()` with a valid `Group` object.
+
+**Q: How do I hide the kick, ban, and scope change options from the long-press menu?**
+**A:** Call `setKickMemberOptionVisibility(View.GONE)`, `setBanMemberOptionVisibility(View.GONE)`, and `setScopeChangeOptionVisibility(View.GONE)` on the component instance.
+
+**Q: How do I exclude the group owner from the member list?**
+**A:** Call `excludeOwner(true)` on the `CometChatGroupMembers` instance.
+
+## Next Steps
+
+- [Groups component](/ui-kit/android/groups)
+- [Users component](/ui-kit/android/users)
+- [Conversations component](/ui-kit/android/conversations)
+- [Message List component](/ui-kit/android/message-list)
diff --git a/ui-kit/android/groups.mdx b/ui-kit/android/groups.mdx
index e9ae37801..f0523235b 100644
--- a/ui-kit/android/groups.mdx
+++ b/ui-kit/android/groups.mdx
@@ -2,385 +2,529 @@
title: "Groups"
---
-## Overview
+`CometChatGroups` displays a searchable list of groups, acting as a container component that encapsulates and formats `CometChatListBase` and `CometChatGroupList`.
+
+## AI Agent Component Spec
+
+
+
+```json
+{
+ "component": "CometChatGroups",
+ "package": "com.cometchat.chatuikit.groups",
+ "xmlElement": "",
+ "description": "Scrollable list of all available groups with search, avatars, names, and group type indicators (public, private, password-protected).",
+ "primaryOutput": {
+ "method": "setOnItemClick",
+ "type": "OnItemClick"
+ },
+ "methods": {
+ "data": {
+ "setGroupsRequestBuilder": {
+ "type": "GroupsRequest.GroupsRequestBuilder",
+ "default": "SDK default",
+ "note": "Pass the builder, not the result of .build()"
+ },
+ "setSearchRequestBuilder": {
+ "type": "GroupsRequest.GroupsRequestBuilder",
+ "default": "Same as main builder",
+ "note": "Separate builder for search results"
+ }
+ },
+ "callbacks": {
+ "setOnItemClick": "OnItemClick",
+ "setOnItemLongClick": "OnItemLongClick",
+ "setOnBackPressListener": "OnBackPress",
+ "setOnSelection": "OnSelection",
+ "setOnError": "OnError",
+ "setOnLoad": "OnLoad",
+ "setOnEmpty": "OnEmpty"
+ },
+ "visibility": {
+ "setBackIconVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.GONE" },
+ "setToolbarVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setLoadingStateVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setErrorStateVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setEmptyStateVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setSeparatorVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setGroupTypeVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setSearchBoxVisibility": { "type": "int", "default": "View.VISIBLE" }
+ },
+ "selection": {
+ "setSelectionMode": {
+ "type": "UIKitConstants.SelectionMode",
+ "values": ["NONE", "SINGLE", "MULTIPLE"],
+ "default": "NONE"
+ }
+ },
+ "viewSlots": {
+ "setItemView": "GroupsViewHolderListener — entire list item row",
+ "setLeadingView": "GroupsViewHolderListener — avatar / left section",
+ "setTitleView": "GroupsViewHolderListener — name / title text",
+ "setSubtitleView": "GroupsViewHolderListener — subtitle text below name",
+ "setTrailingView": "GroupsViewHolderListener — right section",
+ "setLoadingView": "@LayoutRes int — loading spinner",
+ "setEmptyView": "@LayoutRes int — empty state",
+ "setErrorView": "@LayoutRes int — error state",
+ "setOverflowMenu": "View — toolbar menu",
+ "setOptions": "Function2> — long-press context menu (replaces defaults)",
+ "addOptions": "Function2> — long-press context menu (appends to defaults)"
+ },
+ "advanced": {
+ "selectGroup": "Group, SelectionMode — programmatic selection",
+ "clearSelection": "void — clears all selected groups",
+ "getSelectedGroups": "List — returns selected items",
+ "setSearchKeyword": "String — programmatic search",
+ "setTitleText": "String — custom toolbar title",
+ "setSearchPlaceholderText": "String — search placeholder",
+ "getBinding": "CometchatGroupListBinding — root ViewBinding",
+ "getViewModel": "GroupsViewModel — internal ViewModel access",
+ "getAdapter": "GroupsAdapter — internal adapter access",
+ "setAdapter": "GroupsAdapter — replace the default adapter"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatGroupsStyle"
+ }
+ }
+ },
+ "events": [
+ {
+ "name": "CometChatGroupEvents.ccGroupCreated",
+ "payload": "Group",
+ "description": "Logged-in user created a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupDeleted",
+ "payload": "Group",
+ "description": "Logged-in user deleted a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupLeft",
+ "payload": "Action, User, Group",
+ "description": "Logged-in user left a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberJoined",
+ "payload": "User, Group",
+ "description": "Logged-in user joined a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberAdded",
+ "payload": "List, List, Group, User",
+ "description": "Logged-in user added members to a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberKicked",
+ "payload": "Action, User, User, Group",
+ "description": "Logged-in user kicked a member from a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberBanned",
+ "payload": "Action, User, User, Group",
+ "description": "Logged-in user banned a member from a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberUnBanned",
+ "payload": "Action, User, User, Group",
+ "description": "Logged-in user unbanned a member from a group"
+ },
+ {
+ "name": "CometChatGroupEvents.ccGroupMemberScopeChanged",
+ "payload": "Action, User, String, String, Group",
+ "description": "Logged-in user changed a member's scope"
+ },
+ {
+ "name": "CometChatGroupEvents.ccOwnershipChanged",
+ "payload": "Group, GroupMember",
+ "description": "Logged-in user transferred group ownership"
+ }
+ ],
+ "sdkListeners": [
+ "onGroupMemberJoined",
+ "onGroupMemberLeft",
+ "onGroupMemberKicked",
+ "onGroupMemberBanned",
+ "onGroupMemberUnbanned",
+ "onGroupMemberScopeChanged",
+ "onMemberAddedToGroup"
+ ]
+}
+```
-`CometChatGroups` functions as a standalone [component](/ui-kit/android/components-overview#components) designed to create a screen displaying a list of groups, with the added functionality of enabling groups to search for specific groups. Acting as a container component, CometChatGroups encapsulates and formats the `CometChatListBase` and `CometChatGroupList` components without introducing any additional behavior of its own.
+
-
-
-
+## Where It Fits
+
+`CometChatGroups` is a list component. It renders all available groups and emits the selected `Group` via `setOnItemClick`. Wire it to `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to build a group messaging layout.
+
+
+
+```kotlin ChatActivity.kt lines
+class ChatActivity : AppCompatActivity() {
+
+ private lateinit var groups: CometChatGroups
+ private lateinit var messageHeader: CometChatMessageHeader
+ private lateinit var messageList: CometChatMessageList
+ private lateinit var messageComposer: CometChatMessageComposer
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_chat)
+
+ groups = findViewById(R.id.groups)
+ messageHeader = findViewById(R.id.message_header)
+ messageList = findViewById(R.id.message_list)
+ messageComposer = findViewById(R.id.message_composer)
+
+ groups.setOnItemClick { view, position, group ->
+ messageHeader.setGroup(group)
+ messageList.setGroup(group)
+ messageComposer.setGroup(group)
+ }
+ }
+}
+```
+
-***
+
+```java ChatActivity.java lines
+public class ChatActivity extends AppCompatActivity {
-## Usage
+ private CometChatGroups groups;
+ private CometChatMessageHeader messageHeader;
+ private CometChatMessageList messageList;
+ private CometChatMessageComposer messageComposer;
-***
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ groups = findViewById(R.id.groups);
+ messageHeader = findViewById(R.id.message_header);
+ messageList = findViewById(R.id.message_list);
+ messageComposer = findViewById(R.id.message_composer);
+
+ groups.setOnItemClick((view, position, group) -> {
+ messageHeader.setGroup(group);
+ messageList.setGroup(group);
+ messageComposer.setGroup(group);
+ });
+ }
+}
+```
+
+
-### Integration
+## Quick Start
-The following code snippet illustrates how you can can launch `CometChatGroups`.
+Add the component to your layout XML:
-
-
-```xml
+```xml layout_activity.xml lines
```
-
-
-
-
-***
-
-### Actions
-
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and Group-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+
+
+
-##### setOnItemClick
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.
-Function invoked when a Group item is clicked, typically used to open a Group profile or chat screen.
+To add programmatically in an Activity:
-
-```java YourActivity.java
-cometchatGroups.setOnItemClick((view1, position, group) -> {
-
- });
+
+```kotlin YourActivity.kt lines
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(CometChatGroups(this))
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatGroups.onItemClick = OnItemClick { view, position, group ->
-
- }
+
+```java YourActivity.java lines
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(new CometChatGroups(this));
+}
```
-
-
-***
-
-##### setOnItemLongClick
-
-Function executed when a Group item is long-pressed, allowing additional actions like delete or block.
+Or in a Fragment:
-
-```java YourActivity.java
-cometchatGroups.setOnItemLongClick((view1, position, group) -> {
-
- });
+
+```kotlin YourFragment.kt lines
+override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ return CometChatGroups(requireContext())
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatGroups.onItemLongClick = OnItemLongClick({ view, position, group ->
-
- })
+
+```java YourFragment.java lines
+@Override
+public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return new CometChatGroups(getContext());
+}
```
-
-
-***
-
-##### setOnBackPressListener
+## Filtering Groups
-`OnBackPressListener` is triggered when you press the back button in the app bar. It has a predefined behavior; when clicked, it navigates to the previous activity. However, you can override this action using the following code snippet.
+Pass a `GroupsRequest.GroupsRequestBuilder` to `setGroupsRequestBuilder`. Pass the builder instance — not the result of `.build()`.
-
-```java YourActivity.java
-cometchatGroups.setOnBackPressListener(() -> {
-
- });
+
+```kotlin lines
+val builder = GroupsRequestBuilder()
+ .setLimit(10)
+ .joinedOnly(true)
+cometchatGroups.setGroupsRequestBuilder(builder)
```
-
-
-```kotlin YourActivity.kt
-cometchatGroups.onBackPressListener = OnBackPress {
-
- }
+
+```java lines
+GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder()
+ .setLimit(10)
+ .joinedOnly(true);
+cometchatGroups.setGroupsRequestBuilder(builder);
```
-
-
-***
+### Filter Recipes
-##### setOnSelect
+| Recipe | Code |
+| --- | --- |
+| Joined only | `builder.joinedOnly(true)` |
+| Limit to 10 per page | `builder.setLimit(10)` |
+| Search by keyword | `builder.setSearchKeyWord("design")` |
+| Filter by tags | `builder.setTags(Arrays.asList("vip"))` |
+| With tags | `builder.withTags(true)` |
-Called when a item from the fetched list is selected, useful for multi-selection features.
-
-
-
-```java YourActivity.java
-cometchatGroups.setOnSelect(t -> {
+> The component uses infinite scroll — the next page loads as the user scrolls to the bottom. Refer to [GroupsRequestBuilder](/sdk/android/retrieve-groups) for the full builder API.
- });
-```
+### Search Request Builder
-
+Use `setSearchRequestBuilder` to customize the search list separately from the main list:
+
-```kotlin YourActivity.kt
-cometchatGroups.setOnSelect(object : OnSelection {
- override fun onSelection(t: MutableList?) {
-
- }
- })
+```kotlin lines
+val searchBuilder = GroupsRequestBuilder()
+ .setLimit(10)
+ .setSearchKeyWord("**")
+cometchatGroups.setSearchRequestBuilder(searchBuilder)
```
-
+
+```java lines
+GroupsRequest.GroupsRequestBuilder searchBuilder = new GroupsRequest.GroupsRequestBuilder()
+ .setLimit(10)
+ .setSearchKeyWord("**");
+cometchatGroups.setSearchRequestBuilder(searchBuilder);
+```
+
-***
+## Actions and Events
-##### OnError
+### Callback Methods
-This action doesn't change the behavior of the component but rather listens for any errors that occur in the groups component.
+#### `setOnItemClick`
-
-
-```java YourActivity.java
-cometchatGroups.setOnError(cometchatException -> {
+Fires when a group row is tapped. Primary navigation hook — set the active group and render the message view.
- });
+
+
+```kotlin YourActivity.kt lines
+cometchatGroups.onItemClick = OnItemClick { view, position, group ->
+
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatGroups.setOnError {
-
- }
+
+```java YourActivity.java lines
+cometchatGroups.setOnItemClick((view1, position, group) -> {
+
+});
```
-
-
-***
+> **What this does:** Replaces the default item-click behavior. When a user taps a group, your custom lambda executes instead of the built-in navigation.
-##### setOnLoad
+#### `setOnItemLongClick`
-Invoked when the list is successfully fetched and loaded, helping track component readiness.
+Fires when a group row is long-pressed. Use for additional actions like delete or leave.
-
-```java YourActivity.java
-cometchatGroups.setOnLoad(list -> {
-
-});
+
+```kotlin YourActivity.kt lines
+cometchatGroups.onItemLongClick = OnItemLongClick({ view, position, group ->
+
+})
```
-
-
-```kotlin YourActivity.kt
-cometchatGroups.setOnLoad(object : OnLoad {
- override fun onLoad(list: MutableList?) {
+
+```java YourActivity.java lines
+cometchatGroups.setOnItemLongClick((view1, position, group) -> {
- }
-})
+});
```
-
-
-***
+#### `setOnBackPressListener`
-##### setOnEmpty
-
-Called when the list is empty, enabling custom handling such as showing a placeholder message.
+Fires when the user presses the back button in the app bar. Default: navigates to the previous activity.
-
-```java YourActivity.java
-cometchatGroups.setOnEmpty(() -> {
-
- });
-```
+
+```kotlin YourActivity.kt lines
+cometchatGroups.onBackPressListener = OnBackPress {
+}
+```
-
-```kotlin YourActivity.kt
-cometchatGroups.setOnEmpty{
+
+```java YourActivity.java lines
+cometchatGroups.setOnBackPressListener(() -> {
- }
+});
```
-
-
-***
+#### `setOnSelection`
-### Filters
-
-Filters allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK.
-
-##### 1. GroupsRequestBuilder
-
-The [GroupsRequestBuilder](/sdk/android/retrieve-groups) enables you to filter and customize the group list based on available parameters in GroupsRequestBuilder. This feature allows you to create more specific and targeted queries when fetching groups. The following are the parameters available in [GroupsRequestBuilder](/sdk/android/retrieve-groups)
-
-| Property | Description | Code |
-| ------------------ | ------------------------------------------------------------------------------------------------------------------- | --------------------------- |
-| **Limit** | Configure the maximum number of groups to fetch in a single request, optimizing pagination for smoother navigation. | `.setLimit(Int)` |
-| **Search Keyword** | Employed to retrieve groups that match the provided string, facilitating precise searches. | `.setSearchKeyWord(String)` |
-| **Joined Only** | Exclusively fetches joined groups. | `.joinedOnly(boolean)` |
-| **Tags** | Utilized to fetch groups containing the specified tags. | `.setTags(List)` |
-| **With Tags** | Utilized to retrieve groups with specific tags. | `.withTags(boolean)` |
-
-**Example**
-
-In the example below, we are applying a filter to the Group List based on only joined groups.
+Fires when a group is checked/unchecked in multi-select mode. Requires `setSelectionMode` to be set.
-
-```java
-GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder().setLimit(10).joinedOnly(true);
-cometchatGroups.setGroupsRequestBuilder(builder);
+
+```kotlin YourActivity.kt lines
+cometchatGroups.setOnSelection(object : OnSelection {
+ override fun onSelection(t: MutableList?) {
+
+ }
+})
```
-
-
-```kotlin
-val builder = GroupsRequestBuilder().setLimit(10).joinedOnly(true)
-cometchatGroups.setGroupsRequestBuilder(builder)
-```
+
+```java YourActivity.java lines
+cometchatGroups.setOnSelection(t -> {
+});
+```
-
-***
+#### `setOnError`
-##### 2. SearchRequestBuilder
-
-The SearchRequestBuilder uses [GroupsRequestBuilder](/sdk/android/retrieve-groups) enables you to filter and customize the search list based on available parameters in GroupsRequestBuilder. This feature allows you to keep uniformity between the displayed Groups List and searched Group List.
-
-**Example**
+Fires on internal errors (network failure, auth issue, SDK exception).
-
-```java
-GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder().setLimit(10).setSearchKeyWord("**");
-cometchatGroups.setSearchRequestBuilder(builder);
-```
+
+```kotlin YourActivity.kt lines
+cometchatGroups.setOnError {
+}
+```
-
-```kotlin
-val builder = GroupsRequestBuilder().setLimit(10).setSearchKeyWord("**")
-cometchatGroups.setSearchRequestBuilder(builder)
-```
+
+```java YourActivity.java lines
+cometchatGroups.setOnError(cometchatException -> {
+});
+```
-
-***
-
-### Events
+#### `setOnLoad`
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed.
-
-The list of events emitted by the Groups component is as follows.
-
-| Events | Description |
-| ----------------------------- | ---------------------------------------------------------------------------------------------------------- |
-| `ccGroupCreated()` | This will get triggered when the logged in user creates a group |
-| `ccGroupDeleted()` | This will get triggered when the logged in user deletes a group |
-| `ccGroupLeft()` | This will get triggered when the logged in user leaves a group |
-| `ccGroupMemberScopeChanged()` | This will get triggered when the logged in user changes the scope of another group member |
-| `ccGroupMemberBanned()` | This will get triggered when the logged in user bans a group member from the group |
-| `ccGroupMemberKicked()` | This will get triggered when the logged in user kicks another group member from the group |
-| `ccGroupMemberUnbanned()` | This will get triggered when the logged in user unbans a user banned from the group |
-| `ccGroupMemberJoined()` | This will get triggered when the logged in user joins a group |
-| `ccGroupMemberAdded()` | This will get triggered when the logged in user add new members to the group |
-| `ccOwnershipChanged` | This will get triggered when the logged in user transfer the ownership of their group to some other member |
-
-##### 1. Add `CometChatGroupEvents` Listener's
+Fires when the list is successfully fetched and loaded.
-
-```java
-CometChatGroupEvents.addGroupListener("LISTENER_TAG", new CometChatGroupEvents() {
- @Override
- public void ccGroupCreated(Group group) {
- super.ccGroupCreated(group);
- }
-
- @Override
- public void ccGroupDeleted(Group group) {
- super.ccGroupDeleted(group);
- }
-
- @Override
- public void ccGroupLeft(Action actionMessage, User leftUser, Group leftGroup) {
- super.ccGroupLeft(actionMessage, leftUser, leftGroup);
- }
+
+```kotlin YourActivity.kt lines
+cometchatGroups.setOnLoad(object : OnLoad {
+ override fun onLoad(list: MutableList?) {
- @Override
- public void ccGroupMemberJoined(User joinedUser, Group joinedGroup) {
- super.ccGroupMemberJoined(joinedUser, joinedGroup);
}
+})
+```
+
- @Override
- public void ccGroupMemberAdded(List actionMessages, List usersAdded, Group userAddedIn, User addedBy) {
- super.ccGroupMemberAdded(actionMessages, usersAdded, userAddedIn, addedBy);
- }
+
+```java YourActivity.java lines
+cometchatGroups.setOnLoad(list -> {
- @Override
- public void ccGroupMemberKicked(Action actionMessage, User kickedUser, User kickedBy, Group kickedFrom) {
- super.ccGroupMemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom);
- }
+});
+```
+
+
- @Override
- public void ccGroupMemberBanned(Action actionMessage, User bannedUser, User bannedBy, Group bannedFrom) {
- super.ccGroupMemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom);
- }
+#### `setOnEmpty`
- @Override
- public void ccGroupMemberUnBanned(Action actionMessage, User unbannedUser, User unBannedBy, Group unBannedFrom) {
- super.ccGroupMemberUnBanned(actionMessage, unbannedUser, unBannedBy, unBannedFrom);
- }
+Fires when the list is empty, enabling custom handling such as showing a placeholder.
- @Override
- public void ccGroupMemberScopeChanged(Action actionMessage, User updatedUser, String scopeChangedTo, String scopeChangedFrom, Group group) {
- super.ccGroupMemberScopeChanged(actionMessage, updatedUser, scopeChangedTo, scopeChangedFrom, group);
- }
+
+
+```kotlin YourActivity.kt lines
+cometchatGroups.setOnEmpty {
+
+}
+```
+
- @Override
- public void ccOwnershipChanged(Group group, GroupMember newOwner) {
- super.ccOwnershipChanged(group, newOwner);
- }
+
+```java YourActivity.java lines
+cometchatGroups.setOnEmpty(() -> {
+
});
```
-
+
+
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap, long-press, back, select) and confirm your custom logic executes instead of the default behavior.
+
+### Global UI Events
+
+`CometChatGroupEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed.
+| Event | Fires when | Payload |
+| --- | --- | --- |
+| `ccGroupCreated` | The logged-in user creates a group | `Group` |
+| `ccGroupDeleted` | The logged-in user deletes a group | `Group` |
+| `ccGroupLeft` | The logged-in user leaves a group | `Action, User, Group` |
+| `ccGroupMemberJoined` | The logged-in user joins a group | `User, Group` |
+| `ccGroupMemberAdded` | The logged-in user adds members to a group | `List, List, Group, User` |
+| `ccGroupMemberKicked` | The logged-in user kicks a member | `Action, User, User, Group` |
+| `ccGroupMemberBanned` | The logged-in user bans a member | `Action, User, User, Group` |
+| `ccGroupMemberUnBanned` | The logged-in user unbans a member | `Action, User, User, Group` |
+| `ccGroupMemberScopeChanged` | The logged-in user changes a member's scope | `Action, User, String, String, Group` |
+| `ccOwnershipChanged` | The logged-in user transfers group ownership | `Group, GroupMember` |
+
+
-```kotlin
+```kotlin Add Listener lines
CometChatGroupEvents.addGroupListener("LISTENER_TAG", object : CometChatGroupEvents() {
override fun ccGroupCreated(group: Group?) {
super.ccGroupCreated(group)
@@ -456,299 +600,188 @@ CometChatGroupEvents.addGroupListener("LISTENER_TAG", object : CometChatGroupEve
})
```
-
+Remove Listener
-
-
-***
-
-##### 2. Removing `CometChatGroupEvents` Listener's
-
-
-
-```java
-CometChatGroupEvents.removeListeners();
```
-
-
-
-
-```kotlin
CometChatGroupEvents.removeListeners()
```
-
-
-
-***
-
-## Customization
-
-To fit your app's design requirements, you can customize the appearance of the groups component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
-
-### Style
-
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
-
-
-
-
-
-```html
-
-
-
-```
-
-
-```java
-cometchatGroups.setStyle(R.style.CustomGroupsStyle);
-```
-
-
-
-
-```kotlin
-cometchatGroups.setStyle(R.style.CustomGroupsStyle)
-```
-
-
-
-
-
-***
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_groups.xml).
-
-### Functionality
-
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements.
-
-Below is a list of customizations along with corresponding code snippets
-
-| Methods | Description | Code |
-| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
-| setBackIconVisibility | Used to toggle visibility for back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` |
-| setToolbarVisibility | Used to toggle visibility for back button in the app bar | `.setToolbarVisibility(View.GONE);` |
-| setLoadingStateVisibility | Used to hide loading state while fetching groups | `.setLoadingStateVisibility(View.GONE);` |
-| setErrorStateVisibility | Used to hide error state on fetching groups | `.setErrorStateVisibility(View.GONE);` |
-| setEmptyStateVisibility | Used to hide empty state on fetching groups | `.setEmptyStateVisibility(View.GONE);` |
-| setSeparatorVisibility | Used to control visibility of Separators in the list view | `.setSeparatorVisibility(View.GONE);` |
-| setGroupTypeVisibility | Used to control visibility of status indicator shown for the group type | `.setGroupTypeVisibility(View.GONE);` |
-| setSearchBoxVisibility | Used to hide search box shown in the tool bar | `.setSearchBoxVisibility(View.GONE);` |
-| setSelectionMode | This method determines the selection mode for groups, enabling user to select either a single groups or multiple groups at once. | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
-| setSearchkeyword | Used for fetching groups matching the passed keywords | `.setSearchkeyword("anything");` |
-
-***
-
-### Advanced
-
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
-
-#### setOptions
-
-Defines the available actions when users interact with a group item, such as long-pressing or swiping.
-
-Use Cases:
-
-* Enable actions like "Mute Notifications", "Leave Group", "Pin Group".
-* Provide admin-only actions like "Manage Members", "Delete Group".
-
-
-
-```java
-cometchatGroups.setOptions((context, group) -> Collections.emptyList());
-```
-
-
-
-
-```kotlin
-cometchatGroups.options = Function2?> { context, Group -> emptyList() }
-```
-
-
+```java Add Listener lines
+CometChatGroupEvents.addGroupListener("LISTENER_TAG", new CometChatGroupEvents() {
+ @Override
+ public void ccGroupCreated(Group group) {
+ super.ccGroupCreated(group);
+ }
-
+ @Override
+ public void ccGroupDeleted(Group group) {
+ super.ccGroupDeleted(group);
+ }
-***
+ @Override
+ public void ccGroupLeft(Action actionMessage, User leftUser, Group leftGroup) {
+ super.ccGroupLeft(actionMessage, leftUser, leftGroup);
+ }
-#### addOptions
+ @Override
+ public void ccGroupMemberJoined(User joinedUser, Group joinedGroup) {
+ super.ccGroupMemberJoined(joinedUser, joinedGroup);
+ }
-This method extends the existing set of actions available when Groups long press a Group item. Unlike setOptionsDefines, which replaces the default options, addOptionsAdds allows developers to append additional actions without removing the default ones. Example use cases include:
+ @Override
+ public void ccGroupMemberAdded(List actionMessages, List usersAdded, Group userAddedIn, User addedBy) {
+ super.ccGroupMemberAdded(actionMessages, usersAdded, userAddedIn, addedBy);
+ }
-* Adding a "Report Spam" action
-* Introducing a "Save to Notes" option
-* Integrating third-party actions such as "Share to Cloud Storage"
+ @Override
+ public void ccGroupMemberKicked(Action actionMessage, User kickedUser, User kickedBy, Group kickedFrom) {
+ super.ccGroupMemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom);
+ }
-This method provides flexibility in modifying Group interaction capabilities.
+ @Override
+ public void ccGroupMemberBanned(Action actionMessage, User bannedUser, User bannedBy, Group bannedFrom) {
+ super.ccGroupMemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom);
+ }
-
-
-```java
-cometchatGroups.addOptions((context, group) -> Collections.emptyList());
-```
+ @Override
+ public void ccGroupMemberUnBanned(Action actionMessage, User unbannedUser, User unBannedBy, Group unBannedFrom) {
+ super.ccGroupMemberUnBanned(actionMessage, unbannedUser, unBannedBy, unBannedFrom);
+ }
-
+ @Override
+ public void ccGroupMemberScopeChanged(Action actionMessage, User updatedUser, String scopeChangedTo, String scopeChangedFrom, Group group) {
+ super.ccGroupMemberScopeChanged(actionMessage, updatedUser, scopeChangedTo, scopeChangedFrom, group);
+ }
-
-```kotlin
-cometchatGroups.addOptions { context, group -> emptyList() }
+ @Override
+ public void ccOwnershipChanged(Group group, GroupMember newOwner) {
+ super.ccOwnershipChanged(group, newOwner);
+ }
+});
```
-
-
-
-
-***
-
-#### setLoadingView
-
-Configures a custom loading view displayed while groups are being fetched.
+Remove Listener
-Use Cases:
-
-* Show a spinner with "Loading groups..." text.
-* Display a skeleton loader for a smooth UI experience.
-
-
-
-```java
-cometchatGroups.setLoadingView(R.layout.your_loading_view);
```
-
-
-
-
-```kotlin
-cometchatGroups.loadingView = R.layout.your_loading_view
+CometChatGroupEvents.removeListeners();
```
-
-
-***
-
-#### setEmptyView
-
-Defines a view that appears when no groups are available.
-
-Use Cases:
-
-* Show a message like "No groups found, create one now!".
-* Display an illustration with a "Create New Group" button.
+### SDK Events (Real-Time, Automatic)
+
+The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.
+
+| SDK Listener | Internal behavior |
+| --- | --- |
+| `onGroupMemberJoined` | Updates the group list when a member joins |
+| `onGroupMemberLeft` | Updates the group list when a member leaves |
+| `onGroupMemberKicked` | Updates the group list when a member is kicked |
+| `onGroupMemberBanned` | Updates the group list when a member is banned |
+| `onGroupMemberUnbanned` | Updates the group list when a member is unbanned |
+| `onGroupMemberScopeChanged` | Updates the group list when a member's scope changes |
+| `onMemberAddedToGroup` | Updates the group list when members are added |
+
+> Automatic: group membership changes update the list in real time.
+
+## Functionality
+
+Small functional customizations such as toggling visibility of UI elements and configuring selection modes.
+
+| Methods | Description | Code |
+| --- | --- | --- |
+| `setBackIconVisibility` | Toggles visibility for the back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` |
+| `setToolbarVisibility` | Toggles visibility for the toolbar in the app bar | `.setToolbarVisibility(View.GONE);` |
+| `setLoadingStateVisibility` | Hides the loading state while fetching groups | `.setLoadingStateVisibility(View.GONE);` |
+| `setErrorStateVisibility` | Hides the error state on fetching groups | `.setErrorStateVisibility(View.GONE);` |
+| `setEmptyStateVisibility` | Hides the empty state on fetching groups | `.setEmptyStateVisibility(View.GONE);` |
+| `setSeparatorVisibility` | Controls visibility of separators in the list view | `.setSeparatorVisibility(View.GONE);` |
+| `setGroupTypeVisibility` | Controls visibility of the group type indicator (public, private, password) | `.setGroupTypeVisibility(View.GONE);` |
+| `setSearchBoxVisibility` | Controls visibility of the search box in the toolbar | `.setSearchBoxVisibility(View.GONE);` |
+| `setSelectionMode` | Determines the selection mode (single or multiple) | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| `setSearchKeyword` | Programmatically triggers a search with the given keyword | `.setSearchKeyword("design");` |
+| `setTitleText` | Sets a custom title in the toolbar | `.setTitleText("My Groups");` |
+| `setTitleVisibility` | Toggles visibility for the title text in the toolbar | `.setTitleVisibility(View.GONE);` |
+| `setSearchPlaceholderText` | Sets the placeholder text for the search input | `.setSearchPlaceholderText("Find groups...");` |
+
+- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden.
+
+## Custom View Slots
+
+Each slot replaces a section of the default UI. Slots that accept a `Group` parameter receive the group object for that row via the `GroupsViewHolderListener` pattern (`createView` + `bindView`).
+
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Leading view | `setLeadingView(GroupsViewHolderListener)` | Avatar / left section |
+| Title view | `setTitleView(GroupsViewHolderListener)` | Name / title text |
+| Subtitle view | `setSubtitleView(GroupsViewHolderListener)` | Subtitle text below name |
+| Trailing view | `setTrailingView(GroupsViewHolderListener)` | Right section |
+| Item view | `setItemView(GroupsViewHolderListener)` | Entire list item row |
+| Loading view | `setLoadingView(@LayoutRes int)` | Loading spinner |
+| Empty view | `setEmptyView(@LayoutRes int)` | Empty state |
+| Error view | `setErrorView(@LayoutRes int)` | Error state |
+| Overflow menu | `setOverflowMenu(View)` | Toolbar menu |
+| Options (replace) | `setOptions(Function2)` | Long-press context menu (replaces defaults) |
+| Options (append) | `addOptions(Function2)` | Long-press context menu (appends to defaults) |
+
+### `setLeadingView`
+
+Replace the avatar / left section.
-
-```java
-cometchatGroups.setEmptyView(R.layout.your_empty_view);
-```
-
-
-
-```kotlin
-cometchatGroups.emptyView = R.layout.your_empty_view
-```
-
-
-
-
-
-***
-
-#### setErrorView
-
-Configures the UI when an error occurs while fetching groups.
-
-Use Cases:
-
-* Display a retry button with "Failed to load groups, try again.".
-* Show a friendly error illustration.
-
-
-
-```java
-cometchatGroups.setErrorView(R.layout.your_empty_view);
-```
-
-
+```kotlin lines
+cometchatGroups.setLeadingView(object : GroupsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
+ return null
+ }
-
-```kotlin
-cometchatGroups.errorView = R.layout.your_error_view
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ }
+})
```
-
-
-
-***
-
-#### setLeadingView
-
-Sets a custom leading view that appears at the start of each group item.
-
-Use Cases:
-
-* Display the group profile picture.
-* Add an icon indicating Public or Private groups.
-
-
-```java
+```java lines
cometchatGroups.setLeadingView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
-
- }
- });
-```
-
-
-
-
-```kotlin
-cometchatGroups.setLeadingView(object: GroupsViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
- return null
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
}
- override fun bindView(context: Context, view: View, Group: group, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+
}
-})
+});
```
-
-
+> **What this does:** Registers a `GroupsViewHolderListener` that provides a custom view for the leading (left) area of each group item. `createView` inflates your layout, and `bindView` populates it with group data.
+
+Join status badge example:
+
-You can indeed create a custom layout file named `custom_leading_avatar_view.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
+Create a `custom_leading_avatar_view.xml` layout:
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
-
-```xml custom_leading_avatar_view.xml
+```xml custom_leading_avatar_view.xml lines
-
-```java
-cometchatGroups.setLeadingView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_leading_avatar_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- Group group,
- RecyclerView.ViewHolder holder,
- List groupList,
- int position) {
- LinearLayout groupAvatar = createdView.findViewById(R.id.leading_avatar_view);
- groupAvatar.setBackground(group.isJoined() ? ResourcesCompat.getDrawable(getResources(),
- R.drawable.group_leading_joined,
- null) : ResourcesCompat.getDrawable(getResources(),
- R.drawable.group_leading_join,
- null));
- groupAvatar.setOnLongClickListener(v -> {
- if (group.isJoined()) {
- Toast.makeText(context, "Group already joined", Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(context, "Joining group", Toast.LENGTH_SHORT).show();
- }
- return true;
- });
- }
- });
-```
-
-
-
-```kotlin
+```kotlin lines
cometchatGroups.setLeadingView(object : GroupsViewHolderListener() {
- override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_leading_avatar_view, null)
- }
+ override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_leading_avatar_view, null)
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupList: List,
- position: Int
- ) {
- val groupAvatar = createdView.findViewById(R.id.leading_avatar_view)
- groupAvatar.background = if (group.isJoined) ResourcesCompat.getDrawable(
- resources,
- R.drawable.group_leading_joined,
- null
- ) else ResourcesCompat.getDrawable(
- resources,
- R.drawable.group_leading_join,
- null
- )
- groupAvatar.setOnLongClickListener { v: View? ->
- if (group.isJoined) {
- Toast.makeText(context, "Group already joined", Toast.LENGTH_SHORT).show()
- } else {
- Toast.makeText(context, "Joining group", Toast.LENGTH_SHORT).show()
- }
- true
- }
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ val groupAvatar = createdView.findViewById(R.id.leading_avatar_view)
+ groupAvatar.background = if (group.isJoined) ResourcesCompat.getDrawable(
+ resources,
+ R.drawable.group_leading_joined,
+ null
+ ) else ResourcesCompat.getDrawable(
+ resources,
+ R.drawable.group_leading_join,
+ null
+ )
+ groupAvatar.setOnLongClickListener { v: View? ->
+ if (group.isJoined) {
+ Toast.makeText(context, "Group already joined", Toast.LENGTH_SHORT).show()
+ } else {
+ Toast.makeText(context, "Joining group", Toast.LENGTH_SHORT).show()
}
- })
+ true
+ }
+ }
+})
```
-
-
-
-***
-
-#### setTitleView
-
-Customizes the title view of each group item, which typically displays the group name.
-
-Use Cases:
-
-* Style group names with custom fonts and colors.
-* Show a verified badge for official groups.
-
-
-```java
-cometchatGroups.setTitleView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+```java lines
+cometchatGroups.setLeadingView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_leading_avatar_view, null);
+ }
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ Group group,
+ RecyclerView.ViewHolder holder,
+ List groupList,
+ int position) {
+ LinearLayout groupAvatar = createdView.findViewById(R.id.leading_avatar_view);
+ groupAvatar.setBackground(group.isJoined() ? ResourcesCompat.getDrawable(getResources(),
+ R.drawable.group_leading_joined,
+ null) : ResourcesCompat.getDrawable(getResources(),
+ R.drawable.group_leading_join,
+ null));
+ groupAvatar.setOnLongClickListener(v -> {
+ if (group.isJoined()) {
+ Toast.makeText(context, "Group already joined", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(context, "Joining group", Toast.LENGTH_SHORT).show();
}
+ return true;
});
+ }
+});
```
-
+
+### `setTitleView`
+
+Replace the name / title text.
+
+
-```kotlin
-cometchatGroups.setTitleView(object: GroupsViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatGroups.setTitleView(object : GroupsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, Group: group, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
}
})
```
-
+
+```java lines
+cometchatGroups.setTitleView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+
+ }
+});
+```
+
+Group type icon example:
+
-You can indeed create a custom layout file named `custom_title_view.xml` for more complex or unique list items.
+Create a `custom_group_title_view.xml` layout:
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
-
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
-
-```xml custom_title_view.xml
+```xml custom_group_title_view.xml lines
+
+```kotlin lines
+cometchatGroups.setTitleView(object : GroupsViewHolderListener() {
+ override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_group_title_view, null)
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ val layout = createdView.findViewById(R.id.group_layout)
+ val layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ layout.layoutParams = layoutParams
+ val name = createdView.findViewById(R.id.title)
+ name.text = group.name
+ val type = createdView.findViewById(R.id.type)
+ if (CometChatConstants.GROUP_TYPE_PUBLIC == group.groupType) {
+ type.visibility = View.VISIBLE
+ type.background = ResourcesCompat.getDrawable(resources, R.drawable.public_icon, null)
+ } else if (CometChatConstants.GROUP_TYPE_PASSWORD == group.groupType) {
+ type.visibility = View.VISIBLE
+ type.background = ResourcesCompat.getDrawable(resources, R.drawable.passowrd_icon, null)
+ } else if (CometChatConstants.GROUP_TYPE_PRIVATE == group.groupType) {
+ type.visibility = View.VISIBLE
+ type.background = ResourcesCompat.getDrawable(resources, R.drawable.private_icon, null)
+ } else {
+ type.visibility = View.GONE
+ }
+ }
+})
+```
+
+
-```java
+```java lines
cometchatGroups.setTitleView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_group_title_view, null);
- }
-
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
- LinearLayout layout = createdView.findViewById(R.id.user_layout);
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- layout.setLayoutParams(layoutParams);
- TextView name = createdView.findViewById(R.id.title);
- name.setText(group.getName());
- View type = createdView.findViewById(R.id.role);
-
- if (CometChatConstants.GROUP_TYPE_PUBLIC.equals(group.getType())) {
- type.setVisibility(View.VISIBLE);
- type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.public_icon, null));
- } else if (CometChatConstants.GROUP_TYPE_PASSWORD.equals(group.getType())) {
- type.setVisibility(View.VISIBLE);
- type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.passowrd_icon, null));
- } else if (CometChatConstants.GROUP_TYPE_PRIVATE.equals(roup.getType())) {
- type.setVisibility(View.VISIBLE);
- type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.private_icon, null));
- } else {
- type.setVisibility(View.GONE);
- }
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_group_title_view, null);
+ }
- }
- });
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+ LinearLayout layout = createdView.findViewById(R.id.user_layout);
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ layout.setLayoutParams(layoutParams);
+ TextView name = createdView.findViewById(R.id.title);
+ name.setText(group.getName());
+ View type = createdView.findViewById(R.id.type);
+
+ if (CometChatConstants.GROUP_TYPE_PUBLIC.equals(group.getGroupType())) {
+ type.setVisibility(View.VISIBLE);
+ type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.public_icon, null));
+ } else if (CometChatConstants.GROUP_TYPE_PASSWORD.equals(group.getGroupType())) {
+ type.setVisibility(View.VISIBLE);
+ type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.passowrd_icon, null));
+ } else if (CometChatConstants.GROUP_TYPE_PRIVATE.equals(group.getGroupType())) {
+ type.setVisibility(View.VISIBLE);
+ type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.private_icon, null));
+ } else {
+ type.setVisibility(View.GONE);
+ }
+ }
+});
```
-
+
+
+### `setSubtitleView`
+
+Replace the subtitle text below the group's name.
+
+
-```kotlin
-cometchatGroups.setTitleView(object : GroupsViewHolderListener() {
- override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_group_title_view, null)
- }
+```kotlin lines
+cometchatGroups.setSubtitleView(object : GroupsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
+ return null
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupList: List,
- position: Int
- ) {
- val layout = createdView.findViewById(R.id.group_layout)
- val layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- layout.layoutParams = layoutParams
- val name = createdView.findViewById(R.id.title)
- name.text = group.name
- val type = createdView.findViewById(R.id.type)
- if (CometChatConstants.GROUP_TYPE_PUBLIC == group.groupType) {
- type.visibility = View.VISIBLE
- type.background = ResourcesCompat.getDrawable(resources, R.drawable.public_icon, null)
- } else if (CometChatConstants.GROUP_TYPE_PASSWORD == group.groupType) {
- type.visibility = View.VISIBLE
- type.background = ResourcesCompat.getDrawable(resources, R.drawable.passowrd_icon, null)
- } else if (CometChatConstants.GROUP_TYPE_PRIVATE == group.groupTyp) {
- type.visibility = View.VISIBLE
- type.background = ResourcesCompat.getDrawable(resources, R.drawable.private_icon, null)
- } else {
- type.visibility = View.GONE
- }
- }
- })
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ }
+})
```
-
-
-
-***
+
+```java lines
+cometchatGroups.setSubtitleView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
-#### setTrailingView
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
-Allows custom elements to be added at the end of each group item, such as buttons or indicators.
+ }
+});
+```
+
+
-Use Cases:
+Example with member count and description:
-* Show unread message counts.
-* Add a quick Join or Leave button.
+
+
+
-
-```java
-cometchatGroups.setTrailingView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+
+```kotlin YourActivity.kt lines
+cometchatGroups.setSubtitleView(object : GroupsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View {
+ return TextView(context)
+ }
- }
- });
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ val textView = createdView as TextView
+ textView.text =
+ if (group.membersCount > 1) group.membersCount.toString() + " members" else group.membersCount.toString() + " member" + " • " + group.description
+ }
+})
```
+
+
+
+```java YourActivity.java lines
+cometchatGroups.setSubtitleView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return new TextView(context);
+ }
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+ TextView textView = (TextView) createdView;
+ textView.setText(group.getMembersCount() > 1 ? group.getMembersCount() + " members" : group.getMembersCount() + " member" + " • " + group.getDescription());
+ }
+});
+```
+
+
+### `setTrailingView`
+
+Replace the right section of each group item.
+
-```kotlin
-cometchatGroups.setTrailingView(object: GroupsViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatGroups.setTrailingView(object : GroupsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, Group: Group, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
}
})
```
-
+
+```java lines
+cometchatGroups.setTrailingView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+
+ }
+});
+```
+
+Join button example:
+
-You can indeed create a custom layout file named `custom_tail_view.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
-
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
+Create a `custom_tail_view.xml` layout:
-```xml custom_tail_view.xml
+```xml custom_tail_view.xml lines
-
-```java
-cometchatGroups.setTrailingView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- Group group,
- RecyclerView.ViewHolder holder,
- List groupList,
- int position) {
- MaterialButton button = createdView.findViewById(R.id.button);
- button.setText(group.isJoined() ? "Joined" : "+ Join");
- }
- });
-```
-
-
-
-```kotlin
+```kotlin lines
cometchatGroups.setTrailingView(object : GroupsViewHolderListener() {
- override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupList: List,
- position: Int
- ) {
- val button = createdView.findViewById(R.id.button)
- button.text = (if (group.isJoined) "Joined" else "+ Join")
+ override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null)
+ }
- }
- })
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ val button = createdView.findViewById(R.id.button)
+ button.text = (if (group.isJoined) "Joined" else "+ Join")
+ }
+})
```
-
-
-
-***
-
-#### setItemView
-
-Assigns a fully custom ListItem layout to the Groups component, replacing the default design.
-
-Use Cases:
-
-* Add a description below the group name.
-* Customize layout to include additional metadata.
-
-
-```java
-cometchatGroups.setItemView(new GroupsViewHolderListener() {
+```java lines
+cometchatGroups.setTrailingView(new GroupsViewHolderListener() {
@Override
- public View createView(Context context, CometchatListBaseItemsBinding cometChatListItem) {
- return null;
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null);
}
@Override
- public void bindView(Context context, View view, Group group, RecyclerView.ViewHolder viewHolder, List list, int i) {
-
+ public void bindView(Context context,
+ View createdView,
+ Group group,
+ RecyclerView.ViewHolder holder,
+ List groupList,
+ int position) {
+ MaterialButton button = createdView.findViewById(R.id.button);
+ button.setText(group.isJoined() ? "Joined" : "+ Join");
}
});
```
-
+
+
+### `setItemView`
+Replace the entire list item row.
+
+
-```kotlin
+```kotlin lines
cometchatGroups.setItemView(object : GroupsViewHolderListener() {
override fun createView(
context: Context?,
- CometchatListBaseItemsBinding: CometChatListItem?
+ listItem: CometchatListBaseItemsBinding?
): View? {
return null
}
override fun bindView(
- context: Context?,
- view: View?,
- group: Group?,
- viewHolder: RecyclerView.ViewHolder?,
- list: List?,
- i: Int
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
) {
-
}
})
```
-
+
+```java lines
+cometchatGroups.setItemView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+
+ }
+});
+```
+
-**Example**
+Custom list item example:
-You can indeed create a custom layout file named `item_list.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
-
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
-
-```xml custom_group_list_itemd.xml
+Create a `custom_group_list_item.xml` layout:
+```xml custom_group_list_item.xml lines
-
-```java YourActivity.java
-cometChatGroup.setItemView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return View.inflate(context,R.layout.custom_group_list_item,null);
- }
+
+```kotlin YourActivity.kt lines
+cometchatGroups.setItemView(object : GroupsViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View {
+ return View.inflate(context, R.layout.custom_group_list_item, null)
+ }
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
- TextView groupName = createdView.findViewById(R.id.tvName);
- TextView groupMemberCount = createdView.findViewById(R.id.tvSubtitle);
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- createdView.setLayoutParams(params);
- groupName.setText(group.getName());
- groupMemberCount.setText(group.getMembersCount() > 1 ? group.getMembersCount() + " members" : group.getMembersCount() + " member" + " • " + group.getDescription());
- }
- });
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ group: Group,
+ holder: RecyclerView.ViewHolder,
+ groupList: List,
+ position: Int
+ ) {
+ val groupName = createdView.findViewById(R.id.tvName)
+ val groupMemberCount = createdView.findViewById(R.id.tvSubtitle)
+ val params = LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ createdView.layoutParams = params
+ groupName.text = group.name
+ groupMemberCount.text =
+ if (group.membersCount > 1) group.membersCount.toString() + " members" else group.membersCount.toString() + " member" + " • " + group.description
+ }
+})
```
-
-
-```kotlin YourActivity.kt
-cometChatGroup.setItemView(object : GroupsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatListBaseItemsBinding?
- ): View {
- return View.inflate(context, R.layout.custom_group_list_item, null)
- }
+
+```java YourActivity.java lines
+cometchatGroups.setItemView(new GroupsViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return View.inflate(context, R.layout.custom_group_list_item, null);
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupList: List,
- position: Int
- ) {
- val groupName = createdView.findViewById(R.id.tvName)
- val groupMemberCount = createdView.findViewById(R.id.tvSubtitle)
- val params = LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- )
- createdView.layoutParams = params
- groupName.text = group.name
- groupMemberCount.text =
- if (group.membersCount > 1) group.membersCount.toString() + " members" else group.membersCount.toString() + " member" + " • " + group.description
- }
- })
+ @Override
+ public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
+ TextView groupName = createdView.findViewById(R.id.tvName);
+ TextView groupMemberCount = createdView.findViewById(R.id.tvSubtitle);
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ createdView.setLayoutParams(params);
+ groupName.setText(group.getName());
+ groupMemberCount.setText(group.getMembersCount() > 1 ? group.getMembersCount() + " members" : group.getMembersCount() + " member" + " • " + group.getDescription());
+ }
+});
```
-
-
-***
-
-#### setSubTitleView
-
-Customizes the subtitle view for each group item, which typically displays extra information.
-
-Use Cases:
+### `setOptions`
-* Show last message preview.
-* Display the number of members.
+Replace the long-press context menu entirely.
-
-```java
-CometChatGroup.setSubtitleView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
-
- }
- });
+
+```kotlin lines
+cometchatGroups.options = Function2?> { context, group -> emptyList() }
```
-
-
-```kotlin
-cometChatGroup.setSubtitleView(object : GroupsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatListBaseItemsBinding?
- ): View {
- return null
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupList: List,
- position: Int
- ) {
-
- }
- })
+
+```java lines
+cometchatGroups.setOptions((context, group) -> Collections.emptyList());
```
-
-
-**Example**
+### `addOptions`
-
-
-
-
-You can indeed create a custom layout file named `subtitle_layout.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `GroupsViewHolderListener`. The inflation process prepares the layout for use in your application:
-
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the Group object:
+Append to the long-press context menu without removing defaults.
-
-```java YourActivity.java
-cometChatGroup.setSubtitleView(new GroupsViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return new TextView(context);
- }
-
- @Override
- public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List groupList, int position) {
- TextView textView = (TextView) createdView;
- textView.setText(group.getMembersCount() > 1 ? group.getMembersCount() + " members" : group.getMembersCount() + " member" + " • " + group.getDescription());
-
- }
- });
+
+```kotlin lines
+cometchatGroups.addOptions { context, group -> emptyList() }
```
-
-
-```kotlin YourActivity.kt
-group.setSubtitleView(object : GroupsViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatListBaseItemsBinding?
- ): View {
- return TextView(context)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- group: Group,
- holder: RecyclerView.ViewHolder,
- groupList: List,
- position: Int
- ) {
- val textView = createdView as TextView
- textView.text =
- if (group.membersCount > 1) group.membersCount.toString() + " members" else group.membersCount.toString() + " member" + " • " + group.description
- }
- })
+
+```java lines
+cometchatGroups.addOptions((context, group) -> Collections.emptyList());
```
-
-
-***
+### `setLoadingView`
+
+Sets a custom loading view displayed when data is being fetched.
-#### SetOverflowMenu
+
+
+```kotlin lines
+cometchatGroups.loadingView = R.layout.your_loading_view
+```
+
-Customizes the overflow menu (three-dot ⋮ icon) with additional options.
+
+```java lines
+cometchatGroups.setLoadingView(R.layout.your_loading_view);
+```
+
+
-Use Cases:
+### `setEmptyView`
-* Add options like "Invite Members", "Report Group".
-* Enable admin-specific options like "Manage Group Settings".
+Configures a custom view displayed when there are no groups in the list.
-
-```java
-cometchatGroups.setOverflowMenu(View v);
+
+```kotlin lines
+cometchatGroups.emptyView = R.layout.your_empty_view
```
+
+
+```java lines
+cometchatGroups.setEmptyView(R.layout.your_empty_view);
+```
+
+
+### `setErrorView`
+
+Defines a custom error state view that appears when an issue occurs while loading groups.
+
-```kotlin
-cometchatGroups.setOverflowMenu(v)
+```kotlin lines
+cometchatGroups.errorView = R.layout.your_error_view
```
-
+
+```java lines
+cometchatGroups.setErrorView(R.layout.your_error_view);
+```
+
-**Example**
+### `setOverflowMenu`
+
+Replace the toolbar overflow menu.
-You need to create a `overflow_menu_layout.xml` as a custom view file. Which we will inflate and pass to `.setOverflowMenu()`.
+Create an `overflow_menu_layout.xml` layout:
-```xml overflow_menu_layout.xml
+```xml overflow_menu_layout.xml lines
```
-You inflate the view and pass it to `setOverflowMenu`. You can get the child view reference and can handle click actions.
-
+
+```kotlin YourActivity.kt lines
+val view: View = layoutInflater.inflate(R.layout.overflow_menu_layout, null)
+val imgRefresh = view.findViewById(R.id.ivMenu)
+imgRefresh.setOnClickListener { v: View? ->
+ Toast.makeText(requireContext(), "Clicked on Refresh", Toast.LENGTH_SHORT).show()
+}
+cometchatGroups.setOverflowMenu(view)
+```
+
+
-```java YourActivity.java
+```java YourActivity.java lines
View view = getLayoutInflater().inflate(R.layout.overflow_menu_layout, null);
ImageView imgRefresh = view.findViewById(R.id.ivMenu);
imgRefresh.setOnClickListener(v -> {
@@ -1496,19 +1548,370 @@ imgRefresh.setOnClickListener(v -> {
});
cometchatGroups.setOverflowMenu(view);
```
+
+
+
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the group list item, and the data binding populates correctly for each group.
+
+
+## Common Patterns
+
+### Hide all chrome — minimal list
+
+
+
+```kotlin lines
+cometchatGroups.setGroupTypeVisibility(View.GONE)
+cometchatGroups.setSeparatorVisibility(View.GONE)
+cometchatGroups.setToolbarVisibility(View.GONE)
+```
+
+
+```java lines
+cometchatGroups.setGroupTypeVisibility(View.GONE);
+cometchatGroups.setSeparatorVisibility(View.GONE);
+cometchatGroups.setToolbarVisibility(View.GONE);
+```
+
+### Joined groups only
+
+
-```kotlin YourActivity.kt
-val view: View = layoutInflater.inflate(R.layout.overflow_menu_layout, null)
-val imgRefresh = view.findViewById(R.id.ivMenu)
-imgRefresh.setOnClickListener { v: View? ->
- Toast.makeText(requireContext(), "Clicked on Refresh", Toast.LENGTH_SHORT).show()
-}
-cometchatGroups.setOverflowMenu(view)
+```kotlin lines
+val builder = GroupsRequestBuilder()
+ .joinedOnly(true)
+cometchatGroups.setGroupsRequestBuilder(builder)
+```
+
+
+
+```java lines
+GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder()
+ .joinedOnly(true);
+cometchatGroups.setGroupsRequestBuilder(builder);
+```
+
+
+
+### Filter by tags
+
+
+
+```kotlin lines
+val builder = GroupsRequestBuilder()
+ .setTags(listOf("vip", "premium"))
+cometchatGroups.setGroupsRequestBuilder(builder)
+```
+
+
+
+```java lines
+GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder()
+ .setTags(Arrays.asList("vip", "premium"));
+cometchatGroups.setGroupsRequestBuilder(builder);
+```
+
+
+
+## Advanced Methods
+
+### Programmatic Selection
+
+#### `selectGroup`
+
+Programmatically selects or deselects a group. Works with both `SINGLE` and `MULTIPLE` selection modes.
+
+
+
+```kotlin lines
+// Select a group in single-select mode
+cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.SINGLE)
+
+// Select a group in multi-select mode
+cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.MULTIPLE)
+```
+
+
+
+```java lines
+// Select a group in single-select mode
+cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.SINGLE);
+
+// Select a group in multi-select mode
+cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.MULTIPLE);
+```
+
+
+
+> In `SINGLE` mode, selecting a new group replaces the previous selection. In `MULTIPLE` mode, calling this on an already-selected group deselects it (toggle behavior).
+
+#### `clearSelection`
+
+Clears all selected groups and resets the selection UI.
+
+
+
+```kotlin lines
+cometchatGroups.clearSelection()
+```
+
+
+
+```java lines
+cometchatGroups.clearSelection();
+```
+
+
+
+#### `getSelectedGroups`
+
+Returns the list of currently selected `Group` objects.
+
+
+
+```kotlin lines
+val selected = cometchatGroups.selectedGroups
+```
+
+
+
+```java lines
+List selected = cometchatGroups.getSelectedGroups();
+```
+
+
+
+### Selected Groups List
+
+When using multi-select mode, a horizontal list of selected groups can be shown above the main list.
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSelectedGroupsListVisibility` | `int (View.VISIBLE / View.GONE)` | Show or hide the selected groups strip |
+| `setSelectedGroupAvatarStyle` | `@StyleRes int` | Avatar style for selected group chips |
+| `setSelectedGroupItemTextColor` | `@ColorInt int` | Text color for selected group names |
+| `setSelectedGroupItemTextAppearance` | `@StyleRes int` | Text appearance for selected group names |
+| `setSelectedGroupItemRemoveIcon` | `Drawable` | Icon for the remove button on each chip |
+| `setSelectedGroupItemRemoveIconTint` | `@ColorInt int` | Tint color for the remove icon |
+
+### Search Input Customization
+
+The built-in search box can be customized programmatically:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSearchPlaceholderText` | `String` | Sets the placeholder text for the search input |
+| `setSearchInputTextColor` | `@ColorInt int` | Text color of the search input |
+| `setSearchInputTextAppearance` | `@StyleRes int` | Text appearance of the search input |
+| `setSearchInputPlaceHolderTextColor` | `@ColorInt int` | Placeholder text color |
+| `setSearchInputPlaceHolderTextAppearance` | `@StyleRes int` | Placeholder text appearance |
+| `setSearchInputIcon` | `Drawable` | Leading icon in the search box |
+| `setSearchInputIconTint` | `@ColorInt int` | Tint for the leading icon |
+| `setSearchInputEndIcon` | `Drawable` | Trailing icon in the search box |
+| `setSearchInputEndIconTint` | `@ColorInt int` | Tint for the trailing icon |
+| `setSearchInputStrokeWidth` | `@Dimension int` | Stroke width of the search box border |
+| `setSearchInputStrokeColor` | `@ColorInt int` | Stroke color of the search box border |
+| `setSearchInputBackgroundColor` | `@ColorInt int` | Background color of the search box |
+| `setSearchInputCornerRadius` | `@Dimension int` | Corner radius of the search box |
+
+### Internal Access
+
+These methods provide direct access to internal components for advanced use cases.
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getBinding()` | `CometchatGroupListBinding` | The ViewBinding for the component's root layout |
+| `getViewModel()` | `GroupsViewModel` | The ViewModel managing group data and state |
+| `getAdapter()` | `GroupsAdapter` | The adapter powering the RecyclerView |
+| `setAdapter(GroupsAdapter)` | `void` | Replaces the default adapter with a custom one |
+
+> Use these only when the standard API is insufficient. Directly manipulating the adapter or ViewModel may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatGroupsStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
+
+```xml themes.xml lines
+
+
```
+
+
+```kotlin lines
+cometchatGroups.setStyle(R.style.CustomGroupsStyle)
+```
+
+```java lines
+cometchatGroups.setStyle(R.style.CustomGroupsStyle);
+```
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_groups.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon |
+| `setBackIcon` | `Drawable` | Custom back icon drawable |
+| `setTitleTextColor` | `@ColorInt int` | Title text color in the toolbar |
+| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance in the toolbar |
+| `setItemTitleTextColor` | `@ColorInt int` | Text color for group item titles |
+| `setItemTitleTextAppearance` | `@StyleRes int` | Text appearance for group item titles |
+| `setItemBackgroundColor` | `@ColorInt int` | Background color for list items |
+| `setItemSelectedBackgroundColor` | `@ColorInt int` | Background color for selected list items |
+| `setSeparatorColor` | `@ColorInt int` | Color of list item separators |
+| `setStrokeColor` | `@ColorInt int` | Stroke color of the component border |
+| `setStrokeWidth` | `@Dimension int` | Stroke width of the component border |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component |
+| `setSubtitleTextColor` | `@ColorInt int` | Text color for group item subtitles |
+| `setSubtitleTextAppearance` | `@StyleRes int` | Text appearance for group item subtitles |
+| `setEmptyStateTextColor` | `@ColorInt int` | Title text color for the empty state |
+| `setEmptyStateTextAppearance` | `@StyleRes int` | Title text appearance for the empty state |
+| `setEmptyStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the empty state |
+| `setEmptyStateSubTitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the empty state |
+| `setErrorStateTextColor` | `@ColorInt int` | Title text color for the error state |
+| `setErrorStateTextAppearance` | `@StyleRes int` | Title text appearance for the error state |
+| `setErrorStateSubtitleColor` | `@ColorInt int` | Subtitle text color for the error state |
+| `setErrorStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the error state |
+| `setRetryButtonTextColor` | `@ColorInt int` | Text color for the retry button |
+| `setRetryButtonTextAppearance` | `@StyleRes int` | Text appearance for the retry button |
+| `setRetryButtonBackgroundColor` | `@ColorInt int` | Background color for the retry button |
+| `setRetryButtonStrokeColor` | `@ColorInt int` | Stroke color for the retry button |
+| `setRetryButtonStrokeWidth` | `@Dimension int` | Stroke width for the retry button |
+| `setRetryButtonCornerRadius` | `@Dimension int` | Corner radius for the retry button |
+| `setAvatarStyle` | `@StyleRes int` | Style for group avatars |
+| `setStatusIndicatorStyle` | `@StyleRes int` | Style for group type status indicators |
+
+### Checkbox Style Properties (Selection Mode)
+
+When using `SINGLE` or `MULTIPLE` selection mode, checkboxes appear on each item:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setCheckBoxStrokeWidth` | `@Dimension int` | Stroke width of the checkbox border |
+| `setCheckBoxCornerRadius` | `@Dimension int` | Corner radius of the checkbox |
+| `setCheckBoxStrokeColor` | `@ColorInt int` | Stroke color of the checkbox border |
+| `setCheckBoxBackgroundColor` | `@ColorInt int` | Background color of unchecked checkbox |
+| `setCheckBoxCheckedBackgroundColor` | `@ColorInt int` | Background color of checked checkbox |
+| `setCheckBoxSelectIcon` | `Drawable` | Icon shown when checkbox is checked |
+| `setCheckBoxSelectIconTint` | `@ColorInt int` | Tint for the checkbox select icon |
+| `setDiscardSelectionIcon` | `Drawable` | Icon for the discard selection button |
+| `setDiscardSelectionIconTint` | `@ColorInt int` | Tint for the discard selection icon |
+| `setSubmitSelectionIcon` | `Drawable` | Icon for the submit selection button |
+| `setSubmitSelectionIconTint` | `@ColorInt int` | Tint for the submit selection icon |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override behavior on group interaction | Activity/Fragment | `setOn` callbacks | `setOnItemClick((v, pos, g) -> { ... })` |
+| Filter which groups appear | Activity/Fragment | `setGroupsRequestBuilder` | `setGroupsRequestBuilder(builder)` |
+| Customize search results | Activity/Fragment | `setSearchRequestBuilder` | `setSearchRequestBuilder(builder)` |
+| Toggle visibility of UI elements | Activity/Fragment | `setVisibility(int)` | `setGroupTypeVisibility(View.GONE)` |
+| Replace a section of the list item | Activity/Fragment | `setView` | `setLeadingView(listener)` |
+| Change colors, fonts, spacing | `themes.xml` | `CometChatGroupsStyle` | `#F76808` |
+| Avatar style (corner radius, background) | `themes.xml` | `cometchatGroupsAvatar` | `8dp` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometchatGroups.setStyle(R.style.CustomGroupsStyle);` |
+| Back button visibility | Activity/Fragment | `setBackIconVisibility(int)` | `.setBackIconVisibility(View.VISIBLE);` |
+| Toolbar visibility | Activity/Fragment | `setToolbarVisibility(int)` | `.setToolbarVisibility(View.GONE);` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE);` |
+| Empty state visibility | Activity/Fragment | `setEmptyStateVisibility(int)` | `.setEmptyStateVisibility(View.GONE);` |
+| Loading state visibility | Activity/Fragment | `setLoadingStateVisibility(int)` | `.setLoadingStateVisibility(View.GONE);` |
+| Separator visibility | Activity/Fragment | `setSeparatorVisibility(int)` | `.setSeparatorVisibility(View.GONE);` |
+| Group type indicator visibility | Activity/Fragment | `setGroupTypeVisibility(int)` | `.setGroupTypeVisibility(View.GONE);` |
+| Selection mode (single/multiple) | Activity/Fragment | `setSelectionMode(SelectionMode)` | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| Search keyword | Activity/Fragment | `setSearchKeyword(String)` | `.setSearchKeyword("design");` |
+| Search box visibility | Activity/Fragment | `setSearchBoxVisibility(int)` | `.setSearchBoxVisibility(View.GONE);` |
+| Custom toolbar title | Activity/Fragment | `setTitleText(String)` | `.setTitleText("My Groups");` |
+| Title visibility | Activity/Fragment | `setTitleVisibility(int)` | `.setTitleVisibility(View.GONE);` |
+| Search placeholder | Activity/Fragment | `setSearchPlaceholderText(String)` | `.setSearchPlaceholderText("Find groups...");` |
+| Long-press options (replace) | Activity/Fragment | `setOptions(Function2)` | See `setOptions` code above |
+| Long-press options (append) | Activity/Fragment | `addOptions(Function2)` | See `addOptions` code above |
+| Loading view | Activity/Fragment | `setLoadingView(int)` | `.setLoadingView(R.layout.your_loading_view);` |
+| Empty view | Activity/Fragment | `setEmptyView(int)` | `.setEmptyView(R.layout.your_empty_view);` |
+| Error view | Activity/Fragment | `setErrorView(int)` | `.setErrorView(R.layout.your_error_view);` |
+| Leading view (avatar area) | Activity/Fragment | `setLeadingView(GroupsViewHolderListener)` | See `setLeadingView` code above |
+| Title view | Activity/Fragment | `setTitleView(GroupsViewHolderListener)` | See `setTitleView` code above |
+| Trailing view | Activity/Fragment | `setTrailingView(GroupsViewHolderListener)` | See `setTrailingView` code above |
+| Entire list item | Activity/Fragment | `setItemView(GroupsViewHolderListener)` | See `setItemView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(GroupsViewHolderListener)` | See `setSubtitleView` code above |
+| Overflow menu | Activity/Fragment | `setOverflowMenu(View)` | `cometchatGroups.setOverflowMenu(view);` |
+| Programmatic selection | Activity/Fragment | `selectGroup(Group, SelectionMode)` | `.selectGroup(group, SelectionMode.SINGLE);` |
+| Clear selection | Activity/Fragment | `clearSelection()` | `.clearSelection();` |
+| Selected groups strip | Activity/Fragment | `setSelectedGroupsListVisibility(int)` | `.setSelectedGroupsListVisibility(View.VISIBLE);` |
+| Internal adapter access | Activity/Fragment | `getAdapter()` / `setAdapter()` | Advanced use only |
+
+## Accessibility
+
+The component renders a scrollable `RecyclerView` of interactive group items. Each group row responds to tap and long-press gestures. Avatar images include the group name as content description. Group type indicators (public, private, password-protected) provide visual differentiation.
+
+For custom views provided via `setLeadingView`, `setTitleView`, `setTrailingView`, or `setItemView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+Group type status dots are visual-only by default. If screen reader descriptions are needed, provide them via a custom view with appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Group list is empty despite having groups | Verify that a user is logged in with `CometChatUIKit.login()` before displaying the component. The component fetches groups for the logged-in user only. |
+| Only joined groups appear | If you set `joinedOnly(true)` on the `GroupsRequestBuilder`, only groups the user has joined are shown. Remove `joinedOnly(true)` to show all groups. |
+| Filters not applied | Ensure you call `setGroupsRequestBuilder(builder)` on the `CometChatGroups` instance after creating and configuring the builder. |
+| Custom style not visible | Verify the style parent is `CometChatGroupsStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| `setOnItemClick` not firing | If you set `setSelectionMode` to `MULTIPLE`, item clicks may be consumed by the selection logic. Set the selection mode to `NONE` if you need standard click behavior. |
+| Event listener not receiving events | Ensure you call `CometChatGroupEvents.addGroupListener` with a unique tag. If you use the same tag as another listener, the previous one is replaced. |
+| Group type indicator not showing | If you called `setGroupTypeVisibility(View.GONE)`, the group type indicator is hidden. Call `setGroupTypeVisibility(View.VISIBLE)` to restore it. |
+| Custom view returns null in `createView` | If `createView` returns `null`, the default view is used. Return a valid inflated `View` to replace the default. |
+| Search not working | If you set a `SearchRequestBuilder` with `setSearchRequestBuilder`, ensure the builder is configured with `setSearchKeyWord`. If the search keyword is empty, all groups are returned. |
+
+## FAQ
+
+**Q: How do I show only joined groups?**
+**A:** Create a `GroupsRequest.GroupsRequestBuilder`, call `joinedOnly(true)`, and pass it to `setGroupsRequestBuilder`.
+
+**Q: How do I filter groups by tags?**
+**A:** Create a `GroupsRequest.GroupsRequestBuilder`, call `setTags(List)` with the desired tag names, and pass it to `setGroupsRequestBuilder`.
+
+**Q: How do I listen for group creation or deletion events outside the component?**
+**A:** Use `CometChatGroupEvents.addGroupListener("YOUR_TAG", ...)` and override `ccGroupCreated` or `ccGroupDeleted`. Call `CometChatGroupEvents.removeListeners()` to unsubscribe.
+
+**Q: How do I customize the avatar and separator styles?**
+**A:** Define custom styles with parents `CometChatAvatarStyle` and `CometChatGroupsStyle` in `themes.xml`, reference the avatar style in `cometchatGroupsAvatar`, and apply with `setStyle()`.
+
+**Q: How do I add custom long-press options without removing the defaults?**
+**A:** Use `addOptions` instead of `setOptions`. `addOptions` appends your custom `MenuItem` objects to the existing default options.
+
+**Q: How do I replace the entire group list item layout?**
+**A:** Use `setItemView` with a `GroupsViewHolderListener`. Inflate your custom layout in `createView` and populate it with group data in `bindView`.
+
+**Q: Can I use `CometChatGroups` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, call `setContentView(new CometChatGroups(this))`. In a Fragment, return `new CometChatGroups(getContext())` from `onCreateView`.
+
+## Next Steps
+
+- [Conversations component](/ui-kit/android/conversations)
+- [Users component](/ui-kit/android/users)
+- [Group Members component](/ui-kit/android/group-members)
+- [Message List component](/ui-kit/android/message-list)
\ No newline at end of file
diff --git a/ui-kit/android/guide-ai-agent.mdx b/ui-kit/android/guide-ai-agent.mdx
index 5c3e55c8a..6429dd30f 100644
--- a/ui-kit/android/guide-ai-agent.mdx
+++ b/ui-kit/android/guide-ai-agent.mdx
@@ -51,7 +51,7 @@ The AI Agent chat interface provides a familiar messaging experience enhanced wi
Create the AI Assistant chat activity with proper theme and layout configuration.
-```kotlin
+```kotlin lines
class AIAssistantChatActivity : AppCompatActivity() {
private lateinit var binding: ActivityAiAssistantChatBinding
@@ -63,19 +63,24 @@ class AIAssistantChatActivity : AppCompatActivity() {
val messageJson = intent.getStringExtra(getString(R.string.app_base_message))
val userJson = intent.getStringExtra(getString(R.string.app_user))
- if (userJson != null && !userJson.isEmpty())
- val user = User.fromJson(userJson)
- if (messageJson != null && !messageJson.isEmpty())
- val parentMessage = BaseMessage.processMessage(JSONObject(messageJson))
+ var user: User? = null
+ var parentMessage: BaseMessage? = null
+
+ if (!userJson.isNullOrEmpty())
+ user = User.fromJson(userJson)
+ if (!messageJson.isNullOrEmpty())
+ parentMessage = BaseMessage.processMessage(JSONObject(messageJson))
initializeComponents(user, parentMessage)
initClickListeners()
}
- private fun initializeComponents(user: User, parentMessage: BaseMessage) {
- binding.messageHeader.user = user // Set user for header
- binding.messageList.user = user // Set user for message list
- binding.messageComposer.user = user // Set user for composer
+ private fun initializeComponents(user: User?, parentMessage: BaseMessage?) {
+ user?.let {
+ binding.messageHeader.user = it // Set user for header
+ binding.messageList.user = it // Set user for message list
+ binding.messageComposer.user = it // Set user for composer
+ }
if (parentMessage != null) {
// Set message id of parent message to fetch messages with parent.
@@ -92,13 +97,13 @@ class AIAssistantChatActivity : AppCompatActivity() {
```
**File reference:**
-[`AIAssistantChatActivity.kt`](ai-builder/src/main/java/com/cometchat/ai/builder/ui/activity/AIAssistantChatActivity.kt)
+[`AIAssistantChatActivity.kt`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/ai-sample-app/src/main/java/com/cometchat/ai/sampleapp/ui/activity/AIAssistantChatActivity.kt)
### Step - 2 AIAssistantChatActivity layout:
Add `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to your layout to enable a complete AI chat interface. Use the sample XML below as a reference for correct integration.
-```xml
+```xml lines
?attr/cometchatBackgroundColor2
@@ -176,7 +181,7 @@ Define custom styles for the message list and composer to differentiate AI agent
Initialize click listeners of message header to handle new chat creation and chat history access.
-```kotlin
+```kotlin lines
private fun initClickListeners() {
@@ -203,7 +208,7 @@ private fun initClickListeners() {
Create a new activity to host `CometChatAIAssistantChatHistory` component and handle its interactions.
-```kotlin
+```kotlin lines
class AIAssistantChatHistoryActivity : AppCompatActivity() {
private lateinit var binding: ActivityAiAssistantChatHistoryBinding
private var user: User? = null
@@ -248,7 +253,7 @@ class AIAssistantChatHistoryActivity : AppCompatActivity() {
}
// New chat creation from history screen
- binding.cometchatAiAssistantChatHistory.setNewChatButtonClick {
+ binding.cometchatAiAssistantChatHistory.setOnNewChatClickListener {
val intent = Intent(this@AIAssistantChatHistoryActivity, AIAssistantChatActivity::class.java)
intent.putExtra(getString(R.string.app_user), user!!.toJson().toString()) // Pass user to create new chat
startActivity(intent)
@@ -256,7 +261,7 @@ class AIAssistantChatHistoryActivity : AppCompatActivity() {
}
// Close history screen
- binding.cometchatAiAssistantChatHistory.setCloseButtonClick {
+ binding.cometchatAiAssistantChatHistory.setOnCloseClickListener {
// finish the activity
}
}
@@ -267,7 +272,7 @@ class AIAssistantChatHistoryActivity : AppCompatActivity() {
Add `CometChatAIAssistantChatHistory` to your layout to enable access to AI chat history. Use the sample XML below as a reference for correct integration.
-```xml
+```xml lines
Explore this feature in the CometChat AI Builder:
- [GitHub → AI Builder](https://github.com/cometchat/cometchat-uikit-android/tree/v5/ai-builder)
+ [GitHub → AI Builder](https://github.com/cometchat/cometchat-uikit-android/tree/v5/ai-sample-app)
Explore this feature in the CometChat SampleApp:
diff --git a/ui-kit/android/guide-block-unblock-user.mdx b/ui-kit/android/guide-block-unblock-user.mdx
index 8249662ee..3422de5d5 100644
--- a/ui-kit/android/guide-block-unblock-user.mdx
+++ b/ui-kit/android/guide-block-unblock-user.mdx
@@ -27,8 +27,8 @@ Blocking a user stops them from sending messages to the blocker. The CometChat U
|:-------------------------------------|:------------------------------------------------------------|
| `UserDetailActivity.java` | Displays user profile and provides block/unblock options. |
| `MessagesActivity.java` | Hosts the chat screen and toggles UI based on block state. |
-| `CometChatUIKit.blockUsers()` | API to block one or more users by UID. |
-| `CometChatUIKit.unblockUsers()` | API to unblock one or more users by UID. |
+| `CometChat.blockUsers()` | SDK API to block one or more users by UID. |
+| `CometChat.unblockUsers()` | SDK API to unblock one or more users by UID. |
| `User.isBlockedByMe()` | Checks if the current user has blocked this user. |
| `unblockLayout` (View) | Layout shown when a user is blocked, containing unblock. |
| `CometChatMessageComposer` | Hidden when chatting with a blocked user. |
@@ -39,7 +39,20 @@ Blocking a user stops them from sending messages to the blocker. The CometChat U
Update UI when block state changes.
-```java
+
+
+```kotlin lines
+// In MessagesActivity.kt
+private fun updateUserBlockStatus(user: User) {
+ val blocked = user.isBlockedByMe
+ binding.messageComposer.visibility = if (blocked) View.GONE else View.VISIBLE
+ binding.unblockLayout.visibility = if (blocked) View.VISIBLE else View.GONE
+}
+```
+
+
+
+```java lines
// In MessagesActivity.java
private void updateUserBlockStatus(User user) {
boolean blocked = user.isBlockedByMe();
@@ -47,9 +60,11 @@ private void updateUserBlockStatus(User user) {
binding.unblockLayout.setVisibility(blocked ? View.VISIBLE : View.GONE);
}
```
+
+
**File reference:**
-[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/app/src/main/java/com/cometchat/sampleapp/MessagesActivity.java#L120-L130)
+[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)
Ensures the composer and unblock UI reflect the current block state.
@@ -57,20 +72,27 @@ Ensures the composer and unblock UI reflect the current block state.
Define layout elements and their visibility toggles.
-```xml
+```xml activity_messages.xml lines
-
-
+
+
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="12dp"
+ android:visibility="gone">
+
-
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Unblock" />
+
```
**File reference:**
@@ -82,15 +104,36 @@ Prepares the UI containers for dynamic show/hide operations.
Call the unblock API and observe status updates.
-```java
+
+
+```kotlin lines
+// In MessagesActivity.kt
+binding.unblockBtn.setOnClickListener { viewModel.unblockUser() }
+
+// In MessagesViewModel.kt
+fun unblockUser() {
+ CometChat.unblockUsers(listOf(currentUser.uid), object : CometChat.CallbackListener>() {
+ override fun onSuccess(resultMap: HashMap) {
+ unblockButtonState.postValue(false)
+ }
+ override fun onError(e: CometChatException?) {
+ // Handle error
+ }
+ })
+}
+```
+
+
+
+```java lines
// In MessagesActivity.java
binding.unblockBtn.setOnClickListener(v -> viewModel.unblockUser());
// In MessagesViewModel.java
public void unblockUser() {
- CometChatUIKit.unblockUsers(Collections.singletonList(currentUser.getUid()), new CometChat.CallbackListener>() {
+ CometChat.unblockUsers(Collections.singletonList(currentUser.getUid()), new CometChat.CallbackListener>() {
@Override
- public void onSuccess(List uids) {
+ public void onSuccess(HashMap resultMap) {
unblockButtonState.postValue(false);
}
@Override
@@ -100,6 +143,8 @@ public void unblockUser() {
});
}
```
+
+
**File references:**
- [`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)
@@ -111,12 +156,30 @@ Executes unblock logic and updates LiveData to refresh UI.
Allow blocking directly from a user’s profile.
-```java
+
+
+```kotlin lines
+// In UserDetailActivity.kt
+binding.blockMenuItem.setOnClickListener {
+ CometChat.blockUsers(listOf(user.uid), object : CometChat.CallbackListener>() {
+ override fun onSuccess(resultMap: HashMap) {
+ viewModel.refreshUser()
+ }
+ override fun onError(e: CometChatException?) {
+ // Handle error
+ }
+ })
+}
+```
+
+
+
+```java lines
// In UserDetailActivity.java
binding.blockMenuItem.setOnClickListener(v -> {
- CometChatUIKit.blockUsers(Collections.singletonList(user.getUid()), new CometChat.CallbackListener>() {
+ CometChat.blockUsers(Collections.singletonList(user.getUid()), new CometChat.CallbackListener>() {
@Override
- public void onSuccess(List uids) {
+ public void onSuccess(HashMap resultMap) {
viewModel.refreshUser();
}
@Override
@@ -126,6 +189,8 @@ binding.blockMenuItem.setOnClickListener(v -> {
});
});
```
+
+
**File reference:**
[`UserDetailActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/UserDetailsActivity.java)
@@ -173,8 +238,8 @@ Integrates block action into the profile menu, triggering the UI toggle via Live
| Feature | Component / Method |
|:-------------------|:------------------------------------------|
| Check block state | `User.isBlockedByMe()` |
-| Block user | `CometChatUIKit.blockUsers()` |
-| Unblock user | `CometChatUIKit.unblockUsers()` |
+| Block user | `CometChat.blockUsers()` |
+| Unblock user | `CometChat.unblockUsers()` |
| Update UI | `updateUserBlockStatus()` |
| Profile block menu | `UserDetailActivity.blockMenuItem` |
diff --git a/ui-kit/android/guide-call-log-details.mdx b/ui-kit/android/guide-call-log-details.mdx
index 5c80119a1..0f85b5ab4 100644
--- a/ui-kit/android/guide-call-log-details.mdx
+++ b/ui-kit/android/guide-call-log-details.mdx
@@ -28,7 +28,7 @@ This feature is essential for support, moderation, and post-call reviews.
| Component / Class | Role |
|:-----------------------------|:---------------------------------------------------------------------------------------|
-| `CallsFragment` | Fetches and displays the list of recent calls using `CallsRequest`. |
+| `CallsFragment` | Displays the list of recent calls using `CometChatCallLogs` component. |
| `HomeActivity` | Hosts bottom navigation; loads `CallsFragment` for the Calls tab. |
| `CallDetailsActivity` | Container for the call details UI with tab navigation. |
| `CallDetailsTabFragmentAdapter` | Adapter for `ViewPager2` managing detail tabs. |
@@ -41,37 +41,81 @@ This feature is essential for support, moderation, and post-call reviews.
## Integration Steps
-### 1. Show Call Logs in `CallsFragment`
+### 1. Show Call Logs Using `CometChatCallLogs`
-Enable users to browse recent calls.
+Use the UI Kit's `CometChatCallLogs` component to display recent calls. Add it to your fragment layout:
-```java
-// CallsFragment.java
-CallsRequest request = new CallsRequest.CallsRequestBuilder()
- .setLimit(50)
- .build();
-request.fetchNext(
- new CometChat.CallbackListener>() {
- @Override
- public void onSuccess(List calls) {
- adapter.submitList(calls);
- }
- @Override
- public void onError(CometChatException e) {
- // handle error
- }
- }
-);
+```xml fragment_calls.xml lines
+
+
+
+
+
+
+```
+
+Handle call log item clicks to navigate to the details screen:
+
+
+
+```kotlin CallsFragment.kt lines
+// CallsFragment.kt
+val callLogs = view.findViewById(R.id.call_logs)
+callLogs.setOnItemClick { _, _, callLog ->
+ val intent = Intent(activity, CallDetailsActivity::class.java)
+ intent.putExtra("callLog", Gson().toJson(callLog))
+ intent.putExtra("initiator", Gson().toJson(callLog.initiator))
+ intent.putExtra("receiver", Gson().toJson(callLog.receiver))
+ startActivity(intent)
+}
```
+
-**File reference:**
-[`CallsFragment.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/fragments/CallsFragment.java)
+
+```java CallsFragment.java lines
+// CallsFragment.java
+CometChatCallLogs callLogs = view.findViewById(R.id.call_logs);
+callLogs.setOnItemClick((view1, position, callLog) -> {
+ Intent intent = new Intent(getActivity(), CallDetailsActivity.class);
+ intent.putExtra("callLog", new Gson().toJson(callLog));
+ intent.putExtra("initiator", new Gson().toJson(callLog.getInitiator()));
+ intent.putExtra("receiver", new Gson().toJson(callLog.getReceiver()));
+ startActivity(intent);
+});
+```
+
+
### 2. Load `CallsFragment` in `HomeActivity`
Display the Calls tab via bottom navigation.
-```java
+
+
+```kotlin HomeActivity.kt lines
+// HomeActivity.kt
+bottomNav.setOnItemSelectedListener { item ->
+ val frag = if (item.itemId == R.id.nav_calls)
+ CallsFragment()
+ else
+ MessagesFragment()
+ supportFragmentManager
+ .beginTransaction()
+ .replace(R.id.container, frag)
+ .commit()
+ true
+}
+```
+
+
+
+```java HomeActivity.java lines
// HomeActivity.java
bottomNav.setOnItemSelectedListener(item -> {
Fragment frag = item.getItemId() == R.id.nav_calls
@@ -84,15 +128,48 @@ bottomNav.setOnItemSelectedListener(item -> {
return true;
});
```
-
-**File reference:**
-[`HomeActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/HomeActivity.java)
+
+
### 3. Configure `CallDetailsActivity`
Initialize the detail screen with tabs for metadata, participants, history, and recordings.
-```java
+
+
+```kotlin CallDetailsActivity.kt lines
+// CallDetailsActivity.kt
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityCallDetailsBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ val callLog = Gson().fromJson(
+ intent.getStringExtra("callLog"), CallLog::class.java
+ )
+ viewModel = ViewModelProvider(this)[CallDetailsViewModel::class.java]
+ viewModel.setCallLog(callLog)
+
+ // Setup ViewPager2 & TabLayout
+ binding.viewPager.adapter = CallDetailsTabFragmentAdapter(this, callLog)
+ TabLayoutMediator(binding.tabs, binding.viewPager) { tab, pos ->
+ tab.text = when (pos) {
+ 0 -> "Participants"
+ 1 -> "History"
+ else -> "Recordings"
+ }
+ }.attach()
+
+ // Optionally use UI Kit widget directly:
+ // val details = CometChatCallLogDetails(this)
+ // details.setCall(callLog)
+ // setContentView(details)
+}
+```
+
+
+
+```java CallDetailsActivity.java lines
// CallDetailsActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -100,8 +177,8 @@ protected void onCreate(Bundle savedInstanceState) {
binding = ActivityCallDetailsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
- Call callLog = new Gson().fromJson(
- getIntent().getStringExtra("CALL_LOG"), Call.class
+ CallLog callLog = new Gson().fromJson(
+ getIntent().getStringExtra("callLog"), CallLog.class
);
viewModel = new ViewModelProvider(this)
.get(CallDetailsViewModel.class);
@@ -126,19 +203,30 @@ protected void onCreate(Bundle savedInstanceState) {
// setContentView(details);
}
```
-
-**File reference:**
-[`CallDetailsActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/CallDetailsActivity.java)
+
+
### 4. Implement `CometChatCallLogDetails` Component
Use the UI Kit widget for an all-in-one detail view.
-```java
+
+
+```kotlin lines
+val detailsView = CometChatCallLogDetails(this)
+detailsView.setCall(callLog)
+setContentView(detailsView)
+```
+
+
+
+```java lines
CometChatCallLogDetails detailsView = new CometChatCallLogDetails(this);
detailsView.setCall(callLog);
setContentView(detailsView);
```
+
+
## Implementation Flow
@@ -174,7 +262,7 @@ setContentView(detailsView);
| Feature | Component / Method |
|:-----------------------------------|:--------------------------------------------------|
-| Display call logs list | `CallsRequest.fetchNext()` in **CallsFragment** |
+| Display call logs list | `CometChatCallLogs` in **CallsFragment** |
| Navigate to detail screen | Intent + **CallDetailsActivity** |
| Render detail tabs | **CallDetailsTabFragmentAdapter** |
| Single-widget detail view | **CometChatCallLogDetails** |
diff --git a/ui-kit/android/guide-group-chat.mdx b/ui-kit/android/guide-group-chat.mdx
index bfdda082f..a5e2f431a 100644
--- a/ui-kit/android/guide-group-chat.mdx
+++ b/ui-kit/android/guide-group-chat.mdx
@@ -54,7 +54,7 @@ Typically, a FloatingActionButton (FAB) or menu item launches the group-manageme
Add a FAB to launch the group-management dialog.
-```xml
+```xml lines
+
+```kotlin MessagesActivity.kt lines
+// In MessagesActivity.kt
+val fab = findViewById(R.id.fab_group_actions)
+fab.setOnClickListener { showGroupActionsDialog() }
+
+private fun showGroupActionsDialog() {
+ // Present options: Create, Join, View Members, etc.
+}
+```
+
+
+
+```java MessagesActivity.java lines
// In MessagesActivity.java
FloatingActionButton fab = findViewById(R.id.fab_group_actions);
fab.setOnClickListener(v -> showGroupActionsDialog());
@@ -80,15 +94,40 @@ private void showGroupActionsDialog() {
// Present options: Create, Join, View Members, etc.
}
```
-
-**File reference:**
-[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)
+
+
### 3. Create & Join Group
Allow users to create or join a group via Core SDK.
-```java
+
+
+```kotlin lines
+// Create Group
+CometChat.createGroup(
+ Group(groupGuid, groupName, CometChatConstants.GROUP_TYPE_PUBLIC, ""),
+ object : CometChat.CallbackListener() {
+ override fun onSuccess(group: Group) { /* handle success */ }
+ override fun onError(e: CometChatException?) { /* handle error */ }
+ }
+)
+
+// Join Group
+CometChat.joinGroup(
+ groupGuid,
+ CometChatConstants.GROUP_TYPE_PUBLIC,
+ "",
+ object : CometChat.CallbackListener() {
+ override fun onSuccess(group: Group) { /* handle success */ }
+ override fun onError(e: CometChatException?) { /* handle error */ }
+ }
+)
+```
+
+
+
+```java lines
// Create Group
CometChat.createGroup(new Group(
groupGuid,
@@ -109,15 +148,28 @@ CometChat.joinGroup(
}
);
```
-
-**File reference:**
-[`GroupDetailsActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/GroupDetailsActivity.java)
+
+
### 4. View Group Members
Fetch and display the current member list.
-```java
+
+
+```kotlin lines
+val membersRequest = GroupMembersRequest.Builder(groupGuid).setLimit(50).build()
+membersRequest.fetchNext(object : CometChat.CallbackListener>() {
+ override fun onSuccess(members: List) {
+ showMembersDialog(members)
+ }
+ override fun onError(e: CometChatException?) {}
+})
+```
+
+
+
+```java lines
GroupMembersRequest membersRequest = new GroupMembersRequest.Builder(groupGuid).setLimit(50).build();
membersRequest.fetchNext(new CometChat.CallbackListener>() {
@Override
@@ -128,15 +180,38 @@ membersRequest.fetchNext(new CometChat.CallbackListener>() {
public void onError(CometChatException e) {}
});
```
-
-**File reference:**
-[`GroupDetailsActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/GroupDetailsActivity.java)
+
+
### 5. Add Member
Select users not in the group and add them.
-```java
+
+
+```kotlin lines
+val usersRequest = UsersRequest.UsersRequestBuilder().setLimit(50).build()
+usersRequest.fetchNext(object : CometChat.CallbackListener>() {
+ override fun onSuccess(allUsers: List) {
+ // filter out existing members, show selection dialog
+ }
+ override fun onError(e: CometChatException?) {}
+})
+// On selection:
+CometChat.addMembersToGroup(
+ groupGuid,
+ selectedUids,
+ CometChatConstants.SCOPE_PARTICIPANT,
+ object : CometChat.CallbackListener>() {
+ override fun onSuccess(result: HashMap) { /* handle result */ }
+ override fun onError(e: CometChatException?) { /* handle error */ }
+ }
+)
+```
+
+
+
+```java lines
UsersRequest usersRequest = new UsersRequest.UsersRequestBuilder().setLimit(50).build();
usersRequest.fetchNext(new CometChat.CallbackListener>() {
public void onSuccess(List allUsers) {
@@ -153,6 +228,8 @@ CometChat.addMembersToGroup(
}
);
```
+
+
**File reference:**
[`GroupDetailsActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/GroupDetailsActivity.java)
@@ -161,7 +238,40 @@ CometChat.addMembersToGroup(
Perform moderation actions on selected members.
-```java
+
+
+```kotlin lines
+// Ban Member
+CometChat.banGroupMember(
+ uid, groupGuid,
+ object : CometChat.CallbackListener() {
+ override fun onSuccess(result: String) { /* handle success */ }
+ override fun onError(e: CometChatException?) { /* handle error */ }
+ }
+)
+
+// Change Scope
+CometChat.updateGroupMemberScope(
+ uid, groupGuid, CometChatConstants.SCOPE_MODERATOR,
+ object : CometChat.CallbackListener() {
+ override fun onSuccess(result: String) { /* handle success */ }
+ override fun onError(e: CometChatException?) { /* handle error */ }
+ }
+)
+
+// Transfer Ownership
+CometChat.transferGroupOwnership(
+ uid, groupGuid,
+ object : CometChat.CallbackListener() {
+ override fun onSuccess(result: String) { /* handle success */ }
+ override fun onError(e: CometChatException?) { /* handle error */ }
+ }
+)
+```
+
+
+
+```java lines
// Ban Member
CometChat.banGroupMember(
uid,
@@ -184,9 +294,8 @@ CometChat.transferGroupOwnership(
new CometChat.CallbackListener() { /*...*/ }
);
```
-
-**File reference:**
-[`GroupDetailsActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/GroupDetailsActivity.java)
+
+
## Implementation Flow Summary
diff --git a/ui-kit/android/guide-message-privately.mdx b/ui-kit/android/guide-message-privately.mdx
index 989c5edb8..1ea16244e 100644
--- a/ui-kit/android/guide-message-privately.mdx
+++ b/ui-kit/android/guide-message-privately.mdx
@@ -17,7 +17,7 @@ Users tap **Message Privately** → launch `MessagesActivity` with the target us
## Prerequisites
-- Android Studio project with **cometchat-pro/android-chat-sdk v4.0.0+** and **cometchat-pro/android-java-uikit v4.0.0+** in `build.gradle`.
+- Android Studio project with CometChat Android UI Kit v5 (`com.cometchat:chat-uikit-android`) added to `build.gradle`.
- Valid CometChat **App ID**, **Auth Key**, and **Region** initialized.
- `` in `AndroidManifest.xml`.
- Users created in your CometChat app.
@@ -40,7 +40,20 @@ Users tap **Message Privately** → launch `MessagesActivity` with the target us
Navigate from `UserDetailsActivity` to `MessagesActivity` with the selected user.
-```java
+
+
+```kotlin lines
+// In UserDetailsActivity.kt
+binding.messagePrivatelyBtn.setOnClickListener {
+ val intent = Intent(this, MessagesActivity::class.java)
+ intent.putExtra(getString(R.string.app_user), Gson().toJson(user))
+ startActivity(intent)
+}
+```
+
+
+
+```java lines
// In UserDetailsActivity.java
binding.messagePrivatelyBtn.setOnClickListener(v -> {
Intent intent = new Intent(this, MessagesActivity.class);
@@ -48,6 +61,8 @@ binding.messagePrivatelyBtn.setOnClickListener(v -> {
startActivity(intent);
});
```
+
+
**File reference:**
[`UserDetailsActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/UserDetailsActivity.java)
@@ -56,7 +71,27 @@ binding.messagePrivatelyBtn.setOnClickListener(v -> {
Deserialize the `User` JSON extra and configure the chat UI.
-```java
+
+
+```kotlin lines
+// In MessagesActivity.kt
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_messages)
+
+ val userJson = intent.getStringExtra(getString(R.string.app_user))
+ if (userJson != null) {
+ val user = Gson().fromJson(userJson, User::class.java)
+ messageHeader.setUser(user)
+ messageList.setUser(user)
+ composer.setUser(user)
+ }
+}
+```
+
+
+
+```java lines
// In MessagesActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -72,6 +107,8 @@ protected void onCreate(Bundle savedInstanceState) {
}
}
```
+
+
**File reference:**
[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)
@@ -80,7 +117,28 @@ protected void onCreate(Bundle savedInstanceState) {
Send an initial greeting to ensure the chat appears in conversation lists.
-```java
+
+
+```kotlin lines
+// In MainActivity.kt
+val txtMessage = TextMessage(
+ "cometchat-uid-2",
+ "👋",
+ CometChatConstants.RECEIVER_TYPE_USER
+)
+CometChat.sendMessage(txtMessage, object : CometChat.CallbackListener() {
+ override fun onSuccess(msg: BaseMessage) {
+ Log.d("SendMsg", "Initial message sent.")
+ }
+ override fun onError(e: CometChatException?) {
+ Log.e("SendMsg", e?.message ?: "Error sending message")
+ }
+})
+```
+
+
+
+```java lines
// In MainActivity.java
txtMessage = new TextMessage(
"cometchat-uid-2",
@@ -96,6 +154,8 @@ CometChat.sendMessage(txtMessage, new CometChat.CallbackListener()
}
});
```
+
+
**File reference:**
[`MainActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MainActivity.java)
diff --git a/ui-kit/android/guide-new-chat.mdx b/ui-kit/android/guide-new-chat.mdx
index 51c467c9e..e01e66679 100644
--- a/ui-kit/android/guide-new-chat.mdx
+++ b/ui-kit/android/guide-new-chat.mdx
@@ -42,7 +42,22 @@ This streamlines contact/group discovery and boosts engagement by reducing frict
Show a “+” icon that launches `NewChatActivity`.
-```java
+
+
+```kotlin ConversationActivity.kt lines
+// In ConversationActivity.kt
+toolbar.inflateMenu(R.menu.conversation_menu)
+toolbar.setOnMenuItemClickListener { item ->
+ if (item.itemId == R.id.action_new_chat) {
+ startActivity(Intent(this, NewChatActivity::class.java))
+ true
+ } else false
+}
+```
+
+
+
+```java ConversationActivity.java lines
// In ConversationActivity.java
toolbar.inflateMenu(R.menu.conversation_menu);
toolbar.setOnMenuItemClickListener(item -> {
@@ -53,14 +68,34 @@ toolbar.setOnMenuItemClickListener(item -> {
return false;
});
```
-
-Provides entry to the New Chat flow.
+
+
### 2. Implement New Chat Screen
Build a tabbed interface with Users and Groups lists.
-```java
+
+
+```kotlin NewChatActivity.kt lines
+// In NewChatActivity.kt
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_new_chat)
+
+ val tabs = findViewById(R.id.tabLayout)
+ val pager = findViewById(R.id.viewPager)
+ val adapter = NewChatPagerAdapter(this)
+ pager.adapter = adapter
+ TabLayoutMediator(tabs, pager) { tab, pos ->
+ tab.text = if (pos == 0) "Users" else "Groups"
+ }.attach()
+}
+```
+
+
+
+```java NewChatActivity.java lines
// In NewChatActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -76,45 +111,83 @@ protected void onCreate(Bundle savedInstanceState) {
).attach();
}
```
-
-**File reference:**
-[`NewChatActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/NewChatActivity.java)
-
-**Layout reference:**
-[`activity_new_chat.xml`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/res/layout/activity_new_chat.xml)
-
-Initializes tabs and loads `CometChatUsers` / `CometChatGroups` fragments.
+
+
### 3. Handle User or Group Selection
Launch `MessagesActivity` when an item is tapped.
-```java
+
+
+```kotlin NewChatActivity.kt lines
+// In NewChatActivity.kt (Users fragment)
+cometChatUsers.setOnItemClick { view, position, user ->
+ val intent = Intent(this, MessagesActivity::class.java)
+ intent.putExtra("app_user", Gson().toJson(user))
+ startActivity(intent)
+}
+
+// Similarly for CometChatGroups:
+cometChatGroups.setOnItemClick { view, position, group ->
+ val intent = Intent(this, MessagesActivity::class.java)
+ intent.putExtra("app_group", Gson().toJson(group))
+ startActivity(intent)
+}
+```
+
+
+
+```java NewChatActivity.java lines
// In NewChatActivity.java (Users fragment)
-cometChatUsers.setOnItemClick((user, clickListener) -> {
+cometChatUsers.setOnItemClick((view, position, user) -> {
Intent i = new Intent(this, MessagesActivity.class);
i.putExtra("app_user", new Gson().toJson(user));
startActivity(i);
});
// Similarly for CometChatGroups:
-cometChatGroups.setOnItemClick((group, clickListener) -> {
+cometChatGroups.setOnItemClick((view, position, group) -> {
Intent i = new Intent(this, MessagesActivity.class);
i.putExtra("app_group", new Gson().toJson(group));
startActivity(i);
});
```
-
-**File reference:**
-[`NewChatActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/NewChatActivity.java)
-
-Routes selection to the chat interface with proper context.
+
+
### 4. Open the Messages Screen
Read intent extras and configure chat UI.
-```java
+
+
+```kotlin MessagesActivity.kt lines
+// In MessagesActivity.kt
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_messages)
+
+ val userJson = intent.getStringExtra("app_user")
+ val groupJson = intent.getStringExtra("app_group")
+
+ if (userJson != null) {
+ val user = Gson().fromJson(userJson, User::class.java)
+ messageHeader.setUser(user)
+ messageList.setUser(user)
+ composer.setUser(user)
+ } else if (groupJson != null) {
+ val group = Gson().fromJson(groupJson, Group::class.java)
+ messageHeader.setGroup(group)
+ messageList.setGroup(group)
+ composer.setGroup(group)
+ }
+}
+```
+
+
+
+```java MessagesActivity.java lines
// In MessagesActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -137,14 +210,8 @@ protected void onCreate(Bundle savedInstanceState) {
}
}
```
-
-**File reference:**
-[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)
-
-**Layout reference:**
-[`activity_messages.xml`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/res/layout/activity_messages.xml)
-
-Binds the selected conversation context to the UI Kit components.
+
+
## Implementation Flow
diff --git a/ui-kit/android/guide-overview.mdx b/ui-kit/android/guide-overview.mdx
index 23b6fe2b5..3319b2c09 100644
--- a/ui-kit/android/guide-overview.mdx
+++ b/ui-kit/android/guide-overview.mdx
@@ -18,5 +18,6 @@ Use these guides after you have completed the base [Getting Started](/ui-kit/and
| [Message Privately](/ui-kit/android/guide-message-privately) | Launch a direct 1:1 chat from a profile/list; optionally send initial message to surface conversation. |
| [New Chat](/ui-kit/android/guide-new-chat) | Unified entry for starting new 1:1 or group chats with tabbed Users / Groups search + navigation. |
| [Threaded Messages](/ui-kit/android/guide-threaded-messages) | Threaded replies: open parent message context, list replies, compose with parent linkage. |
+| [AI Agent](/ui-kit/android/guide-ai-agent) | Build an AI-powered agent that responds to user messages using CometChat's AI features. |
Need another guide? Open a request via our [Developer Community](http://community.cometchat.com/) or Support.
\ No newline at end of file
diff --git a/ui-kit/android/guide-threaded-messages.mdx b/ui-kit/android/guide-threaded-messages.mdx
index 9acdcab47..1e2f058e9 100644
--- a/ui-kit/android/guide-threaded-messages.mdx
+++ b/ui-kit/android/guide-threaded-messages.mdx
@@ -42,98 +42,201 @@ Users tap a message → open thread screen → view parent message + replies →
Create `res/layout/activity_thread_message.xml`:
-```xml
-
-
-
-
-
+```xml activity_thread_message.xml lines
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
**File reference:**
-[`activity_thread_message.xml`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/app/src/main/res/layout/activity_thread_message.xml)
+[`activity_thread_message.xml`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/res/layout/activity_thread_message.xml)
### Step 2: Set up ThreadMessageActivity
Initialize UI & handle blocked-user flows:
-```java
+
+
+```kotlin lines
+class ThreadMessageActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_thread_message)
+ val header = findViewById(R.id.threadHeader)
+ val messageList = findViewById(R.id.threadMessageList)
+ val composer = findViewById(R.id.threadComposer)
+ val unblock = findViewById(R.id.unblockLayout)
+
+ val rawMessage = intent.getStringExtra("raw_json")
+ val viewModel = ViewModelProvider(this)[ThreadMessageViewModel::class.java]
+ if (rawMessage != null) {
+ val parentMessage = BaseMessage.processMessage(JSONObject(rawMessage))
+ viewModel.setParentMessage(parentMessage)
+ }
+ viewModel.parentMessage.observe(this) { msg ->
+ header.setParentMessage(msg)
+ messageList.setParentMessage(msg.id)
+ composer.setParentMessageId(msg.id)
+ }
+
+ // Handle blocked user
+ if (isBlockedByMe) {
+ composer.visibility = View.GONE
+ unblock.visibility = View.VISIBLE
+ }
+ }
+}
+```
+
+
+
+```java lines
public class ThreadMessageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_message);
- ThreadHeaderView header = findViewById(R.id.threadHeader);
+ CometChatThreadHeader header = findViewById(R.id.threadHeader);
CometChatMessageList messageList = findViewById(R.id.threadMessageList);
CometChatMessageComposer composer = findViewById(R.id.threadComposer);
View unblock = findViewById(R.id.unblockLayout);
- String messageId = getIntent().getStringExtra("message_id");
- viewModel = new ViewModelProvider(this).get(ThreadMessageViewModel.class);
- viewModel.fetchParentMessage(messageId);
- viewModel.getParentMessage().observe(this, msg -> header.setMessage(msg));
- messageList.setParentMessage(messageId);
- composer.setParentMessageId(messageId);
+ String rawMessage = getIntent().getStringExtra("raw_json");
+ ThreadMessageViewModel viewModel = new ViewModelProvider(this).get(ThreadMessageViewModel.class);
+ if (rawMessage != null) {
+ BaseMessage parentMessage = BaseMessage.processMessage(new JSONObject(rawMessage));
+ viewModel.setParentMessage(parentMessage);
+ }
+ viewModel.getParentMessage().observe(this, msg -> {
+ header.setParentMessage(msg);
+ messageList.setParentMessage(msg.getId());
+ composer.setParentMessageId(msg.getId());
+ });
// Handle blocked user
- if (viewModel.isBlocked()) {
+ if (isBlockedByMe) {
composer.setVisibility(View.GONE);
unblock.setVisibility(View.VISIBLE);
}
}
}
```
+
+
**File reference:**
-[`ThreadMessageActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/app/src/main/java/com/cometchat/sampleapp/threads/ThreadMessageActivity.java)
+[`ThreadMessageActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/ThreadMessageActivity.java)
### Step 3: Create ThreadMessageViewModel
-Fetch parent message and expose LiveData:
+Store parent message and expose LiveData:
+
+
+
+```kotlin lines
+class ThreadMessageViewModel : ViewModel() {
+ val parentMessage = MutableLiveData()
+ var id: Long = 0
+ private set
+
+ fun setParentMessage(message: BaseMessage?) {
+ if (message != null) {
+ id = message.id
+ parentMessage.value = message
+ }
+ }
+}
+```
+
-```java
+
+```java lines
public class ThreadMessageViewModel extends ViewModel {
private MutableLiveData parentMessage = new MutableLiveData<>();
+ private long id;
- public void fetchParentMessage(String id) {
- CometChat.getMessage(id, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(BaseMessage msg) {
- parentMessage.postValue(msg);
- }
- @Override public void onError(CometChatException e) {}
- });
+ public void setParentMessage(BaseMessage message) {
+ if (message != null) {
+ this.id = message.getId();
+ parentMessage.setValue(message);
+ }
}
+ public long getId() { return id; }
+
public LiveData getParentMessage() {
return parentMessage;
}
}
```
+
+
**File reference:**
[`ThreadMessageViewModel.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/viewmodels/ThreadMessageViewModel.java)
### Step 4: Hook Thread Entry from Message List
-In `MessagesActivity.java`, capture thread icon taps:
+In your `MessagesActivity`, capture thread icon taps:
-```java
+
+
+```kotlin lines
+messageList.setOnThreadRepliesClick { context, baseMessage, template ->
+ val intent = Intent(context, ThreadMessageActivity::class.java)
+ intent.putExtra("raw_json", baseMessage.rawMessage.toString())
+ intent.putExtra("reply_count", baseMessage.replyCount)
+ context.startActivity(intent)
+}
+```
+
+
+
+```java lines
messageList.setOnThreadRepliesClick((context, baseMessage, template) -> {
Intent intent = new Intent(context, ThreadMessageActivity.class);
- intent.putExtra("message_id", baseMessage.getId());
+ intent.putExtra("raw_json", baseMessage.getRawMessage().toString());
+ intent.putExtra("reply_count", baseMessage.getReplyCount());
context.startActivity(intent);
});
```
+
+
**File reference:**
[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)
@@ -141,8 +244,8 @@ messageList.setOnThreadRepliesClick((context, baseMessage, template) -> {
## Implementation Flow
1. User taps thread icon on a message.
-2. `Intent` launches `ThreadMessageActivity` with `message_id`.
-3. ViewModel fetches parent message details.
+2. `Intent` launches `ThreadMessageActivity` with raw message JSON.
+3. ViewModel stores parent message and exposes via LiveData.
4. Header & `MessageList` render parent + replies.
5. Composer sends new replies under the parent message.
6. Live updates flow automatically via UI Kit.
@@ -163,12 +266,25 @@ messageList.setOnThreadRepliesClick((context, baseMessage, template) -> {
In `UserDetailActivity`, detect and toggle UI:
-```java
+
+
+```kotlin lines
+if (user.isBlockedByMe) {
+ composer.visibility = View.GONE
+ unblockLayout.visibility = View.VISIBLE
+}
+```
+
+
+
+```java lines
if (user.isBlockedByMe()) {
composer.setVisibility(View.GONE);
unblockLayout.setVisibility(View.VISIBLE);
}
```
+
+
**File reference:**
[`UserDetailActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/UserDetailsActivity.java)
@@ -187,9 +303,9 @@ if (user.isBlockedByMe()) {
| Feature | Component / Method |
|---------------------------|------------------------------------------------------|
| Show thread option | `setOnThreadRepliesClick()` |
-| Display thread messages | `messageList.setParentMessage(messageId)` |
-| Show parent message | `header.setMessage(parentMessage)` |
-| Compose reply | `composer.setParentMessageId(messageId)` |
+| Display thread messages | `messageList.setParentMessage(parentMessage.getId())`|
+| Show parent message | `header.setParentMessage(parentMessage)` |
+| Compose reply | `composer.setParentMessageId(parentMessage.getId())` |
| Handle blocked users | `isBlockedByMe()`, hide composer + show unblock UI |
## Next Steps & Further Reading
diff --git a/ui-kit/android/incoming-call.mdx b/ui-kit/android/incoming-call.mdx
index b8ae8e962..135d09368 100644
--- a/ui-kit/android/incoming-call.mdx
+++ b/ui-kit/android/incoming-call.mdx
@@ -2,408 +2,471 @@
title: "Incoming Call"
---
-## Overview
+`CometChatIncomingCall` displays a full-screen incoming call banner with the caller's avatar, name, call type, and accept/reject buttons.
+
+## AI Agent Component Spec
+
+
+
+```json
+{
+ "component": "CometChatIncomingCall",
+ "package": "com.cometchat.chatuikit.calls.incomingcall",
+ "xmlElement": "",
+ "description": "Full-screen incoming call banner with caller avatar, name, call type indicator, and accept/reject buttons.",
+ "primaryOutput": {
+ "method": "setOnAcceptClick",
+ "type": "OnClick"
+ },
+ "methods": {
+ "data": {
+ "setCall": {
+ "type": "Call",
+ "note": "Required. Sets the Call object so accept/reject actions work correctly."
+ }
+ },
+ "callbacks": {
+ "setOnAcceptClick": "OnClick",
+ "setOnRejectClick": "OnClick",
+ "setOnError": "OnError"
+ },
+ "functionality": {
+ "disableSoundForCalls": { "type": "boolean", "default": "false" },
+ "setCustomSoundForCalls": { "type": "@RawRes int", "default": "SDK default ringtone" }
+ },
+ "viewSlots": {
+ "setItemView": "View — entire incoming call card",
+ "setLeadingView": "View — avatar / left section",
+ "setTitleView": "View — caller name / title text",
+ "setSubtitleView": "View — subtitle text below name",
+ "setTrailingView": "View — right section"
+ },
+ "advanced": {
+ "setCall": "Call — sets the call object (required)",
+ "setCallSettingsBuilder": "CometChatCalls.CallSettingsBuilder — custom call settings",
+ "getViewModel": "IncomingCallViewModel — internal ViewModel access",
+ "getBinding": "CometchatIncomingCallComponentBinding — root ViewBinding"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatIncomingCallStyle"
+ }
+ }
+ },
+ "events": [
+ {
+ "name": "CometChatCallEvents.ccCallAccepted",
+ "payload": "Call",
+ "description": "A call was accepted"
+ },
+ {
+ "name": "CometChatCallEvents.ccCallRejected",
+ "payload": "Call",
+ "description": "A call was rejected"
+ }
+ ],
+ "sdkListeners": [
+ "onIncomingCallReceived",
+ "onIncomingCallCancelled"
+ ]
+}
+```
-The `CometChatIncomingCall` is a [Component](/ui-kit/android/components-overview#components) that serves as a visual representation when the user receives an incoming call, such as a voice call or video call, providing options to answer or decline the call.
+
-
-
-
+## Where It Fits
-***
+`CometChatIncomingCall` is a call-handling component. It renders when the logged-in user receives an incoming voice or video call, displaying the caller's information and providing accept/reject controls. Wire it to `CometChatOngoingCallActivity` after the user accepts the call.
-## Usage
+
+
+```kotlin CallHandlerActivity.kt lines
+class CallHandlerActivity : AppCompatActivity() {
-### Integration
+ private lateinit var incomingCall: CometChatIncomingCall
-`CometChatIncomingCall` being a custom component, offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application.
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_call_handler)
-Since `CometChatIncomingCall` can be launched by adding the following code snippet into the XML layout file.
+ incomingCall = findViewById(R.id.incoming_call)
-
-
-```xml
-
-```
+ // Set the Call object received from CometChat SDK
+ incomingCall.setCall(call)
+ incomingCall.setOnAcceptClick {
+ // Navigate to ongoing call screen
+ }
+
+ incomingCall.setOnRejectClick {
+ // Dismiss the incoming call screen
+ finish()
+ }
+ }
+}
+```
-
+
+```java CallHandlerActivity.java lines
+public class CallHandlerActivity extends AppCompatActivity {
-If you're defining the `CometChatIncomingCall` within the XML code or in your activity or fragment then you'll need to extract them and set them on the User object using the appropriate method.
+ private CometChatIncomingCall incomingCall;
-
-
-```java
-CometChatIncomingCall cometchatIncomingCall = binding.incomingCall; // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(getLayoutInflater());` to use views like `binding.incomingCall` after enabling view binding.
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_call_handler);
-User user = new User();
-user.setUid(""); //Required
-user.setName(""); //Required
-user.setAvatar(""); //Required
+ incomingCall = findViewById(R.id.incoming_call);
-cometchatIncomingCall.setUser(user); //Required - set the user object
-```
+ // Set the Call object received from CometChat SDK
+ incomingCall.setCall(call);
+ incomingCall.setOnAcceptClick(() -> {
+ // Navigate to ongoing call screen
+ });
+
+ incomingCall.setOnRejectClick(() -> {
+ // Dismiss the incoming call screen
+ finish();
+ });
+ }
+}
+```
+
-
-```kotlin
-val cometchatIncomingCall: CometChatIncomingCall = binding.incomingCall // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(layoutInflater)` to use views like `binding.incomingCall` after enabling view binding.
+## Quick Start
-val user = User()
-user.uid = "" //Required
-user.name = "" //Required
-user.avatar = "" //Required
+Add the component to your layout XML:
-cometchatIncomingCall.setUser(user) //Required - set the user object
+```xml layout_activity.xml lines
+
```
-
-
-
+
+
+
-##### Activity and Fragment
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.
-You can integrate `CometChatIncomingCall` into your Activity and Fragment by adding the following code snippets into the respective classes.
+In your Activity, get a reference and set the `Call` object:
-
-```java YourActivity.java
-CometChatIncomingCall cometchatIncomingCall;
+
+```kotlin YourActivity.kt lines
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.layout_activity)
+
+ val incomingCall = findViewById(R.id.incoming_call)
+ incomingCall.setCall(call) // Required — pass the Call object from the SDK
+}
+```
+
+
+```java YourActivity.java lines
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.layout_activity);
- cometchatIncomingCall = new CometChatIncomingCall(this);
-
- User user = new User();
- user.setUid(""); //Required
- user.setName(""); //Required
- user.setAvatar(""); //Required
-
- cometchatIncomingCall.setUser(user); //Required - set the user object
-
- setContentView(cometchatIncomingCall);
+ CometChatIncomingCall incomingCall = findViewById(R.id.incoming_call);
+ incomingCall.setCall(call); // Required — pass the Call object from the SDK
}
```
-
+
+
+To add programmatically in an Activity:
-
-```kotlin YourActivity.kt
+
+
+```kotlin YourActivity.kt lines
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- cometchatIncomingCall = CometChatIncomingCall(this)
-
- val user = User()
- user.uid = "" //Required
- user.name = "" //Required
- user.avatar = "" //Required
-
- cometchatIncomingCall.setUser(user) //Required - set the user object
-
- setContentView(cometchatIncomingCall)
+ val incomingCall = CometChatIncomingCall(this)
+ incomingCall.setCall(call)
+ setContentView(incomingCall)
}
```
-
-
-```java YourFragment.java
-CometChatIncomingCall cometchatIncomingCall;
-
+
+```java YourActivity.java lines
@Override
-public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- cometchatIncomingCall = new CometChatIncomingCall(requireContext());
-
- User user = new User();
- user.setUid(""); //Required
- user.setName(""); //Required
- user.setAvatar(""); //Required
-
- cometchatIncomingCall.setUser(user); //Required - set the user object
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- return cometchatIncomingCall;
+ CometChatIncomingCall incomingCall = new CometChatIncomingCall(this);
+ incomingCall.setCall(call);
+ setContentView(incomingCall);
}
```
-
+
-
-```kotlin YourFragment.kt
-private lateinit var cometchatIncomingCall: CometChatIncomingCall
-
-override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
-): View {
- cometchatIncomingCall = CometChatIncomingCall(requireContext())
-
- val user = User()
- user.uid = "" //Required
- user.name = "" //Required
- user.avatar = "" //Required
-
- cometchatIncomingCall.setUser(user) //Required - set the user object
+Or in a Fragment:
- return cometchatIncomingCall
+
+
+```kotlin YourFragment.kt lines
+override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ val incomingCall = CometChatIncomingCall(requireContext())
+ incomingCall.setCall(call)
+ return incomingCall
}
```
-
+
+```java YourFragment.java lines
+@Override
+public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ CometChatIncomingCall incomingCall = new CometChatIncomingCall(getContext());
+ incomingCall.setCall(call);
+ return incomingCall;
+}
+```
+
-***
-
-### Actions
+## Actions and Events
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+### Callback Methods
-##### setOnAcceptClick
+#### `setOnAcceptClick`
-The `setOnAcceptClick` action is typically triggered when the user clicks on the accept button, initiating a predefined action. However, by implementing the following code snippet, you can easily customize or override this default behavior to suit your specific requirements.
+Fires when the user taps the accept button. Override this to replace the default call-accept behavior.
+
+```kotlin YourActivity.kt lines
+cometchatIncomingCall.setOnAcceptClick {
+ // Custom accept logic
+}
+```
+
+
-```java
+```java YourActivity.java lines
cometchatIncomingCall.setOnAcceptClick(new OnClick() {
@Override
public void onClick() {
- //TODO
+ // Custom accept logic
}
});
```
-
-
-
-```kotlin
-cometchatIncomingCall.setOnAcceptCallClick(OnClick {
- //TODO
-})
-```
-
-
-
-***
+> **What this does:** Replaces the default accept-button behavior. When the user taps the accept button, your custom `OnClick` lambda executes instead of the built-in call-accept logic.
-##### setOnRejectClick
+#### `setOnRejectClick`
-The `setOnRejectClick` action is typically triggered when the user clicks on the reject button, initiating a predefined action. However, by implementing the following code snippet, you can easily customize or override this default behavior to suit your specific requirements.
+Fires when the user taps the reject button. Override this to replace the default call-reject behavior.
+
+```kotlin YourActivity.kt lines
+cometchatIncomingCall.setOnRejectClick {
+ // Custom reject logic
+}
+```
+
+
-```java
+```java YourActivity.java lines
cometchatIncomingCall.setOnRejectClick(new OnClick() {
@Override
public void onClick() {
- //TODO
+ // Custom reject logic
}
});
```
-
-
-
-
-```kotlin
-cometchatIncomingCall.setOnDeclineCallClick(OnClick {
- //TODO
-})
-```
-
-
-##### setOnError
+> **What this does:** Replaces the default reject-button behavior. When the user taps the reject button, your custom `OnClick` lambda executes instead of the built-in call-decline logic.
+
+#### `setOnError`
-You can customize this behavior by using the provided code snippet to override the `setOnError` and improve error handling.
+Fires on internal errors (network failure, call failure, SDK exception).
-
-```java
-cometchatIncomingCall.setOnError(new OnError() {
- @Override
- public void onError(Context context, CometChatException e) {
- //TODO
- }
-});
+
+```kotlin YourActivity.kt lines
+cometchatIncomingCall.setOnError { cometchatException ->
+ // Handle error
+}
```
-
-
-```kotlin
-cometchatIncomingCall.setOnError(OnError { context, e ->
- //TODO
-})
+
+```java YourActivity.java lines
+cometchatIncomingCall.setOnError(cometchatException -> {
+ // Handle error
+});
```
-
-
-***
-
-### Filters
-
-**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK.
+> **What this does:** Registers an error listener. If the component encounters an error, your callback receives the `CometChatException` so you can handle it with custom logic.
-The IncomingCall component does not have any exposed filters.
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap accept, tap reject) and confirm your custom logic executes instead of the default behavior.
-***
+### Global UI Events (CometChatCallEvents)
-### Events
+`CometChatCallEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed.
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed.
+| Event | Fires when | Payload |
+| --- | --- | --- |
+| `ccCallAccepted` | A call is accepted | `Call` |
+| `ccCallRejected` | A call is rejected | `Call` |
+| `ccCallEnded` | A call is ended | `Call` |
+| `ccOutgoingCall` | An outgoing call is initiated | `Call` |
-The `CometChatIncomingCall` component does not have any exposed events.
-
-***
-
-## Customization
-
-To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
-
-### Style
-
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
-
-##### 1. IncomingCall Style
+
+
+```kotlin Add Listener lines
+CometChatCallEvents.addListener("LISTENER_TAG", object : CometChatCallEvents() {
+ override fun ccCallAccepted(call: Call?) {
+ super.ccCallAccepted(call)
+ }
-You can customize the appearance of the `IncomingCall` Component by applying the `IncomingCallStyle` to it using the following code snippet.
+ override fun ccCallRejected(call: Call?) {
+ super.ccCallRejected(call)
+ }
-
-
-
+ override fun ccCallEnded(call: Call?) {
+ super.ccCallEnded(call)
+ }
+})
+```
-```xml themes.xml
-
+Remove Listener
-
```
+CometChatCallEvents.removeListener("LISTENER_TAG")
+```
+
-
-```java
-cometchatIncomingCall.setStyle(R.style.CustomIncomingCallStyle);
-```
+```java Add Listener lines
+CometChatCallEvents.addListener("LISTENER_TAG", new CometChatCallEvents() {
+ @Override
+ public void ccCallAccepted(Call call) {
+ super.ccCallAccepted(call);
+ }
-
+ @Override
+ public void ccCallRejected(Call call) {
+ super.ccCallRejected(call);
+ }
-
-```kotlin
-cometchatIncomingCall.setStyle(R.style.CustomIncomingCallStyle)
+ @Override
+ public void ccCallEnded(Call call) {
+ super.ccCallEnded(call);
+ }
+});
```
-
+Remove Listener
+```
+CometChatCallEvents.removeListener("LISTENER_TAG");
+```
+
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_incoming_call.xml).
-
-### Functionality
+### SDK Events
-In this example, we're enhancing the interface by customizing the accept and decline button icons. By setting custom icons for both the accept and decline buttons, users can enjoy a more visually appealing and personalized experience.
+The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.
-Below is a list of customizations along with corresponding code snippets
+| SDK Listener | Internal behavior |
+| --- | --- |
+| `onIncomingCallReceived` | Triggers the incoming call screen display |
+| `onIncomingCallCancelled` | Dismisses the incoming call screen |
-| Property | Description | Code |
-| -------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------- |
-| **setCall** | Sets the Call object for which the incoming call screen is displayed. Required for call actions. | `.setCall(call)` |
-| **setCustomSoundForCalls** | Defines the path for custom sound for calls on the incoming call screen. | `.setCustomSoundForCalls(@RawRes int)` |
-| **disableSoundForCalls** | Defines whether to disable sound for the call on the incoming call screen. | `.disableSoundForCalls(true)` |
+> Automatic: call state changes update the component in real time.
-***
+## Functionality
-### Advanced
+Small functional customizations such as toggling call sounds and setting custom ringtones.
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
+| Method | Description | Code |
+| --- | --- | --- |
+| `disableSoundForCalls` | Disables the ringtone for incoming calls | `.disableSoundForCalls(true);` |
+| `setCustomSoundForCalls` | Sets a custom ringtone from `res/raw` | `.setCustomSoundForCalls(R.raw.custom_ringtone);` |
-#### setItemView
+- **Verify**: After calling `disableSoundForCalls(true)`, confirm no ringtone plays on incoming calls. After calling `setCustomSoundForCalls`, confirm the custom sound plays.
-Allows setting a custom view for rendering each conversation item in the fetched list.
+## Custom View Slots
-Use Cases:
+Each slot replaces a section of the default UI. IncomingCall view slots accept plain `View` objects (not `ViewHolderListener`).
-* Customize the call card UI for incoming calls.
-* Display additional user details (e.g., caller ID, location).
-* Integrate custom animations for call alerts.
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Item view | `setItemView(View)` | Entire incoming call card |
+| Leading view | `setLeadingView(View)` | Avatar / left section |
+| Title view | `setTitleView(View)` | Caller name / title text |
+| Subtitle view | `setSubtitleView(View)` | Subtitle text below name |
+| Trailing view | `setTrailingView(View)` | Right section |
-
-
-```java YourActivity.java
-cometchatIncomingCall.setItemView(view);
-```
+### `setItemView`
-
+Replace the entire incoming call card with a custom view.
+
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
cometchatIncomingCall.setItemView(view)
```
-
+
+```java YourActivity.java lines
+cometchatIncomingCall.setItemView(view);
+```
+
-#### setLeadingView
+> **What this does:** Replaces the entire default incoming call card with your custom `View`. The custom view is responsible for rendering all caller information and call controls.
-Customizes the leading section of the component, usually the caller’s avatar or profile picture.
+### `setLeadingView`
-Use Cases:
-
-* Display a profile picture with call status effects.
-* Show a custom ringing animation around the avatar.
-* Replace the avatar with a caller ID card.
+Replace the avatar / left section.
-
-```java YourActivity.java
-cometchatIncomingCall.setLeadingView(view);
-```
-
-
-
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
cometchatIncomingCall.setLeadingView(view)
```
-
+
+```java YourActivity.java lines
+cometchatIncomingCall.setLeadingView(view);
+```
+
+> **What this does:** Replaces the default leading (left) area of the incoming call screen with your custom `View`.
+
Example:
-```xml leading_view.xml
+```xml leading_view.xml lines
+
+```kotlin YourActivity.kt lines
+val leadingView: View = LayoutInflater.from(this).inflate(R.layout.leading_view, null)
+val avatar = leadingView.findViewById(R.id.avatar)
+val callUser = call.callInitiator as User
+avatar.setAvatar(callUser.name, callUser.avatar)
+leadingView.layoutParams = LinearLayout.LayoutParams(
+ Utils.convertDpToPx(this, 45),
+ Utils.convertDpToPx(this, 45)
+)
+cometchatIncomingCall.setTrailingView(null)
+cometchatIncomingCall.setLeadingView(leadingView)
+```
+
+
-```java YourActivity.java
- View leadingView = LayoutInflater.from(getContext()).inflate(R.layout.leading_view, null);
+```java YourActivity.java lines
+View leadingView = LayoutInflater.from(this).inflate(R.layout.leading_view, null);
CometChatAvatar avatar = leadingView.findViewById(R.id.avatar);
User callUser = (User) call.getCallInitiator();
avatar.setAvatar(callUser.getName(), callUser.getAvatar());
leadingView.setLayoutParams(new LinearLayout.LayoutParams(
- Utils.convertDpToPx(requireContext(), 45),
- Utils.convertDpToPx(requireContext(), 45)
- ));
+ Utils.convertDpToPx(this, 45),
+ Utils.convertDpToPx(this, 45)
+));
cometchatIncomingCall.setTrailingView(null);
cometchatIncomingCall.setLeadingView(leadingView);
```
-
-
-
-
-```kotlin YourActivity.kt
-val leadingView: View = LayoutInflater.from(this).inflate(android.R.layout.leading_view, null)
-val avatar = leadingView.findViewById(android.R.id.avatar)
-val callUser = call.getCallInitiator()
-avatar.setAvatar(callUser.name, callUser.avatar)
-leadingView.layoutParams = LinearLayout.LayoutParams(
- Utils.convertDpToPx(this, 45),
- Utils.convertDpToPx(this, 45)
- )
-cometchatIncomingCall.setTrailingView(null);
-cometchatIncomingCall.setLeadingView(leadingView)
-```
-
-
-***
-
-#### setTitleView
+### `setTitleView`
-Allows setting a custom title view, typically used for the caller’s name or call type.
-
-Use Cases:
-
-* Display the caller’s full name with a verified badge.
-* Indicate the call type (Voice Call, Video Call).
-* Show real-time status ("Ringing...", "Call from Work Contact", etc.).
+Replace the caller name / title text.
-
-```java YourActivity.java
-cometchatIncomingCall.setTitleView(view);
-```
-
-
-
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
cometchatIncomingCall.setTitleView(view)
```
-
+
+```java YourActivity.java lines
+cometchatIncomingCall.setTitleView(view);
+```
+
+> **What this does:** Replaces the default title area of the incoming call screen with your custom `View`.
+
Example:
-```xml custom_title_view.xml
+```xml custom_title_view.xml lines
+
+```kotlin YourActivity.kt lines
+val titleView: View = LayoutInflater.from(this).inflate(R.layout.custom_title_view, null)
+val title = titleView.findViewById(R.id.title)
+title.text = "George Allen"
+titleView.layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+)
+cometchatIncomingCall.setTitleView(titleView)
+```
+
+
-```java YourActivity.java
- View titleView = LayoutInflater.from(this).inflate(R.layout.custom_title_view, null);
+```java YourActivity.java lines
+View titleView = LayoutInflater.from(this).inflate(R.layout.custom_title_view, null);
TextView title = titleView.findViewById(R.id.title);
title.setText("George Allen");
titleView.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- ));
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+));
cometchatIncomingCall.setTitleView(titleView);
```
-
-
-
-
-```kotlin YourActivity.kt
- val titleView: View = LayoutInflater.from(this).inflate(R.layout.custom_title_view, null)
- val title = titleView.findViewById(R.id.title)
- title.text = "George Allen"
- titleView.layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
-cometchatIncomingCall.setTitleView(titleView)
-```
-
-
-***
+### `setSubtitleView`
-#### setSubtitleView
-
-Enables customizing the subtitle view, typically used for additional call details.
-
-Use Cases:
-
-* Display call duration if available.
-* Show network strength indicators.
-* Include a custom message like "Connecting...".
+Replace the subtitle text below the caller's name.
-
-```java YourActivity.java
-cometchatIncomingCall.setSubtitleView(view);
-```
-
-
-
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
cometchatIncomingCall.setSubtitleView(view)
```
-
+
+```java YourActivity.java lines
+cometchatIncomingCall.setSubtitleView(view);
+```
+
-***
-
-#### setTrailingView
+> **What this does:** Replaces the default subtitle area of the incoming call screen with your custom `View`. Use this to show additional information below the caller's name.
-Customizes the trailing section for actions or additional call-related UI elements.
+### `setTrailingView`
-Use Cases:
-
-* Add custom accept/reject buttons.
-* Show a mute button before answering.
-* Display a text response option (e.g., "Can’t talk now")
+Replace the right section of the incoming call card.
-
-```java YourActivity.java
-cometchatIncomingCall.setTrailingView(view);
-```
-
-
-
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
cometchatIncomingCall.setTrailingView(view)
```
-
+
+```java YourActivity.java lines
+cometchatIncomingCall.setTrailingView(view);
+```
+
+> **What this does:** Replaces the default trailing (right) area of the incoming call screen with your custom `View`.
+
Example:
-trailing\_view\.xml
-
-```xml trailing_view.xml
+```xml trailing_view.xml lines
+
+```kotlin YourActivity.kt lines
+val trailingView: View = LayoutInflater.from(this).inflate(R.layout.trailing_view, null)
+val avatar = trailingView.findViewById(R.id.avatar)
+val callUser = call.callInitiator as User
+if (callUser.tags.contains("pro_user")) {
+ avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.pro_user, null)!!)
+}
+avatar.setAvatar(callUser.name, callUser.avatar)
+trailingView.layoutParams = LinearLayout.LayoutParams(
+ Utils.convertDpToPx(this, 45),
+ Utils.convertDpToPx(this, 45)
+)
+cometchatIncomingCall.setTrailingView(trailingView)
+```
+
+
-```java YourActivity.java
-View trailingView = LayoutInflater.from(getContext()).inflate(R.layout.trailing_view, null);
+```java YourActivity.java lines
+View trailingView = LayoutInflater.from(this).inflate(R.layout.trailing_view, null);
CometChatAvatar avatar = trailingView.findViewById(R.id.avatar);
User callUser = (User) call.getCallInitiator();
-if(callUser.getTags().contains("pro_user")){
- avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.pro_user, null));
- }
+if (callUser.getTags().contains("pro_user")) {
+ avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.pro_user, null));
+}
avatar.setAvatar(callUser.getName(), callUser.getAvatar());
trailingView.setLayoutParams(new LinearLayout.LayoutParams(
- Utils.convertDpToPx(requireContext(), 45),
- Utils.convertDpToPx(requireContext(), 45)
- ));
+ Utils.convertDpToPx(this, 45),
+ Utils.convertDpToPx(this, 45)
+));
cometchatIncomingCall.setTrailingView(trailingView);
```
+
+
+
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position on the incoming call screen and displays the expected caller information.
+
+## Common Patterns
+
+### Silent incoming call
+
+
+
+```kotlin lines
+cometchatIncomingCall.disableSoundForCalls(true)
+```
+
+
+
+```java lines
+cometchatIncomingCall.disableSoundForCalls(true);
+```
+
+
+
+### Custom ringtone
+
+
+
+```kotlin lines
+cometchatIncomingCall.setCustomSoundForCalls(R.raw.my_ringtone)
+```
+
+
+```java lines
+cometchatIncomingCall.setCustomSoundForCalls(R.raw.my_ringtone);
+```
+
+
+### Custom call settings
+
-```kotlin YourActivity.kt
-val trailingView: View = LayoutInflater.from(this).inflate(R.layout.trailing_view, null)
-val avatar = trailingView.findViewById(R.id.avatar)
-val callUser = call.getCallInitiator()
-if (callUser.tags.contains("pro_user")) {
- avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.pro_user, null)!!)
- }
-avatar.setAvatar(callUser.name, callUser.avatar)
-trailingView.layoutParams = LinearLayout.LayoutParams(
- Utils.convertDpToPx(this, 45),
- Utils.convertDpToPx(this, 45)
- )
-cometchatIncomingCall.setTrailingView(trailingView)
+```kotlin lines
+val callSettingsBuilder = CometChatCalls.CallSettingsBuilder(this, true)
+ .setDefaultAudioMode("SPEAKER")
+cometchatIncomingCall.setCallSettingsBuilder(callSettingsBuilder)
+```
+
+
+
+```java lines
+CometChatCalls.CallSettingsBuilder callSettingsBuilder = new CometChatCalls.CallSettingsBuilder(this, true)
+ .setDefaultAudioMode("SPEAKER");
+cometchatIncomingCall.setCallSettingsBuilder(callSettingsBuilder);
```
+
+
+
+### Override accept to add logging
+
+
+```kotlin lines
+cometchatIncomingCall.setOnAcceptClick {
+ Log.d("IncomingCall", "Call accepted by user")
+ // Proceed with default accept via ViewModel
+ cometchatIncomingCall.viewModel.acceptCall(call)
+}
+```
+
+```java lines
+cometchatIncomingCall.setOnAcceptClick(() -> {
+ Log.d("IncomingCall", "Call accepted by user");
+ // Proceed with default accept via ViewModel
+ cometchatIncomingCall.getViewModel().acceptCall(call);
+});
+```
+
-***
+## Advanced Methods
+
+### `setCall`
+
+Sets the `Call` object for the incoming call screen. Required for accept/reject actions to work correctly. The component extracts the caller's name, avatar, and call type from this object.
+
+
+
+```kotlin lines
+cometchatIncomingCall.setCall(call)
+```
+
+
+
+```java lines
+cometchatIncomingCall.setCall(call);
+```
+
+
+
+### `setCallSettingsBuilder`
+
+Provides a custom `CallSettingsBuilder` to configure call settings (audio mode, video resolution, etc.) used when the call is accepted.
+
+
+
+```kotlin lines
+val builder = CometChatCalls.CallSettingsBuilder(this, true)
+cometchatIncomingCall.setCallSettingsBuilder(builder)
+```
+
+
+
+```java lines
+CometChatCalls.CallSettingsBuilder builder = new CometChatCalls.CallSettingsBuilder(this, true);
+cometchatIncomingCall.setCallSettingsBuilder(builder);
+```
+
+
+
+### Internal Access
+
+These methods provide direct access to internal components for advanced use cases.
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getViewModel()` | `IncomingCallViewModel` | The ViewModel managing call state and actions |
+| `getBinding()` | `CometchatIncomingCallComponentBinding` | The ViewBinding for the component's root layout |
+
+> Use these only when the standard API is insufficient. Directly manipulating the ViewModel or binding may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatIncomingCallStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
+
+```xml themes.xml lines
+
+
+
+```
+
+
+
+```kotlin lines
+cometchatIncomingCall.setStyle(R.style.CustomIncomingCallStyle)
+```
+
+
+
+```java lines
+cometchatIncomingCall.setStyle(R.style.CustomIncomingCallStyle);
+```
+
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_incoming_call.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setTitleTextColor` | `@ColorInt int` | Text color for the caller name |
+| `setTitleTextAppearance` | `@StyleRes int` | Text appearance for the caller name |
+| `setSubtitleTextColor` | `@ColorInt int` | Text color for the call type subtitle |
+| `setSubtitleTextAppearance` | `@StyleRes int` | Text appearance for the call type subtitle |
+| `setIconTint` | `@ColorInt int` | Tint color for the call type icon |
+| `setVoiceCallIcon` | `Drawable` | Custom icon for voice calls |
+| `setVideoCallIcon` | `Drawable` | Custom icon for video calls |
+| `setAcceptCallButtonBackgroundColor` | `@ColorInt int` | Background color for the accept button |
+| `setRejectCallButtonBackgroundColor` | `@ColorInt int` | Background color for the reject button |
+| `setAcceptButtonTextColor` | `@ColorInt int` | Text color for the accept button |
+| `setRejectButtonTextColor` | `@ColorInt int` | Text color for the reject button |
+| `setAcceptButtonTextAppearance` | `@StyleRes int` | Text appearance for the accept button |
+| `setRejectButtonTextAppearance` | `@StyleRes int` | Text appearance for the reject button |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component card |
+| `setStrokeWidth` | `@Dimension int` | Stroke width of the component border |
+| `setStrokeColor` | `@ColorInt int` | Stroke color of the component border |
+| `setAvatarStyle` | `@StyleRes int` | Style for the caller avatar |
+
+- **Verify**: The incoming call screen displays with a purple background (`#AA9EE8`), custom button colors, and avatars with rounded corners (8dp radius) and an orange background (`#FBAA75`).
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Background color | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallBackgroundColor` | `#AA9EE8` |
+| Icon tint | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallIconTint` | `?attr/cometchatPrimaryColor` |
+| Reject button background | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallRejectButtonBackgroundColor` | `?attr/cometchatColorWhite` |
+| Accept button background | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallAcceptButtonBackgroundColor` | `?attr/cometchatPrimaryColor` |
+| Reject button text color | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallRejectButtonTextColor` | `?attr/cometchatErrorColor` |
+| Accept button text color | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallAcceptButtonTextColor` | `?attr/cometchatColorWhite` |
+| Reject button text appearance | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallRejectButtonTextAppearance` | `?attr/cometchatTextAppearanceButtonMedium` |
+| Accept button text appearance | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallAcceptButtonTextAppearance` | `?attr/cometchatTextAppearanceButtonMedium` |
+| Avatar style | `themes.xml` | `CometChatIncomingCallStyle` with `cometchatIncomingCallAvatarStyle` | `@style/CustomAvatarStyle` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometchatIncomingCall.setStyle(R.style.CustomIncomingCallStyle);` |
+| Call object | Activity/Fragment | `setCall(Call)` | `.setCall(call)` |
+| Custom call sound | Activity/Fragment | `setCustomSoundForCalls(@RawRes int)` | `.setCustomSoundForCalls(R.raw.custom_ringtone);` |
+| Disable call sound | Activity/Fragment | `disableSoundForCalls(boolean)` | `.disableSoundForCalls(true)` |
+| Call settings | Activity/Fragment | `setCallSettingsBuilder(CallSettingsBuilder)` | `.setCallSettingsBuilder(builder)` |
+| Accept button action | Activity/Fragment | `setOnAcceptClick(OnClick)` | See `setOnAcceptClick` code above |
+| Reject button action | Activity/Fragment | `setOnRejectClick(OnClick)` | See `setOnRejectClick` code above |
+| Error handler | Activity/Fragment | `setOnError(OnError)` | See `setOnError` code above |
+| Entire call card view | Activity/Fragment | `setItemView(View)` | `cometchatIncomingCall.setItemView(view);` |
+| Leading view (avatar area) | Activity/Fragment | `setLeadingView(View)` | See `setLeadingView` code above |
+| Title view (caller name) | Activity/Fragment | `setTitleView(View)` | See `setTitleView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(View)` | `cometchatIncomingCall.setSubtitleView(view);` |
+| Trailing view | Activity/Fragment | `setTrailingView(View)` | See `setTrailingView` code above |
+
+## Accessibility
+
+The component renders a full-screen incoming call card with interactive accept and reject buttons. The caller's avatar includes the caller name as content description. The accept and reject buttons are labeled for screen readers.
+
+For custom views provided via `setLeadingView`, `setTitleView`, `setSubtitleView`, or `setTrailingView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+The call type icon (voice/video) is visual-only by default. If screen reader descriptions are needed, provide them via a custom view with appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Incoming call screen is blank | Verify that you call `setCall(call)` with a valid `Call` object. The component extracts the caller's name, avatar, and call type from the `Call` object. |
+| Accept or reject button does nothing | Ensure you call `setCall(call)` with a valid `Call` object. If no `Call` object is set, the accept and reject buttons cannot trigger call actions. |
+| Custom style not visible | Verify the style parent is `CometChatIncomingCallStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| Sound still plays after disabling | Ensure you call `disableSoundForCalls(true)` before the component starts loading. If called after the incoming call is already ringing, it may not take effect. |
+| Custom sound not playing | Verify the sound file exists in your `res/raw` directory and that you pass the correct `@RawRes int` resource ID to `setCustomSoundForCalls`. |
+| `setOnAcceptClick` not firing | Verify you are calling `setOnAcceptClick` on the correct `CometChatIncomingCall` instance. If you have multiple instances, the callback may be set on the wrong one. |
+| Custom leading view not showing | If you set a custom leading view but it does not appear, verify that the view is inflated correctly and has valid layout parameters. A view with zero width or height will not be visible. |
+
+## FAQ
+
+**Q: How do I display the incoming call screen when a call is received?**
+**A:** Add `CometChatIncomingCall` to your layout via XML or programmatically in an Activity/Fragment. Set the `Call` object with `setCall(call)` to display the caller's information and enable accept/reject actions.
+
+**Q: Can I use `CometChatIncomingCall` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, create the instance with `CometChatIncomingCall(this)` and call `setContentView`. In a Fragment, create it with `CometChatIncomingCall(requireContext())` and return it from `onCreateView`.
+
+**Q: How do I customize the accept and reject button colors?**
+**A:** Define a custom style with parent `CometChatIncomingCallStyle` in `themes.xml`. Set `cometchatIncomingCallAcceptButtonBackgroundColor` and `cometchatIncomingCallRejectButtonBackgroundColor` to your desired colors, then apply the style with `setStyle()`.
+
+**Q: Does `CometChatIncomingCall` emit any global events?**
+**A:** The component itself does not emit events, but you can listen for call-related events via `CometChatCallEvents.addListener()` to handle `ccCallAccepted`, `ccCallRejected`, and `ccCallEnded`.
+
+**Q: What is the difference between `setCall` and the old `setUser` method?**
+**A:** `setCall(Call)` is the correct method. It accepts a `Call` object from the CometChat SDK, which contains the caller's user information, call type, and session ID needed for accept/reject actions.
+
+## Next Steps
+
+- [Outgoing Call component](/ui-kit/android/outgoing-call)
+- [Call Buttons component](/ui-kit/android/call-buttons)
+- [Call Logs component](/ui-kit/android/call-logs)
\ No newline at end of file
diff --git a/ui-kit/android/localize.mdx b/ui-kit/android/localize.mdx
index 6bf2205bc..b72791cce 100644
--- a/ui-kit/android/localize.mdx
+++ b/ui-kit/android/localize.mdx
@@ -2,121 +2,372 @@
title: "Localize"
---
-## Overview
-
-CometChat UI Kit provides language localization to adapt to the language of a specific country or region. The CometChatLocalize class allows you to detect the language of your users based on their browser or device settings, and set the language accordingly.
-
-CometChatLocalize is a class that includes methods related to locale. Developers can use these methods to change the language of the UI Kit library.
-
-Presently, the UI Kit supports 19 languages for localization, which are:
-
-* English (en, en-US, en-GB)
-* Chinese (zh, zh-TW)
-* Spanish (es)
-* Hindi (hi)
-* Russian (ru)
-* Portuguese (pt)
-* Malay (ms)
-* French (fr)
-* German (de)
-* Swedish (sv)
-* Lithuanian (lt)
-* Hungarian (hu)
-* Italian (it)
-* Korean (ko)
-* Japanese (ja)
-* Dutch (nl)
-* Turkish (tr)
-
-## Methods
-
-Here are the methods included in the CometChatLocalize class:
-
-* `setLocale(Activity activity, @Language.Code String language)`: This method is used to set the language in the UI Kit. It will take the constant value from the Language class and set the value accordingly.
-
-* `getLocale()`: This method is used to get the current language. By default, it will return the current language from the device/browser.
-
-## Usage
-
-Here is how you can put these methods into use:
+Set the CometChat UI Kit language and override UI text so your Android app matches your users' locale.
+
+## When to use this
+- You want the UI Kit to follow the device language.
+- You want to force a specific language regardless of device settings.
+- You need to override default UI Kit labels with brand-specific wording.
+- You want consistent date and time labels across all UI Kit screens.
+
+## Prerequisites
+- CometChat UI Kit for Android is installed and initialized. Use [Getting Started](/ui-kit/android/getting-started) if needed.
+- You can access an Android `Context` (Activity or Application) to apply locale changes.
+- You can edit `res/values/strings.xml` in your app module.
+
+## Quick start
+1. Choose a language code from Supported languages.
+2. Add a locale call before you render UI Kit screens.
+File: `app/src/main/java//LocalizeActivity.java` or `app/src/main/java//LocalizeActivity.kt`.
+Use the code in Implementation > Set and read the UI Kit locale.
+3. Override UI text keys in `res/values/strings.xml` if you need custom wording.
+4. Rebuild and run the app.
+5. Verify that UI Kit labels render in the selected language and your custom strings appear.
+
+## Core concepts
+- `CometChatLocalize`: Utility class to set and read the UI Kit locale from an Android `Context`.
+- `Language.Code`: Constants for supported language codes to use with `setLocale`.
+- `strings.xml`: Android string resources that control the visible text in UI Kit components.
+- `DateTimeFormatterCallback`: Callback interface to control date and time labels like "Today" or "X mins ago".
+
+### CometChatLocalize methods
+- `setLocale(Context context, @Language.Code String language)`: Sets the UI Kit language using a `Language.Code` value.
+- `getLocale(Context context)`: Returns the current locale country code for the provided context.
+
+### Supported languages
+UI Kit supports 19 languages for localization:
+- Arabic (`ar`)
+- Chinese (`zh`)
+- Chinese (Traditional) (`zh-TW`)
+- Dutch (`nl`)
+- English (`en`)
+- French (`fr`)
+- German (`de`)
+- Hindi (`hi`)
+- Hungarian (`hu`)
+- Italian (`it`)
+- Japanese (`ja`)
+- Korean (`ko`)
+- Lithuanian (`lt`)
+- Malay (`ms`)
+- Portuguese (`pt`)
+- Russian (`ru`)
+- Spanish (`es`)
+- Swedish (`sv`)
+- Turkish (`tr`)
+
+## Implementation
+
+### Set and read the UI Kit locale
+What you're changing: The UI Kit language for your app session.
+
+- **Where to change it**: Your Activity or Application class before UI Kit screens are rendered.
+
+- **Applies to**: All UI Kit screens.
+
+- **Default behavior**: UI Kit uses the device locale.
+
+- **Override**: Call `CometChatLocalize.setLocale(...)` with a `Language.Code` value.
+
+- **Code**:
-
-```java
-CometChatLocalize.setLocale(getActivity(), Language.Code.hi);
-
-String currentLanguage = CometChatLocalize.getLocale();
+
+```kotlin LocalizeActivity.kt lines
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.cometchat.chatuikit.shared.resources.localise.CometChatLocalize
+import com.cometchat.chatuikit.shared.resources.localise.Language
+
+class LocalizeActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ CometChatLocalize.setLocale(this, Language.Code.hi)
+ val currentLocale = CometChatLocalize.getLocale(this)
+
+ setContentView(R.layout.activity_localize)
+ }
+}
```
-
-```kotlin
-CometChatLocalize.setLocale(activity, Language.Code.hi)
-
-val currentLanguage = CometChatLocalize.getLocale()
+
+```java LocalizeActivity.java lines
+import android.os.Bundle;
+import androidx.appcompat.app.AppCompatActivity;
+import com.cometchat.chatuikit.shared.resources.localise.CometChatLocalize;
+import com.cometchat.chatuikit.shared.resources.localise.Language;
+
+public class LocalizeActivity extends AppCompatActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ CometChatLocalize.setLocale(this, Language.Code.hi);
+ String currentLocale = CometChatLocalize.getLocale(this);
+
+ setContentView(R.layout.activity_localize);
+ }
+}
```
-By using the CometChatLocalize class, you can provide a user-friendly, localized experience to your users, enhancing the overall user experience within your application.
+- **What this does**: Sets the UI Kit language to Hindi for the current context and reads the current locale value for later use.
-## Customization
+- **Verify**: Launch a UI Kit screen and confirm labels display in the selected language.
-CometChat UIKit for Android provides a set of predefined text strings used across various UI components. These strings are stored in the strings.xml resource file. To customize these strings, you can override them in your application's strings.xml file. This allows you to tailor the text displayed in different components to better fit your application's language, branding, or terminology.
+### Override UI Kit strings in `strings.xml`
+What you're changing: Visible text used by UI Kit components.
-### Steps to Customize Strings
+- **Where to change it**: `app/src/main/res/values/strings.xml` in your app module.
-1. Identify the String Key
- * Check the UIKit documentation or source code for the exact key of the string you want to modify. [String attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/strings.xml).
-2. Override the String in Your App
- * Add the key-value pair in your app’s res/values/strings.xml file.
-3. Build and Run Your App
- * The changes will automatically reflect wherever the key is used.
-4. Test Your Changes
- * Ensure the updated text appears correctly in all relevant components.
+- **Applies to**: All UI Kit components that reference the string key.
-### How It Works
+- **Default behavior**: UI Kit uses its internal `strings.xml` values.
-Each UI component in the UIKit references specific string resource keys from the `strings.xml` file. By redefining these keys in your application's strings.xml, you can change how they appear in the UIKit components.
+- **Override**: Add the same key to your app's `strings.xml` to override the label.
-Example:
+Example reference from UI Kit `strings.xml`:
-In CometChat UIKit, a string resource is defined as:
-
-```xml strings.xml
+```xml strings.xml lines
Chats
....
```
-This string is used in the `CometChatConversations` component to label the chat list. Customizing the String To change this text to "Conversations", add the following line in your app’s `res/values/strings.xml` file:
+- **What this does**: Shows the default UI Kit label for the conversations list.
+
+Override the key in your app:
-```xml strings.xml
+```xml res/values/strings.xml lines
Conversations
....
```
-Now, wherever cometchat\_chats is referenced in UIKit, it will display "Conversations" instead of the default "Chats". [String attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/strings.xml) for more such customization.
+- **What this does**: Replaces the UI Kit label with your custom text.
+
+Why use this approach:
+- No UI Kit source code changes required.
+- Easy localization using Android resources.
+- UI Kit updates do not overwrite your overrides.
+- You can tailor text without affecting behavior.
+
+### Customize date and time labels
+What you're changing: Global time and date labels such as "Today", "Yesterday", and "X mins ago".
+
+- **Where to change it**: Your UI Kit initialization (where you build `UIKitSettings`).
+
+- **Applies to**: All UI Kit screens that display timestamps.
+
+- **Default behavior**: UI Kit uses its built-in formatter.
+
+- **Override**: Provide a `DateTimeFormatterCallback` when building `UIKitSettings`.
+
+- **Code**:
+
+
+
+```kotlin AppInit.kt lines
+import android.content.Context
+import android.util.Log
+import com.cometchat.chat.core.CometChat
+import com.cometchat.chat.exceptions.CometChatException
+import com.cometchat.chatuikit.shared.cometchatuikit.CometChatUIKit
+import com.cometchat.chatuikit.shared.cometchatuikit.UIKitSettings
+import com.cometchat.chatuikit.shared.interfaces.DateTimeFormatterCallback
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+object AppInit {
+ fun initUiKitWithDateFormatter(
+ context: Context,
+ appId: String,
+ region: String,
+ authKey: String
+ ) {
+ val uiKitSettings = UIKitSettings.UIKitSettingsBuilder()
+ .setAppId(appId)
+ .setRegion(region)
+ .setDateTimeFormatterCallback(object : DateTimeFormatterCallback {
+
+ private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
+ private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
+
+ override fun time(timestamp: Long): String {
+ return fullTimeFormatter.format(Date(timestamp))
+ }
+
+ override fun today(timestamp: Long): String {
+ return "Today"
+ }
+
+ override fun yesterday(timestamp: Long): String {
+ return "Yesterday"
+ }
+
+ override fun lastWeek(timestamp: Long): String {
+ return "Last Week"
+ }
+
+ override fun otherDays(timestamp: Long): String {
+ return dateFormatter.format(Date(timestamp))
+ }
+
+ override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String {
+ return "$diffInMinutesFromNow mins ago"
+ }
+
+ override fun hours(diffInHourFromNow: Long, timestamp: Long): String {
+ return "$diffInHourFromNow hrs ago"
+ }
+ })
+ .setAuthKey(authKey)
+ .build()
+
+ CometChatUIKit.init(context, uiKitSettings, object : CometChat.CallbackListener() {
+ override fun onSuccess(s: String) {
+ Log.d("CometChatInit", "Success: $s")
+ }
+
+ override fun onError(e: CometChatException) {
+ Log.e("CometChatInit", "Error: ${e.message}")
+ }
+ })
+ }
+}
+```
+
+
+
+
+```java AppInit.java lines
+import android.content.Context;
+import android.util.Log;
+import com.cometchat.chat.core.CometChat;
+import com.cometchat.chat.exceptions.CometChatException;
+import com.cometchat.chatuikit.shared.cometchatuikit.CometChatUIKit;
+import com.cometchat.chatuikit.shared.cometchatuikit.UIKitSettings;
+import com.cometchat.chatuikit.shared.interfaces.DateTimeFormatterCallback;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class AppInit {
+ public static void initUiKitWithDateFormatter(
+ Context context,
+ String appId,
+ String region,
+ String authKey
+ ) {
+ UIKitSettings uiKitSettings = new UIKitSettings.UIKitSettingsBuilder()
+ .setAppId(appId)
+ .setRegion(region)
+ .setDateTimeFormatterCallback(new DateTimeFormatterCallback() {
+
+ private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault());
+ private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault());
+
+ @Override
+ public String time(long timestamp) {
+ return fullTimeFormatter.format(new Date(timestamp));
+ }
+
+ @Override
+ public String today(long timestamp) {
+ return "Today";
+ }
+
+ @Override
+ public String yesterday(long timestamp) {
+ return "Yesterday";
+ }
+
+ @Override
+ public String lastWeek(long timestamp) {
+ return "Last Week";
+ }
+
+ @Override
+ public String otherDays(long timestamp) {
+ return dateFormatter.format(new Date(timestamp));
+ }
+
+ @Override
+ public String minutes(long diffInMinutesFromNow, long timestamp) {
+ return diffInMinutesFromNow + " mins ago";
+ }
+
+ @Override
+ public String hours(long diffInHourFromNow, long timestamp) {
+ return diffInHourFromNow + " hrs ago";
+ }
+ })
+ .setAuthKey(authKey)
+ .build();
+
+ CometChatUIKit.init(context, uiKitSettings, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(String s) {
+ Log.d("CometChatInit", "Success: " + s);
+ }
+
+ @Override
+ public void onError(CometChatException e) {
+ Log.e("CometChatInit", "Error: " + e.getMessage());
+ }
+ });
+ }
+}
+```
+
+
+
+
+
+- **What this does**: Registers a global `DateTimeFormatterCallback` so all UI Kit timestamps use your formatting rules.
+
+- **Verify**: Open a conversation list and confirm labels like "Today" or "X mins ago" match your formatter.
+
+For the full callback reference, see [CometChatUIKit methods: DateFormatter](/ui-kit/android/methods#dateformatter).
+
+## Customization matrix
+| What you want to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| UI Kit language (global) | `app/src/main/java//LocalizeActivity.java` | `CometChatLocalize.setLocale(Context, Language.Code)` | `CometChatLocalize.setLocale(this, Language.Code.hi);` |
+| Read current locale (optional) | `app/src/main/java//LocalizeActivity.java` | `CometChatLocalize.getLocale(Context)` | `String currentLocale = CometChatLocalize.getLocale(this);` |
+| UI Kit label text (strings.xml) | `app/src/main/res/values/strings.xml` | `cometchat_chats` | `Conversations` |
+| Global date and time labels | `app/src/main/java//AppInit.java` | `setDateTimeFormatterCallback(...)` | `.setDateTimeFormatterCallback(new DateTimeFormatterCallback() {` |
-### Why Use This Approach?
+## Common pitfalls and fixes
+- Locale applied after UI Kit screens render: Call `CometChatLocalize.setLocale(...)` before you launch any UI Kit screen.
+- Wrong language code: Use a `Language.Code` constant from Supported languages.
+- Strings not updating: Verify the key name matches exactly in `res/values/strings.xml`.
+- Changes not visible: Clean and rebuild the project after editing `strings.xml`.
+- Partial localization: Override all relevant keys used by the UI Kit component you are targeting.
+- Date labels unchanged: Ensure `setDateTimeFormatterCallback(...)` is added to the same `UIKitSettings` instance you pass to `CometChatUIKit.init`.
-1. **No Code Modification Required** - You don’t need to modify the UIKit source code.
-2. **Easy Localization** - You can translate strings into different languages using strings.xml.
-3. **Seamless UIKit Updates** - Updates to UIKit won’t override your customizations.
-4. **Flexible Customization** - You can tailor the UI text without affecting functionality.
+## FAQ
+**Q**: Does `setLocale` affect only UI Kit screens or my entire app?
+**A**: It sets the locale configuration for the provided `Context`, which affects UI Kit screens that use that context.
-### DateTimeFormatter
+**Q**: Can I change the UI Kit language at runtime?
+**A**: Yes. Call `CometChatLocalize.setLocale(...)` again and recreate the affected screens.
-By providing a custom implementation of the DateTimeFormatterCallback, you can globally configure how time and date values are displayed across all UI components in the CometChat UI Kit. This ensures consistent formatting for labels such as "Today", "Yesterday", "X minutes ago", and more, throughout the entire application.
+**Q**: Do I need to edit the UI Kit source to change labels?
+**A**: No. Override the same keys in your app's `res/values/strings.xml`.
-For more detailed information and the full reference for the DateTimeFormatterCallback methods, refer to the DateTimeFormatterCallback methods section in the [CometChatUIKit class](/ui-kit/android/methods#dateformatter)
+**Q**: Where can I find all available string keys?
+**A**: Use the [String attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/strings.xml).
\ No newline at end of file
diff --git a/ui-kit/android/mentions-formatter-guide.mdx b/ui-kit/android/mentions-formatter-guide.mdx
index 3343d01b3..970e21ff7 100644
--- a/ui-kit/android/mentions-formatter-guide.mdx
+++ b/ui-kit/android/mentions-formatter-guide.mdx
@@ -2,48 +2,122 @@
title: "Mentions Formatter"
---
-## Overview
+`CometChatMentionsFormatter` formats and styles @mentions within text messages, enabling users to reference other participants in a conversation with customizable appearance and click handling across the message composer, message bubbles, and conversations list.
-The `CometChatMentionsFormatter` class is a part of the CometChat UI Kit, a ready-to-use chat UI component library for integrating CometChat into your Android applications. This class provides functionality to format mentions within text messages displayed in the chat interface. Mentions allow users to reference other users within a conversation, providing a convenient way to direct messages or involve specific participants.
+## When to Use This
-## Features
+- You need to format @mentions in text messages displayed in the chat interface
+- You want to customize the text style, color, or background of mentions in the message composer
+- You want to style mentions differently in outgoing vs. incoming message bubbles
+- You need to handle click events on mentions in message bubbles (e.g., navigate to a user profile)
+- You want to control which users or group members appear in the mention suggestions list
+- You need to customize how mentions appear in the [CometChatConversations](/ui-kit/android/conversations) last-message preview
-* **Mention Formatting**: Automatically formats mentions within text messages based on provided styles and settings.
-* **Customizable Styles**: Allows customization of text styles for mentions, including colors, fonts, and background colors.
-* **User and Group Member Mentions**: Supports mentions for both individual users and group members, providing flexibility in communication scenarios.
-* **Mention List Generation**: Generates a list of suggested mentions based on user input, facilitating easy selection of recipients during message composition.
-* **Mention Click Handling**: Provides a listener interface for handling click events on mentions, enabling custom actions to be performed when a mention is tapped by the user.
+## Prerequisites
-## Usage
+- CometChat Android UI Kit dependency added to your project
+- `CometChatUIKit.init()` called and completed
+- A logged-in CometChat user
+- Familiarity with the [CometChatMessageComposer](/ui-kit/android/message-composer) component
+- Familiarity with the [CometChatMessageList](/ui-kit/android/message-list) component
+- Familiarity with the [CometChatConversations](/ui-kit/android/conversations) component
-To integrate the `CometChatMentionsFormatter` class into your application:
+## Quick Start
-1. **Initialization**: Create an instance of the `CometChatMentionsFormatter` class and configure it with desired settings, such as mention text styles and limit settings.
+1. Create an instance of `CometChatMentionsFormatter`:
-2. **Set Mention Listeners**: Set listeners for handling mention click events (`setOnMentionClick`).
-
-3. **Format Messages**: Use the `prepareLeftMessageBubbleSpan`, `prepareRightMessageBubbleSpan`, `prepareComposerSpan`, and `prepareConversationSpan` methods to format text messages with mentions appropriately for display in the chat interface.
+
+
+```kotlin
+val mentionFormatter = CometChatMentionsFormatter(context)
+```
+
+
+```java
+CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
+```
+
+
-4. **Customization**: Customize the appearance and behavior of mentions by adjusting the text styles, colors, and other formatting properties as needed.
+> **What this does:** Creates a new `CometChatMentionsFormatter` instance initialized with the given Android `Context`.
-Below is an example demonstrating how to use the `CometChatMentionsFormatter` class in components such as [CometChatConversations](/ui-kit/android/conversations#settextformatters), [CometChatMessageList](/ui-kit/android/message-list#settextformatters), [CometChatMessageComposer](/ui-kit/android/message-composer#settextformatters).
+2. Add the formatter to a text formatters list:
+
+```kotlin
+val textFormatters: MutableList = ArrayList()
+textFormatters.add(mentionFormatter)
+```
+
```java
-// Initialize CometChatMentionsFormatter
-CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(requireContext());
-
-
List textFormatters = new ArrayList<>();
textFormatters.add(mentionFormatter);
-// This can be passed as an array of formatter in CometChatConversations, MessageList or Message Composer by using setTextFormatters method.
```
-
+
+
+> **What this does:** Creates a mutable list of `CometChatTextFormatter` and adds the mentions formatter to it. This list is passed to a component in the next step.
+3. Pass the formatters list to a component using `setTextFormatters()`:
+
+
```kotlin
+messageComposer.setTextFormatters(textFormatters)
+```
+
+
+```java
+messageComposer.setTextFormatters(textFormatters);
+```
+
+
+
+> **What this does:** Passes the text formatters list (containing the mentions formatter) to the `CometChatMessageComposer` component, enabling mention formatting in the composer. You can also pass this list to `CometChatMessageList` or `CometChatConversations` using their respective `setTextFormatters()` methods.
+
+## Core Concepts
+
+### The Formatter Pattern
+
+`CometChatMentionsFormatter` extends `CometChatTextFormatter` and plugs into any component that accepts text formatters via `setTextFormatters()`. The formatter intercepts text rendering and applies mention-specific styling and behavior.
+
+### How Mentions Work
+
+- **Mention Formatting**: The formatter automatically formats mentions within text messages based on provided styles and settings.
+- **Customizable Styles**: You can customize text styles for mentions, including colors, fonts, and background colors.
+- **User and Group Member Mentions**: The formatter supports mentions for both individual users and group members.
+- **Mention List Generation**: The formatter generates a list of suggested mentions based on user input during message composition.
+- **Mention Click Handling**: The formatter provides a listener interface for handling click events on mentions, enabling custom actions when a mention is tapped.
+
+### Formatting Methods
+
+The formatter uses these internal methods to apply mention spans in different contexts:
+
+- `prepareLeftMessageBubbleSpan` — formats mentions in incoming message bubbles
+- `prepareRightMessageBubbleSpan` — formats mentions in outgoing message bubbles
+- `prepareComposerSpan` — formats mentions in the message composer
+- `prepareConversationSpan` — formats mentions in the conversations list
+
+These methods are called automatically by the UI Kit when the formatter is attached to a component.
+
+## Implementation
+
+### Initialization and Basic Usage
+
+What you are changing: Adding `CometChatMentionsFormatter` to a component so that mentions are formatted in the chat interface.
+
+- **Where**: Your Activity or Fragment where you configure `CometChatConversations`, `CometChatMessageList`, or `CometChatMessageComposer`
+- **Applies to**: `CometChatConversations`, `CometChatMessageList`, `CometChatMessageComposer`
+- **Default behavior**: Without a mentions formatter, @mention text renders as plain text with no special styling or click handling
+- **Override**: Create a `CometChatMentionsFormatter` instance, add it to a `List`, and pass the list to the target component via `setTextFormatters()`
+
+**Code:**
+
+
+
+```kotlin lines
// Initialize CometChatMentionsFormatter
val mentionFormatter = CometChatMentionsFormatter(this)
@@ -51,48 +125,42 @@ val textFormatters: MutableList = ArrayList()
textFormatters.add(mentionFormatter)
// This can be passed as an array of formatter in CometChatConversations, MessageList or Message Composer by using setTextFormatters method.
```
-
+
+```java lines
+// Initialize CometChatMentionsFormatter
+CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(requireContext());
+
+List textFormatters = new ArrayList<>();
+textFormatters.add(mentionFormatter);
+// This can be passed as an array of formatter in CometChatConversations, MessageList or Message Composer by using setTextFormatters method.
+```
+
-## Actions
+> **What this does:** Creates a `CometChatMentionsFormatter` instance, adds it to a list of text formatters, and prepares the list to be passed to `CometChatConversations`, `CometChatMessageList`, or `CometChatMessageComposer` via `setTextFormatters()`.
-Actions dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+- **Verify**: After passing the formatters list to a component via `setTextFormatters()`, @mentions in messages render with styled text (colored and formatted) instead of plain text.
-##### setOnMentionClick
+### `setOnMentionClick` Action
-Setting a listener for mention-click events in Message Bubbles enhances interactivity within the chat. This listener is activated when a mention is clicked, returning the corresponding user object. This feature transforms mentions into interactive links, enabling more in-depth and contextual engagement with the user associated with the clicked mention.
+What you are changing: Adding a click listener for mentions in message bubbles so that tapping a mention triggers a custom action.
-**Example**
+- **Where**: `CometChatMentionsFormatter` instance, passed to `CometChatMessageComposer` via `setTextFormatters()`
+- **Applies to**: Mention text in message bubbles rendered by `CometChatMessageList`
+- **Default behavior**: Tapping a mention in a message bubble does nothing
+- **Override**: Call `setOnMentionClick()` on the `CometChatMentionsFormatter` instance with a callback that receives the `context` and the mentioned `user` object
-
-
-```java
-
-// Initialize CometChatMentionsFormatter
-CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
-
-// set callback for the mention click
-
- mentionFormatter.setOnMentionClick((context, user) -> {
- Toast.makeText(context, user.getName(), Toast.LENGTH_SHORT).show();
- });
-
-// This can be passed as an array of formatter in CometChatMessageComposer by using setTextFormatters method.
-List textFormatters = new ArrayList<>();
-textFormatters.add(mentionFormatter);
-messageComposer.setTextFormatters(textFormatters);
-```
-
-
+**Code:**
+
-```kotlin
+```kotlin lines
// Initialize CometChatMentionsFormatter
val mentionFormatter = CometChatMentionsFormatter(context)
@@ -108,37 +176,47 @@ val textFormatters: MutableList = ArrayList()
textFormatters.add(mentionFormatter)
messageComposer.setTextFormatters(textFormatters)
```
-
+
+```java lines
-
+// Initialize CometChatMentionsFormatter
+CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
-## Customization
+// set callback for the mention click
-| Methods | Description | Code |
-| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
-| **setMentionLimit** | Sets the limit for the number of mentions allowed. | `setMentionLimit(int limit)` |
-| **setGroupMembersRequestBuilder** | Sets the builder for fetching group members. | `.setGroupMembersRequestBuilder(group -> new GroupMembersRequest.GroupMembersRequestBuilder(group.getGuid()));` |
-| **setUsersRequestBuilder** | Sets the builder for fetching users. | `.setUsersRequestBuilder(new UsersRequest.UsersRequestBuilder().friendsOnly(true));` |
-| **setMentionsType** | Supports two types of mentions: `USERS` and `USERS_AND_GROUP_MEMBERS`. If set to `USERS`, only users can be mentioned in both one-on-one and group conversations. If set to `USERS_AND_GROUP_MEMBERS`, members of a specific group can be mentioned in group chats, while all users can be mentioned in one-on-one chats. | `.setMentionsType(UIKitConstants.MentionsType.USERS_AND_GROUP_MEMBERS)` |
-| **setMentionsVisibility** | This method allows you to set the scope of mentions visibility within the app, choosing from `USERS_CONVERSATION_ONLY`, `GROUP_CONVERSATION_ONLY`, or `BOTH`. It lets you specify whether mentions are visible only in one-on-one conversations, only in group conversations, or in both. | `.setMentionsVisibility(UIKitConstants.MentionsVisibility.BOTH);` |
-| **setOnMentionClick** | Sets a listener for mention click in Message Bubbles events. | `mentionFormatter.setOnMentionClick((context, user) -> {` `// Add your implementation here` `});` |
+ mentionFormatter.setOnMentionClick((context, user) -> {
+ Toast.makeText(context, user.getName(), Toast.LENGTH_SHORT).show();
+ });
-## Advance
+// This can be passed as an array of formatter in CometChatMessageComposer by using setTextFormatters method.
+List textFormatters = new ArrayList<>();
+textFormatters.add(mentionFormatter);
+messageComposer.setTextFormatters(textFormatters);
+```
+
+
+
+> **What this does:** Sets a click listener on the mentions formatter that displays a `Toast` with the mentioned user's name when a mention is tapped in a message bubble. The formatter is then added to a list and passed to `CometChatMessageComposer` via `setTextFormatters()`.
-For advanced-level customization, you can set the style of the Mentions formatters. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your formatters style.
+- **Verify**: Tapping a mention in a message bubble displays a Toast showing the mentioned user's name.
### Composer Mention Text Style
-Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatMessageComposer](/ui-kit/android/message-composer) refer to the below code snippet
+What you are changing: The visual appearance of mention text inside the `CometChatMessageComposer` input field.
-**Example**
+- **Where**: XML theme style applied via `mentionFormatter.setMessageComposerMentionTextStyle()`
+- **Applies to**: `CometChatMessageComposer`
+- **Default behavior**: Mentions in the composer use the default `CometChatMessageComposerMentionsStyle`
+- **Override**: Define a custom style extending `CometChatMessageComposerMentionsStyle` in your `themes.xml`, then call `setMessageComposerMentionTextStyle()` on the formatter instance
-```xml themes.xml
+**XML Style:**
+
+```xml themes.xml lines
```
-
-
-```java
-// Initialize CometChatMentionsFormatter
-CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
-
-// set style to customize composer mention text
-mentionFormatter.setMessageComposerMentionTextStyle(context, R.style.CustomMessageComposerMentionsStyle);
-
-// This can be passed as an array of formatter in CometChatMessageComposer by using setTextFormatters method.
-List textFormatters = new ArrayList<>();
-textFormatters.add(mentionFormatter);
-messageComposer.setTextFormatters(textFormatters);
-```
+> **What this does:** Defines a custom XML style for mentions in the message composer. It sets the mention text color to `#000000`, the self-mention text color to `#30A46C`, and applies `cometchatTextAppearanceBodyRegular` for both mention and self-mention text appearance.
-
+**Code:**
+
-```kotlin
+```kotlin lines
// Initialize CometChatMentionsFormatter
val mentionFormatter = CometChatMentionsFormatter(context)
// set style to customize composer mention text
@@ -179,22 +245,43 @@ val textFormatters: MutableList = ArrayList()
textFormatters.add(mentionFormatter)
messageComposer.setTextFormatters(textFormatters)
```
-
+
+```java lines
+// Initialize CometChatMentionsFormatter
+CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
+// set style to customize composer mention text
+mentionFormatter.setMessageComposerMentionTextStyle(context, R.style.CustomMessageComposerMentionsStyle);
+
+// This can be passed as an array of formatter in CometChatMessageComposer by using setTextFormatters method.
+List textFormatters = new ArrayList<>();
+textFormatters.add(mentionFormatter);
+messageComposer.setTextFormatters(textFormatters);
+```
+
+> **What this does:** Creates a `CometChatMentionsFormatter`, applies the custom `CustomMessageComposerMentionsStyle` to it, and passes it to `CometChatMessageComposer` via `setTextFormatters()`. Mentions typed in the composer input field render with the custom style.
+
+- **Verify**: Mentions typed in the message composer input field display with the custom text color (`#000000`), self-mention color (`#30A46C`), and the specified text appearance, matching the `CustomMessageComposerMentionsStyle` definition.
+
### Message Bubble Mention Text Style
-Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatMessageList](/ui-kit/android/message-list)
+What you are changing: The visual appearance of mention text inside incoming and outgoing message bubbles in the `CometChatMessageList`.
-**Example**
+- **Where**: XML theme styles applied via `mentionFormatter.setOutgoingBubbleMentionTextStyle()` and `mentionFormatter.setIncomingBubbleMentionTextStyle()`
+- **Applies to**: `CometChatMessageList`
+- **Default behavior**: Incoming mentions use `CometChatIncomingBubbleMentionsStyle` and outgoing mentions use `CometChatOutgoingBubbleMentionsStyle`
+- **Override**: Define custom styles extending `CometChatIncomingBubbleMentionsStyle` and `CometChatOutgoingBubbleMentionsStyle` in your `themes.xml`, then call `setIncomingBubbleMentionTextStyle()` and `setOutgoingBubbleMentionTextStyle()` on the formatter instance
-```xml themes.xml
+**XML Style:**
+
+```xml themes.xml lines
```
-
-
-```java
-// Initialize CometChatMentionsFormatter
-CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
-
-//set style to customize bubble mention text
-mentionFormatter.setOutgoingBubbleMentionTextStyle(context, R.style.CustomOutgoingMessageBubbleMentionStyle);
+> **What this does:** Defines two custom XML styles for mentions in message bubbles. The incoming style sets mention text color to `#D6409F` (pink). The outgoing style sets mention text color to `#FFFFFF` (white) with a background color of `#F9F8FD`. Both styles set self-mention text color to `#30A46C` (green).
-mentionFormatter.setIncomingBubbleMentionTextStyle(context, R.style.CustomIncomingMessageBubbleMentionStyle);
-
-// This can be passed as an array of formatter in CometChatMessageList by using setTextFormatters method.
-List textFormatters = new ArrayList<>();
-textFormatters.add(mentionFormatter);
-messageList.setTextFormatters(textFormatters);
-```
-
-
+**Code:**
+
-```kotlin
+```kotlin lines
// Initialize CometChatMentionsFormatter
val mentionFormatter = CometChatMentionsFormatter(context)
@@ -249,22 +322,45 @@ val textFormatters: MutableList = ArrayList()
textFormatters.add(mentionFormatter)
messageList.setTextFormatters(textFormatters)
```
-
+
+```java lines
+// Initialize CometChatMentionsFormatter
+CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
+//set style to customize bubble mention text
+mentionFormatter.setOutgoingBubbleMentionTextStyle(context, R.style.CustomOutgoingMessageBubbleMentionStyle);
+
+mentionFormatter.setIncomingBubbleMentionTextStyle(context, R.style.CustomIncomingMessageBubbleMentionStyle);
+
+// This can be passed as an array of formatter in CometChatMessageList by using setTextFormatters method.
+List textFormatters = new ArrayList<>();
+textFormatters.add(mentionFormatter);
+messageList.setTextFormatters(textFormatters);
+```
+
+> **What this does:** Creates a `CometChatMentionsFormatter`, applies custom outgoing and incoming bubble mention styles, and passes the formatter to `CometChatMessageList` via `setTextFormatters()`. Mentions in message bubbles render with the custom colors and text appearance.
+
+- **Verify**: Mentions in outgoing message bubbles display with white text (`#FFFFFF`) and a `#F9F8FD` background. Mentions in incoming message bubbles display with pink text (`#D6409F`). Self-mentions in both bubble types display with green text (`#30A46C`).
+
### Conversations Mention Text Style
-Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatConversations](/ui-kit/android/conversations)
+What you are changing: The visual appearance of mention text in the last-message preview of the `CometChatConversations` list.
-**Example**
+- **Where**: XML theme style applied via `mentionFormatter.setConversationsMentionTextStyle()`
+- **Applies to**: `CometChatConversations`
+- **Default behavior**: Mentions in the conversations list use the default `CometChatConversationsMentionsStyle`
+- **Override**: Define a custom style extending `CometChatConversationsMentionsStyle` in your `themes.xml`, then call `setConversationsMentionTextStyle()` on the formatter instance
-```xml themes.xml
+**XML Style:**
+
+```xml themes.xml lines
```
+> **What this does:** Defines a custom XML style for mentions in the conversations list. It sets the mention text color to `#D6409F` (pink) and the self-mention text color to `#30A46C` (green), with `cometchatTextAppearanceBodyRegular` for text appearance.
+
+**Code:**
+
+
+```kotlin lines
+
+// Initialize CometChatMentionsFormatter
+val mentionFormatter = CometChatMentionsFormatter(context)
+//set style to customize conversation mention text
+mentionFormatter.setConversationsMentionTextStyle(context, R.style.CustomConversationsMentionsStyle)
+
+// This can be passed as an array of formatter in CometChatConversations by using setTextFormatters method.
+val textFormatters: MutableList = ArrayList()
+textFormatters.add(mentionFormatter)
+cometChatConversations.setTextFormatters(textFormatters)
+```
+
-```java
+```java lines
// Initialize CometChatMentionsFormatter
CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
@@ -290,23 +404,59 @@ List textFormatters = new ArrayList<>();
textFormatters.add(mentionFormatter);
cometChatConversations.setTextFormatters(textFormatters);
```
-
+
-
-```kotlin
+> **What this does:** Creates a `CometChatMentionsFormatter`, applies the custom `CustomConversationsMentionsStyle`, and passes the formatter to `CometChatConversations` via `setTextFormatters()`. Mentions in the conversations list last-message preview render with the custom style.
-// Initialize CometChatMentionsFormatter
-val mentionFormatter = CometChatMentionsFormatter(context)
-//set style to customize conversation mention text
-mentionFormatter.setConversationsMentionTextStyle(context, R.style.CustomConversationsMentionsStyle)
+- **Verify**: Mentions in the conversations list last-message preview display with pink text (`#D6409F`) for other-user mentions and green text (`#30A46C`) for self-mentions, matching the `CustomConversationsMentionsStyle` definition.
-// This can be passed as an array of formatter in CometChatConversations by using setTextFormatters method.
-val textFormatters: MutableList = ArrayList()
-textFormatters.add(mentionFormatter)
-cometChatConversations.setTextFormatters(textFormatters)
-```
+## Customization Matrix
-
+| What you want to change | Where | Property/API | Example |
+| ----------------------- | ----- | ------------ | ------- |
+| Maximum number of mentions allowed | `CometChatMentionsFormatter` | `setMentionLimit(int limit)` | `mentionFormatter.setMentionLimit(5)` |
+| Group members fetched for mention suggestions | `CometChatMentionsFormatter` | `.setGroupMembersRequestBuilder(group -> new GroupMembersRequest.GroupMembersRequestBuilder(group.getGuid()));` | `.setGroupMembersRequestBuilder(group -> new GroupMembersRequest.GroupMembersRequestBuilder(group.getGuid()));` |
+| Users fetched for mention suggestions | `CometChatMentionsFormatter` | `.setUsersRequestBuilder(new UsersRequest.UsersRequestBuilder().friendsOnly(true));` | `.setUsersRequestBuilder(new UsersRequest.UsersRequestBuilder().friendsOnly(true));` |
+| Who can be mentioned (users only or users and group members) | `CometChatMentionsFormatter` | `.setMentionsType(UIKitConstants.MentionsType.USERS_AND_GROUP_MEMBERS)` | `.setMentionsType(UIKitConstants.MentionsType.USERS_AND_GROUP_MEMBERS)` |
+| Where mentions are visible (one-on-one, group, or both) | `CometChatMentionsFormatter` | `.setMentionsVisibility(UIKitConstants.MentionsVisibility.BOTH);` | `.setMentionsVisibility(UIKitConstants.MentionsVisibility.BOTH);` |
+| Click action on a mention in message bubbles | `CometChatMentionsFormatter` | `setOnMentionClick` | `mentionFormatter.setOnMentionClick((context, user) -> { });` |
+| Mention text style in the message composer | `CometChatMentionsFormatter` | `setMessageComposerMentionTextStyle(context, styleRes)` | `mentionFormatter.setMessageComposerMentionTextStyle(context, R.style.CustomMessageComposerMentionsStyle)` |
+| Mention text style in outgoing message bubbles | `CometChatMentionsFormatter` | `setOutgoingBubbleMentionTextStyle(context, styleRes)` | `mentionFormatter.setOutgoingBubbleMentionTextStyle(context, R.style.CustomOutgoingMessageBubbleMentionStyle)` |
+| Mention text style in incoming message bubbles | `CometChatMentionsFormatter` | `setIncomingBubbleMentionTextStyle(context, styleRes)` | `mentionFormatter.setIncomingBubbleMentionTextStyle(context, R.style.CustomIncomingMessageBubbleMentionStyle)` |
+| Mention text style in conversations list | `CometChatMentionsFormatter` | `setConversationsMentionTextStyle(context, styleRes)` | `mentionFormatter.setConversationsMentionTextStyle(context, R.style.CustomConversationsMentionsStyle)` |
-
+## Common Pitfalls and Fixes
+
+| Pitfall | Fix |
+| ------- | --- |
+| Mentions render as plain text with no styling | Create a `CometChatMentionsFormatter` instance, add it to a `List`, and pass the list to the component via `setTextFormatters()`. |
+| Formatter created but not added to the formatters list | Call `textFormatters.add(mentionFormatter)` before passing the list to the component. If the formatter is not in the list, `setTextFormatters()` has no effect on mention rendering. |
+| Called `setTextFormatters()` with an empty list | Add at least one `CometChatMentionsFormatter` to the list before calling `setTextFormatters()`. |
+| Custom mention style not applied in the composer | Call `mentionFormatter.setMessageComposerMentionTextStyle(context, R.style.YourStyle)` before passing the formatter to `CometChatMessageComposer` via `setTextFormatters()`. |
+| Custom mention style not applied in message bubbles | Call both `mentionFormatter.setOutgoingBubbleMentionTextStyle()` and `mentionFormatter.setIncomingBubbleMentionTextStyle()` before passing the formatter to `CometChatMessageList` via `setTextFormatters()`. If you set only one, the other bubble type uses the default style. |
+| `setOnMentionClick` callback not firing | Ensure the formatter is passed to the component via `setTextFormatters()` after calling `setOnMentionClick()`. The callback fires only for mentions in message bubbles. |
+| Mention suggestions not showing group members | If `setMentionsType` is set to `UIKitConstants.MentionsType.USERS`, only users appear in suggestions. Set it to `UIKitConstants.MentionsType.USERS_AND_GROUP_MEMBERS` to include group members in group chats. |
+
+## FAQ
+
+**Q: Can I use `CometChatMentionsFormatter` with `CometChatConversations`, `CometChatMessageList`, and `CometChatMessageComposer` at the same time?**
+A: Yes. Create a `CometChatMentionsFormatter` instance, add it to a `List`, and pass the list to each component separately via their `setTextFormatters()` method. You can configure different styles for each component on the same formatter instance.
+
+**Q: What is the difference between `setMentionsType` with `USERS` vs. `USERS_AND_GROUP_MEMBERS`?**
+A: If set to `USERS`, only users can be mentioned in both one-on-one and group conversations. If set to `USERS_AND_GROUP_MEMBERS`, members of a specific group can be mentioned in group chats, while all users can be mentioned in one-on-one chats.
+
+**Q: What does `setMentionsVisibility` control?**
+A: `setMentionsVisibility` controls the scope of where mentions are visible. Set it to `UIKitConstants.MentionsVisibility.USERS_CONVERSATION_ONLY` for one-on-one conversations only, `UIKitConstants.MentionsVisibility.GROUP_CONVERSATION_ONLY` for group conversations only, or `UIKitConstants.MentionsVisibility.BOTH` for both.
+
+**Q: How do I customize which users appear in the mention suggestions list?**
+A: Use `setUsersRequestBuilder()` to provide a custom `UsersRequest.UsersRequestBuilder`. For example, `.setUsersRequestBuilder(new UsersRequest.UsersRequestBuilder().friendsOnly(true))` limits suggestions to friends only. Use `setGroupMembersRequestBuilder()` to customize group member suggestions.
+
+**Q: Do I need to define separate XML styles for incoming and outgoing bubble mentions?**
+A: Yes. Incoming and outgoing bubbles use separate style parents (`CometChatIncomingBubbleMentionsStyle` and `CometChatOutgoingBubbleMentionsStyle`). Define a custom style for each and apply them with `setIncomingBubbleMentionTextStyle()` and `setOutgoingBubbleMentionTextStyle()`.
+
+## Next steps
+
+- [Message Composer component](/ui-kit/android/message-composer) — configure the composer where users type and send messages with mentions
+- [Message List component](/ui-kit/android/message-list) — configure the message list where mention-styled bubbles are displayed
+- [Conversations component](/ui-kit/android/conversations) — configure the conversations list where mention-styled last-message previews appear
diff --git a/ui-kit/android/message-bubble-styling.mdx b/ui-kit/android/message-bubble-styling.mdx
index f7103f73f..ff83a43c4 100644
--- a/ui-kit/android/message-bubble-styling.mdx
+++ b/ui-kit/android/message-bubble-styling.mdx
@@ -1,219 +1,176 @@
---
title: "Message Bubble Styling"
+description: "Configure and style incoming, outgoing, and specific message bubbles in your Android UI Kit."
---
+Configure and style incoming, outgoing, and specific message bubbles in your Android UI Kit.
+
+## When to use this
+- You want to customize the look of incoming and outgoing message bubbles.
+- You need different styles for text, image, audio, video, file, sticker, poll, or collaborative bubbles.
+- You want to style call action bubbles, delete bubbles, or AI assistant bubbles.
+- You need to customize quoted reply previews.
+- You prefer centralized styling through `res/values/themes.xml`.
+
+## Prerequisites
+- CometChat UI Kit for Android is installed and initialized.
+- Your app theme extends `CometChatTheme.DayNight`.
+- You can edit `res/values/themes.xml` in your Android module.
+- You rebuild or sync Gradle after updating styles.
+
+## Quick start
+
+
+Define `CustomIncomingMessageBubbleStyle` and `CustomOutgoingMessageBubbleStyle` in `res/values/themes.xml` and connect them to `AppTheme`.
+
+
+Create a custom style for the bubble type (e.g., `CustomIncomingTextBubbleStyle`) and link it inside the hub style.
+
+
+Run the app, open a conversation, and confirm the bubble styling.
+
+
+
## Overview
-Message bubbles are the core visual element in chat applications, encapsulating different types of messages like text, images, or attachments. Customizing message bubbles allows developers to create a consistent and engaging user experience that aligns with their app's theme and design language. This guide provides an overview of how to style outgoing and incoming message bubbles and customize the appearance for specific message types.
+Message bubbles are the core visual element in chat applications. Customizing them allows you to create a consistent user experience that aligns with your app's theme.
+
+This guide covers how to style **Base Message Bubbles** (the container) and **Specific Message Types** (Text, Image, Audio, etc.). Customization options include adjusting the **background color**, **text appearance**, and **bubble shape** to differentiate between incoming and outgoing messages.
-### Incoming Bubble Style
-
-Incoming bubbles represent messages received from other users.
-
-Customization options include:
-
-* Background color: Choose a complementary or contrasting color to distinguish incoming messages.
-* Text appearance: Set unique font styles to highlight received message content.
-* Bubble shape: Use consistent shapes or differentiate them further for visual clarity.
-
-### Outgoing Bubble Style
-
-Outgoing bubbles represent messages sent by the user.
-
-Customization options include:
+## Styling Architecture
-* Background color: Define a distinct color to differentiate user messages.
-* Text appearance: Configure font size, color, and style for message content.
-* Bubble shape: Adjust the corner radius to achieve sharp, rounded, or custom designs.
+To style message bubbles effectively without duplicating code, understand this inheritance hierarchy.
-## Message Bubbles
+
+All code in this guide belongs in `res/values/themes.xml`.
+
-Message bubbles are core elements of the messaging interface. Their collective appearance can be customized to create a consistent design, including color, shape, and overall style for both outgoing and incoming messages. The message bubbles' styles can be customized by extending the predefined styles in your themes.xml file.
+1. **`AppTheme`**: The root theme of your application.
+2. **`Message Bubble Styles`**: Acts as a central hub for all incoming/outgoing message styles. Linked directly to the `AppTheme`.
+3. **`Specific Bubble Styles`**: Targets specific message types (e.g., Text, Video, Audio). These are linked *inside* the Message Bubble Styles.
-**Customizing Incoming Message Bubble**
+### Global Setup
+Define this **once** in your `res/values/themes.xml`. All subsequent custom bubble styles will be routed through these hubs.
-
-
-
-
-```html
-
+```xml themes.xml lines
+
+
+
+
-```
-```html
-
+
```
-**Customizing Outgoing Message Bubble**
+Customizing Incoming Message Bubble
-
+
-```html
-
-
-```
+Customizing Outgoing Message Bubble
-```html
-
-
-```
+
+
+
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_bubble.xml).
+**Attribute references:**
+- [Message bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_bubble.xml)
-### Text Bubble
-Text bubbles display plain text messages. These are the most common bubble type in a chat interface.
+## Core Message Bubbles
-**Default**
+The following sections define how to style specific types of messages. Define the custom style, then link it to the central hubs (`CustomIncomingMessageBubbleStyle` or `CustomOutgoingMessageBubbleStyle`) established above.
+
+### Text Bubble
+Text bubbles display plain text messages. These are the most common bubble type.
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```xml themes.xml
-
+```xml themes.xml lines
+
+
-```
-
-```xml themes.xml
-
-
-```
-**Customizing Outgoing Bubble**
-
-```html
-
-
+
```
+**Attribute reference:**
+- [Text bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_text_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_text_bubble.xml).
### Link Preview Bubble
+Displays a preview of links shared in messages, enriching the experience with titles, descriptions, and images.
-The Link Preview Bubble is designed to display a preview of links shared in messages. It enriches the messaging experience by showing details such as the page title, description, and an image from the linked content, making links more engaging and informative.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
-
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-
-```html
-
-
-
-
-```
-
-```html
-
-
```
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_text_bubble.xml).
### Image Bubble
-
Image bubbles display images shared within a conversation.
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
@@ -221,19 +178,8 @@ Image bubbles display images shared within a conversation.
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
@@ -242,32 +188,20 @@ Image bubbles display images shared within a conversation.
@style/CustomOutgoingImageBubbleStyle
```
+**Attribute reference:**
+- [Image bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_image_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_image_bubble.xml).
### Video Bubble
-
Video bubbles display video messages or clips in a chat.
-**Default**
-
**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
```
+**Attribute reference:**
+- [Video bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_video_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_video_bubble.xml).
### Audio Bubble
-
Audio bubbles represent audio messages or voice recordings.
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
```
+**Attribute reference:**
+- [Audio bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_audio_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_audio_bubble.xml).
### File Bubble
+Displays shared files, such as documents, PDFs, or spreadsheets.
-File bubbles are used to display shared files, such as documents, PDFs, or spreadsheets.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
@@ -420,36 +295,23 @@ File bubbles are used to display shared files, such as documents, PDFs, or sprea
@style/CustomOutgoingFileBubbleStyle
```
+**Attribute reference:**
+- [File bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_file_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_file_bubble.xml).
### Sticker Bubble
+Displays visual stickers shared in a conversation.
-Sticker bubbles display stickers shared in a conversation, enhancing visual expression.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
@@ -457,19 +319,8 @@ Sticker bubbles display stickers shared in a conversation, enhancing visual expr
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
@@ -478,36 +329,23 @@ Sticker bubbles display stickers shared in a conversation, enhancing visual expr
@style/CustomOutgoingStickerBubbleStyle
```
+**Attribute reference:**
+- [Sticker bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_sticker_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_sticker_bubble.xml).
### Poll Bubble
+Displays polls, options, and live results.
-Poll bubbles represent polls shared within the chat, showing options and results.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
@@ -515,19 +353,8 @@ Poll bubbles represent polls shared within the chat, showing options and results
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
```
+**Attribute reference:**
+- [Poll bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_poll_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_poll_bubble.xml).
### Collaborative Bubble
+Displays collaborative content, such as shared documents or tasks.
-Collaborative bubbles display collaborative content, such as shared documents or tasks.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
@@ -574,19 +388,8 @@ Collaborative bubbles display collaborative content, such as shared documents or
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
```
+**Attribute reference:**
+- [Collaborative bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_collaborative_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_collaborative_bubble.xml).
### Meet Call Bubble
+Displays call-related actions and statuses in the chat interface.
-Meet call bubbles display call-related actions and statuses in the chat interface.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
```
+**Attribute reference:**
+- [Meet call bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_meet_call_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_meet_call_bubble.xml).
### Delete Bubble
+Indicates a message that has been removed by the sender.
-Delete bubbles are used to display messages that have been deleted by the sender. These indicate the message removal within the chat interface.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Incoming Bubble**
-
-```html
-
+```xml themes.xml lines
+
@@ -694,57 +460,37 @@ Delete bubbles are used to display messages that have been deleted by the sender
-```
-
-```html
-
-
-```
-
-**Customizing Outgoing Bubble**
-```html
-
+
```
+**Attribute reference:**
+- [Delete bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_delete_bubble.xml)
-```html
-
-
-```
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_delete_bubble.xml).
-### Call Action Bubble
+## List-Level Bubbles & Special Features
-Call action bubbles display call-related actions, such as missed calls, in the chat interface.
+Unlike standard messages, **Call Action** and **Action** bubbles are tied to the **Message List Style**, not the Incoming/Outgoing Hubs. AI Assistants and Quoted Replies have specialized formatting.
-**Default**
+### Call Action Bubble
+Displays call actions like missed calls within the message list.
+**Default & Customization**
-
-**Customization**
-
-**Customizing Bubble**
-
-```html
-
+```xml themes.xml lines
+
+
-```
-```html
-
+
```
+**Attribute references:**
+- [Call action bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_call_action_bubble.xml)
+- [Message list attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_list.xml)
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_call_action_bubble.xml).
### Action Bubble
+Displays global group actions (e.g., "User joined the chat").
-Action bubbles provide a customizable interface for displaying a variety of actions, such as group actions, within a chat.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Bubble**
-
-```html
-
+```xml themes.xml lines
+
+
-```
-```html
-
+
```
+**Attribute reference:**
+- [Action bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_action_bubble.xml)
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_action_bubble.xml).
### AI Assistant Bubble
+Styles interactions generated by the AI assistant. These are anchored to the `IncomingMessageBubbleStyle`.
-AI Assistant bubbles display messages and interactions from an AI assistant within the chat interface.
-
-**Default**
-
+**Default & Customization**
-
-**Customization**
-
-**Customizing Bubble**
-
-```html
-
-
-
-
-
-
+```xml themes.xml lines
+
+
-
-```
+
+
-```html
-
-
```
+**Attribute reference:**
+- [AI assistant bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/att_cometchat_ai_assistant_bubble.xml)
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_action_bubble.xml).
### Quoted Reply
+Styles the preview block when a user replies to a specific message.
-```xml themes.xml
-
-
-
-
-
-
-
-
-
-
-
-```
+```xml themes.xml lines
+
+
-```xml themes.xml
-
+
+
+
+
+
+
-```
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_preview.xml).
\ No newline at end of file
+
+
+```
+**Attribute reference:**
+- [Message preview attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_preview.xml)
+
+## Customization matrix
+
+| What you want to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Incoming bubble background | `res/values/themes.xml` | `cometchatMessageBubbleBackgroundColor` in `CometChatIncomingMessageBubbleStyle` | `#FEEDE1` |
+| Outgoing bubble background | `res/values/themes.xml` | `cometchatMessageBubbleBackgroundColor` in `CometChatOutgoingMessageBubbleStyle` | `#F76808` |
+| Text bubble background | `res/values/themes.xml` | `cometchatTextBubbleBackgroundColor` | `#FEEDE1` |
+| Link preview background | `res/values/themes.xml` | `cometchatTextBubbleLinkPreviewBackgroundColor` | `#FBAA75` |
+| Image bubble background | `res/values/themes.xml` | `cometchatImageBubbleBackgroundColor` | `#FEEDE1` |
+| Video bubble play icon tint | `res/values/themes.xml` | `cometchatVideoBubblePlayIconTint` | `#F76808` |
+| Audio bubble wave color | `res/values/themes.xml` | `cometchatAudioBubbleAudioWaveColor` | `#F76808` |
+| File bubble download icon tint | `res/values/themes.xml` | `cometchatFileBubbleFileDownloadIconTint` | `#F76808` |
+| Poll bubble progress background | `res/values/themes.xml` | `cometchatPollBubbleProgressBackgroundColor` | `#FBAA75` |
+| Collaborative bubble separator | `res/values/themes.xml` | `cometchatCollaborativeBubbleSeparatorColor` | `#FBAA75` |
+| Meet call bubble icon tint | `res/values/themes.xml` | `cometchatMeetCallBubbleCallIconTint` | `#F76808` |
+| Delete bubble background | `res/values/themes.xml` | `cometchatMessageBubbleBackgroundColor` in delete style | `#FBAA75` |
+| Call action bubble text color | `res/values/themes.xml` | `cometchatCallActionBubbleTextColor` | `#F76808` |
+| Action bubble text color | `res/values/themes.xml` | `cometchatActionBubbleTextColor` | `#F76808` |
+| AI assistant bubble background | `res/values/themes.xml` | `cometChatAIAssistantBubbleBackgroundColor` | `@color/cometchat_color_transparent` |
+| Quoted reply preview background | `res/values/themes.xml` | `cometChatMessagePreviewBackgroundColor` | `#ea6d71` |
+| Bubble corner radius | `res/values/themes.xml` | `cometchatMessageBubbleCornerRadius` | `@dimen/cometchat_radius_3` |
+
+## Common pitfalls and fixes
+- Bubble style not applying: Confirm the custom style is linked inside the correct hub (`CustomIncomingMessageBubbleStyle` or `CustomOutgoingMessageBubbleStyle`), and the hub is connected to `AppTheme`.
+- Only incoming or outgoing changes: You must define separate styles for incoming and outgoing bubbles. Changing one does not affect the other.
+- Specific bubble type unchanged: Ensure you link the specific bubble style (e.g., `cometchatTextBubbleStyle`) inside the hub, not directly in `AppTheme`.
+- Call action or action bubble unchanged: These are linked to `CometChatMessageListStyle`, not the incoming/outgoing hubs. Use `cometchatMessageListCallActionBubbleStyle` or `cometchatMessageListActionBubbleStyle`.
+- AI assistant bubble unchanged: This is linked to `CometChatIncomingMessageBubbleStyle` via `cometchatAIAssistantBubbleStyle`.
+- Changes not visible: Rebuild the app after editing `themes.xml`.
+- Dark mode not matching: Update both `values/themes.xml` and `values-night/themes.xml`.
+
+## FAQ
+**Q**: Do I need to define both incoming and outgoing styles?
+**A**: Only if you want different styles for each direction. If you only customize one, the other uses the default.
+
+**Q**: Can I style a specific bubble type without changing the base bubble?
+**A**: Yes. Define a custom style for the specific type (e.g., `CustomIncomingTextBubbleStyle`) and link it inside the hub. The base bubble background remains unchanged.
+
+**Q**: Where do I find all available attributes for a bubble type?
+**A**: Use the Attribute reference links under each bubble section above.
+
+**Q**: How do I style call action bubbles differently from message bubbles?
+**A**: Call action and action bubbles are linked to `CometChatMessageListStyle`, not the incoming/outgoing hubs. See the Call Action Bubble and Action Bubble sections.
+
+**Q**: Can I change the bubble corner radius?
+**A**: Yes. Set `cometchatMessageBubbleCornerRadius` in your incoming or outgoing hub style.
diff --git a/ui-kit/android/message-composer.mdx b/ui-kit/android/message-composer.mdx
index ca7e8ae2e..0abab5b9c 100644
--- a/ui-kit/android/message-composer.mdx
+++ b/ui-kit/android/message-composer.mdx
@@ -2,76 +2,268 @@
title: "Message Composer"
---
-## Overview
+`CometChatMessageComposer` enables users to write and send a variety of messages, including text, image, video, and custom messages. It supports features such as live reactions, attachments, and message editing.
+
+## AI Agent Component Spec
+
+
+
+```json
+{
+ "component": "CometChatMessageComposer",
+ "package": "com.cometchat.chatuikit.messagecomposer",
+ "xmlElement": "",
+ "description": "Message input area with send, attachment, voice note, sticker, and AI buttons. Supports text, media, mentions, and message editing.",
+ "primaryOutput": {
+ "method": "setOnSendButtonClick",
+ "type": "SendButtonClick"
+ },
+ "methods": {
+ "data": {
+ "setUser": {
+ "type": "User",
+ "default": "null",
+ "note": "Sets the target user for one-on-one conversations"
+ },
+ "setGroup": {
+ "type": "Group",
+ "default": "null",
+ "note": "Sets the target group for group conversations"
+ }
+ },
+ "callbacks": {
+ "setOnSendButtonClick": "SendButtonClick — void onClick(Context context, BaseMessage message)",
+ "setOnError": "OnError",
+ "setOnTextChangedListener": "CometChatTextWatcher"
+ },
+ "visibility": {
+ "setAttachmentButtonVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" },
+ "setVoiceNoteButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setSendButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setStickersButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setAuxiliaryButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setImageAttachmentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setCameraAttachmentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setVideoAttachmentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setAudioAttachmentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setFileAttachmentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setPollAttachmentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setCollaborativeDocumentOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setCollaborativeWhiteboardOptionVisibility": { "type": "int", "default": "View.VISIBLE" }
+ },
+ "viewSlots": {
+ "setHeaderView": "View — custom view above the text input area",
+ "setFooterView": "View — custom view below the text input area",
+ "setSendButtonView": "View — replaces the default send button",
+ "setAuxiliaryButtonView": "View — replaces the auxiliary button area (stickers, AI)",
+ "setAttachmentOptions": "List — replaces default attachment options",
+ "setAIOptions": "Function4> — replaces AI options",
+ "setTextFormatters": "List — custom text formatters (mentions, etc.)",
+ "setSuggestionListItemView": "SuggestionListViewHolderListener — custom suggestion list item"
+ },
+ "advanced": {
+ "setParentMessageId": "long — sets the parent message ID for threaded replies",
+ "setInitialComposerText": "String — sets predefined text in the input field",
+ "getText": "String — returns the current raw text",
+ "getProcessedText": "String — returns text with formatting applied",
+ "getComposerViewModel": "MessageComposerViewModel — internal ViewModel access",
+ "getMessageInput": "CometChatMessageInput — internal message input access",
+ "getView": "LinearLayout — root view access"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatMessageComposerStyle"
+ }
+ }
+ },
+ "events": [],
+ "sdkListeners": []
+}
+```
-MessageComposer is a [Component](/ui-kit/android/components-overview#components) that enables users to write and send a variety of messages, including text, image, video, and custom messages.
+
-Features such as **Live Reaction**, **Attachments**, and **Message Editing** are also supported by it.
+## Where It Fits
-
-
-
+`CometChatMessageComposer` is an input component. It renders the message input area and sends messages to the active conversation. Wire it with `CometChatMessageHeader` and `CometChatMessageList` to build a complete messaging layout.
+
+
+
+```kotlin ChatActivity.kt lines
+class ChatActivity : AppCompatActivity() {
+
+ private lateinit var messageHeader: CometChatMessageHeader
+ private lateinit var messageList: CometChatMessageList
+ private lateinit var messageComposer: CometChatMessageComposer
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_chat)
+
+ messageHeader = findViewById(R.id.message_header)
+ messageList = findViewById(R.id.message_list)
+ messageComposer = findViewById(R.id.message_composer)
-## Usage
+ // Set the user on all three components
+ messageHeader.setUser(user)
+ messageList.setUser(user)
+ messageComposer.setUser(user)
+ }
+}
+```
+
+
+
+```java ChatActivity.java lines
+public class ChatActivity extends AppCompatActivity {
+
+ private CometChatMessageHeader messageHeader;
+ private CometChatMessageList messageList;
+ private CometChatMessageComposer messageComposer;
-### Integration
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ messageHeader = findViewById(R.id.message_header);
+ messageList = findViewById(R.id.message_list);
+ messageComposer = findViewById(R.id.message_composer);
+
+ // Set the user on all three components
+ messageHeader.setUser(user);
+ messageList.setUser(user);
+ messageComposer.setUser(user);
+ }
+}
+```
+
+
-The following code snippet illustrates how you can directly incorporate the MessageComposer component into your `layout.xml` file.
+## Quick Start
-```python
+Add the component to your layout XML:
+
+```xml layout_activity.xml lines
+ android:id="@+id/composer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
```
-
+
+
+
-The MessageComposer is responsible for managing runtime permissions. To ensure the **ActivityResultLauncher** is properly initialized, its object should be created in the the **onCreate** state of an activity. To ensure that the composer is loaded within the fragment, it is important to make sure that the fragment is loaded in the `onCreate` state of the activity.
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.
+
+The MessageComposer is responsible for managing runtime permissions. To ensure the **ActivityResultLauncher** is properly initialized, its object should be created in the **onCreate** state of an activity. To ensure that the composer is loaded within the fragment, it is important to make sure that the fragment is loaded in the `onCreate` state of the activity.
-### Actions
+To add programmatically in an Activity:
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+
+
+```kotlin YourActivity.kt lines
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val composer = CometChatMessageComposer(this)
+ composer.setUser(user)
+ setContentView(composer)
+}
+```
+
-##### setOnSendButtonClick
+
+```java YourActivity.java lines
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ CometChatMessageComposer composer = new CometChatMessageComposer(this);
+ composer.setUser(user);
+ setContentView(composer);
+}
+```
+
+
-The `OnSendButtonClick` event gets activated when the send message button is clicked. It has a predefined function of sending messages entered in the composer `EditText`. However, you can overide this action with the following code snippet.
+Or in a Fragment:
-
-```java
- messageComposer.setOnSendButtonClick(new CometChatMessageComposer.SendButtonClick() {
- @Override
- public void onClick(Context context, BaseMessage baseMessage) {
- Toast.makeText(context, "OnSendButtonClicked ..", Toast.LENGTH_SHORT).show();
- }
- });
+
+```kotlin YourFragment.kt lines
+override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ val composer = CometChatMessageComposer(requireContext())
+ composer.setUser(user)
+ return composer
+}
```
+
+
+```java YourFragment.java lines
+@Override
+public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ CometChatMessageComposer composer = new CometChatMessageComposer(getContext());
+ composer.setUser(user);
+ return composer;
+}
+```
+
+## Actions and Events
+
+### Callback Methods
+
+#### `setOnSendButtonClick`
+
+Fires when the send button is tapped. Primary hook — override to intercept or replace the default message-sending logic.
+
+
-```kotlin
- messageComposer.setOnSendButtonClick(object : CometChatMessageComposer.SendButtonClick {
+```kotlin YourActivity.kt lines
+messageComposer.setOnSendButtonClick(object : CometChatMessageComposer.SendButtonClick {
override fun onClick(context: Context, baseMessage: BaseMessage) {
Toast.makeText(context, "OnSendButtonClicked ..", Toast.LENGTH_SHORT).show()
}
- })
+})
```
-
+
+```java YourActivity.java lines
+messageComposer.setOnSendButtonClick(new CometChatMessageComposer.SendButtonClick() {
+ @Override
+ public void onClick(Context context, BaseMessage baseMessage) {
+ Toast.makeText(context, "OnSendButtonClicked ..", Toast.LENGTH_SHORT).show();
+ }
+});
+```
+
-##### setOnError
+> **What this does:** Replaces the default send-button behavior. When a user taps the send button, your custom lambda executes instead of the built-in message sending logic.
+
+#### `setOnError`
-This action doesn't change the behavior of the component but rather listens for any errors that occur in the MessageList component.
+Fires on internal errors (network failure, auth issue, SDK exception).
+
+```kotlin YourActivity.kt lines
+messageComposer.setOnError(object : OnError {
+ override fun onError(context: Context, e: CometChatException) {
+ // Your Exception Handling code.
+ }
+})
+```
+
+
-```java YourActivity.java
+```java YourActivity.java lines
messageComposer.setOnError(new OnError() {
@Override
public void onError(Context context, CometChatException e) {
@@ -79,198 +271,528 @@ messageComposer.setOnError(new OnError() {
}
});
```
-
+
+
+> **What this does:** Registers an error listener. If the component encounters an error, your callback receives the `CometChatException`.
+
+#### `setOnTextChangedListener`
+
+Fires whenever the message input's text value changes, enabling dynamic text handling.
+
-```kotlin YourActivity.kt
-messageComposer.setOnError(object : OnError {
- override fun onError(context: Context, e: CometChatException) {
- // Your Exception Handling code.
+```kotlin YourActivity.kt lines
+messageComposer.setOnTextChangedListener(object : CometChatTextWatcher() {
+ override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {
+ }
+
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ }
+
+ override fun afterTextChanged(editable: Editable) {
}
})
```
-
+
+```java YourActivity.java lines
+messageComposer.setOnTextChangedListener(new CometChatTextWatcher() {
+ @Override
+ public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+});
+```
+
-##### setOnTextChangedListener
+> **What this does:** Registers a `CometChatTextWatcher` that fires callbacks when the text in the composer input field changes. Use `onTextChanged` for real-time character tracking, `beforeTextChanged` for pre-change state, and `afterTextChanged` for post-change processing.
-Function triggered whenever the message input's text value changes, enabling dynamic text handling.
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap send, type text) and confirm your custom logic executes instead of the default behavior.
-
-
-```java YourActivity.java
-messageComposer.setOnTextChangedListener(new CometChatTextWatcher() {
- @Override
- public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
+### Global UI Events (CometChatMessageEvents)
+
+The MessageComposer component does not emit any events of its own. However, message-related events can be observed via `CometChatMessageEvents` from other components in the messaging flow.
+
+### SDK Events
+
+The MessageComposer component does not attach SDK listeners directly. Typing indicators are managed internally when `disableTypingEvents` is `false` (default).
+
+## Functionality
+
+Small functional customizations such as toggling visibility of UI elements and configuring composer behavior.
+
+| Method | Type | Default | Description |
+| --- | --- | --- | --- |
+| `setAttachmentButtonVisibility` | `int` | `View.VISIBLE` | Toggles visibility for the attachment button |
+| `setVoiceNoteButtonVisibility` | `int` | `View.VISIBLE` | Toggles visibility for the voice note recording button |
+| `setSendButtonVisibility` | `int` | `View.VISIBLE` | Toggles visibility for the send button |
+| `setStickersButtonVisibility` | `int` | `View.VISIBLE` | Toggles visibility for the stickers button |
+| `setAuxiliaryButtonVisibility` | `int` | `View.VISIBLE` | Toggles visibility for the auxiliary button area (AI, stickers) |
+| `setImageAttachmentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether image attachments are allowed |
+| `setCameraAttachmentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether camera attachments are allowed |
+| `setVideoAttachmentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether video attachments are allowed |
+| `setAudioAttachmentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether audio attachments are allowed |
+| `setFileAttachmentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether file attachments are allowed |
+| `setPollAttachmentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether polls can be shared |
+| `setCollaborativeDocumentOptionVisibility` | `int` | `View.VISIBLE` | Controls whether collaborative documents can be shared |
+| `setCollaborativeWhiteboardOptionVisibility` | `int` | `View.VISIBLE` | Controls whether collaborative whiteboards can be shared |
+| `disableTypingEvents` | `boolean` | `false` | Disables or enables typing indicator events |
+| `disableSoundForMessages` | `boolean` | `false` | Toggles sound for outgoing messages |
+| `setDisableMentions` | `boolean` | `false` | Disables mentions in text; removes `CometChatMentionsFormatter` instances |
+| `setMaxLine` | `int` | SDK default | Maximum lines allowed in the input field |
+| `setPlaceHolderText` | `String` | SDK default | Sets the placeholder text in the message input field |
+
+- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden.
+
+## Custom View Slots
- }
+Each slot replaces a section of the default composer UI.
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Header view | `setHeaderView(View)` | Custom view above the text input area |
+| Footer view | `setFooterView(View)` | Custom view below the text input area |
+| Send button | `setSendButtonView(View)` | Default send button |
+| Auxiliary button | `setAuxiliaryButtonView(View)` | Auxiliary button area (stickers, AI) |
+| Attachment options | `setAttachmentOptions(List)` | Default attachment options |
+| AI options | `setAIOptions(Function4)` | Default AI options |
+| Text formatters | `setTextFormatters(List)` | Default text formatters |
+| Suggestion list item | `setSuggestionListItemView(SuggestionListViewHolderListener)` | Default suggestion list item view |
- }
+### `setHeaderView`
- @Override
- public void afterTextChanged(Editable editable) {
+Sets a custom view above the text input area.
- }
- });
+
+
+```kotlin lines
+val view: View = LayoutInflater.from(context).inflate(R.layout.custom_header_layout, null)
+cometChatMessageComposer.setHeaderView(view)
```
+
+
+```java lines
+View view = getLayoutInflater().inflate(R.layout.custom_header_layout, null);
+cometChatMessageComposer.setHeaderView(view);
+```
+
-
-```kotlin YourActivity.kt
-messageComposer.setOnTextChangedListener(object : CometChatTextWatcher() {
- override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {
- }
+> **What this does:** Sets a custom `View` as the header of the composer. The header view renders above the text input area.
+
+Example with a "Notes" card header:
+
+
+
+
+
+Create a `custom_header_layout.xml` layout:
+
+```xml custom_header_layout.xml lines
+
+
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
- }
+
- override fun afterTextChanged(editable: Editable) {
- }
- })
+
+
+
+
+
+
+
+
+
```
+
+
+```kotlin lines
+val view: View = LayoutInflater.from(context).inflate(R.layout.custom_header_layout, null)
+cometChatMessageComposer.setHeaderView(view)
+```
+
+```java lines
+View view = getLayoutInflater().inflate(R.layout.custom_header_layout, null);
+cometChatMessageComposer.setHeaderView(view);
+```
+
-***
+### `setFooterView`
-### Filters
+Sets a custom view below the text input area.
-MessageComposer component does not have any available filters.
-
-***
+
+
+```kotlin lines
+cometChatMessageComposer.setFooterView(view)
+```
+
-### Events
+
+```java lines
+cometChatMessageComposer.setFooterView(view);
+```
+
+
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed.
+> **What this does:** Sets a custom `View` as the footer of the composer. The footer view renders below the text input area.
-The MessageComposer Component does not emit any events of its own.
+### `setSendButtonView`
-***
+Replaces the default send button with a custom view.
-## Customization
+
+
+```kotlin lines
+cometChatMessageComposer.setSendButtonView(view)
+```
+
-To fit your app's design requirements, you can customize the appearance of the MessageComposer component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
+
+```java lines
+cometChatMessageComposer.setSendButtonView(view);
+```
+
+
-### Style
+> **What this does:** Replaces the default send button with your custom `View`. The custom view takes over the send button position in the composer.
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
+Custom send button example:
-
+
-```html
-
+First, create a custom send button drawable:
+
+```xml drawable/custom_send_button.xml lines
-
-
-
-
-
+
+
```
-```html
-
-
+
+
+```kotlin lines
+val imageView = ImageView(this)
+imageView.setImageResource(R.drawable.custom_send_button)
+imageView.setOnClickListener {
+ Toast
+ .makeText(this@YourActivity, "Custom Send Button Clicked !!!", Toast.LENGTH_SHORT)
+ .show()
+}
+cometChatMessageComposer.setSendButtonView(imageView)
```
+
-
-```java
-cometChatMessageComposer.setStyle(R.style.CustomMessageComposerStyle);
+```java lines
+ImageView imageView = new ImageView(this);
+imageView.setImageResource(R.drawable.custom_send_button);
+imageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast.makeText(YourActivity.this, "Custom Send Button Clicked !!!", Toast.LENGTH_SHORT).show();
+ }
+});
+cometChatMessageComposer.setSendButtonView(imageView);
```
+
+
+
+### `setAuxiliaryButtonView`
+Replaces the auxiliary button area. The default auxiliary area provides sticker and AI functionality.
+
+
+The MessageComposer uses the AuxiliaryButton for sticker functionality. If you override it with `setAuxiliaryButtonView()`, retrieve the default auxiliary buttons via `CometChatUIKit.getDataSource().getAuxiliaryOption()` and include them in your custom layout to preserve sticker/AI buttons.
+
+
+
+
+```kotlin lines
+cometChatMessageComposer.setAuxiliaryButtonView(view)
+```
+
+```java lines
+cometChatMessageComposer.setAuxiliaryButtonView(view);
+```
+
+
+
+Custom SOS button example:
+
+
+
+
+
+
-```kotlin
-cometChatMessageComposer.setStyle(R.style.CustomMessageComposerStyle)
+```kotlin lines
+val imageView = ImageView(this)
+imageView.setImageResource(android.R.drawable.save_icon)
+val linearLayout = LinearLayout(this)
+linearLayout.orientation = LinearLayout.HORIZONTAL
+
+// code to get default auxiliary buttons
+val view = CometChatUIKit
+ .getDataSource()
+ .getAuxiliaryOption(
+ this,
+ user,
+ group,
+ binding.messageComposer.composerViewModel.getIdMap(),
+ binding.messageComposer.additionParameter
+ )
+
+linearLayout.addView(view)
+linearLayout.addView(imageView)
+cometChatMessageComposer.setAuxiliaryButtonView(linearLayout)
```
+
+
+```java lines
+ImageView imageView = new ImageView(this);
+imageView.setImageResource(R.drawable.save_icon);
+LinearLayout linearLayout = new LinearLayout(this);
+linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+// code to get default auxiliary buttons
+View view = CometChatUIKit
+ .getDataSource()
+ .getAuxiliaryOption(this,
+ user,
+ group,
+ binding.messageComposer.getComposerViewModel().getIdMap(),
+ binding.messageComposer.getAdditionParameter());
+
+linearLayout.addView(view);
+linearLayout.addView(imageView);
+cometChatMessageComposer.setAuxiliaryButtonView(linearLayout);
+```
+
+
+> **What this does:** Creates a horizontal `LinearLayout` containing the default auxiliary buttons (retrieved via `CometChatUIKit.getDataSource().getAuxiliaryOption()`) and a custom `ImageView`. The combined layout replaces the default auxiliary button area, preserving the existing sticker/AI buttons while adding a custom button.
+### `setAttachmentOptions`
+
+Replaces the default attachment options with a custom list of `CometChatMessageComposerAction` objects.
+
+
+
+```kotlin lines
+cometChatMessageComposer.setAttachmentOptions(actionList)
+```
+
+
+
+```java lines
+cometChatMessageComposer.setAttachmentOptions(actionList);
+```
+
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_composer.xml).
+Custom attachment options example:
+
+
+
+
+
+
+
+```kotlin lines
+val actionList = ArrayList()
+
+val action1 = CometChatMessageComposerAction()
+action1.title = "Custom Option 1"
+action1.icon = R.drawable.ic_cp_1
+action1.onClick = {
+ Toast.makeText(context, "Custom Option 1 !!!", Toast.LENGTH_SHORT).show()
+}
+actionList.add(action1)
+
+val action2 = CometChatMessageComposerAction()
+action2.title = "Custom Option 2"
+action2.icon = R.drawable.ic_cp_2
+action2.onClick = {
+ Toast.makeText(context, "Custom Option 2 !!!", Toast.LENGTH_SHORT).show()
+}
+actionList.add(action2)
+
+val action3 = CometChatMessageComposerAction()
+action3.title = "Custom Option 3"
+action3.icon = R.drawable.ic_cp_3
+action3.onClick = {
+ Toast.makeText(context, "Custom Option 3 !!!", Toast.LENGTH_SHORT).show()
+}
+actionList.add(action3)
+
+val action4 = CometChatMessageComposerAction()
+action4.title = "Custom Option 4"
+action4.icon = R.drawable.ic_cp_4
+action4.onClick = {
+ Toast.makeText(context, "Custom Option 4 !!!", Toast.LENGTH_SHORT).show()
+}
+actionList.add(action4)
+
+cometChatMessageComposer.setAttachmentOptions(actionList)
+```
+
+
+
+```java lines
+List actionList = new ArrayList<>();
+
+CometChatMessageComposerAction action1 = new CometChatMessageComposerAction();
+action1.setTitle("Custom Option 1");
+action1.setIcon(R.drawable.ic_cp_1);
+action1.setOnClick(new OnClick() {
+ @Override
+ public void onClick() {
+ Toast.makeText(context, "Custom Option 1 !!!", Toast.LENGTH_SHORT).show();
+ }
+});
+actionList.add(action1);
-***
+CometChatMessageComposerAction action2 = new CometChatMessageComposerAction();
+action2.setTitle("Custom Option 2");
+action2.setIcon(R.drawable.ic_cp_2);
+action2.setOnClick(new OnClick() {
+ @Override
+ public void onClick() {
+ Toast.makeText(context, "Custom Option 2 !!!", Toast.LENGTH_SHORT).show();
+ }
+});
+actionList.add(action2);
-### Functionality
+CometChatMessageComposerAction action3 = new CometChatMessageComposerAction();
+action3.setTitle("Custom Option 3");
+action3.setIcon(R.drawable.ic_cp_3);
+action3.setOnClick(new OnClick() {
+ @Override
+ public void onClick() {
+ Toast.makeText(context, "Custom Option 3 !!!", Toast.LENGTH_SHORT).show();
+ }
+});
+actionList.add(action3);
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements.
+CometChatMessageComposerAction action4 = new CometChatMessageComposerAction();
+action4.setTitle("Custom Option 4");
+action4.setIcon(R.drawable.ic_cp_4);
+action4.setOnClick(new OnClick() {
+ @Override
+ public void onClick() {
+ Toast.makeText(context, "Custom Option 4 !!!", Toast.LENGTH_SHORT).show();
+ }
+});
+actionList.add(action4);
-Below is a list of customizations along with corresponding code snippets
+cometChatMessageComposer.setAttachmentOptions(actionList);
+```
+
+
-| Property | Description | Code |
-| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
-| **User** | Used to pass user object of which header specific details will be shown | `.setUser(user)` |
-| **Group** | Used to pass group object of which header specific details will be shown | `.setGroup(Group)` |
-| **disableTypingEvents** | Used to disable/enable typing events , default false | `.disableTypingEvents(boolean)` |
-| **disableSoundForMessages** | Used to toggle sound for outgoing messages | `.disableSoundForMessages(boolean)` |
-| **setInitialComposerText** | Used to set predefined text | `.setInitialComposerText("Your_Text")` |
-| **setMaxLine** | Maximum lines allowed to increase in the input field | `.setMaxLine(int)` |
-| **setAuxiliaryButtonAlignment** | controls position auxiliary button view , can be **left** or **right** . default **right** | `.setAuxiliaryButtonAlignment(AuxiliaryButtonsAlignment)` |
-| **setDisableMentions** | Sets whether mentions in text should be disabled. Processes the text formatters If there are text formatters available and the disableMentions flag is set to true, it removes any formatters that are instances of CometChatMentionsFormatter. | `.setDisableMentions(true);` |
-| **setCustomSoundForMessages** | Used to give custom sounds to outgoing messages | `.setCustomSoundForMessages(String)` |
-| **setAttachmentButtonVisibility** | Hides the attachment button in the composer | `.setAttachmentButtonVisibility(View.VISIBLE)` |
-| **setStickersButtonVisibility** | Hides the stickers button in the composer | `.setStickersButtonVisibility(View.GONE)` |
-| **setSendButtonVisibility** | Hides the send button in the composer | `.setSendButtonVisibility(View.VISIBLE)` |
-| **setCameraAttachmentOptionVisibility** | Controls whether camera attachments are allowed | `.setCameraAttachmentOptionVisibility(View.VISIBLE)` |
-| **setImageAttachmentOptionVisibility** | Controls whether image attachments are allowed | `.setImageAttachmentOptionVisibility(View.VISIBLE)` |
-| **setVideoAttachmentOptionVisibility** | Controls whether video attachments are allowed | `.setVideoAttachmentOptionVisibility(View.VISIBLE)` |
-| **setAudioAttachmentOptionVisibility** | Controls whether audio attachments are allowed | `.setAudioAttachmentOptionVisibility(View.VISIBLE)` |
-| **setFileAttachmentOptionVisibility** | Controls whether file attachments are allowed | `.setFileAttachmentOptionVisibility(View.VISIBLE)` |
-| **setPollAttachmentOptionVisibility** | Controls whether polls can be shared | `.setPollAttachmentOptionVisibility(View.VISIBLE)` |
-| **setCollaborativeDocumentOptionVisibility** | Controls whether collaborative documents can be shared | `.setCollaborativeDocumentOptionVisibility(View.VISIBLE)` |
-| **setCollaborativeWhiteboardOptionVisibility** | Controls whether collaborative whiteboards can be shared | `.setCollaborativeWhiteboardOptionVisibility(View.VISIBLE)` |
+> **What this does:** Creates four custom `CometChatMessageComposerAction` objects, each with a title, icon, and click handler. The list replaces the default attachment options (camera, image, video, audio, file, poll, etc.) with these four custom actions.
-***
+### `setAIOptions`
-### Advanced
+Replaces the default AI options with a custom provider function.
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
+
+
+```kotlin lines
+cometChatMessageComposer.setAIOptions { context, user, group, idMap ->
+ val actionList = ArrayList()
+ // Build custom AI actions
+ actionList
+}
+```
+
-***
+
+```java lines
+cometChatMessageComposer.setAIOptions((context, user, group, idMap) -> {
+ List actionList = new ArrayList<>();
+ // Build custom AI actions
+ return actionList;
+});
+```
+
+
-#### setTextFormatters
+> **What this does:** Registers a function that returns a list of `CometChatMessageComposerAction` objects for the AI options sheet. The function receives the current context, user, group, and ID map.
-Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel check out [CometChatMentionsFormatter](/ui-kit/android/mentions-formatter-guide)
+### `setTextFormatters`
-**Example**
+Assigns a list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters. To configure the existing Mentions look and feel check out [CometChatMentionsFormatter](/ui-kit/android/mentions-formatter-guide).
-```xml themes.xml
-
+```xml themes.xml lines
+```
+
-```kotlin
-val view: View = LayoutInflater.from(context).inflate(R.layout.custom_header_layout, null)
-cometChatMessageComposer.setHeaderView(view)
+```kotlin lines
+cometChatMessageComposer.setStyle(R.style.CustomMessageComposerStyle)
```
-
+
+```java lines
+cometChatMessageComposer.setStyle(R.style.CustomMessageComposerStyle);
+```
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_composer.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setCornerRadius` | `int` | Corner radius of the component |
+| `setComposeBoxBackgroundColor` | `@ColorInt int` | Background color of the compose box |
+| `setComposeBoxStrokeWidth` | `@Dimension int` | Stroke width of the compose box border |
+| `setComposeBoxStrokeColor` | `@ColorInt int` | Stroke color of the compose box border |
+| `setComposeBoxCornerRadius` | `@Dimension int` | Corner radius of the compose box |
+| `setComposeBoxBackgroundDrawable` | `Drawable` | Custom background drawable for the compose box |
+| `setSeparatorColor` | `@ColorInt int` | Color of the separator line |
+| `setAttachmentIcon` | `Drawable` | Custom attachment icon drawable |
+| `setAttachmentIconTint` | `@ColorInt int` | Tint color for the attachment icon |
+| `setVoiceRecordingIcon` | `Drawable` | Custom voice recording icon drawable |
+| `setVoiceRecordingIconTint` | `@ColorInt int` | Tint color for the voice recording icon |
+| `setAIIcon` | `Drawable` | Custom AI icon drawable |
+| `setAIIconTint` | `@ColorInt int` | Tint color for the AI icon |
+| `setActiveSendButtonDrawable` | `Drawable` | Drawable for the active send button |
+| `setInactiveSendButtonDrawable` | `Drawable` | Drawable for the inactive send button |
+| `setActiveStickerIcon` | `Drawable` | Drawable for the active sticker icon |
+| `setActiveStickerIconTint` | `@ColorInt int` | Tint for the active sticker icon |
+| `setInactiveStickerIcon` | `Drawable` | Drawable for the inactive sticker icon |
+| `setInactiveStickerIconTint` | `@ColorInt int` | Tint for the inactive sticker icon |
+| `setMessageInputStyle` | `@StyleRes int` | Style for the message input field |
+| `setMentionsStyle` | `@StyleRes int` | Style for mentions rendering |
+| `setMediaRecorderStyle` | `@StyleRes int` | Style for the media recorder |
+| `setSuggestionListStyle` | `@StyleRes int` | Style for the suggestion list |
+| `setAttachmentOptionSheetStyle` | `@StyleRes int` | Style for the attachment option sheet |
+| `setAIOptionSheetStyle` | `@StyleRes int` | Style for the AI option sheet |
+
+### Edit Preview Style Properties
+
+When editing a message, a preview appears above the input. These properties control its appearance:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setEditPreviewTitleTextAppearance` | `@StyleRes int` | Text appearance for the edit preview title |
+| `setEditPreviewTitleTextColor` | `@ColorInt int` | Text color for the edit preview title |
+| `setEditPreviewMessageTextAppearance` | `@StyleRes int` | Text appearance for the edit preview message |
+| `setEditPreviewMessageTextColor` | `@ColorInt int` | Text color for the edit preview message |
+| `setEditPreviewBackgroundColor` | `@ColorInt int` | Background color for the edit preview |
+| `setEditPreviewCornerRadius` | `@Dimension int` | Corner radius for the edit preview |
+| `setEditPreviewStrokeColor` | `@ColorInt int` | Stroke color for the edit preview |
+| `setEditPreviewStrokeWidth` | `@Dimension int` | Stroke width for the edit preview |
+| `setEditPreviewCloseIcon` | `Drawable` | Close icon for the edit preview |
+| `setEditPreviewCloseIconTint` | `@ColorInt int` | Tint for the edit preview close icon |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override send button behavior | Activity/Fragment | `setOnSendButtonClick` | `setOnSendButtonClick(sendButtonClick)` |
+| Listen for text changes | Activity/Fragment | `setOnTextChangedListener` | `setOnTextChangedListener(textWatcher)` |
+| Handle errors | Activity/Fragment | `setOnError` | `setOnError(onError)` |
+| Target user | Activity/Fragment | `setUser(User)` | `.setUser(user)` |
+| Target group | Activity/Fragment | `setGroup(Group)` | `.setGroup(group)` |
+| Thread replies | Activity/Fragment | `setParentMessageId(long)` | `.setParentMessageId(parentMessage.getId())` |
+| Attachment button visibility | Activity/Fragment | `setAttachmentButtonVisibility(int)` | `.setAttachmentButtonVisibility(View.GONE)` |
+| Voice note button visibility | Activity/Fragment | `setVoiceNoteButtonVisibility(int)` | `.setVoiceNoteButtonVisibility(View.GONE)` |
+| Send button visibility | Activity/Fragment | `setSendButtonVisibility(int)` | `.setSendButtonVisibility(View.GONE)` |
+| Stickers button visibility | Activity/Fragment | `setStickersButtonVisibility(int)` | `.setStickersButtonVisibility(View.GONE)` |
+| Auxiliary button visibility | Activity/Fragment | `setAuxiliaryButtonVisibility(int)` | `.setAuxiliaryButtonVisibility(View.GONE)` |
+| Image attachment option | Activity/Fragment | `setImageAttachmentOptionVisibility(int)` | `.setImageAttachmentOptionVisibility(View.GONE)` |
+| Camera attachment option | Activity/Fragment | `setCameraAttachmentOptionVisibility(int)` | `.setCameraAttachmentOptionVisibility(View.GONE)` |
+| Video attachment option | Activity/Fragment | `setVideoAttachmentOptionVisibility(int)` | `.setVideoAttachmentOptionVisibility(View.GONE)` |
+| Audio attachment option | Activity/Fragment | `setAudioAttachmentOptionVisibility(int)` | `.setAudioAttachmentOptionVisibility(View.GONE)` |
+| File attachment option | Activity/Fragment | `setFileAttachmentOptionVisibility(int)` | `.setFileAttachmentOptionVisibility(View.GONE)` |
+| Poll attachment option | Activity/Fragment | `setPollAttachmentOptionVisibility(int)` | `.setPollAttachmentOptionVisibility(View.GONE)` |
+| Collaborative document option | Activity/Fragment | `setCollaborativeDocumentOptionVisibility(int)` | `.setCollaborativeDocumentOptionVisibility(View.GONE)` |
+| Collaborative whiteboard option | Activity/Fragment | `setCollaborativeWhiteboardOptionVisibility(int)` | `.setCollaborativeWhiteboardOptionVisibility(View.GONE)` |
+| Typing events | Activity/Fragment | `disableTypingEvents(boolean)` | `.disableTypingEvents(true)` |
+| Outgoing message sound | Activity/Fragment | `disableSoundForMessages(boolean)` | `.disableSoundForMessages(true)` |
+| Custom outgoing message sound | Activity/Fragment | `setCustomSoundForMessages(int)` | `.setCustomSoundForMessages(R.raw.custom_sound)` |
+| Predefined text | Activity/Fragment | `setInitialComposerText(String)` | `.setInitialComposerText("Hello!")` |
+| Max input lines | Activity/Fragment | `setMaxLine(int)` | `.setMaxLine(5)` |
+| Placeholder text | Activity/Fragment | `setPlaceHolderText(String)` | `.setPlaceHolderText("Type a message...")` |
+| Disable mentions | Activity/Fragment | `setDisableMentions(boolean)` | `.setDisableMentions(true)` |
+| Auxiliary button alignment | Activity/Fragment | `setAuxiliaryButtonAlignment(AuxiliaryButtonsAlignment)` | `.setAuxiliaryButtonAlignment(alignment)` |
+| Header view | Activity/Fragment | `setHeaderView(View)` | See `setHeaderView` code above |
+| Footer view | Activity/Fragment | `setFooterView(View)` | See `setFooterView` code above |
+| Send button view | Activity/Fragment | `setSendButtonView(View)` | See `setSendButtonView` code above |
+| Auxiliary button view | Activity/Fragment | `setAuxiliaryButtonView(View)` | See `setAuxiliaryButtonView` code above |
+| Attachment options (replace) | Activity/Fragment | `setAttachmentOptions(List)` | See `setAttachmentOptions` code above |
+| AI options (replace) | Activity/Fragment | `setAIOptions(Function4)` | See `setAIOptions` code above |
+| Text formatters | Activity/Fragment | `setTextFormatters(List)` | See `setTextFormatters` code above |
+| Suggestion list item view | Activity/Fragment | `setSuggestionListItemView(listener)` | See `setSuggestionListItemView` code above |
+| Attachment icon tint | `themes.xml` | `cometchatMessageComposerAttachmentIconTint` | `#F76808` |
+| Voice recording icon tint | `themes.xml` | `cometchatMessageComposerVoiceRecordingIconTint` | `#F76808` |
+| Active sticker icon tint | `themes.xml` | `cometchatMessageComposerActiveStickerIconTint` | `#F76808` |
+| Inactive sticker icon tint | `themes.xml` | `cometchatMessageComposerInactiveStickerIconTint` | `#F76808` |
+| AI icon tint | `themes.xml` | `cometchatMessageComposerAIIconTint` | `#F76808` |
+| Active send button drawable | `themes.xml` | `cometchatMessageComposerActiveSendButtonDrawable` | `@drawable/active_send_button` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometChatMessageComposer.setStyle(R.style.CustomMessageComposerStyle);` |
+| Mentions text style | `themes.xml` | `CometChatMessageComposerMentionsStyle` | `#000000` |
+| Compose box background | Activity/Fragment | `setComposeBoxBackgroundColor(int)` | `.setComposeBoxBackgroundColor(Color.WHITE)` |
+| Compose box stroke | Activity/Fragment | `setComposeBoxStrokeColor(int)` | `.setComposeBoxStrokeColor(Color.GRAY)` |
+| Separator color | Activity/Fragment | `setSeparatorColor(int)` | `.setSeparatorColor(Color.LTGRAY)` |
+| Edit preview style | Activity/Fragment | `setEditPreview*` methods | See Style section above |
+
+## Accessibility
+
+The component renders a message input area with interactive buttons for send, attachment, voice note, stickers, and AI. The text input field supports standard Android accessibility — TalkBack announces the placeholder text and current input content.
+
+For custom views provided via `setHeaderView`, `setFooterView`, `setSendButtonView`, or `setAuxiliaryButtonView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+Voice recording and attachment buttons include built-in content descriptions. If you replace them with custom views, provide appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load. |
+| Messages not sending to the correct conversation | Ensure you call `.setUser(user)` or `.setGroup(group)` on the `CometChatMessageComposer` instance to associate it with the correct conversation. |
+| `ActivityResultLauncher` not initialized | The `CometChatMessageComposer` manages runtime permissions. Ensure its object is created in the `onCreate` state of an Activity. If using a Fragment, ensure the Fragment is loaded in the `onCreate` state of the Activity. |
+| Custom style not visible | Verify the style parent is `CometChatMessageComposerStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| Sticker button disappears after setting auxiliary view | The MessageComposer uses the AuxiliaryButton for sticker functionality. If you override it with `setAuxiliaryButtonView()`, retrieve the default auxiliary buttons via `CometChatUIKit.getDataSource().getAuxiliaryOption()` and include them in your custom layout. |
+| Attachment options not showing custom actions | Ensure you pass the list of `CometChatMessageComposerAction` objects to `setAttachmentOptions(actionList)`. Calling `setAttachmentOptions()` without a list does not add custom actions. |
+| Typing indicators still sent after disabling | Ensure you call `disableTypingEvents(true)` before the component starts loading. If called after the component is already active, it may not take effect immediately. |
+| `setOnSendButtonClick` not firing | If you set a custom send button view with `setSendButtonView()`, the `setOnSendButtonClick` callback may not fire because the custom view replaces the default send button entirely. Attach your click listener directly to the custom view instead. |
+| Mentions not rendering with custom style | Ensure you create a `CometChatMentionsFormatter`, call `setMessageComposerMentionTextStyle()` with your custom style resource, and pass the formatter in a list to `setTextFormatters()`. |
+| Predefined text not appearing | Ensure you call `setInitialComposerText("Your_Text")` after the component is initialized and attached to the view hierarchy. |
+
+## FAQ
+
+**Q: Does the MessageComposer support filters or events?**
+**A:** No. The MessageComposer component does not have any available filters and does not emit any events of its own.
+
+**Q: How do I set the target user or group for the composer?**
+**A:** Call `.setUser(user)` for a one-on-one conversation or `.setGroup(group)` for a group conversation on the `CometChatMessageComposer` instance.
+
+**Q: How do I keep the default sticker button when adding a custom auxiliary view?**
+**A:** Retrieve the default auxiliary buttons using `CometChatUIKit.getDataSource().getAuxiliaryOption()`, add them to a `LinearLayout` along with your custom view, and pass the combined layout to `setAuxiliaryButtonView()`.
+
+**Q: How do I customize the attachment options?**
+**A:** Create a list of `CometChatMessageComposerAction` objects, each with a title, icon, and click handler, and pass the list to `setAttachmentOptions(actionList)`. This replaces the default attachment options entirely.
+
+**Q: How do I customize the mentions appearance in the composer?**
+**A:** Define a custom style with parent `CometChatMessageComposerMentionsStyle` in `themes.xml`, create a `CometChatMentionsFormatter`, call `setMessageComposerMentionTextStyle()` with your style, and pass the formatter to `setTextFormatters()`.
+
+**Q: Can I use `CometChatMessageComposer` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, create the composer in `onCreate`. In a Fragment, create it in `onCreateView`. The key requirement is that the composer must be created during the `onCreate` lifecycle state to properly initialize the `ActivityResultLauncher`.
+
+## Next Steps
+
+- [Message Header component](/ui-kit/android/message-header)
+- [Message List component](/ui-kit/android/message-list)
+- [Conversations component](/ui-kit/android/conversations)
diff --git a/ui-kit/android/message-header.mdx b/ui-kit/android/message-header.mdx
index 5a871eaf3..a65f94ee0 100644
--- a/ui-kit/android/message-header.mdx
+++ b/ui-kit/android/message-header.mdx
@@ -2,474 +2,696 @@
title: "Message Header"
---
-## Overview
+`CometChatMessageHeader` displays [User](/sdk/android/users-overview) or [Group](/sdk/android/groups-overview) details in a toolbar header bar, including avatar, name, status, typing indicator, call buttons, and back navigation.
+
+## AI Agent Component Spec
+
+
+
+```json
+{
+ "component": "CometChatMessageHeader",
+ "package": "com.cometchat.chatuikit.messageheader",
+ "xmlElement": "",
+ "description": "Header bar displaying user/group avatar, name, status, typing indicator, call buttons, and back navigation for a chat screen.",
+ "primaryInput": {
+ "methods": ["setUser(User)", "setGroup(Group)"],
+ "note": "One of these must be called for the component to display data."
+ },
+ "methods": {
+ "data": {
+ "setUser": {
+ "type": "User",
+ "note": "Sets the user whose details are displayed in the header"
+ },
+ "setGroup": {
+ "type": "Group",
+ "note": "Sets the group whose details are displayed in the header"
+ }
+ },
+ "callbacks": {
+ "setOnBackButtonPressed": "OnBackPress",
+ "setOnBackPress": "OnBackPress",
+ "setOnError": "OnError",
+ "setNewChatButtonClick": "OnClick",
+ "setChatHistoryButtonClick": "OnClick"
+ },
+ "visibility": {
+ "setBackIconVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.GONE" },
+ "setUserStatusVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setGroupStatusVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setVideoCallButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setVoiceCallButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setMenuIconVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setNewChatButtonVisibility": { "type": "int", "default": "View.VISIBLE" },
+ "setChatHistoryButtonVisibility": { "type": "int", "default": "View.VISIBLE" }
+ },
+ "viewSlots": {
+ "setItemView": "Function3 — replaces the entire header layout",
+ "setLeadingView": "Function3 — avatar / left section",
+ "setTitleView": "Function3 — name / title text",
+ "setSubtitleView": "Function3 — subtitle text below name",
+ "setTrailingView": "Function3 — right section (action buttons)",
+ "setAuxiliaryButtonView": "Function3 — additional action button next to trailing view",
+ "setOptions": "List — overflow popup menu items"
+ },
+ "advanced": {
+ "setDateTimeFormatter": "DateTimeFormatterCallback — custom date/time formatting",
+ "setLastSeenText": "Function2 — custom last seen text",
+ "setBackIcon": "View — custom back icon view",
+ "setBackButtonView": "Drawable — custom back icon drawable",
+ "setPopupMenuStyle": "@StyleRes int — style for the popup menu",
+ "getMessageHeaderViewModel": "MessageHeaderViewModel — internal ViewModel access",
+ "getAdditionParameter": "AdditionParameter — data source addition parameter"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatMessageHeaderStyle"
+ }
+ }
+ },
+ "events": [],
+ "sdkListeners": [
+ "onUserOnline",
+ "onUserOffline",
+ "onTypingStarted",
+ "onTypingEnded",
+ "onGroupMemberJoined",
+ "onGroupMemberLeft",
+ "onGroupMemberKicked",
+ "onGroupMemberBanned",
+ "onGroupMemberScopeChanged"
+ ]
+}
+```
-`MessageHeader` is a [Component](/ui-kit/android/components-overview#components) that showcases the [User](/sdk/android/users-overview) or [Group](/sdk/android/groups-overview) details in the toolbar. Furthermore, it also presents a typing indicator and a back navigation button for ease of use.
+
-
-
-
+## Where It Fits
-***
+`CometChatMessageHeader` is a header bar component. It sits at the top of a chat screen and displays the avatar, name, and status of the user or group in the conversation. Wire it alongside `CometChatMessageList` and `CometChatMessageComposer` to build a complete messaging layout.
-## Usage
+
+
+```kotlin ChatActivity.kt lines
+class ChatActivity : AppCompatActivity() {
-### Integration
+ private lateinit var messageHeader: CometChatMessageHeader
+ private lateinit var messageList: CometChatMessageList
+ private lateinit var messageComposer: CometChatMessageComposer
-You can add `MessageHeader` component directly into the \`layout.xml\`\` file.
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_chat)
-```xml your_layout.xml
-
+ messageHeader = findViewById(R.id.message_header)
+ messageList = findViewById(R.id.message_list)
+ messageComposer = findViewById(R.id.message_composer)
+
+ // Set the user for all components
+ messageHeader.setUser(user)
+ messageList.setUser(user)
+ messageComposer.setUser(user)
+ }
+}
+```
+
+
+
+```java ChatActivity.java lines
+public class ChatActivity extends AppCompatActivity {
+
+ private CometChatMessageHeader messageHeader;
+ private CometChatMessageList messageList;
+ private CometChatMessageComposer messageComposer;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ messageHeader = findViewById(R.id.message_header);
+ messageList = findViewById(R.id.message_list);
+ messageComposer = findViewById(R.id.message_composer);
+
+ // Set the user for all components
+ messageHeader.setUser(user);
+ messageList.setUser(user);
+ messageComposer.setUser(user);
+ }
+}
```
+
+
-### Actions
+## Quick Start
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+Add the component to your layout XML:
-The `MessageHeader` component does not have any exposed actions.
+```xml your_layout.xml lines
+
+```
-##### OnError
+
+
+
-This action doesn't change the behavior of the component but rather listens for any errors that occur in the Users component.
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.
-
-
-```java YourActivity.java
-cometchatMessageHeader.setOnError(cometchatException -> {
+Set a `User` or `Group` on the component — this is required for it to display data:
- });
+
+
+```kotlin YourActivity.kt lines
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.your_layout)
+
+ val messageHeader = findViewById(R.id.header)
+ messageHeader.setUser(user)
+}
```
+
+
+```java YourActivity.java lines
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.your_layout);
+
+ CometChatMessageHeader messageHeader = findViewById(R.id.header);
+ messageHeader.setUser(user);
+}
+```
+
-
-```kotlin YourActivity.kt
-cometchatMessageHeader.setOnError {
+Or set a group:
- }
+
+
+```kotlin lines
+messageHeader.setGroup(group)
```
-
+
+```java lines
+messageHeader.setGroup(group);
+```
+
-***
+## Actions and Events
-##### setOnBackPressListener
+### Callback Methods
-`OnBackPressListener` is triggered when you press the back button in the app bar. It has a predefined behavior; when clicked, it navigates to the previous activity. However, you can override this action using the following code snippet.
+#### `setOnBackButtonPressed`
+
+Fires when the user presses the back button in the header. Default: navigates to the previous activity.
-
-```java YourActivity.java
-cometchatMessageHeader.setOnBackPressListener(() -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatMessageHeader.setOnBackButtonPressed {
+ // Custom back navigation logic
+}
```
-
-
-```kotlin YourActivity.kt
-cometchatMessageHeader.onBackPressListener = OnBackPress {
-
- }
+
+```java YourActivity.java lines
+cometchatMessageHeader.setOnBackButtonPressed(() -> {
+ // Custom back navigation logic
+});
```
-
-
-***
+> **What this does:** Overrides the default back-press navigation. When the user taps the back button, your custom logic runs instead.
-##### setNewChatButtonClick
+#### `setOnBackPress`
-`setOnNewChatButtonClick` is triggered when you press the new chat button in the app bar. It has a predefined behavior; when clicked, it navigates to the previous activity. However, you can override this action using the following code snippet.
+Alternative setter for the back press callback. Functionally identical to `setOnBackButtonPressed`.
-
-```java YourActivity.java
-cometchatMessageHeader.setNewChatButtonClick(() -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatMessageHeader.onBackPressListener = OnBackPress {
+ // Custom back navigation logic
+}
```
+
+
+```java YourActivity.java lines
+cometchatMessageHeader.setOnBackPress(() -> {
+ // Custom back navigation logic
+});
+```
+
-
-```kotlin YourActivity.kt
-cometchatMessageHeader.setNewChatButtonClick {
+#### `setOnError`
- }
-```
+Fires on internal errors (network failure, auth issue, SDK exception). This does not change the component's behavior.
+
+
+```kotlin YourActivity.kt lines
+cometchatMessageHeader.setOnError {
+ // Handle error
+}
+```
+
+```java YourActivity.java lines
+cometchatMessageHeader.setOnError(cometchatException -> {
+ // Handle error
+});
+```
+
-***
+> **What this does:** Registers an error listener. If the component encounters an error, your callback receives the `CometChatException`.
-##### setChatHistoryButtonClick
+#### `setNewChatButtonClick`
-`setChatHistoryButtonClick` is triggered when you press the chat history button in the app bar. It has a predefined behavior; when clicked, it navigates to the previous activity. However, you can override this action using the following code snippet.
+Fires when the new chat button is tapped (visible in AI agent conversations).
-
-```java YourActivity.java
-cometchatMessageHeader.setChatHistoryButtonClick(() -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatMessageHeader.setNewChatButtonClick {
+ // Handle new chat button click
+}
```
+
+
+```java YourActivity.java lines
+cometchatMessageHeader.setNewChatButtonClick(() -> {
+ // Handle new chat button click
+});
+```
+
+
+#### `setChatHistoryButtonClick`
+Fires when the chat history button is tapped (visible in AI agent conversations).
+
+
-```kotlin YourActivity.kt
+```kotlin YourActivity.kt lines
cometchatMessageHeader.setChatHistoryButtonClick {
-
- }
+ // Handle chat history button click
+}
```
-
+
+```java YourActivity.java lines
+cometchatMessageHeader.setChatHistoryButtonClick(() -> {
+ // Handle chat history button click
+});
+```
+
-***
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (back-press) and confirm your custom logic executes instead of the default behavior.
-### Filters
+### Global UI Events
-**Filters** allow you to customize the data displayed in a list within a `Component`. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using `RequestBuilders` of Chat SDK.
+The `CometChatMessageHeader` component does not emit any global UI events.
-The `MessageHeader` component does not have any exposed filters.
+### SDK Events (Real-Time, Automatic)
-### Events
+The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed.
+| SDK Listener | Internal behavior |
+| --- | --- |
+| `onUserOnline` | Updates online status indicator for the user |
+| `onUserOffline` | Updates offline status indicator for the user |
+| `onTypingStarted` | Shows typing indicator in the subtitle area |
+| `onTypingEnded` | Hides typing indicator and restores subtitle |
+| `onGroupMemberJoined` | Updates group member count |
+| `onGroupMemberLeft` | Updates group member count |
+| `onGroupMemberKicked` | Updates group member count |
+| `onGroupMemberBanned` | Updates group member count |
-The `MessageHeader` component does not produce any events.
+> Automatic: user presence, typing indicators, and group member count changes update in real time.
-## Customization
+## Functionality
-To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
+Small functional customizations such as toggling visibility of UI elements and setting the user or group object.
-### Style
+| Methods | Description | Code |
+| --- | --- | --- |
+| `setUser` | Passes a user object to display that user's header details. Required for the component to function. | `.setUser(user)` |
+| `setGroup` | Passes a group object to display that group's header details. Required for the component to function. | `.setGroup(group)` |
+| `setBackIconVisibility` | Toggles visibility for the back button | `.setBackIconVisibility(View.VISIBLE)` |
+| `setUserStatusVisibility` | Toggles visibility for the user's online/offline status indicator | `.setUserStatusVisibility(View.GONE)` |
+| `setGroupStatusVisibility` | Toggles visibility for the group status indicator | `.setGroupStatusVisibility(View.GONE)` |
+| `setVideoCallButtonVisibility` | Toggles visibility for the video call button | `.setVideoCallButtonVisibility(View.GONE)` |
+| `setVoiceCallButtonVisibility` | Toggles visibility for the voice call button | `.setVoiceCallButtonVisibility(View.GONE)` |
+| `setMenuIconVisibility` | Toggles visibility for the overflow menu icon | `.setMenuIconVisibility(View.GONE)` |
+| `setNewChatButtonVisibility` | Toggles visibility for the new chat button (AI agent conversations) | `.setNewChatButtonVisibility(View.GONE)` |
+| `setChatHistoryButtonVisibility` | Toggles visibility for the AI chat history button | `.setChatHistoryButtonVisibility(View.GONE)` |
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
+- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden. After calling `setUser(user)`, confirm the header displays that user's name and avatar.
-
-
-
+## Custom View Slots
-```xml themes.xml
-
+Each slot replaces a section of the default header UI. Slots accept a `Function3` callback that receives the current context, user, and group objects.
-
-```
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Item view | `setItemView(Function3)` | Entire header layout |
+| Leading view | `setLeadingView(Function3)` | Avatar / left section |
+| Title view | `setTitleView(Function3)` | Name / title text |
+| Subtitle view | `setSubtitleView(Function3)` | Subtitle text below name |
+| Trailing view | `setTrailingView(Function3)` | Right section (action buttons) |
+| Auxiliary button | `setAuxiliaryButtonView(Function3)` | Additional action button next to trailing view |
+| Options | `setOptions(List
-
-```java
-cometChatMessageHeader.setLeadingView(new Function3() {
- @Override
- public View apply(Context context, User user, Group group) {
- View view = LayoutInflater.from(context).inflate(R.layout.header_leading_view, null);
- CometChatAvatar avatar = view.findViewById(R.id.avatar);
- View view1 = view.findViewById(R.id.batch_view);
- if (user != null) {
- avatar.setAvatar(user.getName(), user.getAvatar());
- if ("admin".equals(user.getRole())) {
- view1.setVisibility(View.VISIBLE);
- }
- } else {
- avatar.setAvatar(group.getName(), group.getIcon());
- if (group.getOwner().equals(CometChatUIKit.getLoggedInUser().getUid())) {
- view1.setVisibility(View.VISIBLE);
- }
- }
+```java lines
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(Utils.convertDpToPx(context, 45), Utils.convertDpToPx(context, 45));
- view.setLayoutParams(params);
- return view;
- }
- });
-```
-
+cometchatMessageHeader.setDateTimeFormatter(new DateTimeFormatterCallback() {
-
-```kotlin
-cometChatMessageHeader.leadingView = object : Function3 {
- override fun apply(t: Context?, k: User?, s: Group?): View? {
- val view: View = LayoutInflater.from(context).inflate(R.layout.header_leading_view, null)
- val avatar = view.findViewById(R.id.avatar)
- val view1 = view.findViewById(R.id.batch_view)
- if (user != null) {
- avatar.setAvatar(user.name, user.avatar)
- if ("admin" == user.role) {
- view1.visibility = View.VISIBLE
- }
- } else {
- avatar.setAvatar(group.name, group.icon)
- if (group.owner == CometChatUIKit.getLoggedInUser().uid) {
- view1.visibility = View.VISIBLE
- }
- }
+ private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault());
+ private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault());
- val params = LinearLayout.LayoutParams(Utils.convertDpToPx(context, 45), Utils.convertDpToPx(context, 45))
- view.layoutParams = params
- return view
- }
+ @Override
+ public String time(long timestamp) {
+ return fullTimeFormatter.format(new Date(timestamp));
}
-```
-
+ @Override
+ public String today(long timestamp) {
+ return "Today";
+ }
-
+ @Override
+ public String yesterday(long timestamp) {
+ return "Yesterday";
+ }
+
+ @Override
+ public String lastWeek(long timestamp) {
+ return "Last Week";
+ }
-***
+ @Override
+ public String otherDays(long timestamp) {
+ return dateFormatter.format(new Date(timestamp));
+ }
+
+ @Override
+ public String minutes(long diffInMinutesFromNow, long timestamp) {
+ return diffInMinutesFromNow + " mins ago";
+ }
-#### setTrailingView
+ @Override
+ public String hours(long diffInHourFromNow, long timestamp) {
+ return diffInHourFromNow + " hrs ago";
+ }
+ });
+```
+
+
-Enables customization of the trailing view, typically used for action buttons or indicators.
+> **What this does:** Overrides the default date/time formatting for the message header. Today's messages show "Today", yesterday's show "Yesterday", recent messages show "X mins ago" or "X hrs ago", last week's show "Last Week", and older messages show the full date in "dd MMM yyyy" format.
-Use Cases:
+### `setLastSeenText`
-* Add an options menu (⋮) for more actions.
-* Display a mute/unmute toggle.
-* Show a connection strength indicator for calls.
+Provides a custom implementation for the "last seen" text displayed below the user's name. Only applies to user conversations.
-
-```java YourActivity.java
-cometchatMessageHeader.setTrailingView((context, user, group) -> {
-
- });
+
+```kotlin lines
+cometchatMessageHeader.setLastSeenText { context, user ->
+ if (user.status == "online") {
+ "Active now"
+ } else {
+ "Last seen recently"
+ }
+}
```
+
+
+```java lines
+cometchatMessageHeader.setLastSeenText((context, user) -> {
+ if (user.getStatus().equals("online")) {
+ return "Active now";
+ }
+ return "Last seen recently";
+});
+```
+
+
+> **What this does:** Replaces the default last seen text with custom logic. Returns "Active now" for online users and "Last seen recently" for offline users.
+### `setBackIcon`
+
+Replaces the default back icon with a completely custom `View`.
+
+
-```kotlin YourActivity.kt
-cometchatMessageHeader.setTrailingView(object : Function3 {
- override fun apply(context: Context?, user: User?, group: Group?): View? {
-
- }
- })
+```kotlin lines
+val customBackButton = ImageView(context)
+customBackButton.setImageResource(R.drawable.custom_back_icon)
+cometchatMessageHeader.setBackIcon(customBackButton)
```
-
+
+```java lines
+ImageView customBackButton = new ImageView(context);
+customBackButton.setImageResource(R.drawable.custom_back_icon);
+cometchatMessageHeader.setBackIcon(customBackButton);
+```
+
-**Example**
+### `setPopupMenuStyle`
-
-
-
+Sets a custom style for the overflow popup menu.
-
-```java
-cometChatMessageHeader.setTrailingView((context, user, group) -> {
- ImageView imageView = new ImageView(context);
- imageView.setImageResource(R.drawable.save_icon);
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(Utils.convertDpToPx(context, 24), Utils.convertDpToPx(context, 24));
- params.leftMargin = Utils.convertDpToPx(context, 16);
- imageView.setLayoutParams(params);
- return imageView;
- });
+
+```kotlin lines
+cometchatMessageHeader.setPopupMenuStyle(R.style.CustomPopupMenuStyle)
```
+
+
+```java lines
+cometchatMessageHeader.setPopupMenuStyle(R.style.CustomPopupMenuStyle);
+```
+
+
+### AI Agent Button Customization
+For AI agent conversations, the header shows new chat and chat history buttons. Customize their icons and tints:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setNewChatIcon` | `Drawable` | Custom icon for the new chat button |
+| `setNewChatIconTint` | `@ColorInt int` | Tint color for the new chat icon |
+| `setChatHistoryIcon` | `Drawable` | Custom icon for the chat history button |
+| `setChatHistoryIconTint` | `@ColorInt int` | Tint color for the chat history icon |
+
+### Internal Access
+
+These methods provide direct access to internal components for advanced use cases.
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getMessageHeaderViewModel()` | `MessageHeaderViewModel` | The ViewModel managing header data and state |
+| `getAdditionParameter()` | `AdditionParameter` | Data source addition parameter for configurators |
+| `getUser()` | `User` | The currently set User object |
+| `getGroup()` | `Group` | The currently set Group object |
+
+> Use these only when the standard API is insufficient. Directly manipulating the ViewModel may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatMessageHeaderStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
+
+```xml themes.xml lines
+
+
+
+```
+
+
-```kotlin
-cometChatMessageHeader.setTrailingView { context, user, group ->
- val imageView = ImageView(context)
- imageView.setImageResource(R.drawable.save_icon)
- val params = LinearLayout.LayoutParams(
- Utils.convertDpToPx(context, 24),
- Utils.convertDpToPx(context, 24)
- )
- params.leftMargin = Utils.convertDpToPx(context, 16)
- imageView.layoutParams = params
- imageView
- }
+```kotlin lines
+cometchatMessageHeader.setStyle(R.style.CustomMessageHeaderStyle)
```
+
+
+```java lines
+cometchatMessageHeader.setStyle(R.style.CustomMessageHeaderStyle);
+```
+
+
+> **What this does:** Applies the `CustomMessageHeaderStyle` theme to the `CometChatMessageHeader` component, changing the title text color, avatar style, and call button icon tints.
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_header.xml).
-
\ No newline at end of file
+- **Verify**: The header title text displays in orange (`#F76808`), and the voice and video call icons display with orange tint (`#F76808`).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setTitleTextColor` | `@ColorInt int` | Title text color |
+| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance |
+| `setSubtitleTextColor` | `@ColorInt int` | Subtitle text color |
+| `setSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance |
+| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon |
+| `setMenuIconTint` | `@ColorInt int` | Tint color for the menu icon |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component |
+| `setAvatarStyle` | `@StyleRes int` | Style for the avatar |
+| `setStatusIndicatorStyle` | `@StyleRes int` | Style for the online/offline status indicator |
+| `setTypingIndicatorStyle` | `@StyleRes int` | Style for the typing indicator |
+| `setCallButtonsStyle` | `@StyleRes int` | Style for the call buttons |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| User object | Activity/Fragment | `setUser(User)` | `.setUser(user)` |
+| Group object | Activity/Fragment | `setGroup(Group)` | `.setGroup(group)` |
+| Override back-press behavior | Activity/Fragment | `setOnBackButtonPressed(OnBackPress)` | `setOnBackButtonPressed { ... }` |
+| Handle errors | Activity/Fragment | `setOnError(OnError)` | `setOnError { e -> ... }` |
+| Title text color | `themes.xml` | `CometChatMessageHeaderStyle` with `cometchatMessageHeaderTitleTextColor` | `#F76808` |
+| Avatar style | `themes.xml` | `CometChatMessageHeaderStyle` with `cometchatMessageHeaderAvatarStyle` | `@style/CustomAvatarStyle` |
+| Call button icon tints | `themes.xml` | `CometChatCallButtonsStyle` with `cometchatCallButtonsVideoCallIconTint` / `cometchatCallButtonsVoiceCallIconTint` | `#F76808` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometchatMessageHeader.setStyle(R.style.CustomMessageHeaderStyle);` |
+| Back button visibility | Activity/Fragment | `setBackIconVisibility(int)` | `.setBackIconVisibility(View.VISIBLE)` |
+| User status visibility | Activity/Fragment | `setUserStatusVisibility(int)` | `.setUserStatusVisibility(View.GONE)` |
+| Group status visibility | Activity/Fragment | `setGroupStatusVisibility(int)` | `.setGroupStatusVisibility(View.GONE)` |
+| Video call button visibility | Activity/Fragment | `setVideoCallButtonVisibility(int)` | `.setVideoCallButtonVisibility(View.GONE)` |
+| Voice call button visibility | Activity/Fragment | `setVoiceCallButtonVisibility(int)` | `.setVoiceCallButtonVisibility(View.GONE)` |
+| Menu icon visibility | Activity/Fragment | `setMenuIconVisibility(int)` | `.setMenuIconVisibility(View.GONE)` |
+| New chat button visibility | Activity/Fragment | `setNewChatButtonVisibility(int)` | `.setNewChatButtonVisibility(View.GONE)` |
+| Chat history button visibility | Activity/Fragment | `setChatHistoryButtonVisibility(int)` | `.setChatHistoryButtonVisibility(View.GONE)` |
+| Date/time formatting | Activity/Fragment | `setDateTimeFormatter(DateTimeFormatterCallback)` | See `setDateTimeFormatter` code above |
+| Custom last seen text | Activity/Fragment | `setLastSeenText(Function2)` | See `setLastSeenText` code above |
+| Entire header layout | Activity/Fragment | `setItemView(Function3)` | See `setItemView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(Function3)` | See `setSubtitleView` code above |
+| Leading view (avatar area) | Activity/Fragment | `setLeadingView(Function3)` | See `setLeadingView` code above |
+| Trailing view | Activity/Fragment | `setTrailingView(Function3)` | See `setTrailingView` code above |
+| Title view | Activity/Fragment | `setTitleView(Function3)` | See `setTitleView` code above |
+| Auxiliary button view | Activity/Fragment | `setAuxiliaryButtonView(Function3)` | See `setAuxiliaryButtonView` code above |
+| Header popup menu options | Activity/Fragment | `setOptions(List
+
-#### setTimeFormat
+
-Defines the format in which time appears for each message bubble.
+
-Use Cases:
+
-* Use 12-hour or 24-hour formats based on user preference.
-* Display relative time ("Just now", "5 min ago").
-* Add AM/PM indicators for clarity.
+
+
+
-
-
-```java
-messageList.setTimeFormat(new SimpleDateFormat("hh:mm a",Locale.getDefault()));
+
```
-
+> **What this does:** Defines a custom header layout with three pill-shaped buttons: "Notes", "Pinned Messages", and "Saved Links". Each button uses a `MaterialCardView` with an icon and label styled with the primary color.
+
-```kotlin
-messageList.setTimeFormat(SimpleDateFormat("hh:mm a",Locale.getDefault()))
+```kotlin lines
+cometChatMessageList.setHeaderView(View.inflate(context, R.layout.custom_header_layout, null))
```
-
-
-
-***
-
-#### setNewMessageIndicatorView
-
-Customizes the unread message indicator view.
-
-Use Cases:
-
-* Set a custom view for the unread message indicator.
-
-
-```java
-messageList.setNewMessageIndicatorView(customView);
+```java lines
+cometChatMessageList.setHeaderView(View.inflate(getContext(), R.layout.custom_header_layout, null));
```
-
+
-
-```kotlin
-messageList.setNewMessageIndicatorView(customView)
-```
+> **What this does:** Inflates the `custom_header_layout.xml` and sets it as the header view of the message list. The three pill buttons display above the messages.
-
+### `setFooterView`
-
+Sets a custom footer view displayed at the bottom of the message list.
-***
+
+
+
-#### setLoadingView
+```xml custom_footer_layout.xml lines
-Customizes the loading indicator when messages are being fetched.
+
+
-Use Cases:
+
-* Show a spinner or skeleton loader for smooth UX.
-* Display a "Fetching messages..." text.
+
-
-
-```java
-cometchatMessageList.setLoadingView(R.layout.your_loading_view);
-```
+
-
+
+
+
-
-```kotlin
-cometchatMessageList.loadingView = R.layout.your_loading_view
-```
+
-
+
-
+
-***
+
+
+
-#### setEmptyView
+
-Defines a custom view to be displayed when no messages are available.
+
-Use Cases:
+
-* Show a friendly message like "No messages yet. Start the conversation!".
+
+
+
-
-
-```java
-cometchatMessageList.setEmptyView(R.layout.your_empty_view);
+
```
-
+> **What this does:** Defines a custom footer layout with three pill-shaped buttons: "Notes", "Pinned Messages", and "Saved Links". Each button uses a `MaterialCardView` with an icon and label styled with the primary color.
+
-```kotlin
-cometchatMessageList.emptyView = R.layout.your_empty_view
+```kotlin lines
+cometChatMessageList.setFooterView(View.inflate(context, R.layout.custom_footer_layout, null))
```
-
-
-
-***
-
-#### setErrorView
-
-Custom error state view displayed when fetching messages fails.
-
-Use Cases:
-
-* Show a retry button when an error occurs.
-* Display a friendly message like "Couldn't load messages. Check your connection.".
-
-
-```java
-cometchatMessageList.setErrorView(R.layout.your_empty_view);
-```
-
-
-
-
-```kotlin
-cometchatMessageList.errorView = R.layout.your_error_view
+```java lines
+cometChatMessageList.setFooterView(View.inflate(getContext(), R.layout.custom_footer_layout, null));
```
-
-
-***
-
-#### setAIAssistantEmptyChatGreetingView
+> **What this does:** Inflates the `custom_footer_layout.xml` and sets it as the footer view of the message list. The three pill buttons display below the messages.
-Custom empty state view displayed in case of chats with AI Assistants.
+### `setLoadingStateView`
-Use Cases:
-
-* Show an empty state view for chats with AI Assistants.
-* Display a friendly message like "Hey, I am your AI Assistant".
+Customizes the loading indicator when messages are being fetched.
-
-```java
-cometchatMessageList.setAIAssistantEmptyChatGreetingView(R.layout.ai_assistant_empty_view);
+
+```kotlin lines
+cometchatMessageList.setLoadingStateView(R.layout.your_loading_view)
```
-
-
-```kotlin
-cometchatMessageList.setAIAssistantEmptyChatGreetingView(R.layout.ai_assistant_empty_view)
+
+```java lines
+cometchatMessageList.setLoadingStateView(R.layout.your_loading_view);
```
-
-
-***
-
-#### setAIAssistantSuggestedMessages
+> **What this does:** Replaces the default loading spinner with your custom layout resource. The custom view displays while messages are being fetched.
-Sets the list of suggested messages for AI Assistant chats, allowing you to define which predefined queries or prompts are displayed to users.
+### `setEmptyStateView`
-Use Cases:
-
-* Display a list of suggested messages for users to interact with the AI Assistant.
-* Provide quick prompts or queries to help users start a conversation with the AI.
+Defines a custom view displayed when no messages are available.
-
-```java
-List aiSuggestedMessages = new ArrayList<>();
-aiSuggestedMessages.add("How can I help you today?");
-aiSuggestedMessages.add("Tell me more about your issue.");
-aiSuggestedMessages.add("Can you provide more details?");
-aiSuggestedMessages.add("What would you like to achieve?");
-
-cometchatMessageList.setAIAssistantSuggestedMessages(aiSuggestedMessages);
+
+```kotlin lines
+cometchatMessageList.setEmptyStateView(R.layout.your_empty_view)
```
-
-
-```kotlin
-val aiSuggestedMessages = mutableListOf()
-aiSuggestedMessages.add("How can I help you today?")
-aiSuggestedMessages.add("Tell me more about your issue.")
-aiSuggestedMessages.add("Can you provide more details?")
-aiSuggestedMessages.add("What would you like to achieve?")
-
-cometchatMessageList.setAIAssistantSuggestedMessages(aiSuggestedMessages)
+
+```java lines
+cometchatMessageList.setEmptyStateView(R.layout.your_empty_view);
```
-
-
-***
-
-#### setAiAssistantTools
-
-Sets the available tools for the AI assistant by accepting a `HashMap` containing tool names as keys and their corresponding `ToolCallListener` as values. This allows you to define and manage the tools that the AI assistant can utilize during interactions.
+> **What this does:** Replaces the default empty state with your custom layout resource. The custom view displays when the message list has no items.
+### `setErrorStateView`
-Use Cases:
-
-* Dynamically update UI elements based on tool actions.
-* Enable contextual actions based on user interactions with AI tools.
+Custom error state view displayed when fetching messages fails.
-
-```java
-HashMap toolCallListenerMap = new HashMap<>();
-toolCallListenerMap.put("toolName", new ToolCallListener() {
- @Override
- public void call(String args) {
- cometchatMessageList.setStyle(R.style.CustomCometChatMessageListStyle);
- cometchatMessageList.refreshStyle();
- }
-});
-
-cometchatMessageList.setAiAssistantTools(toolCallListenerMap);
+
+```kotlin lines
+cometchatMessageList.setErrorStateView(R.layout.your_error_view)
```
-
-
-```kotlin
-val toolCallListenerMap = HashMap()
-toolCallListenerMap["toolName"] = ToolCallListener { args ->
- cometchatMessageList.setStyle(R.style.CustomCometChatMessageListStyle)
- cometchatMessageList.refreshStyle()
-}
-
-cometchatMessageList.setAiAssistantTools(toolCallListenerMap)
+
+```java lines
+cometchatMessageList.setErrorStateView(R.layout.your_error_view);
```
-
-
-***
-
-#### setStreamingSpeed
+> **What this does:** Replaces the default error state with your custom layout resource. The custom view displays when the component encounters an error during message fetching.
-Sets the streaming speed for AI Assistant responses in ms, allowing you to control how quickly the AI's replies are displayed to the user.
+### `setNewMessageIndicatorView`
-
-Use Cases:
-
-* Manipulate the speed of AI responses to enhance user experience.
+Replaces the default "new messages" indicator that appears when new messages arrive while the user has scrolled up.
-
-```java
-cometchatMessageList.setStreamingSpeed(100);
+
+```kotlin YourActivity.kt lines
+val customIndicator = LayoutInflater.from(this).inflate(R.layout.custom_new_message_indicator, null)
+cometchatMessageList.setNewMessageIndicatorView(customIndicator)
```
-
-
-```kotlin
-cometchatMessageList.setStreamingSpeed(100)
+
+```java YourActivity.java lines
+View customIndicator = LayoutInflater.from(this).inflate(R.layout.custom_new_message_indicator, null);
+cometchatMessageList.setNewMessageIndicatorView(customIndicator);
```
-
-
-***
+> **What this does:** Replaces the default new message indicator with a custom layout. The indicator appears when new messages arrive while the user is scrolled up in the message list.
+
+### `setTemplates`
-#### setTextFormatters
+`CometChatMessageTemplate` is a pre-defined structure for creating message views (message bubbles). For more information, refer to [CometChatMessageTemplate](/ui-kit/android/message-template).
-Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel check out [MentionsFormatter Guide](/ui-kit/android/mentions-formatter-guide) **Example**
+### `setTextFormatters`
+
+Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel check out [MentionsFormatter Guide](/ui-kit/android/mentions-formatter-guide).
-```xml themes.xml
+```xml themes.xml lines
-
+
+```
+
+> **What this does:** Defines custom mention styles for incoming and outgoing message bubbles. Incoming mentions appear in pink (`#D6409F`) and outgoing mentions appear in white (`#FFFFFF`), both with green self-mentions (`#30A46C`).
+
+
+
+```kotlin lines
+
+// Initialize CometChatMentionsFormatter
+val mentionFormatter = CometChatMentionsFormatter(context)
+
+//set style to customize bubble mention text
+mentionFormatter.setOutgoingBubbleMentionTextStyle(context, R.style.CustomOutgoingMessageBubbleMentionStyle)
+
+mentionFormatter.setIncomingBubbleMentionTextStyle(context, R.style.CustomIncomingMessageBubbleMentionStyle)
+
+// This can be passed as an array of formatter in CometChatMessageList by using setTextFormatters method.
+val textFormatters: MutableList = ArrayList()
+textFormatters.add(mentionFormatter)
+messageList.setTextFormatters(textFormatters)
```
+
-
-```java
+```java lines
// Initialize CometChatMentionsFormatter
CometChatMentionsFormatter mentionFormatter = new CometChatMentionsFormatter(context);
@@ -966,382 +1042,670 @@ List textFormatters = new ArrayList<>();
textFormatters.add(mentionFormatter);
messageList.setTextFormatters(textFormatters);
```
-
+
-
-```kotlin
-
-// Initialize CometChatMentionsFormatter
-val mentionFormatter = CometChatMentionsFormatter(context)
+> **What this does:** Creates a `CometChatMentionsFormatter`, applies custom outgoing and incoming mention styles, adds it to a list of text formatters, and passes that list to the message list component. Mentions in message bubbles render with the custom colors.
-//set style to customize bubble mention text
-mentionFormatter.setOutgoingBubbleMentionTextStyle(context, R.style.CustomOutgoingMessageBubbleMentionStyle)
+### `setDateFormat`
-mentionFormatter.setIncomingBubbleMentionTextStyle(context, R.style.CustomIncomingMessageBubbleMentionStyle)
+Specifies a custom format for displaying sticky date separators in the chat.
-// This can be passed as an array of formatter in CometChatMessageList by using setTextFormatters method.
-val textFormatters: MutableList = ArrayList()
-textFormatters.add(mentionFormatter)
-messageList.setTextFormatters(textFormatters)
+
+
+```kotlin lines
+messageList.setDateFormat(SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()))
```
-
+
+```java lines
+messageList.setDateFormat(new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()));
+```
+
-#### setHeaderView
-
-This method allows you to set a custom header view for the message list. By providing a View object, you can customize the appearance and content of the header displayed at the top of the message list.
+> **What this does:** Sets the sticky date separator format to "MMM dd, yyyy" (e.g., "Jul 10, 2024") using the device's default locale.
-Use Cases:
+### `setTimeFormat`
-* Add a custom branding/logo to the chat.
-* Display chat status ("John is typing...").
-* Show last seen status.
+Defines the format in which time appears for each message bubble.
-
-```java
-cometChatMessageList.setHeaderView(view);
+
+```kotlin lines
+messageList.setTimeFormat(SimpleDateFormat("hh:mm a", Locale.getDefault()))
```
+
+
+```java lines
+messageList.setTimeFormat(new SimpleDateFormat("hh:mm a", Locale.getDefault()));
+```
+
+
+> **What this does:** Sets the message bubble time format to "hh:mm a" (e.g., "02:30 PM") using the device's default locale.
+### `setDateTimeFormatter`
+
+Provides a custom implementation of `DateTimeFormatterCallback` to configure how time and date values are displayed. Each method corresponds to a specific case:
+
+- `time(long timestamp)` — Custom full timestamp format
+- `today(long timestamp)` — Called when a message is from today
+- `yesterday(long timestamp)` — Called for yesterday's messages
+- `lastWeek(long timestamp)` — Messages from the past week
+- `otherDays(long timestamp)` — Older messages
+- `minutes(long diffInMinutesFromNow, long timestamp)` — e.g., "5 minutes ago"
+- `hours(long diffInHourFromNow, long timestamp)` — e.g., "2 hours ago"
+
+
-```kotlin
-cometChatMessageList.setHeaderView(view)
-```
+```kotlin lines
+import java.text.SimpleDateFormat
+import java.util.*
+
+cometchatMessageList.setDateTimeFormatter(object : DateTimeFormatterCallback {
+
+ private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
+ private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
+
+ override fun time(timestamp: Long): String {
+ return fullTimeFormatter.format(Date(timestamp))
+ }
+
+ override fun today(timestamp: Long): String {
+ return "Today"
+ }
+
+ override fun yesterday(timestamp: Long): String {
+ return "Yesterday"
+ }
+
+ override fun lastWeek(timestamp: Long): String {
+ return "Last Week"
+ }
+
+ override fun otherDays(timestamp: Long): String {
+ return dateFormatter.format(Date(timestamp))
+ }
+
+ override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String {
+ return "$diffInMinutesFromNow mins ago"
+ }
+ override fun hours(diffInHourFromNow: Long, timestamp: Long): String {
+ return "$diffInHourFromNow hrs ago"
+ }
+ });
+```
-
+
+```java lines
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
-**Example**
-
-
-
+cometchatMessageList.setDateTimeFormatter(new DateTimeFormatterCallback() {
-```html custom_header_layout.xml
+ private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault());
+ private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault());
-
-
+ @Override
+ public String time(long timestamp) {
+ return fullTimeFormatter.format(new Date(timestamp));
+ }
-
+ @Override
+ public String today(long timestamp) {
+ return "Today";
+ }
-
+ @Override
+ public String yesterday(long timestamp) {
+ return "Yesterday";
+ }
-
+ @Override
+ public String lastWeek(long timestamp) {
+ return "Last Week";
+ }
-
-
-
+ @Override
+ public String otherDays(long timestamp) {
+ return dateFormatter.format(new Date(timestamp));
+ }
-
+ @Override
+ public String minutes(long diffInMinutesFromNow, long timestamp) {
+ return diffInMinutesFromNow + " mins ago";
+ }
-
+ @Override
+ public String hours(long diffInHourFromNow, long timestamp) {
+ return diffInHourFromNow + " hrs ago";
+ }
+ });
+```
+
+
-
+> **What this does:** Overrides the default date/time formatting for message timestamps. Today's messages show "Today", yesterday's show "Yesterday", recent messages show "X mins ago" or "X hrs ago", last week's show "Last Week", and older messages show the full date in "dd MMM yyyy" format.
-
-
-
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the message list, and the data binding populates correctly.
-
-
+## Common Patterns
-
+### Hide all chrome — minimal message list
-
-
-
+
+
+```kotlin lines
+cometChatMessageList.setAvatarVisibility(View.GONE)
+cometChatMessageList.setReceiptsVisibility(View.GONE)
+cometChatMessageList.setStickyDateVisibility(View.GONE)
+cometChatMessageList.setGroupActionMessageVisibility(View.GONE)
+```
+
+
+
+```java lines
+cometChatMessageList.setAvatarVisibility(View.GONE);
+cometChatMessageList.setReceiptsVisibility(View.GONE);
+cometChatMessageList.setStickyDateVisibility(View.GONE);
+cometChatMessageList.setGroupActionMessageVisibility(View.GONE);
+```
+
+
+
+### Hide all message action options
+
+
+
+```kotlin lines
+cometChatMessageList.setReplyInThreadOptionVisibility(View.GONE)
+cometChatMessageList.setEditMessageOptionVisibility(View.GONE)
+cometChatMessageList.setDeleteMessageOptionVisibility(View.GONE)
+cometChatMessageList.setCopyMessageOptionVisibility(View.GONE)
+cometChatMessageList.setMessageReactionOptionVisibility(View.GONE)
+cometChatMessageList.setTranslateMessageOptionVisibility(View.GONE)
+cometChatMessageList.setMessagePrivatelyOptionVisibility(View.GONE)
+cometChatMessageList.setMessageInfoOptionVisibility(View.GONE)
+cometChatMessageList.setReplyOptionVisibility(View.GONE)
+cometChatMessageList.setShareMessageOptionVisibility(View.GONE)
+cometChatMessageList.setMarkAsUnreadOptionVisibility(View.GONE)
+cometChatMessageList.setFlagOptionVisibility(View.GONE)
+```
+
+
+
+```java lines
+cometChatMessageList.setReplyInThreadOptionVisibility(View.GONE);
+cometChatMessageList.setEditMessageOptionVisibility(View.GONE);
+cometChatMessageList.setDeleteMessageOptionVisibility(View.GONE);
+cometChatMessageList.setCopyMessageOptionVisibility(View.GONE);
+cometChatMessageList.setMessageReactionOptionVisibility(View.GONE);
+cometChatMessageList.setTranslateMessageOptionVisibility(View.GONE);
+cometChatMessageList.setMessagePrivatelyOptionVisibility(View.GONE);
+cometChatMessageList.setMessageInfoOptionVisibility(View.GONE);
+cometChatMessageList.setReplyOptionVisibility(View.GONE);
+cometChatMessageList.setShareMessageOptionVisibility(View.GONE);
+cometChatMessageList.setMarkAsUnreadOptionVisibility(View.GONE);
+cometChatMessageList.setFlagOptionVisibility(View.GONE);
+```
+
+
-
-```
+### Enable AI features
-
-```java
-cometChatMessageList.setHeaderView(View.inflate(getContext(), R.layout.custom_header_layout, null));
+
+```kotlin lines
+cometChatMessageList.setEnableSmartReplies(true)
+cometChatMessageList.setEnableConversationStarter(true)
+cometChatMessageList.setEnableConversationSummary(true)
```
+
+
+```java lines
+cometChatMessageList.setEnableSmartReplies(true);
+cometChatMessageList.setEnableConversationStarter(true);
+cometChatMessageList.setEnableConversationSummary(true);
+```
+
+
+### Custom quick reactions
+
-```kotlin
-cometChatMessageList.setHeaderView(View.inflate(context, R.layout.custom_header_layout, null))
+```kotlin lines
+cometChatMessageList.setQuickReactions(listOf("👻", "😈", "🙀", "🤡", "❤️"))
```
-
+
+```java lines
+cometChatMessageList.setQuickReactions(Arrays.asList("👻", "😈", "🙀", "🤡", "❤️"));
+```
+
-***
+### Start from unread messages
-#### setFooterView
+
+
+```kotlin lines
+cometChatMessageList.setStartFromUnreadMessages(true)
+```
+
+
+
+```java lines
+cometChatMessageList.setStartFromUnreadMessages(true);
+```
+
+
+
+## Advanced Methods
-This method allows you to set a custom footer view for the message list. By providing a View object, you can customize the appearance and content of the footer displayed at the bottom of the message list.
+### Scroll and Navigation
-Use Cases:
+#### `scrollToBottom`
-* Add quick reply buttons.
-* Display typing indicators ("John is typing...").
-* Show a disclaimer or privacy notice.
+Programmatically scrolls to the bottom of the message list.
+
+```kotlin lines
+cometChatMessageList.scrollToBottom()
+```
+
+
-```java
-cometChatMessageList.setFooterView(view);
+```java lines
+cometChatMessageList.scrollToBottom();
+```
+
+
+
+#### `scrollToMessageId`
+
+Scrolls to a specific message by its ID and highlights it.
+
+
+
+```kotlin lines
+cometChatMessageList.scrollToMessageId(messageId)
```
+
+
+```java lines
+cometChatMessageList.scrollToMessageId(messageId);
+```
+
+
+#### `gotoMessage`
+
+Navigates to a specific message by ID.
+
-```kotlin
-cometChatMessageList.setFooterView(view)
+```kotlin lines
+cometChatMessageList.gotoMessage(messageId)
+```
+
+
+
+```java lines
+cometChatMessageList.gotoMessage(messageId);
```
+
+
+
+### Message Manipulation
+#### `addMessage`
+
+Programmatically adds a message to the list.
+
+
+
+```kotlin lines
+cometChatMessageList.addMessage(baseMessage)
+```
+
+```java lines
+cometChatMessageList.addMessage(baseMessage);
+```
+
-**Example**
+#### `setList`
-
-
-
+Replaces the entire message list with a new list.
-```xml custom_footer_layout.xml
+
+
+```kotlin lines
+cometChatMessageList.setList(messageList)
+```
+
-
-
+
+```java lines
+cometChatMessageList.setList(messageList);
+```
+
+
-
+#### `updateMessage`
-
+Updates a message at a given index.
-
+
+
+```kotlin lines
+cometChatMessageList.updateMessage(index)
+```
+
-
-
-
+
+```java lines
+cometChatMessageList.updateMessage(index);
+```
+
+
-
+### Threaded Messages
-
+#### `setParentMessage`
-
+Sets the parent message ID for threaded message view.
-
-
-
+
+
+```kotlin lines
+cometChatMessageList.setParentMessage(parentMessageId)
+```
+
-
+
+```java lines
+cometChatMessageList.setParentMessage(parentMessageId);
+```
+
+
-
+### AI Features
-
+#### `generateConversationSummary`
-
-
-
+Triggers the generation of a conversation summary by fetching it from the ViewModel.
-
+
+
+```kotlin lines
+cometChatMessageList.generateConversationSummary()
+```
+
+
+
+```java lines
+cometChatMessageList.generateConversationSummary();
```
+
+
+
+#### `setAIAssistantSuggestedMessages`
+
+Sets suggested messages for the AI assistant.
+
+```kotlin lines
+cometChatMessageList.setAIAssistantSuggestedMessages(listOf("How can I help?", "Tell me more"))
+```
+
+
-```java
-cometChatMessageList.setFooterView(View.inflate(getContext(), R.layout.custom_footer_layout, null));
+```java lines
+cometChatMessageList.setAIAssistantSuggestedMessages(Arrays.asList("How can I help?", "Tell me more"));
+```
+
+
+
+#### `setAiAssistantTools`
+
+Registers custom AI assistant tool call listeners.
+
+
+
+```kotlin lines
+val tools = HashMap()
+cometChatMessageList.setAiAssistantTools(tools)
```
+
+
+```java lines
+HashMap tools = new HashMap<>();
+cometChatMessageList.setAiAssistantTools(tools);
+```
+
+### Bubble Margins
+
+| Method | Description |
+| --- | --- |
+| `setLeftBubbleMargin(top, bottom, left, right)` | Sets margins for incoming (left) message bubbles |
+| `setRightBubbleMargin(top, bottom, left, right)` | Sets margins for outgoing (right) message bubbles |
+| `setBubbleMargin(top, bottom, left, right)` | Sets margins for all message bubbles |
+
+### Internal Access
+
+These methods provide direct access to internal components for advanced use cases.
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getAdapter()` | `MessageAdapter` | The adapter powering the RecyclerView |
+| `setAdapter(MessageAdapter)` | `void` | Replaces the default adapter with a custom one |
+| `getViewModel()` | `MessageListViewModel` | The ViewModel managing message data and state |
+| `getRecyclerView()` | `RecyclerView` | The internal RecyclerView |
+| `getView()` | `LinearLayout` | The root view of the component |
+| `getNewMessageLayout()` | `MaterialCardView` | The new message indicator layout |
+| `getNewMessageImageView()` | `ImageView` | The new message indicator image |
+| `getStickyHeaderDecoration()` | `StickyHeaderDecoration` | The sticky date header decoration |
+| `getParentMessageId()` | `long` | The parent message ID for threaded view |
+| `getMentionsFormatter()` | `CometChatMentionsFormatter` | The mentions formatter instance |
+| `atBottom()` | `boolean` | Whether the list is scrolled to the bottom |
+| `isHasMore()` | `boolean` | Whether more messages are available to load |
+| `setAutoFetch(boolean)` | `void` | Controls automatic message fetching |
+| `setMentionAllLabelId(String, String)` | `void` | Sets the mention-all label ID and display text |
+
+> Use these only when the standard API is insufficient. Directly manipulating the adapter or ViewModel may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatMessageListStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
+
+```xml themes.xml lines
+
+
+
+```
+
+> **What this does:** Defines two custom styles: `CustomOutgoingMessageBubbleStyle` sets the outgoing message bubble background to orange (`#F76808`); `CustomCometChatMessageListStyle` sets the message list background to light peach (`#FEEDE1`) and applies the custom outgoing bubble style.
+
+
-```kotlin
-cometChatMessageList.setFooterView(View.inflate(context, R.layout.custom_footer_layout, null))
+```kotlin lines
+cometChatMessageList.setStyle(R.style.CustomCometChatMessageListStyle)
```
+
+
+```java lines
+cometChatMessageList.setStyle(R.style.CustomCometChatMessageListStyle);
+```
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_list.xml).
-
\ No newline at end of file
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setIncomingMessageBubbleStyle` | `@StyleRes int` | Style for incoming message bubbles |
+| `setOutgoingMessageBubbleStyle` | `@StyleRes int` | Style for outgoing message bubbles |
+| `setDateSeparatorStyle` | `@StyleRes int` | Style for date separator headers |
+| `setDeleteDialogStyle` | `@StyleRes int` | Style for the delete confirmation dialog |
+| `setMessageInformationStyle` | `@StyleRes int` | Style for the message information sheet |
+| `setMessageOptionSheetStyle` | `@StyleRes int` | Style for the message option action sheet |
+| `setReactionListStyle` | `@StyleRes int` | Style for the reaction list bottom sheet |
+| `setModerationViewStyle` | `@StyleRes int` | Style for the moderation view |
+| `setFlagMessageStyle` | `@StyleRes int` | Style for the flag/report message dialog |
+| `setBadgeStyle` | `@StyleRes int` | Style for the unread message badge |
+| `setAISmartRepliesStyle` | `@StyleRes int` | Style for AI smart replies |
+| `setAIConversationStarterStyle` | `@StyleRes int` | Style for AI conversation starters |
+| `setAIConversationSummaryStyle` | `@StyleRes int` | Style for AI conversation summary |
+| `setErrorStateTitleTextColor` | `@ColorInt int` | Title text color for the error state |
+| `setErrorStateTitleTextAppearance` | `@StyleRes int` | Title text appearance for the error state |
+| `setErrorStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the error state |
+| `setErrorStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the error state |
+| `setNewMessageIndicatorIconTint` | `@ColorInt int` | Tint color for the new message indicator icon |
+| `setAddReactionIcon` | `int` | Custom icon for the add reaction button |
+
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override behavior on user interaction | Activity/Fragment | `setOn` callbacks | `setOnThreadRepliesClick((ctx, msg, tpl) -> { ... })` |
+| Filter which messages appear | Activity/Fragment | `setMessagesRequestBuilder` | `setMessagesRequestBuilder(builder)` |
+| Customize reactions fetching | Activity/Fragment | `setReactionsRequestBuilder` | `setReactionsRequestBuilder(builder)` |
+| Toggle visibility of UI elements | Activity/Fragment | `setVisibility(int)` | `setReceiptsVisibility(View.GONE)` |
+| Replace header/footer views | Activity/Fragment | `setHeaderView` / `setFooterView` | `setHeaderView(view)` |
+| Change colors, fonts, spacing | `themes.xml` | `CometChatMessageListStyle` | `#FEEDE1` |
+| Outgoing bubble style | `themes.xml` | `cometchatMessageListOutgoingMessageBubbleStyle` | `#F76808` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometChatMessageList.setStyle(R.style.CustomCometChatMessageListStyle);` |
+| Set user for messages | Activity/Fragment | `setUser(User)` | `.setUser(user);` |
+| Set group for messages | Activity/Fragment | `setGroup(Group)` | `.setGroup(group);` |
+| Message alignment | Activity/Fragment | `setMessageAlignment(UIKitConstants.MessageListAlignment)` | `.setMessageAlignment(UIKitConstants.MessageListAlignment.STANDARD);` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE);` |
+| Incoming/outgoing message sound | Activity/Fragment | `disableSoundForMessages(boolean)` | `.disableSoundForMessages(true);` |
+| Custom message sound | Activity/Fragment | `setCustomSoundForMessages(int)` | `.setCustomSoundForMessages(@RawRes resource);` |
+| Avatar visibility | Activity/Fragment | `setAvatarVisibility(int)` | `.setAvatarVisibility(View.GONE);` |
+| Scroll to bottom on new message | Activity/Fragment | `scrollToBottomOnNewMessage(boolean)` | `.scrollToBottomOnNewMessage(true);` |
+| Read/delivered receipts visibility | Activity/Fragment | `setReceiptsVisibility(int)` | `.setReceiptsVisibility(View.GONE);` |
+| Quick reactions list | Activity/Fragment | `setQuickReactions(List)` | `.setQuickReactions(Arrays.asList("👻","😈","🙀","🤡","❤️"));` |
+| Sticky date visibility | Activity/Fragment | `setStickyDateVisibility(int)` | `.setStickyDateVisibility(View.GONE);` |
+| Thread reply option visibility | Activity/Fragment | `setReplyInThreadOptionVisibility(int)` | `.setReplyInThreadOptionVisibility(View.GONE);` |
+| Translate option visibility | Activity/Fragment | `setTranslateMessageOptionVisibility(int)` | `.setTranslateMessageOptionVisibility(View.GONE);` |
+| Edit option visibility | Activity/Fragment | `setEditMessageOptionVisibility(int)` | `.setEditMessageOptionVisibility(View.GONE);` |
+| Delete option visibility | Activity/Fragment | `setDeleteMessageOptionVisibility(int)` | `.setDeleteMessageOptionVisibility(View.GONE);` |
+| Reaction option visibility | Activity/Fragment | `setMessageReactionOptionVisibility(int)` | `.setMessageReactionOptionVisibility(View.GONE);` |
+| Private message option visibility | Activity/Fragment | `setMessagePrivatelyOptionVisibility(int)` | `.setMessagePrivatelyOptionVisibility(View.GONE);` |
+| Copy option visibility | Activity/Fragment | `setCopyMessageOptionVisibility(int)` | `.setCopyMessageOptionVisibility(View.GONE);` |
+| Message info option visibility | Activity/Fragment | `setMessageInfoOptionVisibility(int)` | `.setMessageInfoOptionVisibility(View.GONE);` |
+| Group action message visibility | Activity/Fragment | `setGroupActionMessageVisibility(int)` | `.setGroupActionMessageVisibility(View.GONE);` |
+| Reply option visibility | Activity/Fragment | `setReplyOptionVisibility(int)` | `.setReplyOptionVisibility(View.GONE);` |
+| Share option visibility | Activity/Fragment | `setShareMessageOptionVisibility(int)` | `.setShareMessageOptionVisibility(View.GONE);` |
+| Mark as unread option | Activity/Fragment | `setMarkAsUnreadOptionVisibility(int)` | `.setMarkAsUnreadOptionVisibility(View.GONE);` |
+| Flag/report option | Activity/Fragment | `setFlagOptionVisibility(int)` | `.setFlagOptionVisibility(View.GONE);` |
+| Moderation view visibility | Activity/Fragment | `setModerationViewVisibility(int)` | `.setModerationViewVisibility(View.GONE);` |
+| Swipe to reply | Activity/Fragment | `setSwipeToReplyEnabled(boolean)` | `.setSwipeToReplyEnabled(false);` |
+| Start from unread messages | Activity/Fragment | `setStartFromUnreadMessages(boolean)` | `.setStartFromUnreadMessages(true);` |
+| Conversation starters | Activity/Fragment | `setEnableConversationStarter(boolean)` | `.setEnableConversationStarter(true);` |
+| Smart replies | Activity/Fragment | `setEnableSmartReplies(boolean)` | `.setEnableSmartReplies(true);` |
+| Smart replies keywords | Activity/Fragment | `setAISmartRepliesKeywords(List)` | `.setAISmartRepliesKeywords(Arrays.asList("hello", "hi"));` |
+| Smart replies delay | Activity/Fragment | `setSmartRepliesDelayDuration(int)` | `.setSmartRepliesDelayDuration(5000);` |
+| Conversation summary | Activity/Fragment | `setEnableConversationSummary(boolean)` | `.setEnableConversationSummary(true);` |
+| Unread message threshold | Activity/Fragment | `setUnreadMessageThreshold(int)` | `.setUnreadMessageThreshold(10);` |
+| Date/time formatting | Activity/Fragment | `setDateTimeFormatter(DateTimeFormatterCallback)` | See `setDateTimeFormatter` code above |
+| Sticky date format | Activity/Fragment | `setDateFormat(SimpleDateFormat)` | `messageList.setDateFormat(new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()));` |
+| Message bubble time format | Activity/Fragment | `setTimeFormat(SimpleDateFormat)` | `messageList.setTimeFormat(new SimpleDateFormat("hh:mm a", Locale.getDefault()));` |
+| Loading view | Activity/Fragment | `setLoadingStateView(int)` | `cometchatMessageList.setLoadingStateView(R.layout.your_loading_view);` |
+| Empty view | Activity/Fragment | `setEmptyStateView(int)` | `cometchatMessageList.setEmptyStateView(R.layout.your_empty_view);` |
+| Error view | Activity/Fragment | `setErrorStateView(int)` | `cometchatMessageList.setErrorStateView(R.layout.your_error_view);` |
+| Header view | Activity/Fragment | `setHeaderView(View)` | `cometChatMessageList.setHeaderView(view);` |
+| Footer view | Activity/Fragment | `setFooterView(View)` | `cometChatMessageList.setFooterView(view);` |
+| New message indicator view | Activity/Fragment | `setNewMessageIndicatorView(View)` | `cometchatMessageList.setNewMessageIndicatorView(view);` |
+| Text formatters (mentions) | Activity/Fragment | `setTextFormatters(List)` | See `setTextFormatters` code above |
+| Message templates | Activity/Fragment | `setTemplates(List)` | See [CometChatMessageTemplate](/ui-kit/android/message-template) |
+| Refresh style | Activity/Fragment | `refreshStyle()` | `.refreshStyle();` |
+| Streaming speed | Activity/Fragment | `setStreamingSpeed(Integer)` | `.setStreamingSpeed(100);` |
+| Bubble margins | Activity/Fragment | `setLeftBubbleMargin` / `setRightBubbleMargin` / `setBubbleMargin` | `.setBubbleMargin(4, 4, 8, 8);` |
+| Internal adapter access | Activity/Fragment | `getAdapter()` / `setAdapter()` | Advanced use only |
+
+## Accessibility
+
+The component renders a scrollable `RecyclerView` of message bubbles. Each message bubble responds to tap and long-press gestures. Avatar images include the user name as content description. Date separators and sticky headers provide temporal navigation context for screen readers.
+
+For custom views provided via `setHeaderView`, `setFooterView`, or `setNewMessageIndicatorView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+Read receipt indicators and reaction pills are visual-only by default. If screen reader descriptions are needed, provide them via custom views with appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Message list shows only loading indicator | You must call `.setUser(user)` or `.setGroup(group)` on the `CometChatMessageList` instance. Without a `User` or `Group` object, the component cannot fetch messages. |
+| Messages not appearing for the correct conversation | Verify that the `User` or `Group` object passed to `setUser()` or `setGroup()` has the correct UID or GUID. The component fetches messages for the specified entity only. |
+| Custom style not visible | Verify the style parent is `CometChatMessageListStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| Filters not applied | Ensure you call `setMessagesRequestBuilder(builder)` on the `CometChatMessageList` instance after creating and configuring the builder. Note that UID, GUID, types, and categories are always altered inside the message list. |
+| `setOnThreadRepliesClick` not firing | Verify that threaded messages exist in the conversation. The callback only fires when a user taps a message bubble that has thread replies. |
+| Reactions not responding to custom click handlers | Ensure you set the reaction callbacks (`setOnReactionClick`, `setOnReactionLongClick`, `setOnAddMoreReactionsClick`) before the component loads messages. |
+| Smart replies not appearing | Ensure `setEnableSmartReplies(true)` is called. If you set `setAISmartRepliesKeywords`, verify that incoming messages contain at least one of the specified keywords. |
+| Sound still plays after `disableSoundForMessages(true)` | Ensure you call `disableSoundForMessages(true)` before the component starts loading. If called after data is already loaded, it may not take effect for existing notifications. |
+
+## FAQ
+
+**Q: How do I display messages for a group instead of a user?**
+**A:** Call `.setGroup(group)` with a `Group` object instead of `.setUser(user)`. The component fetches and displays messages for the specified group conversation.
+
+**Q: How do I filter messages by a search keyword?**
+**A:** Create a `MessagesRequest.MessagesRequestBuilder`, call `.setSearchKeyword("your keyword")`, and pass it to `setMessagesRequestBuilder`. Note that UID, GUID, types, and categories are always overridden internally by the message list.
+
+**Q: How do I customize the date format for sticky date separators?**
+**A:** Call `messageList.setDateFormat(new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()))` to set a custom date format for the sticky date headers.
+
+**Q: Does the MessageList component emit any events?**
+**A:** No. The MessageList component does not emit any events of its own. If you need to listen for message-level events, use the CometChat SDK's message listeners directly.
+
+**Q: How do I add a custom header or footer to the message list?**
+**A:** Call `cometChatMessageList.setHeaderView(view)` to add a custom view above the messages, or `cometChatMessageList.setFooterView(view)` to add one below the messages. Pass any inflated `View` object.
+
+**Q: How do I enable AI-powered features like smart replies and conversation starters?**
+**A:** Call `setEnableSmartReplies(true)` for smart replies, `setEnableConversationStarter(true)` for conversation starters, and `setEnableConversationSummary(true)` for conversation summaries. You can also configure keywords with `setAISmartRepliesKeywords` and delay with `setSmartRepliesDelayDuration`.
+
+**Q: How do I scroll to a specific message programmatically?**
+**A:** Use `cometChatMessageList.scrollToMessageId(messageId)` to scroll to and highlight a specific message, or `cometChatMessageList.scrollToBottom()` to scroll to the latest message.
+
+## Next Steps
+
+- [Message Header component](/ui-kit/android/message-header)
+- [Message Composer component](/ui-kit/android/message-composer)
+- [Conversations component](/ui-kit/android/conversations)
diff --git a/ui-kit/android/message-template.mdx b/ui-kit/android/message-template.mdx
index d56aafb32..0df9ed9e3 100644
--- a/ui-kit/android/message-template.mdx
+++ b/ui-kit/android/message-template.mdx
@@ -2,270 +2,196 @@
title: "Message Template"
---
-## Overview
+A `MessageTemplate` defines and customizes both the structure and the behavior of the [MessageBubble](/ui-kit/android/message-bubble-styling#message-bubbles). It acts as a schema for creating `MessageBubble` components, allowing you to manage the appearance and interactions of message bubbles within your application.
-A MessageTemplate provides you with the capability to define and customize both the structure and the behavior of the [MessageBubble](/ui-kit/android/message-bubble-styling#message-bubbles). It acts as a schema or design blueprint for the creation of a variety of [MessageBubble](/ui-kit/android/message-bubble-styling#message-bubbles) components, allowing you to manage the appearance and interactions of [MessageBubble](/ui-kit/android/message-bubble-styling#message-bubbles) within your application effectively and consistently.
+## When to Use This
-### Structure
+- You need to customize the header, content, footer, bottom, or status info view of a message bubble
+- You want to replace the default bubble layout with a completely custom view
+- You need to add or modify the long-press options on a message bubble
+- You want to create a new template for a custom message type (e.g., a contact card)
+- You need to change how a specific message type (text, image, etc.) renders in the [MessageList](/ui-kit/android/message-list)
-
-
-
-
-The MessageBubble structure can typically be broken down into the following views:
-
-1. **Leading view**: This is where the sender's avatar is displayed. It's typically on the left of the MessageBubble for messages from others and on the right for messages from the current user.
-
-2. **Header view**: This displays the sender's name and is especially useful in group chats where multiple users are sending messages.
-
-3. **Content view**: This is the core of the MessageBubble where the message content (text, images, videos, etc.) is displayed.
-
-4. **Bottom view**: This view can be used to extend the MessageBubble with additional elements, such as link previews or a 'load more' button for long messages. It's typically placed beneath the Content view.
-
-5. **Footer view**: This is where the timestamp of the message and its delivery or read status are displayed. It's located at the bottom of the MessageBubble.
-
-### Properties
-
-MessageTemplate provides you with methods that allow you to alter various properties of the MessageBubble. These properties include aspects such as the `type` and `category` of a message, the appearance and behavior of the header, content, and footer sections of the message bubble,
-
-1. **Type**
-
- Using `setType()` you can set the type of CometChatMessage, This will map your MessageTemplate to the corresponding CometChatMessage. You can set the MessageTemplate Type using the following code snippet.
-
- ```swift
- messageTemplate.setType(UIKitConstants.MessageType.CUSTOM);
- ```
-
-2. **Category**
-
- Using `.setCategory()` you can set the category of a MessageTemplate. This will create a MessageTemplate with the specified category and link it with a CometChatMessage of the same category.
-
- Please refer to our guide on [Message Categories](/sdk/android/message-structure-and-hierarchy) for a deeper understanding of message categories.
-
- ```swift
- messageTemplate.setCategory(UIKitConstants.MessageCategory.CUSTOM);
- ```
-
-3. **Header View**
-
- The .`setHeaderView()` method allows you to assign a custom header view to the MessageBubble. By default, it is configured to display the sender's name.
-
-```typescript
-messageTemplate.setHeaderView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return null;
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
-
- }
- });
-```
+## Prerequisites
-4. **Content View**
-
- The `.setContentView()` method allows you to assign a custom content view to the MessageBubble. By default, it displays the [Text Bubble](/ui-kit/android/message-bubble-styling#text-bubble), [Image Bubble](/ui-kit/android/message-bubble-styling#image-bubble), [File Bubble](/ui-kit/android/message-bubble-styling#file-bubble), [Audio Bubble](/ui-kit/android/message-bubble-styling#audio-bubble), or [Video Bubble](/ui-kit/android/message-bubble-styling#video-bubble), depending on the message type.
-
-```typescript
-messageTemplate.setContentView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return null;
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
-
- }
- });
-```
-
-5. **Footer View**
-
- The `.setFooterView()` method allows you to assign a custom Footer view to the MessageBubble. By default, it displays the receipt and timestamp.
-
-```typescript
-messageTemplate.setFooterView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return null;
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
-
- }
- });
-```
-
-6. **Bottom View**
-
- The `.setBottomView()` method allows you to assign a custom Bottom view to the MessageBubble.By defuault is has buttons such as link previews or a 'load more' button for long messages.
-
-```typescript
-messageTemplate.setBottomView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return null;
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
-
- }
- });
-```
+- CometChat Android UI Kit dependency added to your project
+- `CometChatUIKit.init()` called and completed
+- A logged-in CometChat user
+- Familiarity with the [MessageList](/ui-kit/android/message-list) component
+- Familiarity with [MessageBubble styling](/ui-kit/android/message-bubble-styling#message-bubbles)
-7. **Bubble View**
+## Quick Start
- The `.setBubbleView()` method allows you to assign a custom Bubble view to the MessageBubble. By default, headerView, contentView, and footerView together form a message bubble.
+1. Get the list of existing message templates from the data source:
-```typescript
-messageTemplate.setBubbleView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return null;
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
-
- }
- });
-```
-
-8. **Options**
-
-The `.setOptions()` lets you set the list of actions that a user can perform on a message. This includes actions like reacting to, editing, or deleting a message.
-
-```csharp
-messageTemplate.setOptions((context, baseMessage, group) -> Collections.emptyList());
+
+
+```kotlin
+val messageTemplates = CometChatUIKit.getDataSource().getMessageTemplates(messagelist.additionParameter)
```
-
-## Customization
-
-Let's dive into how you can use the [properties](#properties) of MessageTemplate to customize an existing template or add a new one to the [MessageList](/ui-kit/android/message-list) component.
-
-The First step is to fetch the list of existing templates when you want to modify or add to them. This can be done using the getAllMessageTemplates() method from the DataSource of the CometChatUIKit class.
-
-```swift
-List messageTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates(messagelist.getAddtionalParameters());
+
+
+```java
+List messageTemplates = CometChatUIKit.getDataSource().getMessageTemplates(messagelist.getAdditionParameter());
```
+
+
-### Existing Templates
+> **What this does:** Retrieves all registered message templates from the UI Kit data source, giving you the full list of templates to modify or extend.
-You will need to first get the MessageTemplate object for the type of message you want to customize. You will be customizing the TextMessage Bubble here. The code snippet to get the Text MessageTemplate is as follows.
+2. Find the template for the message type you want to customize (e.g., text messages):
+
+```kotlin
+for (template in messageTemplates) {
+ if (template.type == UIKitConstants.MessageType.TEXT) {
+ // Code to customize text message template
+ }
+}
+```
+
```java
-List messageTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates(messagelist.getAddtionalParameters());
-
for(CometChatMessageTemplate template : messageTemplates){
if(template.getType().equals(UIKitConstants.MessageType.TEXT)){
// Code to customize text message template
}
}
```
-
+
+> **What this does:** Iterates through the templates list and matches the template whose `type` equals `UIKitConstants.MessageType.TEXT`, so you can customize only text message bubbles.
+
+3. Customize a view on the matched template (e.g., set a custom content view):
+
+
```kotlin
-val messageTemplates: List = CometChatUIKit.dataSource.messageTemplates(messagelist.getAddtionalParameters())
+template.setContentView(object : MessagesViewHolderListener() {
+ override fun createView(
+ context: Context,
+ cometChatMessageBubble: CometChatMessageBubble,
+ messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment
+ ): View {
+ return LayoutInflater.from(context).inflate(R.layout.your_custom_layout, null)
+ }
-for (template in messageTemplates) {
- if (template.type == UIKitConstants.MessageType.TEXT) {
- // Code to customize text message template
+ override fun bindView(
+ context: Context,
+ view: View,
+ baseMessage: BaseMessage,
+ messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment,
+ viewHolder: RecyclerView.ViewHolder,
+ list: List,
+ i: Int
+ ) {
+ // Bind your custom view data here
}
-}
+})
```
-
+
+```java
+template.setContentView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
+ return LayoutInflater.from(context).inflate(R.layout.your_custom_layout, null);
+ }
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ BaseMessage message,
+ UIKitConstants.MessageBubbleAlignment alignment,
+ RecyclerView.ViewHolder holder,
+ List messageList,
+ int position) {
+ // Bind your custom view data here
+ }
+});
+```
+
-You will be using [MessageList](/ui-kit/android/message-list) Component for example here so to apply Template to MessageList you will need to use `setTemplates` method.
+> **What this does:** Overrides the content view of the matched template by providing a `MessagesViewHolderListener` that inflates a custom layout in `createView()` and binds message data to it in `bindView()`.
-You can apply MessageTemplates to MessagesList Component using the following code snippet.
+4. Apply the modified templates to the `MessageList` component:
+
+```kotlin
+messageList.setTemplates(messageTemplates)
+```
+
```java
-List messageTemplates = CometChatUIKit.getDataSource(getMessageTemplates());
-
-for(CometChatMessageTemplate template : messageTemplates){
- Log.e(TAG, "messageTemplate: Type = "+template.getType());
- if(template.getType().equals(UIKitConstants.MessageType.TEXT)){
- // Code to customize text message template
- }
-}
-
messageList.setTemplates(messageTemplates);
```
-
+
-
-```kotlin
+> **What this does:** Passes the modified templates list to the `MessageList` component so it uses your customized templates when rendering message bubbles.
-val messageTemplates = CometChatUI.getAllMessageTemplates()
+## Core Concepts
-for (template in messageTemplates) {
- Log.e(TAG, "messageTemplate: Type = ${template.type}")
- if (template.type == UIKitConstants.MessageType.TEXT) {
- // Code to customize text message template
- }
-}
+### MessageBubble Structure
-messageList.setTemplates(messageTemplates)
+
+
+
+
+The `MessageBubble` structure is broken down into these views:
+
+1. **Leading view**: Displays the sender's avatar. It appears on the left of the `MessageBubble` for messages from others and on the right for messages from the current user.
+
+2. **Header view**: Displays the sender's name. This is useful in group chats where multiple users are sending messages.
+
+3. **Content view**: The core of the `MessageBubble` where the message content (text, images, videos, etc.) is displayed.
+
+4. **Bottom view**: Extends the `MessageBubble` with additional elements, such as link previews or a "load more" button for long messages. It is placed beneath the Content view.
+
+5. **Footer view**: Displays the timestamp of the message and its delivery or read status. It is located at the bottom of the `MessageBubble`.
+
+### Template Properties
+
+`MessageTemplate` provides methods that allow you to alter various properties of the `MessageBubble`, including the `type` and `category` of a message, and the appearance and behavior of the header, content, and footer sections.
+
+**Type**: Use `setType()` to set the type of `CometChatMessage`. This maps your `MessageTemplate` to the corresponding `CometChatMessage`.
+
+```java
+messageTemplate.setType(UIKitConstants.MessageType.CUSTOM);
```
-
+> **What this does:** Sets the message type on the template so the UI Kit knows which incoming messages this template applies to.
-
+**Category**: Use `setCategory()` to set the category of a `MessageTemplate`. This creates a `MessageTemplate` with the specified category and links it with a `CometChatMessage` of the same category. Refer to the guide on [Message Categories](/sdk/android/message-structure-and-hierarchy) for a deeper understanding.
+
+```java
+messageTemplate.setCategory(UIKitConstants.MessageCategory.CUSTOM);
+```
+
+> **What this does:** Sets the message category on the template, linking it to messages of the same category (e.g., `CUSTOM`).
+
+## Implementation
+
+### Header View
-#### Header view
+What you are changing: The header area of the message bubble, which displays above the content view.
-The `.setHeaderView()` method of MessageTemplate allows you to add custom views to the header of your message bubbles. In the example below, we will add a custom layout `custom_txt_header_layout.xml` to the header view of every text message in the MessageList.
+- **Where**: `MessagesViewHolderListener` passed to `template.setHeaderView()`
+- **Applies to**: Any message type matched by the template (e.g., `UIKitConstants.MessageType.TEXT`)
+- **Default behavior**: Displays the sender's name
+- **Override**: Pass a `MessagesViewHolderListener` to `setHeaderView()` that inflates a custom layout in `createView()` and binds data in `bindView()`
-```xml message_template_header_view.xml
+**XML Layout:**
+
+```xml message_template_header_view.xml lines
```
-
-
-```java
-template.setHeaderView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return LayoutInflater.from(context).inflate(R.layout.message_template_header_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
- TextView textView = createdView.findViewById(R.id.name_with_status);
- textView.setText(message.getSender().getName() + " • " + "\uD83D\uDDD3\uFE0F In meeting");
-
- }
-});
-```
+> **What this does:** Defines a custom header layout with a single `TextView` that shows the sender's name and a status indicator.
-
+**Code:**
+
-```kotlin
-template.setHeaderView(object : MessagesViewHolderListener {
+```kotlin lines
+template.setHeaderView(object : MessagesViewHolderListener() {
override fun createView(
context: Context,
cometChatMessageBubble: CometChatMessageBubble,
@@ -329,26 +234,56 @@ template.setHeaderView(object : MessagesViewHolderListener {
i: Int
) {
val textView = view.findViewById(R.id.name_with_status)
- textView.setText(message.getSender().getName() + " • " + "\uD83D\uDDD3\uFE0F In meeting")
+ textView.setText(baseMessage.getSender().getName() + " • " + "\uD83D\uDDD3\uFE0F In meeting")
}
})
```
-
+
+```java lines
+template.setHeaderView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
+ return LayoutInflater.from(context).inflate(R.layout.message_template_header_view, null);
+ }
+
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ BaseMessage message,
+ UIKitConstants.MessageBubbleAlignment alignment,
+ RecyclerView.ViewHolder holder,
+ List messageList,
+ int position) {
+ TextView textView = createdView.findViewById(R.id.name_with_status);
+ textView.setText(message.getSender().getName() + " • " + "\uD83D\uDDD3\uFE0F In meeting");
+ }
+});
+```
+
-In this code, The createView() method inflates the 'image\_bubble\_content\_view\.xml' as the header view for every message. The bindView() method allows you to bind your custom view, which will be called every time a ViewHolder for that message type is bound.
+> **What this does:** The `createView()` method inflates `message_template_header_view.xml` as the header view for every message. The `bindView()` method sets the sender's name and a status emoji on the `TextView`, and is called every time a ViewHolder for that message type is bound.
+
+- **Verify**: Each text message bubble displays a custom header showing the sender's name followed by " • 🗓️ In meeting" in the primary color, replacing the default sender name header.
-#### Content view
+### Content View
-The `.setContentView()` method of MessageTemplate allows you to add a custom view to the content of your message bubbles. In the example below, we will add a custom layout `custom_message_content_layout.xml` to the content view of every text message in the MessageList.
+What you are changing: The main content area of the message bubble where the message body is displayed.
+
+- **Where**: `MessagesViewHolderListener` passed to `template.setContentView()`
+- **Applies to**: Any message type matched by the template (e.g., `UIKitConstants.MessageType.IMAGE`)
+- **Default behavior**: Displays the [Text Bubble](/ui-kit/android/message-bubble-styling#text-bubble), [Image Bubble](/ui-kit/android/message-bubble-styling#image-bubble), [File Bubble](/ui-kit/android/message-bubble-styling#file-bubble), [Audio Bubble](/ui-kit/android/message-bubble-styling#audio-bubble), or [Video Bubble](/ui-kit/android/message-bubble-styling#video-bubble), depending on the message type
+- **Override**: Pass a `MessagesViewHolderListener` to `setContentView()` that inflates a custom layout in `createView()` and binds data in `bindView()`
-```xml image_bubble_content_view.xml
+**XML Layout:**
+
+```xml image_bubble_content_view.xml lines
-
@@ -384,77 +319,13 @@ The `.setContentView()` method of MessageTemplate allows you to add a custom vie
```
-
-
-```java
- List templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.getAdditionParameter());
+> **What this does:** Defines a custom content layout with a `CometChatImageBubble`, a "Buy Now" label below it, and a hidden `CometChatDeleteBubble` that appears when the message is deleted.
- for (CometChatMessageTemplate template : templates) {
- if (template.getType().equals(UIKitConstants.MessageType.IMAGE)) {
-
- template.setContentView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context,
- CometChatMessageBubble cometChatMessageBubble,
- UIKitConstants.MessageBubbleAlignment messageBubbleAlignment) {
- return LayoutInflater.from(context).inflate(R.layout.image_bubble_content_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View view,
- BaseMessage baseMessage,
- UIKitConstants.MessageBubbleAlignment messageBubbleAlignment,
- RecyclerView.ViewHolder viewHolder,
- List list,
- int i) {
- if (view != null) {
- int deleteStyle;
- int bubbleStyle;
-
- if (messageBubbleAlignment == UIKitConstants.MessageBubbleAlignment.RIGHT) {
- deleteStyle = com.cometchat.chatuikit.R.style.CometChatIncomingMessageDeleteStyle;
- bubbleStyle = com.cometchat.chatuikit.R.style.CometChatIncomingImageMessageBubbleStyle;
- } else {
- deleteStyle = com.cometchat.chatuikit.R.style.CometChatOutgoingDeleteBubbleStyle;
- bubbleStyle = com.cometchat.chatuikit.R.style.CometChatOutgoingImageBubbleStyle;
- }
-
- LinearLayout linearLayout = view.findViewById(R.id.image_bubble_container);
- CometChatImageBubble cometchatImageBubble = view.findViewById(R.id.imageBubble);
- CometChatDeleteBubble deletedBubble = view.findViewById(com.cometchat.chatuikit.R.id.cometchat_delete_text_bubble);
- MediaMessage mediaMessage = (MediaMessage) baseMessage;
- if (mediaMessage.getDeletedAt() == 0) {
- cometchatImageBubble.setStyle(bubbleStyle);
- deletedBubble.setVisibility(View.GONE);
- cometchatImageBubble.setVisibility(View.VISIBLE);
- Attachment attachment = mediaMessage.getAttachment();
- File file = Utils.getFileFromLocalPath(mediaMessage);
- cometchatImageBubble.setImageUrl(file,
- attachment != null ? attachment.getFileUrl() : "",
- attachment != null ? attachment
- .getFileExtension()
- .equalsIgnoreCase("gif") : Utils.isGifFile(file));
- } else {
- linearLayout.setVisibility(View.GONE);
- deletedBubble.setVisibility(View.VISIBLE);
- deletedBubble.setStyle(deleteStyle);
- }
-
- }
- }
- });
- break;
- }
-
- }
- messageList.setTemplates(templates);
-```
-
-
+**Code:**
+
-```kotlin
+```kotlin lines
val templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.additionParameter)
for (template in templates) {
@@ -517,22 +388,95 @@ val templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList
}
messageList.setTemplates(templates)
```
-
+
+```java lines
+ List templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.getAdditionParameter());
+
+ for (CometChatMessageTemplate template : templates) {
+ if (template.getType().equals(UIKitConstants.MessageType.IMAGE)) {
+ template.setContentView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context,
+ CometChatMessageBubble cometChatMessageBubble,
+ UIKitConstants.MessageBubbleAlignment messageBubbleAlignment) {
+ return LayoutInflater.from(context).inflate(R.layout.image_bubble_content_view, null);
+ }
+
+ @Override
+ public void bindView(Context context,
+ View view,
+ BaseMessage baseMessage,
+ UIKitConstants.MessageBubbleAlignment messageBubbleAlignment,
+ RecyclerView.ViewHolder viewHolder,
+ List list,
+ int i) {
+ if (view != null) {
+ int deleteStyle;
+ int bubbleStyle;
+
+ if (messageBubbleAlignment == UIKitConstants.MessageBubbleAlignment.RIGHT) {
+ deleteStyle = com.cometchat.chatuikit.R.style.CometChatIncomingMessageDeleteStyle;
+ bubbleStyle = com.cometchat.chatuikit.R.style.CometChatIncomingImageMessageBubbleStyle;
+ } else {
+ deleteStyle = com.cometchat.chatuikit.R.style.CometChatOutgoingDeleteBubbleStyle;
+ bubbleStyle = com.cometchat.chatuikit.R.style.CometChatOutgoingImageBubbleStyle;
+ }
+
+ LinearLayout linearLayout = view.findViewById(R.id.image_bubble_container);
+ CometChatImageBubble cometchatImageBubble = view.findViewById(R.id.imageBubble);
+ CometChatDeleteBubble deletedBubble = view.findViewById(com.cometchat.chatuikit.R.id.cometchat_delete_text_bubble);
+ MediaMessage mediaMessage = (MediaMessage) baseMessage;
+ if (mediaMessage.getDeletedAt() == 0) {
+ cometchatImageBubble.setStyle(bubbleStyle);
+ deletedBubble.setVisibility(View.GONE);
+ cometchatImageBubble.setVisibility(View.VISIBLE);
+ Attachment attachment = mediaMessage.getAttachment();
+ File file = Utils.getFileFromLocalPath(mediaMessage);
+ cometchatImageBubble.setImageUrl(file,
+ attachment != null ? attachment.getFileUrl() : "",
+ attachment != null ? attachment
+ .getFileExtension()
+ .equalsIgnoreCase("gif") : Utils.isGifFile(file));
+ } else {
+ linearLayout.setVisibility(View.GONE);
+ deletedBubble.setVisibility(View.VISIBLE);
+ deletedBubble.setStyle(deleteStyle);
+ }
+
+ }
+ }
+ });
+ break;
+ }
+
+ }
+ messageList.setTemplates(templates);
+```
+
-In this code, The createView() method inflates the 'image\_bubble\_content\_view\.xml' as the content view for every message. The bindView() method allows you to bind your custom view, which will be called every time a ViewHolder for that message type is bound.
+> **What this does:** The `createView()` method inflates `image_bubble_content_view.xml` as the content view for every image message. The `bindView()` method handles displaying the image with `CometChatImageBubble` when the message is not deleted, and showing a `CometChatDeleteBubble` when the message has been deleted.
-#### Status info view
+- **Verify**: Image message bubbles display a `CometChatImageBubble` with a "Buy Now" label below it. If the message is deleted, the image is hidden and a delete bubble appears instead.
-The `.setStatusInfoView()` method of MessageTemplate allows you to add a custom status info to your message bubbles. In the example below, we will add a custom layout `status_info_layout.xml` to the footerview and empty layout to the status info view view of every text message in the MessageList.
+### Status Info View
+
+What you are changing: The status info area inside the message bubble, which displays delivery/read status indicators.
+
+- **Where**: `MessagesViewHolderListener` passed to `template.setStatusInfoView()` (and optionally `template.setFooterView()` for relocated status content)
+- **Applies to**: Any message type matched by the template (e.g., `UIKitConstants.MessageType.TEXT`)
+- **Default behavior**: Displays the message receipt and timestamp inside the bubble
+- **Override**: Pass a `MessagesViewHolderListener` to `setStatusInfoView()` that returns a minimal empty view, and move the status content to the footer view using `setFooterView()`
-```xml status_info_layout.xml
+**XML Layout:**
+
+```xml status_info_layout.xml lines
-
```
-
-
-```java
- List templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.getAdditionParameter());
-
- for (CometChatMessageTemplate template : templates) {
- if (template.getType().equals(UIKitConstants.MessageType.TEXT)) {
-
- template.setStatusInfoView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context,
- CometChatMessageBubble cometChatMessageBubble,
- UIKitConstants.MessageBubbleAlignment messageBubbleAlignment) {
- View view = new View(context);
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- context.getResources().getDimensionPixelSize(com.cometchat.chatuikit.R.dimen.cometchat_1dp),
- context.getResources().getDimensionPixelSize(com.cometchat.chatuikit.R.dimen.cometchat_12dp));
- view.setLayoutParams(layoutParams);
- return view;
- }
-
- @Override
- public void bindView(Context context,
- View view,
- BaseMessage baseMessage,
- UIKitConstants.MessageBubbleAlignment messageBubbleAlignment,
- RecyclerView.ViewHolder viewHolder,
- List list,
- int i) {
-
- }
- });
-
- template.setFooterView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context,
- CometChatMessageBubble cometChatMessageBubble,
- UIKitConstants.MessageBubbleAlignment messageBubbleAlignment) {
- return LayoutInflater.from(context).inflate(R.layout.status_info_layout, null);
-
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage baseMessage,
- UIKitConstants.MessageBubbleAlignment messageBubbleAlignment,
- RecyclerView.ViewHolder viewHolder,
- List list,
- int i) {
- TextView tvTime = createdView.findViewById(R.id.time);
- CometChatMessageReceipt receipt = createdView.findViewById(R.id.receipt);
- if (messageBubbleAlignment.equals(UIKitConstants.MessageBubbleAlignment.RIGHT)) {
- receipt.setVisibility(View.VISIBLE);
- receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(baseMessage));
- } else {
- receipt.setVisibility(View.GONE);
- }
- tvTime.setText(new SimpleDateFormat("hh:mm a").format(baseMessage.getSentAt() * 1000));
- }
- });
- break;
- }
-
- }
- messageList.setTemplates(templates);
-```
+> **What this does:** Defines a custom status info layout with a time `TextView` and a `CometChatMessageReceipt` view arranged horizontally, aligned to the end of the bubble.
-
+**Code:**
+
-```kotlin
+```kotlin lines
val templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.additionParameter)
for (template in templates) {
@@ -699,22 +578,96 @@ The `.setStatusInfoView()` method of MessageTemplate allows you to add a custom
}
messageList.setTemplates(templates)
```
-
+
+```java lines
+ List templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.getAdditionParameter());
+
+ for (CometChatMessageTemplate template : templates) {
+ if (template.getType().equals(UIKitConstants.MessageType.TEXT)) {
+
+ template.setStatusInfoView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context,
+ CometChatMessageBubble cometChatMessageBubble,
+ UIKitConstants.MessageBubbleAlignment messageBubbleAlignment) {
+ View view = new View(context);
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ context.getResources().getDimensionPixelSize(com.cometchat.chatuikit.R.dimen.cometchat_1dp),
+ context.getResources().getDimensionPixelSize(com.cometchat.chatuikit.R.dimen.cometchat_12dp));
+ view.setLayoutParams(layoutParams);
+ return view;
+ }
+
+ @Override
+ public void bindView(Context context,
+ View view,
+ BaseMessage baseMessage,
+ UIKitConstants.MessageBubbleAlignment messageBubbleAlignment,
+ RecyclerView.ViewHolder viewHolder,
+ List list,
+ int i) {
+
+ }
+ });
+
+ template.setFooterView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context,
+ CometChatMessageBubble cometChatMessageBubble,
+ UIKitConstants.MessageBubbleAlignment messageBubbleAlignment) {
+ return LayoutInflater.from(context).inflate(R.layout.status_info_layout, null);
+
+ }
+
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ BaseMessage baseMessage,
+ UIKitConstants.MessageBubbleAlignment messageBubbleAlignment,
+ RecyclerView.ViewHolder viewHolder,
+ List list,
+ int i) {
+ TextView tvTime = createdView.findViewById(R.id.time);
+ CometChatMessageReceipt receipt = createdView.findViewById(R.id.receipt);
+ if (messageBubbleAlignment.equals(UIKitConstants.MessageBubbleAlignment.RIGHT)) {
+ receipt.setVisibility(View.VISIBLE);
+ receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(baseMessage));
+ } else {
+ receipt.setVisibility(View.GONE);
+ }
+ tvTime.setText(new SimpleDateFormat("hh:mm a").format(baseMessage.getSentAt() * 1000));
+ }
+ });
+ break;
+ }
+ }
+ messageList.setTemplates(templates);
+```
+
-In this code, The createView() method inflates the `status_info_layout.xml` as the footer info view for every message. The bindView() method allows you to bind your custom view, which will be called every time a ViewHolder for that message type is bound.
+> **What this does:** The `setStatusInfoView()` replaces the default in-bubble status info with a minimal 1dp×12dp empty view. The `setFooterView()` inflates `status_info_layout.xml` as the footer, displaying the timestamp and message receipt outside the bubble. If the alignment is `RIGHT` (sent messages), the receipt icon is visible; if `LEFT` (received messages), the receipt icon is hidden.
-#### Bottom View
+- **Verify**: Text message bubbles show the timestamp and delivery receipt below the bubble (in the footer area) instead of inside the bubble. Sent messages display both the time and receipt icon; received messages display only the time.
-The `.setBottomView()` method of MessageTemplate allows you to add a custom button view to your message bubbles. In the example below, we will add a custom layout `custom_message_bottom_layout.xml` to the bottom view of every text message in the MessageList.
+### Bottom View
+
+What you are changing: The bottom area of the message bubble, placed beneath the content view.
+
+- **Where**: `MessagesViewHolderListener` passed to `template.setBottomView()`
+- **Applies to**: Any message type matched by the template (e.g., `UIKitConstants.MessageType.TEXT`)
+- **Default behavior**: Displays buttons such as link previews or a "load more" button for long messages
+- **Override**: Pass a `MessagesViewHolderListener` to `setBottomView()` that inflates a custom layout in `createView()` and binds data in `bindView()`
-```xml message_template_bottom_view.xml
+**XML Layout:**
+
+```xml message_template_bottom_view.xml lines
```
-
-
-```java
-template.setBottomView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
- return LayoutInflater.from(context).inflate(R.layout.message_template_bottom_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
- createdView.setVisibility(View.GONE);
- if (baseMessage.getMetadata() != null && MessageReceiptUtils.MessageReceipt(baseMessage).equals(Receipt.ERROR)) {
- createdView.setVisibility(View.VISIBLE);
- }
- }
-});
-```
+> **What this does:** Defines a custom bottom view layout with an error icon and a red warning text, used to display a policy warning below the message content.
-
+**Code:**
+
-```kotlin
-template.setBottomView(object : MessagesViewHolderListener {
+```kotlin lines
+template.setBottomView(object : MessagesViewHolderListener() {
override fun createView(
context: Context,
cometChatMessageBubble: CometChatMessageBubble,
@@ -800,29 +731,60 @@ template.setBottomView(object : MessagesViewHolderListener {
list: List,
i: Int
) {
- createdView.setVisibility(View.GONE);
+ view.setVisibility(View.GONE);
if (baseMessage.getMetadata() != null && MessageReceiptUtils.MessageReceipt(baseMessage).equals(Receipt.ERROR)) {
- createdView.setVisibility(View.VISIBLE);
+ view.setVisibility(View.VISIBLE);
}
}
})
```
-
+
+```java lines
+template.setBottomView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
+ return LayoutInflater.from(context).inflate(R.layout.message_template_bottom_view, null);
+ }
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ BaseMessage message,
+ UIKitConstants.MessageBubbleAlignment alignment,
+ RecyclerView.ViewHolder holder,
+ List messageList,
+ int position) {
+ createdView.setVisibility(View.GONE);
+ if (message.getMetadata() != null && MessageReceiptUtils.MessageReceipt(message).equals(Receipt.ERROR)) {
+ createdView.setVisibility(View.VISIBLE);
+ }
+ }
+});
+```
+
-In this code, The createView() method inflates the 'custom\_message\_bottom\_layout.xml' as the bottom view for every message. The bindView() method allows you to bind your custom view, which will be called every time a ViewHolder for that message type is bound.
+> **What this does:** The `createView()` method inflates `message_template_bottom_view.xml` as the bottom view for every message. The `bindView()` method hides the bottom view by default and shows it only if the message has metadata and the message receipt equals `Receipt.ERROR`.
+
+- **Verify**: The bottom view is hidden by default. If a message has an error receipt (`Receipt.ERROR`) and non-null metadata, a red warning banner with an error icon and text appears below the message content.
-#### Footer View
+### Footer View
-The `.setFooterView()` method of MessageTemplate allows you to add a footer view to your message bubbles. In the example below, we will add a custom layout custom\_menu\_layout.xml to the bottom view of every text message in the MessageList.
+What you are changing: The footer area of the message bubble, located at the bottom of the bubble.
+
+- **Where**: `MessagesViewHolderListener` passed to `template.setFooterView()`
+- **Applies to**: Any message type matched by the template (e.g., `UIKitConstants.MessageType.TEXT`)
+- **Default behavior**: Displays the receipt and timestamp
+- **Override**: Pass a `MessagesViewHolderListener` to `setFooterView()` that inflates a custom layout in `createView()` and binds data in `bindView()`
-```html
+**XML Layout:**
+
+```html lines
-
@@ -849,9 +811,40 @@ The `.setFooterView()` method of MessageTemplate allows you to add a footer view
```
+> **What this does:** Defines a custom footer layout with a thin separator line and a `CometChatMessageReaction` view that displays message reactions.
+
+**Code:**
+
+
+```kotlin lines
+template.setFooterView(object : MessagesViewHolderListener() {
+ override fun createView(context: Context, messageBubble: CometChatMessageBubble, alignment: MessageBubbleAlignment): View {
+ return LayoutInflater.from(context).inflate(R.layout.message_template_footer_view, null)
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ message: BaseMessage,
+ alignment: MessageBubbleAlignment,
+ holder: RecyclerView.ViewHolder,
+ messageList: List,
+ position: Int
+ ) {
+ val messageReaction = createdView.findViewById(R.id.cometchat_reaction_view)
+ val reactionLayout = createdView.findViewById(R.id.cometchat_reaction_layout_parent_container)
+ if (alignment == MessageBubbleAlignment.RIGHT) reactionLayout.setBackgroundColor(CometChatTheme.getPrimaryColor(context))
+ else reactionLayout.setBackgroundColor(CometChatTheme.getNeutralColor300(context))
+
+ messageReaction.setStyle(R.style.CometChatReactionStyle)
+ messageReaction.bindReactionsToMessage(message, 4)
+ }
+ })
+```
+
-```java
+```java lines
template.setFooterView(new MessagesViewHolderListener() {
@Override
public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) {
@@ -878,53 +871,31 @@ template.setFooterView(new MessagesViewHolderListener() {
}
});
```
-
+
-
-```kotlin
-template.setFooterView(object : MessagesViewHolderListener() {
- override fun createView(context: Context, messageBubble: CometChatMessageBubble, alignment: MessageBubbleAlignment): View {
- return LayoutInflater.from(context).inflate(R.layout.message_template_footer_view, null)
- }
-
- override fun bindView(
- context: Context,
- createdView: View,
- message: BaseMessage,
- alignment: MessageBubbleAlignment,
- holder: RecyclerView.ViewHolder,
- messageList: List,
- position: Int
- ) {
- val messageReaction = createdView.findViewById(R.id.cometchat_reaction_view)
- val reactionLayout = createdView.findViewById(R.id.cometchat_reaction_layout_parent_container)
- if (alignment == MessageBubbleAlignment.RIGHT) reactionLayout.setBackgroundColor(CometChatTheme.getPrimaryColor(context))
- else reactionLayout.setBackgroundColor(CometChatTheme.getNeutralColor300(context))
-
- messageReaction.setStyle(R.style.CometChatReactionStyle)
- messageReaction.bindReactionsToMessage(message, 4)
- }
- })
-```
-
-
+> **What this does:** The `createView()` method inflates a custom footer layout with a `CometChatMessageReaction` view. The `bindView()` method sets the background color based on alignment (primary color for sent messages, neutral color for received messages), applies the `CometChatReactionStyle`, and binds up to 4 reactions to the message.
-
+- **Verify**: Each message bubble displays a reactions bar in the footer area with a separator line above it. Sent message footers use the primary color background; received message footers use the neutral color background. Up to 4 reactions are displayed per message.
-In this code, The createView() method inflates the 'custom\_menu\_layout.xml' as the footer view for every message. The bindView() method allows you to bind your custom view, which will be called every time a ViewHolder for that message type is bound.
+### Bubble View
-#### Bubble View
+What you are changing: The entire message bubble, replacing the default combination of header, content, and footer views with a fully custom layout.
-The` .setBubbleView()` method of MessageTemplate allows you to add a bubble view to your message bubbles. In the example below, we will add a custom layout custom\_message\_content\_layout.xml to the bubble view of every text message in the MessageList.
+- **Where**: `MessagesViewHolderListener` passed to `template.setBubbleView()`
+- **Applies to**: Any message type matched by the template (e.g., `UIKitConstants.MessageType.TEXT`)
+- **Default behavior**: The `headerView`, `contentView`, and `footerView` together form a message bubble
+- **Override**: Pass a `MessagesViewHolderListener` to `setBubbleView()` that inflates a completely custom bubble layout in `createView()` and binds data in `bindView()`
+**XML Layouts:**
+
drawable/left\_bubble\_bg
-```html
+```html lines
```
+> **What this does:** Defines a vector drawable for the left (incoming) bubble background with a speech-bubble tail pointing left, using the neutral color.
+
drawable/right\_bubble\_bg
-```html
+```html lines
```
-```html
+> **What this does:** Defines a vector drawable for the right (outgoing) bubble background with a speech-bubble tail pointing right, using the primary color.
+
+outgoing\_text\_bubble\_view.xml
+
+```html lines
-
```
-```html
+> **What this does:** Defines the outgoing (sent) text bubble layout with a right-aligned bubble background, a text message `TextView`, a timestamp, and a `CometChatMessageReceipt` view.
+
+incoming\_text\_bubble\_view.xml
+
+```html lines
```
-
-
-```java
-template.setBubbleView(new MessagesViewHolderListener() {
- @Override
- public View createView(Context context,
- CometChatMessageBubble messageBubble,
- UIKitConstants.MessageBubbleAlignment alignment) {
- if (alignment.equals(UIKitConstants.MessageBubbleAlignment.LEFT))
- return LayoutInflater.from(context).inflate(R.layout.incoming_text_bubble_view, null);
- else
- return LayoutInflater.from(context).inflate(R.layout.outgoing_text_bubble_view, null);
- }
-
- @Override
- public void bindView(Context context,
- View createdView,
- BaseMessage message,
- UIKitConstants.MessageBubbleAlignment alignment,
- RecyclerView.ViewHolder holder,
- List messageList,
- int position) {
-
- TextView textView = createdView.findViewById(R.id.text_message);
- TextView tvTime = createdView.findViewById(R.id.time);
- if (alignment.equals(UIKitConstants.MessageBubbleAlignment.RIGHT)) {
- CometChatMessageReceipt receipt = createdView.findViewById(R.id.receipt);
- receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(message));
- }
-
- TextMessage textMessage = (TextMessage) message;
-
- tvTime.setText(new SimpleDateFormat("hh:mm a").format(textMessage.getSentAt() * 1000));
- textView.setText(textMessage.getText());
- }
- });
-```
+> **What this does:** Defines the incoming (received) text bubble layout with a left-aligned bubble background, a text message `TextView`, and a timestamp (no receipt icon for incoming messages).
-
+**Code:**
+
-```kotlin
+```kotlin lines
template.setBubbleView(object : MessagesViewHolderListener() {
override fun createView(
context: Context,
@@ -1119,31 +1065,100 @@ template.setBubbleView(object : MessagesViewHolderListener() {
receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(message))
}
- val textMessage = message as TextMessage
+ val textMessage = message as TextMessage
+
+ tvTime.text = SimpleDateFormat("hh:mm a").format(textMessage.sentAt * 1000)
+ textView.text = textMessage.text
+ }
+ })
+```
+
+
+```java lines
+template.setBubbleView(new MessagesViewHolderListener() {
+ @Override
+ public View createView(Context context,
+ CometChatMessageBubble messageBubble,
+ UIKitConstants.MessageBubbleAlignment alignment) {
+ if (alignment.equals(UIKitConstants.MessageBubbleAlignment.LEFT))
+ return LayoutInflater.from(context).inflate(R.layout.incoming_text_bubble_view, null);
+ else
+ return LayoutInflater.from(context).inflate(R.layout.outgoing_text_bubble_view, null);
+ }
+
+ @Override
+ public void bindView(Context context,
+ View createdView,
+ BaseMessage message,
+ UIKitConstants.MessageBubbleAlignment alignment,
+ RecyclerView.ViewHolder holder,
+ List messageList,
+ int position) {
+
+ TextView textView = createdView.findViewById(R.id.text_message);
+ TextView tvTime = createdView.findViewById(R.id.time);
+ if (alignment.equals(UIKitConstants.MessageBubbleAlignment.RIGHT)) {
+ CometChatMessageReceipt receipt = createdView.findViewById(R.id.receipt);
+ receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(message));
+ }
- tvTime.text = SimpleDateFormat("hh:mm a").format(textMessage.sentAt * 1000)
- textView.text = textMessage.text
- }
- })
-```
+ TextMessage textMessage = (TextMessage) message;
+ tvTime.setText(new SimpleDateFormat("hh:mm a").format(textMessage.getSentAt() * 1000));
+ textView.setText(textMessage.getText());
+ }
+ });
+```
-
-#### Options List
+> **What this does:** The `createView()` method inflates `incoming_text_bubble_view.xml` if the alignment is `LEFT` (received messages) or `outgoing_text_bubble_view.xml` if the alignment is `RIGHT` (sent messages). The `bindView()` method sets the message text, timestamp, and receipt icon (for sent messages only), completely replacing the default bubble structure.
-The `.setOptions()` method in the MessageTemplate allows you to customize the options that appear in the action sheet when a message is long-pressed. By default, CometChat UI Kit provides a set of options like "Reply", "Forward", "Edit", and "Delete".
+- **Verify**: Text messages display with custom speech-bubble-shaped backgrounds — outgoing messages use the primary color with a right-pointing tail, incoming messages use the neutral color with a left-pointing tail. Each bubble shows the message text, timestamp, and (for sent messages) a delivery receipt icon.
-However, if you wish to override or modify these options, you can use the `.setOptions()` method and pass a list of `CometChatMessageOption`. This list of options will replace the default set.
+### Options List
+
+What you are changing: The list of actions that appear in the action sheet when a message is long-pressed.
+
+- **Where**: Lambda/callback passed to `template.setOptions()` or `messageTemplate.setOptions()`
+- **Applies to**: Any message type matched by the template
+- **Default behavior**: Displays a set of options like "Reply", "Forward", "Edit", and "Delete"
+- **Override**: Pass a lambda to `setOptions()` that returns a custom list of `CometChatMessageOption` objects
+**Code:**
+
+
+```kotlin lines
+ val messageTemplates = ChatConfigurator
+ .getDataSource()
+ .getMessageTemplates(messageList.additionParameter)
+
+ for (messageTemplate in messageTemplates) {
+ messageTemplate.setOptions { context: Context?, baseMessage: BaseMessage?, group: Group? ->
+ val refreshOption =
+ CometChatMessageOption(
+ "REFRESH",
+ "Refresh",
+ android.R.drawable.ic_refresh
+ ) { Toast.makeText(context, "Refresh clicked", Toast.LENGTH_SHORT).show() }
+ val options: MutableList =
+ ArrayList()
+ options.add(refreshOption)
+ options.addAll(CometChatUIKit.getDataSource().getMessageOptions(context, baseMessage, group))
+ options
+ }
+ }
+
+messageList.setTemplates(messageTemplates)
+```
+
-```java
+```java lines
List messageTemplates = ChatConfigurator
.getDataSource()
.getMessageTemplates(messageList.getAdditionParameter());
@@ -1166,51 +1181,57 @@ List messageTemplates = ChatConfigurator
messageList.setTemplates(messageTemplates);
```
-
+
-
-```kotlin
- val messageTemplates = ChatConfigurator
- .getDataSource()
- .getMessageTemplates(messageList.additionParameter)
-
- for (messageTemplate in messageTemplates) {
- messageTemplate.setOptions { context: Context?, baseMessage: BaseMessage?, group: Group? ->
- val refreshOption =
- CometChatMessageOption(
- "REFRESH",
- "Refresh",
- android.R.drawable.ic_refresh
- ) { Toast.makeText(context, "Refresh clicked", Toast.LENGTH_SHORT).show() }
- val options: MutableList =
- ArrayList()
- options.add(refreshOption)
- options.addAll(CometChatUIKit.getDataSource().getMessageOptions(context, baseMessage, group))
- options
- }
- }
-
-messageList.setTemplates(messageTemplates)
-```
+> **What this does:** Creates a custom "Refresh" option using `CometChatMessageOption` with an ID of `"REFRESH"`, a label, an icon, and a click handler that shows a toast. This option is prepended to the default options list retrieved from `CometChatUIKit.getDataSource().getMessageOptions()`, so the "Refresh" option appears first in the long-press action sheet for all message types.
-
+- **Verify**: Long-pressing any message displays an action sheet with "Refresh" as the first option, followed by the default options (Reply, Forward, Edit, Delete, etc.). Tapping "Refresh" shows a toast message "Refresh clicked".
-
+### New Template
-### New Templates
+What you are changing: Adding an entirely new message template for a custom message type that does not have a default template.
-You can create an entirely new template for custom messages is one of the powerful features of CometChat's MessageTemplate.
+- **Where**: Create a new `CometChatMessageTemplate` instance and add it to the templates list
+- **Applies to**: Custom message types (e.g., a "card" type with `UIKitConstants.MessageCategory.CUSTOM`)
+- **Default behavior**: Custom message types without a template are not rendered in the `MessageList`
+- **Override**: Create a new `CometChatMessageTemplate`, set its `type` and `category`, define a `setBubbleView()`, and add it to the templates list
-First, let's see how to send a custom message:
+**Sending a custom message:**
+
+```kotlin lines
+ val jsonObject = JSONObject()
+ try {
+ jsonObject.put("contact_name", "John Doe")
+ jsonObject.put("contact_avatar", "https://img.freepik.com/free-vector/blue-circle-with-white-user_78370-4707.jpg?semt=ais_hybrid")
+ jsonObject.put("contact_number", "+91 1234567890")
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ val customMessage = CustomMessage(
+ if (user != null) user!!.uid else group.getGuid(),
+ if (user != null) CometChatConstants.RECEIVER_TYPE_USER else CometChatConstants.RECEIVER_TYPE_GROUP,
+ "card",
+ jsonObject
+ )
+
+ CometChatUIKit.sendCustomMessage(customMessage, object : CallbackListener() {
+ override fun onSuccess(customMessage: CustomMessage?) {
+ }
+
+ override fun onError(e: CometChatException?) {
+ }
+ })
+```
+
-```java
+```java lines
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("contact_name", "John Doe");
@@ -1236,42 +1257,14 @@ First, let's see how to send a custom message:
}
});
```
-
-
-
-
-```kotlin
- val jsonObject = JSONObject()
- try {
- jsonObject.put("contact_name", "John Doe")
- jsonObject.put("contact_avatar", "https://img.freepik.com/free-vector/blue-circle-with-white-user_78370-4707.jpg?semt=ais_hybrid")
- jsonObject.put("contact_number", "+91 1234567890")
- } catch (e: Exception) {
- e.printStackTrace()
- }
- val customMessage = CustomMessage(
- if (user != null) user!!.uid else group.getGuid(),
- if (user != null) CometChatConstants.RECEIVER_TYPE_USER else CometChatConstants.RECEIVER_TYPE_GROUP,
- "card",
- jsonObject
- )
-
- CometChatUIKit.sendCustomMessage(customMessage, object : CallbackListener() {
- override fun onSuccess(customMessage: CustomMessage?) {
- }
-
- override fun onError(e: CometChatException?) {
- }
- })
-```
-
-
-Now, we'll create a new MessageTemplate to render this custom message in the MessageList:
+> **What this does:** Creates a `CustomMessage` with type `"card"` containing contact data (`contact_name`, `contact_avatar`, `contact_number`) as a `JSONObject`, and sends it using `CometChatUIKit.sendCustomMessage()`.
-```xml contact_card.xml
+**XML Layout for the contact card:**
+
+```xml contact_card.xml lines
-
-
```
+> **What this does:** Defines a contact card layout using `MaterialCardView` with a `CometChatAvatar`, contact name, timestamp, receipt icon, a separator, and two action buttons ("Add Contact" and "Message").
+
+**Creating and registering the new template:**
+
+
+```kotlin lines
+ val contactTemplate = CometChatMessageTemplate()
+ contactTemplate.setType("card")
+ contactTemplate.setCategory(UIKitConstants.MessageCategory.CUSTOM)
+ contactTemplate.setBubbleView(object : MessagesViewHolderListener() {
+ override fun createView(
+ context: Context,
+ cometChatMessageBubble: CometChatMessageBubble,
+ messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment
+ ): View {
+ return LayoutInflater.from(context).inflate(R.layout.contact_card, null)
+ }
+
+ override fun bindView(
+ context: Context,
+ view: View,
+ baseMessage: BaseMessage,
+ alignment: UIKitConstants.MessageBubbleAlignment,
+ viewHolder: RecyclerView.ViewHolder,
+ list: List,
+ i: Int
+ ) {
+ val layoutParams = LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ view.layoutParams = layoutParams
+ val avatar = view.findViewById(R.id.avatar)
+ val name = view.findViewById(R.id.contactName)
+ val time = view.findViewById(R.id.time)
+ val receipt = view.findViewById(R.id.receipt)
+
+ val customMessage = baseMessage as CustomMessage
+ val jsonObject = customMessage.customData
+ try {
+ name.text = jsonObject.getString("contact_name")
+ avatar.avatar = jsonObject.getString("contact_avatar")
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ if (alignment == UIKitConstants.MessageBubbleAlignment.RIGHT) {
+ receipt.visibility = View.VISIBLE
+ receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(baseMessage))
+ } else {
+ receipt.visibility = View.GONE
+ }
+
+ time.text = SimpleDateFormat("hh:mm a").format(baseMessage.getSentAt() * 1000)
+ }
+ })
+
+ messageTemplates.add(contactTemplate)
+ messageList.setTemplates(messageTemplates)
+```
+
-```java
+```java lines
List messageTemplates = ChatConfigurator
.getDataSource()
.getMessageTemplates(messageList.getAdditionParameter());
@@ -1446,70 +1500,62 @@ Now, we'll create a new MessageTemplate to render this custom message in the Mes
messageTemplates.add(contactTemplate);
messageList.setTemplates(messageTemplates);
```
-
+
-
-```kotlin
- val contactTemplate = CometChatMessageTemplate()
- contactTemplate.setType("card")
- contactTemplate.setCategory(UIKitConstants.MessageCategory.CUSTOM)
- contactTemplate.setBubbleView(object : MessagesViewHolderListener() {
- override fun createView(
- context: Context,
- cometChatMessageBubble: CometChatMessageBubble,
- messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment
- ): View {
- return LayoutInflater.from(context).inflate(R.layout.contact_card, null)
- }
+> **What this does:** Creates a new `CometChatMessageTemplate` with type `"card"` and category `UIKitConstants.MessageCategory.CUSTOM`. The `setBubbleView()` inflates `contact_card.xml` and binds the contact name, avatar, timestamp, and receipt from the `CustomMessage`'s `customData` JSON. The new template is added to the existing templates list and applied to the `MessageList` via `setTemplates()`. This renders the custom "card" message as a contact card in the chat.
- override fun bindView(
- context: Context,
- view: View,
- baseMessage: BaseMessage,
- alignment: UIKitConstants.MessageBubbleAlignment,
- viewHolder: RecyclerView.ViewHolder,
- list: List,
- i: Int
- ) {
- val layoutParams = LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- )
- view.layoutParams = layoutParams
- val avatar = view.findViewById(R.id.avatar)
- val name = view.findViewById(R.id.contactName)
- val time = view.findViewById(R.id.time)
- val receipt = view.findViewById(R.id.receipt)
+- **Verify**: Custom messages with type `"card"` appear in the `MessageList` as a purple contact card showing the contact's avatar, name, timestamp, delivery receipt (for sent messages), and two action buttons ("Add Contact" and "Message").
- val customMessage = baseMessage as CustomMessage
- val jsonObject = customMessage.customData
- try {
- name.text = jsonObject.getString("contact_name")
- avatar.avatar = jsonObject.getString("contact_avatar")
- } catch (e: Exception) {
- e.printStackTrace()
- }
+## Customization Matrix
- if (alignment == UIKitConstants.MessageBubbleAlignment.RIGHT) {
- receipt.visibility = View.VISIBLE
- receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(baseMessage))
- } else {
- receipt.visibility = View.GONE
- }
+| What you want to change | Where | Property/API | Example |
+| ----------------------- | ----- | ------------ | ------- |
+| Message type mapping | `CometChatMessageTemplate` | `setType()` | `messageTemplate.setType(UIKitConstants.MessageType.CUSTOM)` |
+| Message category mapping | `CometChatMessageTemplate` | `setCategory()` | `messageTemplate.setCategory(UIKitConstants.MessageCategory.CUSTOM)` |
+| Header area (sender name) | `CometChatMessageTemplate` | `setHeaderView()` | Pass a `MessagesViewHolderListener` that inflates a custom header layout |
+| Content area (message body) | `CometChatMessageTemplate` | `setContentView()` | Pass a `MessagesViewHolderListener` that inflates a custom content layout |
+| Footer area (timestamp/receipt) | `CometChatMessageTemplate` | `setFooterView()` | Pass a `MessagesViewHolderListener` that inflates a custom footer layout |
+| Bottom area (below content) | `CometChatMessageTemplate` | `setBottomView()` | Pass a `MessagesViewHolderListener` that inflates a custom bottom layout |
+| Status info (in-bubble receipt) | `CometChatMessageTemplate` | `setStatusInfoView()` | Pass a `MessagesViewHolderListener` that returns a minimal or custom view |
+| Entire bubble layout | `CometChatMessageTemplate` | `setBubbleView()` | Pass a `MessagesViewHolderListener` that inflates a fully custom bubble layout |
+| Long-press action options | `CometChatMessageTemplate` | `setOptions()` | Pass a lambda returning a list of `CometChatMessageOption` objects |
- time.text = SimpleDateFormat("hh:mm a").format(baseMessage.getSentAt() * 1000)
- }
- })
+## Common Pitfalls and Fixes
- messageTemplates.add(contactTemplate)
- messageList.setTemplates(messageTemplates)
-```
+| Pitfall | Fix |
+| ------- | --- |
+| Modified templates but message bubbles do not change | Call `messageList.setTemplates(messageTemplates)` after modifying the templates. If you do not apply the templates to the `MessageList`, your changes have no effect. |
+| Returning `null` from `createView()` causes blank bubbles | Do return a valid `View` from `createView()`. If you return `null`, the message bubble renders as empty with no visible content. |
+| Custom view data not updating when scrolling | Bind all dynamic data in `bindView()`, not in `createView()`. The `bindView()` method is called every time a ViewHolder is bound, while `createView()` is called only once per ViewHolder creation. |
+| Template customization applies to wrong message type | Verify the `template.getType()` (Java) or `template.type` (Kotlin) matches the intended `UIKitConstants.MessageType` before applying customizations. |
+| New custom template messages do not appear in the `MessageList` | Add the new `CometChatMessageTemplate` to the templates list using `messageTemplates.add(contactTemplate)` before calling `messageList.setTemplates(messageTemplates)`. |
+| Receipt icon appears on received messages | In `bindView()`, check the alignment: if `messageBubbleAlignment` equals `UIKitConstants.MessageBubbleAlignment.RIGHT`, show the receipt; if `LEFT`, hide it with `receipt.setVisibility(View.GONE)`. |
+| Custom message type not matched by template | Set both `setType()` and `setCategory()` on the new template to match the custom message's type and category (e.g., `"card"` and `UIKitConstants.MessageCategory.CUSTOM`). |
-
+## FAQ
-
+**Q: Do I need to call `setTemplates()` every time I modify a template?**
+
+A: Yes. After modifying any template in the templates list, call `messageList.setTemplates(messageTemplates)` to apply the changes to the `MessageList`. Without this call, the `MessageList` continues using the original templates.
+
+**Q: What is the difference between `setBubbleView()` and `setContentView()`?**
+
+A: `setContentView()` replaces only the content area of the message bubble while keeping the default header and footer views. `setBubbleView()` replaces the entire bubble — header, content, and footer — with a single custom layout. Use `setBubbleView()` when you need full control over the bubble appearance.
+
+**Q: How do I create a template for a custom message type?**
+
+A: Create a new `CometChatMessageTemplate` instance, call `setType()` with your custom type string (e.g., `"card"`), call `setCategory()` with `UIKitConstants.MessageCategory.CUSTOM`, define the bubble view using `setBubbleView()`, add the template to the templates list, and call `messageList.setTemplates()`.
+
+**Q: Can I customize templates for built-in message types like text or image?**
+
+A: Yes. Fetch the existing templates using `CometChatUIKit.getDataSource().getAllMessageTemplates()`, iterate through them to find the template matching the desired `UIKitConstants.MessageType` (e.g., `TEXT` or `IMAGE`), apply your customizations, and call `messageList.setTemplates()`.
+
+**Q: What happens if `createView()` returns a view but `bindView()` does not set any data?**
+
+A: The custom layout inflated in `createView()` is displayed with its default XML values (e.g., placeholder text, default visibility). Dynamic data such as the message text, sender name, or timestamp will not appear unless you set them in `bindView()`.
-In this code, replace "customType" with the same type as your custom message, and define your custom view in the setContentView() method.
+## Next steps
-This way, your custom message will be rendered in the MessageList using the custom view defined in your new MessageTemplate.
+- [Message List component](/ui-kit/android/message-list) — Learn how to configure and customize the `MessageList` where templates are applied
+- [Message Bubble styling](/ui-kit/android/message-bubble-styling) — Explore styling options for the default message bubble views (Text Bubble, Image Bubble, File Bubble, Audio Bubble, Video Bubble)
diff --git a/ui-kit/android/methods.mdx b/ui-kit/android/methods.mdx
index 3cbfd0f59..5cb9d2c5b 100644
--- a/ui-kit/android/methods.mdx
+++ b/ui-kit/android/methods.mdx
@@ -2,48 +2,54 @@
title: "Methods"
---
-## Overview
+`CometChatUIKit` provides wrapper methods around the CometChat SDK for initialization, authentication, user creation, date formatting, and sending messages — while automatically managing internal UI Kit events so that components like Message List and Conversations stay in sync.
-The UI Kit's core function is to extend the [Chat SDK](/sdk/android/overview), essentially translating the raw data and functionality provided by the underlying methods into visually appealing and easy-to-use UI components.
+## When to use this
-To effectively manage and synchronize the UI elements and data across all components in the UI Kit, we utilize internal events. These internal events enable us to keep track of changes in real-time and ensure that the UI reflects the most current state of data.
+- You need to initialize the CometChat UI Kit and SDK before rendering any UI components.
+- You need to log a user in or out of CometChat using an Auth Key (development) or Auth Token (production).
+- You need to create a new CometChat user dynamically from your app.
+- You need to send text, media, custom, or interactive messages through the UI Kit so that the Message List and Conversations components update automatically.
+- You need to customize how dates and times are displayed across all UI Kit components.
-The CometChat UI Kit has thoughtfully encapsulated the critical [Chat SDK](/sdk/android/overview) methods within its wrapper to efficiently manage internal eventing. This layer of abstraction simplifies interaction with the underlying CometChat SDK, making it more user-friendly for developers.
+## Prerequisites
-## Methods
+- The `cometchat-chat-uikit-android` dependency added to your project.
+- Your CometChat App ID, Region, and Auth Key (or Auth Token) from the [CometChat dashboard](https://app.cometchat.com/).
+- `CometChatUIKit.init()` called before invoking any other UI Kit method.
-You can access the methods using the `CometChatUIKit` class. This class provides access to all the public methods exposed by the CometChat UI Kit.
+## API reference
-### Init
+### Initialization
-As a developer, you need to invoke this method every time before you use any other methods provided by the UI Kit.
+#### Init
-This initialization is a critical step that ensures the UI Kit and Chat SDK function correctly and as intended in your application. Typical practice is to make this one of the first lines of code executed in your application's lifecycle when it comes to implementing CometChat.
+You must invoke this method before using any other methods provided by the UI Kit. This initialization ensures the UI Kit and Chat SDK function correctly in your application. Call this as one of the first lines of code in your application's lifecycle.
-Make sure you replace the **APP\_ID**, **REGION** and **AUTH\_KEY** with your CometChat App ID, Region and Auth Key in the below code. The `Auth Key` is an optional property of the `UIKitSettings` Class. It is intended for use primarily during proof-of-concept (POC) development or in the early stages of application development. You can use the [Auth Token](#login-using-auth-token) to log in securely.
+Make sure you replace the `APP_ID`, `REGION` and `AUTH_KEY` with your CometChat App ID, Region and Auth Key in the below code. The `Auth Key` is an optional property of the `UIKitSettings` Class. It is intended for use primarily during proof-of-concept (POC) development or in the early stages of application development. You can use the [Auth Token](#login-using-auth-token) to log in securely.
-
-
-```java
-CometChatUIKit.init(Context context, UIKitSettings authSettings, CometChat.CallbackListener callbackListener)
-```
-
-
+**Signature:**
+
```kotlin
CometChatUIKit.init(context: Context, authSettings: UIKitSettings, callbackListener: CometChat.CallbackListener)
```
-
-
+
+```java
+CometChatUIKit.init(Context context, UIKitSettings authSettings, CometChat.CallbackListener callbackListener)
+```
+
-As a developer, the `UIKitSettings` is an important parameter of the `init()` function. It functions as a base settings object, housing properties such as `appId`, `region`, and `authKey`, contained within `UIKitSettings`.
+> **What this does:** Declares the `init()` method signature. It accepts a `Context`, a `UIKitSettings` configuration object, and a `CallbackListener` that reports success or failure.
+
+The `UIKitSettings` is an important parameter of the `init()` function. It serves as the base settings object, housing properties such as `appId`, `region`, and `authKey`.
Here's the table format for the properties available in `UIKitSettings`:
@@ -60,13 +66,31 @@ Here's the table format for the properties available in `UIKitSettings`:
| **setExtensions** | `List` | Sets the list of extension that need to be added in UI Kit |
| **dateTimeFormatterCallback** | `DateTimeFormatterCallback` | Interface containing callback methods to format different types of timestamps. |
-***
-
-The concluding code block:
+**Usage:**
+
+```kotlin lines
+val uiKitSettings: UIKitSettings = UIKitSettingsBuilder()
+ .setRegion(your_region)
+ .setAppId(your_appID)
+ .setAuthKey(your_authKey)
+ .subscribePresenceForAllUsers()
+ .build()
+
+CometChatUIKit.init(context, uiKitSettings, object : CometChat.CallbackListener() {
+ override fun onSuccess(response: String) {
+ Log.i(TAG, "CometChat init onSuccess: $response")
+ }
+
+ override fun onError(e: CometChatException) {
+ Log.e(TAG, "CometChat init exception: $e")
+ }
+})
+```
+
-```java
+```java lines
UIKitSettings uiKitSettings = new UIKitSettings.UIKitSettingsBuilder()
.setRegion(your_region)
.setAppId(your_appID)
@@ -78,6 +102,7 @@ CometChatUIKit.init(context, uiKitSettings, new CometChat.CallbackListener
+
-
-```kotlin
-val uiKitSettings: UIKitSettings = UIKitSettingsBuilder()
- .setRegion(your_region)
- .setAppId(your_appID)
- .setAuthKey(your_authKey)
- .subscribePresenceForAllUsers()
- .build()
-
-CometChatUIKit.init(context, uiKitSettings, object : CometChat.CallbackListener() {
- override fun onSuccess(response: String) {
- Log.i(TAG, "CometChat init onSuccess: $response")
- }
-
- override fun onError(e: CometChatException) {
- Log.e(TAG, "CometChat init exception: $e")
- }
-})
-```
+> **What this does:** Creates a `UIKitSettings` object with your app ID, region, and auth key, then initializes the CometChat UI Kit. On success, the SDK and UI Kit are ready for use. On error, the `CometChatException` provides failure details.
-
+---
-
+### Authentication
-***
+#### Login using Auth Key
-### Login using Auth Key
+Only the `UID` of a user is needed to log in. This simple authentication procedure is useful when you are creating a POC or if you are in the development phase. For production apps, use [Auth Token](#login-using-auth-token) instead of Auth Key.
-Only the `UID` of a user is needed to log in. This simple authentication procedure is useful when you are creating a POC or if you are in the development phase. For production apps, we suggest you use [AuthToken](#login-using-auth-token) instead of Auth Key.
+**Signature:**
-
-```java
-CometChatUIKit.login(String uid, CometChat.CallbackListener callbackListener)
-```
-
-
-
```kotlin
CometChatUIKit.login(uid: String, callbackListener: CometChat.CallbackListener)
```
-
-
+
+```java
+CometChatUIKit.login(String uid, CometChat.CallbackListener callbackListener)
+```
+
-The concluding code block:
+> **What this does:** Declares the `login()` method signature. It accepts a user ID string and a `CallbackListener` that returns the logged-in `User` object on success.
+
+**Usage:**
+
+```kotlin lines
+CometChatUIKit.login(UID, object : CometChat.CallbackListener() {
+ override fun onSuccess(user: User) {
+ Log.i(TAG, "CometChat Login Successful : $user")
+ }
+
+ override fun onError(e: CometChatException) {
+ Log.e(TAG, "CometChat Login Failed : ${e.message}")
+ }
+})
+```
+
-```java
+```java lines
CometChatUIKit.login(UID, new CometChat.CallbackListener() {
@Override
public void onSuccess(User user) {
@@ -151,27 +169,14 @@ CometChatUIKit.login(UID, new CometChat.CallbackListener() {
}
});
```
-
+
-
-```kotlin
-CometChatUIKit.login(UID, object : CometChat.CallbackListener() {
- override fun onSuccess(user: User) {
- Log.i(TAG, "CometChat Login Successful : $user")
- }
-
- override fun onError(e: CometChatException) {
- Log.e(TAG, "CometChat Login Failed : ${e.message}")
- }
-})
-```
-
-
+> **What this does:** Logs in a user by their `UID` using the Auth Key configured during initialization. On success, the `User` object is returned. On error, the `CometChatException` provides failure details.
-
+---
-### Login using Auth Token
+#### Login using Auth Token
This advanced authentication procedure does not use the Auth Key directly in your client code thus ensuring safety.
@@ -181,102 +186,85 @@ This advanced authentication procedure does not use the Auth Key directly in you
3. Load the Auth Token in your client and pass it to the `loginWithAuthToken()` method.
-
-
- ```java
- CometChatUIKit.loginWithAuthToken(String authToken, CometChat.CallbackListener callbackListener)
- ```
-
-
-
-
- ```kotlin
- CometChatUIKit.loginWithAuthToken(authToken: String, callbackListener: CometChat.CallbackListener)
- ```
-
-
-
-
+**Signature:**
- The concluding code block:
-
-
-
- ```java
- CometChatUIKit.loginWithAuthToken(AuthToken, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(User user) {
- Log.i(TAG, "CometChat Login Successful : " + user.toString());
- }
- @Override
- public void onError(CometChatException e) {
- Log.e(TAG, "CometChat Login Failed : " + e.getMessage());
- }
- });
- ```
+
+
+```kotlin
+CometChatUIKit.loginWithAuthToken(authToken: String, callbackListener: CometChat.CallbackListener)
+```
+
+
+```java
+CometChatUIKit.loginWithAuthToken(String authToken, CometChat.CallbackListener callbackListener)
+```
+
+
-
+> **What this does:** Declares the `loginWithAuthToken()` method signature. It accepts a server-generated auth token string and a `CallbackListener` that returns the logged-in `User` object on success.
-
- ```kotlin
- CometChatUIKit.loginWithAuthToken(AuthToken, object : CometChat.CallbackListener() {
- override fun onSuccess(user: User) {
- Log.i(TAG, "CometChat Login Successful : $user")
- }
+**Usage:**
- override fun onError(e: CometChatException) {
- Log.e(TAG, "CometChat Login Failed : ${e.message}")
- }
- })
- ```
+
+
+```kotlin
+CometChatUIKit.loginWithAuthToken(AuthToken, object : CometChat.CallbackListener() {
+ override fun onSuccess(user: User) {
+ Log.i(TAG, "CometChat Login Successful : $user")
+ }
-
+ override fun onError(e: CometChatException) {
+ Log.e(TAG, "CometChat Login Failed : ${e.message}")
+ }
+})
+```
+
+
+```java
+CometChatUIKit.loginWithAuthToken(AuthToken, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(User user) {
+ Log.i(TAG, "CometChat Login Successful : " + user.toString());
+ }
+ @Override
+ public void onError(CometChatException e) {
+ Log.e(TAG, "CometChat Login Failed : " + e.getMessage());
+ }
+});
+```
+
+
-
+> **What this does:** Logs in a user using a server-generated Auth Token instead of an Auth Key. This is the recommended approach for production apps because the Auth Key never appears in client code. On success, the `User` object is returned.
-***
+---
### Logout
-The CometChat UI Kit and Chat SDK effectively handle the session of the logged-in user within the framework. Before a new user logs in, it is crucial to clean this data to avoid potential conflicts or unexpected behavior. This can be achieved by invoking the `.logout()` function
-
-
-
-```java
- CometChatUIKit.logout(CometChat.CallbackListener callbackListener)
-```
+The CometChat UI Kit and Chat SDK effectively handle the session of the logged-in user within the framework. Before a new user logs in, it is crucial to clean this data to avoid potential conflicts or unexpected behavior. This can be achieved by invoking the `logout()` function.
-
+**Signature:**
+
```kotlin
- CometChatUIKit.logout(callbackListener: CometChat.CallbackListener)
+CometChatUIKit.logout(callbackListener: CometChat.CallbackListener)
```
-
-
-
-
-The concluding code block:
-
-
```java
-CometChatUIKit.logout(new CometChat.CallbackListener() {
- @Override
- public void onSuccess(String s) {
- // your action on logout
- }
- @Override
- public void onError(CometChatException e) {
- }
-});
+CometChatUIKit.logout(CometChat.CallbackListener callbackListener)
```
-
+
+
+> **What this does:** Declares the `logout()` method signature. It accepts a `CallbackListener` that reports success or failure of the logout operation.
+
+**Usage:**
+
-```kotlin
+```kotlin lines
CometChatUIKit.logout(object: CometChat.CallbackListener() {
override fun onSuccess(s: String) {
// your action on logout
@@ -287,56 +275,52 @@ CometChatUIKit.logout(object: CometChat.CallbackListener() {
}
})
```
-
-
+
+```java lines
+CometChatUIKit.logout(new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(String s) {
+ // your action on logout
+ }
+ @Override
+ public void onError(CometChatException e) {
+ }
+});
+```
+
-***
+> **What this does:** Logs out the current user, clears the session data, and tears down the internal event system. Call this before logging in a different user to avoid conflicts.
-### Create User
+---
-As a developer, you can dynamically create users on CometChat using the `.createUser()` function. This can be extremely useful for situations where users are registered or authenticated by your system and then need to be created on CometChat.
+### Create User
-
-
-```java
-CometChatUIKit.createUser(User user, CometChat.CallbackListener callbackListener);
-```
+You can dynamically create users on CometChat using the `createUser()` function. This is useful when users are registered or authenticated by your system and then need to be created on CometChat.
-
+**Signature:**
+
```kotlin
CometChatUIKit.createUser(user: User, callbackListener: CometChat.CallbackListener)
```
-
-
-
-
-The concluding code block:
-
-
```java
-User user = new User("user_uid","user_name");
-user.setAvatar("user_avatar_url");
-
-CometChatUIKit.createUser(user, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(User user) {
- }
- @Override
- public void onError(CometChatException e) {
- }
-});
+CometChatUIKit.createUser(User user, CometChat.CallbackListener callbackListener);
```
-
+
+
+> **What this does:** Declares the `createUser()` method signature. It accepts a `User` object (with UID, name, and optional avatar) and a `CallbackListener` that returns the created `User` on success.
+
+**Usage:**
+
-```kotlin
+```kotlin lines
val user = User("user_uid", "user_name")
user.setAvatar("user_avatar_url")
@@ -350,16 +334,31 @@ CometChatUIKit.createUser(user, object : CometChat.CallbackListener() {
}
})
```
-
+
+```java lines
+User user = new User("user_uid","user_name");
+user.setAvatar("user_avatar_url");
+CometChatUIKit.createUser(user, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(User user) {
+ }
+ @Override
+ public void onError(CometChatException e) {
+ }
+});
+```
+
-***
+> **What this does:** Creates a new user on CometChat with the specified UID, name, and avatar URL. On success, the created `User` object is returned. On error, the `CometChatException` provides failure details.
+
+---
### DateFormatter
-By providing a custom implementation of the DateTimeFormatterCallback, you can globally configure how time and date values are displayed across all UI components in the CometChat UI Kit. This ensures consistent formatting for labels such as "Today", "Yesterday", "X minutes ago", and more, throughout the entire application.
+By providing a custom implementation of the `DateTimeFormatterCallback`, you can globally configure how time and date values are displayed across all UI components in the CometChat UI Kit. This ensures consistent formatting for labels such as "Today", "Yesterday", "X minutes ago", and more, throughout the entire application.
Each method in the interface corresponds to a specific case:
@@ -367,7 +366,7 @@ Each method in the interface corresponds to a specific case:
`today(long timestamp)` → Called when a message is from today
-`yesterday(long timestamp)` → Called for yesterday’s messages
+`yesterday(long timestamp)` → Called for yesterday's messages
`lastWeek(long timestamp)` → Messages from the past week
@@ -379,12 +378,70 @@ Each method in the interface corresponds to a specific case:
`hours(long diffInHourFromNow, long timestamp)` → e.g., "2 hours ago"
-
-
-```java
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
+**Usage:**
+
+
+
+```kotlin lines
+import java.text.SimpleDateFormat
+import java.util.*
+
+val uiKitSettings = UIKitSettings.UIKitSettingsBuilder()
+ .setAppId(appId)
+ .setRegion(region)
+ .setDateTimeFormatterCallback(object : DateTimeFormatterCallback {
+
+ private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
+ private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
+
+ override fun time(timestamp: Long): String {
+ return fullTimeFormatter.format(Date(timestamp))
+ }
+
+ override fun today(timestamp: Long): String {
+ return "Today"
+ }
+
+ override fun yesterday(timestamp: Long): String {
+ return "Yesterday"
+ }
+
+ override fun lastWeek(timestamp: Long): String {
+ return "Last Week"
+ }
+
+ override fun otherDays(timestamp: Long): String {
+ return dateFormatter.format(Date(timestamp))
+ }
+
+ override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String {
+ return "$diffInMinutesFromNow mins ago"
+ }
+
+ override fun hours(diffInHourFromNow: Long, timestamp: Long): String {
+ return "$diffInHourFromNow hrs ago"
+ }
+ })
+ .setAuthKey(authKey)
+ .subscribePresenceForAllUsers()
+ .build()
+
+CometChatUIKit.init(context, uiKitSettings, object : CometChat.CallbackListener() {
+ override fun onSuccess(s: String?) {
+ Log.d("CometChatInit", "Success: $s")
+ }
+
+ override fun onError(e: CometChatException?) {
+ Log.e("CometChatInit", "Error: ${e?.message}")
+ }
+})
+```
+
+
+```java lines
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
UIKitSettings uiKitSettings = new UIKitSettings.UIKitSettingsBuilder()
.setAppId(appId)
@@ -445,116 +502,43 @@ CometChatUIKit.init(context, uiKitSettings, new CometChat.CallbackListener
-
-
-```kotlin
-import java.text.SimpleDateFormat
-import java.util.*
-
-val uiKitSettings = UIKitSettings.UIKitSettingsBuilder()
- .setAppId(appId)
- .setRegion(region)
- .setDateTimeFormatterCallback(object : DateTimeFormatterCallback {
-
- private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
- private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
-
- override fun time(timestamp: Long): String {
- return fullTimeFormatter.format(Date(timestamp))
- }
-
- override fun today(timestamp: Long): String {
- return "Today"
- }
-
- override fun yesterday(timestamp: Long): String {
- return "Yesterday"
- }
-
- override fun lastWeek(timestamp: Long): String {
- return "Last Week"
- }
-
- override fun otherDays(timestamp: Long): String {
- return dateFormatter.format(Date(timestamp))
- }
-
- override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String {
- return "$diffInMinutesFromNow mins ago"
- }
-
- override fun hours(diffInHourFromNow: Long, timestamp: Long): String {
- return "$diffInHourFromNow hrs ago"
- }
- })
- .setAuthKey(authKey)
- .subscribePresenceForAllUsers()
- .build()
-
-CometChatUIKit.init(context, uiKitSettings, object : CometChat.CallbackListener() {
- override fun onSuccess(s: String?) {
- Log.d("CometChatInit", "Success: $s")
- }
-
- override fun onError(e: CometChatException?) {
- Log.e("CometChatInit", "Error: ${e?.message}")
- }
-})
-```
-
-
-
-***
+> **What this does:** Configures a custom `DateTimeFormatterCallback` on `UIKitSettings` and passes it to `CometChatUIKit.init()`. This globally overrides how timestamps appear across all UI Kit components — today's messages show "Today", yesterday's show "Yesterday", recent messages show "X mins ago" or "X hrs ago", last week's show "Last Week", and older messages show the full date in "dd MMM yyyy" format.
+
+---
### Base Message
#### Text Message
-As a developer, if you need to send a text message to a single user or a group, you'll need to utilize the `sendMessage()` function. This function requires a `TextMessage` object as its argument, which contains the necessary information for delivering the message.
+To send a text message to a single user or a group, use the `sendTextMessage()` function. This function requires a `TextMessage` object as its argument, which contains the necessary information for delivering the message.
-
-
-```java
-CometChatUIKit.sendTextMessage(TextMessage textMessage, CometChat.CallbackListener messageCallbackListener)
-```
+> It's essential to understand the difference between `CometChatUIKit.sendTextMessage()` and `CometChat.sendTextMessage()`. When you use `CometChatUIKit.sendTextMessage()`, it automatically adds the message to the [MessagesListComponent](/ui-kit/android/message-list) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendTextMessage()` only sends the message and doesn't automatically update these components in the UI Kit.
-
+**Signature:**
+
```kotlin
CometChatUIKit.sendTextMessage(textMessage: TextMessage, messageCallbackListener: CometChat.CallbackListener)
```
-
-
-
-
-> It's essential to understand the difference between `CometChatUIKit.sendTextMessage()` and `CometChat.sendTextMessage()`. When you use `CometChatUIKit.sendTextMessage()`, it automatically adds the message to the [MessagesListComponent](/ui-kit/android/message-list) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendTextMessage()` only sends the message and doesn't automatically update these components in the UI Kit.
-
-The concluding code block:
-
-
```java
-TextMessage textMessage = new TextMessage("receiver_uid", "your_text_message", CometChatConstants.RECEIVER_TYPE_USER);
-CometChatUIKit.sendTextMessage(textMessage, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(TextMessage message) {
- }
- @Override
- public void onError(CometChatException e) {
- }
-});
+CometChatUIKit.sendTextMessage(TextMessage textMessage, CometChat.CallbackListener messageCallbackListener)
```
-
+
+
+> **What this does:** Declares the `sendTextMessage()` method signature. It accepts a `TextMessage` object and a `CallbackListener` that returns the sent `TextMessage` on success.
+**Usage:**
+
+
-```kotlin
+```kotlin lines
val textMessage = TextMessage("receiver_uid", "your_text_message", CometChatConstants.RECEIVER_TYPE_USER)
CometChatUIKit.sendTextMessage(textMessage, object : CometChat.CallbackListener() {
override fun onSuccess(message: TextMessage) {
@@ -566,57 +550,54 @@ CometChatUIKit.sendTextMessage(textMessage, object : CometChat.CallbackListener<
}
})
```
-
-
+
+```java lines
+TextMessage textMessage = new TextMessage("receiver_uid", "your_text_message", CometChatConstants.RECEIVER_TYPE_USER);
+CometChatUIKit.sendTextMessage(textMessage, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(TextMessage message) {
+ }
+ @Override
+ public void onError(CometChatException e) {
+ }
+});
+```
+
-***
+> **What this does:** Creates a `TextMessage` targeting a user with the receiver type `RECEIVER_TYPE_USER`, then sends it through the UI Kit. The message automatically appears in the Message List and Conversations components.
+
+---
#### Media Message
-As a developer, if you need to send a media message to a single user or a group, you'll need to utilize the `sendMediaMessage()` function. This function requires a `MediaMessage` object as its argument, which contains the necessary information for delivering the message.
+To send a media message to a single user or a group, use the `sendMediaMessage()` function. This function requires a `MediaMessage` object as its argument, which contains the necessary information for delivering the message.
-
-
-```java
-CometChatUIKit.sendMediaMessage(MediaMessage mediaMessage, CometChat.CallbackListener messageCallbackListener)
-```
+> It's essential to understand the difference between `CometChatUIKit.sendMediaMessage()` and `CometChat.sendMediaMessage()`. When you use `CometChatUIKit.sendMediaMessage()`, it automatically adds the message to the [MessagesListComponent](/ui-kit/android/message-list) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendMediaMessage()` only sends the message and doesn't automatically update these components in the UI Kit.
-
+**Signature:**
+
```kotlin
CometChatUIKit.sendMediaMessage(mediaMessage: MediaMessage, messageCallbackListener: CometChat.CallbackListener)
```
-
-
-
-
-> It's essential to understand the difference between `CometChatUIKit.sendMediaMessage()` and `CometChat.sendMediaMessage()`. When you use `CometChatUIKit.sendMediaMessage()`, it automatically adds the message to the [MessagesListComponent](/ui-kit/android/message-list) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendMediaMessage()` only sends the message and doesn't automatically update these components in the UI Kit.
-
-The concluding code block:
-
-
```java
-MediaMessage mediaMessage = new MediaMessage("receiver_uid", new File("your_filePath"), CometChatConstants.MESSAGE_TYPE_FILE, CometChatConstants.RECEIVER_TYPE_USER);
-
-CometChatUIKit.sendMediaMessage(mediaMessage, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(MediaMessage mediaMessage) {
- }
- @Override
- public void onError(CometChatException e) {
- }
-});
+CometChatUIKit.sendMediaMessage(MediaMessage mediaMessage, CometChat.CallbackListener messageCallbackListener)
```
-
+
+> **What this does:** Declares the `sendMediaMessage()` method signature. It accepts a `MediaMessage` object and a `CallbackListener` that returns the sent `MediaMessage` on success.
+
+**Usage:**
+
+
-```kotlin
+```kotlin lines
val mediaMessage = MediaMessage("receiver_uid", File("your_filePath"), CometChatConstants.MESSAGE_TYPE_FILE, CometChatConstants.RECEIVER_TYPE_USER)
CometChatUIKit.sendMediaMessage(mediaMessage, object : CometChat.CallbackListener() {
@@ -629,65 +610,55 @@ CometChatUIKit.sendMediaMessage(mediaMessage, object : CometChat.CallbackListene
}
})
```
-
+
+```java lines
+MediaMessage mediaMessage = new MediaMessage("receiver_uid", new File("your_filePath"), CometChatConstants.MESSAGE_TYPE_FILE, CometChatConstants.RECEIVER_TYPE_USER);
+CometChatUIKit.sendMediaMessage(mediaMessage, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(MediaMessage mediaMessage) {
+ }
+ @Override
+ public void onError(CometChatException e) {
+ }
+});
+```
+
-***
+> **What this does:** Creates a `MediaMessage` with a file path and message type `MESSAGE_TYPE_FILE`, then sends it through the UI Kit. The message automatically appears in the Message List and Conversations components.
+
+---
#### Custom Message
-As a developer, if you need to send a media message to a single user or a group, you'll need to utilize the `sendCustomMessage()` function. This function requires a `CustomMessage` object as its argument, which contains the necessary information for delivering the message.
+To send a custom message to a single user or a group, use the `sendCustomMessage()` function. This function requires a `CustomMessage` object as its argument, which contains the necessary information for delivering the message.
-
-
-```java
-CometChatUIKit.sendCustomMessage(CustomMessage customMessage, CometChat.CallbackListener messageCallbackListener)
-```
+> It's essential to understand the difference between `CometChatUIKit.sendCustomMessage()` and `CometChat.sendCustomMessage()`. When you use `CometChatUIKit.sendCustomMessage()`, it automatically adds the message to the [MessagesList](/ui-kit/android/message-list) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendCustomMessage()` only sends the message and doesn't automatically update these components in the UI Kit.
-
+**Signature:**
+
```kotlin
CometChatUIKit.sendCustomMessage(customMessage: CustomMessage, messageCallbackListener: CometChat.CallbackListener)
```
-
-
-
-
-> It's essential to understand the difference between `CometChatUIKit.sendCustomMessage()` and `CometChat.sendCustomMessage()`. When you use `CometChatUIKit.sendCustomMessage()`, it automatically adds the message to the [MessagesList](/ui-kit/android/message-list) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendCustomMessage()` only sends the message and doesn't automatically update these components in the UI Kit.
-
-The concluding code block:
-
-
```java
-String customType = "your_message_type";
-JSONObject customData = new JSONObject();
-
-customData.put("key1","value1");
-customData.put("key2","value2");
-customData.put("key3","value3");
-customData.put("key4","value4");
-
-CustomMessage customMessage = new CustomMessage("receiver_uid", CometChatConstantsRECEIVER_TYPE_USER,customType, customData);
-
-CometChatUIKit.sendCustomMessage(customMessage, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(CustomMessage mediaMessage) {
- }
- @Override
- public void onError(CometChatException e) {
- }
-});
+CometChatUIKit.sendCustomMessage(CustomMessage customMessage, CometChat.CallbackListener messageCallbackListener)
```
-
+
+> **What this does:** Declares the `sendCustomMessage()` method signature. It accepts a `CustomMessage` object and a `CallbackListener` that returns the sent `CustomMessage` on success.
+
+**Usage:**
+
+
-```kotlin
+```kotlin lines
val customType = "your_message_type"
val customData = JSONObject()
@@ -708,43 +679,104 @@ CometChatUIKit.sendCustomMessage(customMessage, object : CometChat.CallbackListe
}
})
```
-
+
+```java lines
+String customType = "your_message_type";
+JSONObject customData = new JSONObject();
+customData.put("key1","value1");
+customData.put("key2","value2");
+customData.put("key3","value3");
+customData.put("key4","value4");
+
+CustomMessage customMessage = new CustomMessage("receiver_uid", CometChatConstants.RECEIVER_TYPE_USER,customType, customData);
+
+CometChatUIKit.sendCustomMessage(customMessage, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(CustomMessage mediaMessage) {
+ }
+ @Override
+ public void onError(CometChatException e) {
+ }
+});
+```
+
+> **What this does:** Creates a `CustomMessage` with a custom type string and JSON data payload, then sends it through the UI Kit. The message automatically appears in the Message List and Conversations components.
+
> Note: To display custom messages in the [MessageList](/ui-kit/android/message-list), you must create and register a new [MessageTemplate](/ui-kit/android/message-template) that defines how to render your custom message type.
-***
+---
### Interactive Message
#### Form Message
-As a developer, if you need to send a Form message to a single user or a group, you'll need to utilize the `sendFormMessage()` function. This function requires a `FormMessage` object as its argument, which contains the necessary information to create a form bubble for that messages
+To send a Form message to a single user or a group, utilize the `sendFormMessage()` function. This function requires a `FormMessage` object as its argument, which contains the necessary information to create a form bubble for that message.
+
+**Signature:**
+
+```kotlin
+CometChatUIKit.sendFormMessage(formmessage: FormMessage, disableLocalEvents: Boolean, messageCallbackListener: CometChat.CallbackListener)
+```
+
```java
-CometChatUIKit.sendFormMessage(FormMessage formmessage, CometChat.CallbackListener messageCallbackListener)
+CometChatUIKit.sendFormMessage(FormMessage formmessage, boolean disableLocalEvents, CometChat.CallbackListener messageCallbackListener)
```
-
+
+> **What this does:** Declares the `sendFormMessage()` method signature. It accepts a `FormMessage` object and a `CallbackListener` that returns the sent `FormMessage` on success.
+
+**Usage:**
+
+
-```kotlin
-CometChatUIKit.sendFormMessage(formmessage: FormMessage, messageCallbackListener: CometChat.CallbackListener)
-```
+```kotlin lines
+val cometChatMessages = findViewById(R.id.messages)
+cometChatMessages.setUser(user)
-
+val elementEntities = mutableListOf()
+val textInputElement1 = TextInputElement("element1", "Name")
+val textInputElement2 = TextInputElement("element2", "Last Name")
+val textInputElement3 = TextInputElement("element3", "Address").apply {
+ maxLines = 5
+}
+elementEntities.add(textInputElement1)
+elementEntities.add(textInputElement2)
+elementEntities.add(textInputElement3)
-
+val urlNavigationAction = URLNavigationAction("https://www.cometchat.com/")
-The concluding code block:
+val submitElement = ButtonElement("idSubmit", "submit", urlNavigationAction).apply {
+ disableAfterInteracted = true
+}
+val formMessage = FormMessage("uid-1001", UIKitConstants.ReceiverType.USER, elementEntities, submitElement).apply {
+ title = "Socity Survey"
+ allowSenderInteraction = true
+ sender = CometChatUIKit.loggedInUser
+ sentAt = System.currentTimeMillis() / 1000
+ receiver = user
+}
-
+CometChatUIKit.sendFormMessage(formMessage, false, object : CometChat.CallbackListener() {
+ override fun onSuccess(formMessage: FormMessage) {
+ // Handle success
+ }
+
+ override fun onError(e: CometChatException) {
+ e.printStackTrace()
+ }
+})
+```
+
-```java
+```java lines
CometChatMessages cometChatMessages = findViewById(R.id.messages);
cometChatMessages.setUser(user);
@@ -783,39 +815,58 @@ CometChatMessages cometChatMessages = findViewById(R.id.messages);
}
});
```
+
+
+
+> **What this does:** Creates a `FormMessage` with three text input fields (Name, Last Name, Address) and a submit button that navigates to a URL. The form is sent to user `uid-1001` and allows the sender to interact with it. The message appears as an interactive form bubble in the Message List.
+
+---
+
+#### Card Message
+
+To send a Card message to a single user or a group, utilize the `sendCardMessage()` function. This function requires a `CardMessage` object as its argument, which contains the necessary information to create a card bubble for the message.
+
+**Signature:**
+
+
+
+```kotlin
+CometChatUIKit.sendCardMessage(cardMessage: CardMessage, disableLocalEvents: Boolean, messageCallbackListener: CometChat.CallbackListener)
+```
+
+
+```java
+CometChatUIKit.sendCardMessage(CardMessage cardMessage, boolean disableLocalEvents, CometChat.CallbackListener messageCallbackListener)
+```
+
+
-
+> **What this does:** Declares the `sendCardMessage()` method signature. It accepts a `CardMessage` object and a `CallbackListener` that returns the sent `CardMessage` on success.
-
-```kotlin
-val cometChatMessages = findViewById(R.id.messages)
-cometChatMessages.setUser(user)
+**Usage:**
-val elementEntities = mutableListOf()
-val textInputElement1 = TextInputElement("element1", "Name")
-val textInputElement2 = TextInputElement("element2", "Last Name")
-val textInputElement3 = TextInputElement("element3", "Address").apply {
- maxLines = 5
-}
-elementEntities.add(textInputElement1)
-elementEntities.add(textInputElement2)
-elementEntities.add(textInputElement3)
+
+
+```kotlin lines
+val elementEntities = mutableListOf()
val urlNavigationAction = URLNavigationAction("https://www.cometchat.com/")
-val submitElement = ButtonElement("idSubmit", "submit", urlNavigationAction).apply {
+val buttonElement = ButtonElement("idbtn", "submit", urlNavigationAction).apply {
disableAfterInteracted = true
+ text = "Learn more"
}
-val formMessage = FormMessage("uid-1001", UIKitConstants.ReceiverType.USER, elementEntities, submitElement).apply {
- title = "Socity Survey"
- allowSenderInteraction = true
+elementEntities.add(buttonElement)
+
+val cardMessage = CardMessage(receiverId, receivertype, "Decorative Text to show on Card", elementEntities).apply {
+ imageUrl = "https://anyImageUrl.com"
sender = CometChatUIKit.loggedInUser
sentAt = System.currentTimeMillis() / 1000
receiver = user
}
-CometChatUIKit.sendFormMessage(formMessage, false, object : CometChat.CallbackListener() {
- override fun onSuccess(formMessage: FormMessage) {
+CometChatUIKit.sendCardMessage(cardMessage, false, object : CometChat.CallbackListener() {
+ override fun onSuccess(cardMessage: CardMessage) {
// Handle success
}
@@ -824,39 +875,9 @@ CometChatUIKit.sendFormMessage(formMessage, false, object : CometChat.CallbackLi
}
})
```
-
-
-
-
-
-***
-
-#### Card Message
-
-As a developer, if you need to send a Card message to a single user or a group, you'll need to utilize the `sendCardMessage()` function. This function requires a `CardMessage` object as its argument, which contains the necessary information to create a card bubble for the messages
-
-
-
-```java
-CometChatUIKit.sendCardMessage(CardMessage cardMessage, CometChat.CallbackListener messageCallbackListener)
-```
-
-
-
-
-```kotlin
-CometChatUIKit.sendCardMessage(cardMessage: CardMessage, messageCallbackListener: CometChat.CallbackListener)
-```
-
-
-
-
-The concluding code block:
-
-
-```java
+```java lines
List elementEntities = new ArrayList<>();
URLNavigationAction urlNavigationAction = new URLNavigationAction("https://www.cometchat.com/");
@@ -885,71 +906,79 @@ CometChatUIKit.sendCardMessage(cardMessage, false, new CometChat.CallbackListene
}
});
```
-
+
+
+> **What this does:** Creates a `CardMessage` with decorative text, an image URL, and a "Learn more" button that navigates to a URL. The card is sent to the specified receiver and appears as an interactive card bubble in the Message List.
+
+---
+
+#### Scheduler Message
+To send a Scheduler message to a single user or a group, use the `sendSchedulerMessage()` function. This function requires a `SchedulerMessage` object as its argument, which contains the necessary information to create a SchedulerMessage bubble for the messages.
+
+**Signature:**
+
+
```kotlin
-val elementEntities = mutableListOf()
+CometChatUIKit.sendSchedulerMessage(schedulerMessage: SchedulerMessage, disableLocalEvents: Boolean, messageCallbackListener: CometChat.CallbackListener)
+```
+
+
+```java
+CometChatUIKit.sendSchedulerMessage(SchedulerMessage schedulerMessage, boolean disableLocalEvents, CometChat.CallbackListener messageCallbackListener)
+```
+
+
-val urlNavigationAction = URLNavigationAction("https://www.cometchat.com/")
+> **What this does:** Declares the `sendSchedulerMessage()` method signature. It accepts a `SchedulerMessage` object and a `CallbackListener` that returns the sent `SchedulerMessage` on success.
-val buttonElement = ButtonElement("idbtn", "submit", urlNavigationAction).apply {
- disableAfterInteracted = true
- text = "Learn more"
-}
-elementEntities.add(buttonElement)
+**Usage:**
-val cardMessage = CardMessage(receiverId, receivertype, "Decorative Text to show on Card", elementEntities).apply {
- imageUrl = "https://anyImageUrl.com"
+
+
+```kotlin lines
+val schedulerMessage = SchedulerMessage().apply {
+ duration = 60
+ allowSenderInteraction = true
+ title = "Meet Dr. Jackob"
+ bufferTime = 15
+ avatarUrl = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRdRz0HEBl1wvncmX6rU8wFrRDxt2cvn2Dq9w&usqp=CAU"
+ goalCompletionText = "Meeting Scheduled Successfully!!"
+ timezoneCode = TimeZone.getDefault().id
+ dateRangeStart = "2024-01-01"
+ dateRangeEnd = "2024-12-31"
+ receiverUid = "cometchat-uid-1"
+ availability = hashMapOf(
+ "monday" to listOf(TimeRange("0000", "1359")),
+ "tuesday" to listOf(TimeRange("0000", "1559")),
+ "wednesday" to listOf(TimeRange("0000", "0659")),
+ "thursday" to listOf(TimeRange("0000", "0959")),
+ "friday" to listOf(TimeRange("0000", "1059"))
+ )
+ scheduleElement = ButtonElement("21", "Submit",
+ APIAction("https://www.example.com", "POST", "data")
+ )
+ receiverType = CometChatConstants.RECEIVER_TYPE_USER
sender = CometChatUIKit.loggedInUser
sentAt = System.currentTimeMillis() / 1000
receiver = user
}
-CometChatUIKit.sendCardMessage(cardMessage, false, object : CometChat.CallbackListener() {
- override fun onSuccess(cardMessage: CardMessage) {
- // Handle success
+CometChatUIKit.sendSchedulerMessage(schedulerMessage, false, object : CometChat.CallbackListener() {
+ override fun onSuccess(schedulerMessage: SchedulerMessage) {
+ // SchedulerMessage sent successfully
}
override fun onError(e: CometChatException) {
- e.printStackTrace()
+ // Error occurred while sending SchedulerMessage
}
})
```
-
-
-
-
-
-***
-
-#### Scheduler Message
-
-As a developer, if you need to send a Scheduler message to a single user or a group, you'll need to utilize the `sendCardMessage()` function. This function requires a `SchedulerMessage` object as its argument, which contains the necessary information to create a SchedulerMessage bubble for the messages
-
-
-
-```java
-CometChatUIKit.sendSchedulerMessage(SchedulerMessage schedulerMessage, CometChat.CallbackListener messageCallbackListener)
-```
-
-
-
-
-```kotlin
-CometChatUIKit.sendSchedulerMessage(schedulerMessage: SchedulerMessage, messageCallbackListener: CometChat.CallbackListener)
-```
-
-
-
-
-The concluding code block:
-
-
-```java
+```java lines
SchedulerMessage schedulerMessage = new SchedulerMessage();
schedulerMessage.setDuration(60);
schedulerMessage.setAllowSenderInteraction(true); // true to set the sender as the scheduler
@@ -993,81 +1022,63 @@ SchedulerMessage schedulerMessage = new SchedulerMessage();
}
});
```
-
-
-
-
-```kotlin
-val schedulerMessage = SchedulerMessage().apply {
- duration = 60
- allowSenderInteraction = true
- title = "Meet Dr. Jackob"
- bufferTime = 15
- avatarUrl = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRdRz0HEBl1wvncmX6rU8wFrRDxt2cvn2Dq9w&usqp=CAU"
- goalCompletionText = "Meeting Scheduled Successfully!!"
- timezoneCode = TimeZone.getDefault().id
- dateRangeStart = "2024-01-01"
- dateRangeEnd = "2024-12-31"
- receiverUid = "cometchat-uid-1"
- availability = hashMapOf(
- "monday" to listOf(TimeRange("0000", "1359")),
- "tuesday" to listOf(TimeRange("0000", "1559")),
- "wednesday" to listOf(TimeRange("0000", "0659")),
- "thursday" to listOf(TimeRange("0000", "0959")),
- "friday" to listOf(TimeRange("0000", "1059"))
- )
- scheduleElement = ButtonElement("21", "Submit",
- APIAction("https://www.example.com", "POST", "data")
- )
- receiverType = CometChatConstants.RECEIVER_TYPE_USER
- sender = CometChatUIKit.loggedInUser
- sentAt = System.currentTimeMillis() / 1000
- receiver = user
-}
-
-CometChatUIKit.sendSchedulerMessage(schedulerMessage, false, object : CometChat.CallbackListener() {
- override fun onSuccess(schedulerMessage: SchedulerMessage) {
- // SchedulerMessage sent successfully
- }
-
- override fun onError(e: CometChatException) {
- // Error occurred while sending SchedulerMessage
- }
-})
-```
-
-
-***
+> **What this does:** Creates a `SchedulerMessage` configured with a 60-minute meeting duration, 15-minute buffer, weekly availability slots, and a submit button that posts to an API endpoint. The scheduler bubble lets the receiver pick a time slot and appears in the Message List.
+
+---
#### Custom InteractiveMessage
-As a developer, if you need to send a Custom Interactive message to a single user or a group, you'll need to utilize the `sendCustomInteractiveMessage()` function. This function requires a `CustomInteractiveMessage` object as its argument.
+To send a Custom Interactive message to a single user or a group, use the `sendCustomInteractiveMessage()` function. This function requires a `CustomInteractiveMessage` object as its argument.
+
+**Signature:**
+
+```kotlin
+CometChatUIKit.sendCustomInteractiveMessage(customInteractiveMessage: CustomInteractiveMessage, disableLocalEvents: Boolean, messageCallbackListener: CometChat.CallbackListener)
+```
+
```java
-CometChatUIKit.sendCustomInteractiveMessage(CustomInteractiveMessage customInteractiveMessage, CometChat.CallbackListener messageCallbackListener)
+CometChatUIKit.sendCustomInteractiveMessage(CustomInteractiveMessage customInteractiveMessage, boolean disableLocalEvents, CometChat.CallbackListener messageCallbackListener)
```
-
+
+
+> **What this does:** Declares the `sendCustomInteractiveMessage()` method signature. It accepts a `CustomInteractiveMessage` object and a `CallbackListener` that returns the sent `CustomInteractiveMessage` on success.
+
+**Usage:**
+
-```kotlin
-CometChatUIKit.sendCustomInteractiveMessage(customInteractiveMessage: CustomInteractiveMessage, messageCallbackListener: CometChat.CallbackListener)
-```
+```kotlin lines
+val jsonObject = JSONObject()
+try {
+ jsonObject.put("text", "custom Interactive message")
+} catch (e: JSONException) {
+ throw RuntimeException(e)
+}
-
+val customInteractiveMessage = CustomInteractiveMessage(receiverId, receiverType, jsonObject) // receiverType could be user/group
+customInteractiveMessage.sender = CometChatUIKit.getLoggedInUser()
+customInteractiveMessage.receiver = user // set Receiver user/group object
-
+CometChatUIKit.sendCustomInteractiveMessage(customInteractiveMessage, false, object : CometChat.CallbackListener() {
+ override fun onSuccess(customInteractiveMessage: CustomInteractiveMessage) {
-The concluding code block:
+ }
-
+ override fun onError(e: CometChatException) {
+ e.printStackTrace()
+ }
+})
+```
+
-```java
+```java lines
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("text", "custom Interactive message");
@@ -1090,37 +1101,51 @@ CometChatUIKit.sendCustomInteractiveMessage(customInteractiveMessage, false, new
}
});
```
-
+
-
-```kotlin
-val jsonObject = JSONObject()
-try {
- jsonObject.put("text", "custom Interactive message")
-} catch (e: JSONException) {
- throw RuntimeException(e)
-}
+> **What this does:** Creates a `CustomInteractiveMessage` with a JSON payload and sends it through the UI Kit. The message is delivered to the specified receiver and can be rendered with a custom template.
-val customInteractiveMessage = CustomInteractiveMessage(receiverId, receiverType, jsonObject) // receiverType could be user/group
-customInteractiveMessage.sender = CometChatUIKit.getLoggedInUser()
-customInteractiveMessage.receiver = user // set Receiver user/group object
+> Note: To display custom messages in the [MessageList](/ui-kit/android/message-list), you must create and register a new [MessageTemplate](/ui-kit/android/message-template#new-templates) that defines how to render your custom message types
-CometChatUIKit.sendCustomInteractiveMessage(customInteractiveMessage, false, object : CometChat.CallbackListener() {
- override fun onSuccess(customInteractiveMessage: CustomInteractiveMessage) {
+---
- }
+## Common pitfalls and fixes
- override fun onError(e: CometChatException) {
- e.printStackTrace()
- }
-})
-```
+| Pitfall | Fix |
+| ------- | --- |
+| Calling UI Kit methods before `CometChatUIKit.init()` completes | Call `init()` first and wait for the `onSuccess` callback before calling `login()`, `sendTextMessage()`, or any other UI Kit method. |
+| Using Auth Key in production | Auth Key is for development and POC only. For production apps, use `CometChatUIKit.loginWithAuthToken()` with a server-generated Auth Token so the Auth Key never appears in client code. |
+| Not handling `onError` callbacks | Every UI Kit method accepts a `CallbackListener` with `onError`. If you leave `onError` empty, failures are silently ignored. Log the `CometChatException` or display an error message to the user. |
+| Calling `CometChat.sendTextMessage()` instead of `CometChatUIKit.sendTextMessage()` | If you use the SDK method directly (`CometChat.sendTextMessage()`), the Message List and Conversations components do not update automatically. Use the `CometChatUIKit` wrapper methods to keep UI components in sync. |
+| Not logging out before switching users | If you log in a new user without calling `CometChatUIKit.logout()` first, session data from the previous user may cause conflicts. Call `logout()` and wait for `onSuccess` before logging in a different user. |
+| Sending a custom message without a registered `MessageTemplate` | Custom messages and custom interactive messages do not appear in the Message List unless you create and register a [MessageTemplate](/ui-kit/android/message-template) that defines how to render them. |
+| Missing `receiver` or `sender` on interactive messages | For `FormMessage`, `CardMessage`, `SchedulerMessage`, and `CustomInteractiveMessage`, set both `sender` (via `CometChatUIKit.getLoggedInUser()`) and `receiver` (the target `User` or `Group` object) before sending. |
-
+## FAQ
-
+**What is the difference between `CometChatUIKit.sendTextMessage()` and `CometChat.sendTextMessage()`?**
-> Note: To display custom messages in the [MessageList](/ui-kit/android/message-list), you must create and register a new [MessageTemplate](/ui-kit/android/message-template#new-templates) that defines how to render your custom message types
+`CometChatUIKit.sendTextMessage()` is a wrapper around the SDK method that automatically updates the Message List and Conversations components via internal events. `CometChat.sendTextMessage()` only sends the message over the network and does not trigger UI Kit component updates. The same pattern applies to `sendMediaMessage()`, `sendCustomMessage()`, and all interactive message methods.
+
+**When should I use Auth Key vs Auth Token for login?**
+
+Use `CometChatUIKit.login()` with Auth Key during development and proof-of-concept work. For production apps, use `CometChatUIKit.loginWithAuthToken()` with a server-generated Auth Token. This keeps the Auth Key on your server and out of client code.
+
+**How do I customize date and time formatting across all UI Kit components?**
+
+Implement the `DateTimeFormatterCallback` interface and pass it to `UIKitSettings.UIKitSettingsBuilder` via `setDateTimeFormatterCallback()` before calling `CometChatUIKit.init()`. Each method in the interface (`time`, `today`, `yesterday`, `lastWeek`, `otherDays`, `minute`, `minutes`, `hour`, `hours`) controls a specific timestamp display case. You can also override formatting per component using `setDateTimeFormatter()` on individual components like `CometChatConversations`, `CometChatMessageList`, etc.
+
+**Do I need to call `init()` every time the app launches?**
+
+Yes. Call `CometChatUIKit.init()` once during your application's startup lifecycle (for example, in your `Application` class or main Activity's `onCreate`). The UI Kit and SDK require initialization before any other method call.
+
+**How do I send a message to a group instead of a user?**
+
+Use `CometChatConstants.RECEIVER_TYPE_GROUP` instead of `CometChatConstants.RECEIVER_TYPE_USER` when creating the message object, and pass the group ID as the receiver ID.
+
+## Next steps
-***
+- [Events reference](/ui-kit/android/events) — Learn how to listen for real-time UI Kit events (user, group, conversation, message, call, and UI events).
+- [Message List component](/ui-kit/android/message-list) — Display and customize the message list where sent messages appear.
+- [Conversations component](/ui-kit/android/conversations) — Display and customize the conversations list that updates when messages are sent.
diff --git a/ui-kit/android/outgoing-call.mdx b/ui-kit/android/outgoing-call.mdx
index 00699ff2e..0c571cb24 100644
--- a/ui-kit/android/outgoing-call.mdx
+++ b/ui-kit/android/outgoing-call.mdx
@@ -2,154 +2,171 @@
title: "Outgoing Call"
---
-## Overview
-
-The `CometChatOutgoingCall` [Component](/ui-kit/android/components-overview#components) is a visual representation of a user-initiated call, whether it's a voice or video call. It serves as an interface for managing outgoing calls, providing users with essential options to control the call experience. This component typically includes information about the call recipient, call controls for canceling the call, and feedback on the call status, such as indicating when the call is in progress.
-
-
-
-
-
-***
-
-## Usage
-
-### Integration
-
-`CometChatOutgoingCall` being a custom component, offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application.
-
-Since `CometChatOutgoingCall` can be launched by adding the following code snippet into the XML layout file.
-
-
-
-```xml
-
+`CometChatOutgoingCall` displays a full-screen outgoing call UI with the recipient's avatar, name, call status, and an end-call button. It handles call-accepted and call-rejected transitions automatically.
+
+## AI Agent Component Spec
+
+
+
+```json
+{
+ "component": "CometChatOutgoingCall",
+ "package": "com.cometchat.chatuikit.calls.outgoingcall",
+ "xmlElement": "",
+ "description": "Full-screen outgoing call UI with recipient avatar, name, call status, and end-call button.",
+ "primaryOutput": {
+ "method": "setOnEndCallClick",
+ "type": "OnClick"
+ },
+ "methods": {
+ "data": {
+ "setCall": {
+ "type": "Call",
+ "note": "Sets the call object and extracts the receiver User automatically"
+ },
+ "setUser": {
+ "type": "User",
+ "note": "Sets the user directly (uid, name, avatar required)"
+ }
+ },
+ "callbacks": {
+ "setOnEndCallClick": "OnClick",
+ "setOnError": "OnError"
+ },
+ "functionality": {
+ "disableSoundForCall": { "type": "boolean", "default": "false" },
+ "setCustomSoundForCalls": { "type": "@RawRes int", "default": "SDK default" }
+ },
+ "viewSlots": {
+ "setTitleView": "Function2 — title text area",
+ "setSubtitleView": "Function2 — subtitle text area",
+ "setAvatarView": "Function2 — avatar / profile picture area",
+ "setEndCallView": "Function2 — end-call button area"
+ },
+ "advanced": {
+ "setCallSettingsBuilder": "CometChatCalls.CallSettingsBuilder — ongoing call configuration",
+ "getViewModel": "OutgoingViewModel — internal ViewModel access"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatOutgoingCallStyle"
+ }
+ }
+ },
+ "events": [
+ {
+ "name": "CometChatCallEvents.ccCallAccepted",
+ "payload": "Call",
+ "description": "Outgoing call was accepted by the receiver"
+ },
+ {
+ "name": "CometChatCallEvents.ccCallRejected",
+ "payload": "Call",
+ "description": "Outgoing call was rejected by the receiver"
+ }
+ ]
+}
```
-
+
-
+## Where It Fits
-If you're defining the `CometChatOutgoingCall` within the XML code or in your activity or fragment then you'll need to extract them and set the User object or Call object using the appropriate method.
+`CometChatOutgoingCall` is a call-initiation component. It renders the outgoing call screen and transitions to the ongoing call screen when the receiver accepts. Wire it to `CometChatCallEvents` to handle call-accepted and call-rejected transitions.
-
-```java
-CometChatOutgoingCall cometchatOutgoingCall = binding.outgoingCall; // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(getLayoutInflater());` to use views like `binding.outgoingCall` after enabling view binding.
+
+```kotlin CallActivity.kt lines
+class CallActivity : AppCompatActivity() {
-User user = new User();
-user.setUid(""); //Required
-user.setName(""); //Required
-user.setAvatar(""); //Required
+ private lateinit var outgoingCall: CometChatOutgoingCall
-cometchatOutgoingCall.setUser(user); //Required - set the user object
-//OR
-cometchatOutgoingCall.setCall(call); //Required - set the call object
-```
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_call)
+ outgoingCall = findViewById(R.id.outgoing_call)
+ outgoingCall.setCall(call) // pass the Call object from CometChat SDK
+ }
+}
+```
-
-```kotlin
-val cometchatOutgoingCall: CometChatOutgoingCall = binding.outgoingCall // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(layoutInflater)` to use views like `binding.outgoingCall` after enabling view binding.
+
+```java CallActivity.java lines
+public class CallActivity extends AppCompatActivity {
+ private CometChatOutgoingCall outgoingCall;
-val user = User()
-user.uid = "" //Required
-user.name = "" //Required
-user.avatar = "" //Required
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_call);
-cometchatOutgoingCall.setUser(user) //Required - set the user object
-//OR
-cometchatOutgoingCall.setCall(call) //Required - set the call object
+ outgoingCall = findViewById(R.id.outgoing_call);
+ outgoingCall.setCall(call); // pass the Call object from CometChat SDK
+ }
+}
```
-
-
-##### Activity and Fragment
+## Quick Start
-You can integrate `CometChatOutgoingCall` into your Activity and Fragment by adding the following code snippets into the respective classes.
+Add the component to your layout XML:
-
-
-```java YourActivity.java
-CometChatOutgoingCall cometchatOutgoingCall;
-
-@Override
-protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- cometchatOutgoingCall = new CometChatOutgoingCall(this);
-
- User user = new User();
- user.setUid(""); //Required
- user.setName(""); //Required
- user.setAvatar(""); //Required
+```xml layout_activity.xml lines
+
+```
- cometchatOutgoingCall.setUser(user); //Required - set the user object
- //OR
- cometchatOutgoingCall.setCall(call); //Required - set the call object
+
+
+
- setContentView(cometchatOutgoingCall);
-}
-```
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.
-
+To add programmatically in an Activity:
-
-```kotlin YourActivity.kt
+
+
+```kotlin YourActivity.kt lines
private lateinit var cometchatOutgoingCall: CometChatOutgoingCall
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
cometchatOutgoingCall = CometChatOutgoingCall(this)
-
- val user = User()
- user.uid = "" //Required
- user.name = "" //Required
- user.avatar = "" //Required
-
- cometchatOutgoingCall.setUser(user) //Required - set the user object
- //OR
- cometchatOutgoingCall.setCall(call) //Required - set the call object
-
+ cometchatOutgoingCall.setCall(call) // Required — set the Call object
setContentView(cometchatOutgoingCall)
}
```
-
-
-```java YourFragment.java
+
+```java YourActivity.java lines
CometChatOutgoingCall cometchatOutgoingCall;
@Override
-public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- cometchatOutgoingCall = new CometChatOutgoingCall(requireContext());
-
- User user = new User();
- user.setUid(""); //Required
- user.setName(""); //Required
- user.setAvatar(""); //Required
-
- cometchatOutgoingCall.setUser(user); //Required - set the user object
- //OR
- cometchatOutgoingCall.setCall(call); //Required - set the call object
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- return cometchatOutgoingCall;
+ cometchatOutgoingCall = new CometChatOutgoingCall(this);
+ cometchatOutgoingCall.setCall(call); // Required — set the Call object
+ setContentView(cometchatOutgoingCall);
}
```
-
+
+
+Or in a Fragment:
-
-```kotlin YourFragment.kt
+
+
+```kotlin YourFragment.kt lines
private lateinit var cometchatOutgoingCall: CometChatOutgoingCall
override fun onCreateView(
@@ -158,133 +175,101 @@ override fun onCreateView(
savedInstanceState: Bundle?
): View {
cometchatOutgoingCall = CometChatOutgoingCall(requireContext())
-
- val user = User()
- user.uid = "" //Required
- user.name = "" //Required
- user.avatar = "" //Required
-
- cometchatOutgoingCall.setUser(user) //Required - set the user object
- //OR
- cometchatOutgoingCall.setCall(call) //Required - set the call object
-
+ cometchatOutgoingCall.setCall(call) // Required — set the Call object
return cometchatOutgoingCall
}
```
-
-
+
+```java YourFragment.java lines
+CometChatOutgoingCall cometchatOutgoingCall;
-***
+@Override
+public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ cometchatOutgoingCall = new CometChatOutgoingCall(requireContext());
+ cometchatOutgoingCall.setCall(call); // Required — set the Call object
+ return cometchatOutgoingCall;
+}
+```
+
+
-### Actions
+## Actions and Events
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+### Callback Methods
-##### setOnError
+#### `setOnEndCallClick`
-This action doesn't change the behavior of the component but rather listens for any errors that occur in the MessageList component.
+Fires when the end-call button is tapped. Default: cancels the outgoing call via the SDK.
-
-```java YourActivity.java
- cometchatOutgoingCall.setOnError(new OnError() {
- @Override
- public void onError(CometChatException cometchatException) {
-
- }
- });
-```
-
-
-
-```kotlin YourActivity.kt
- cometchatOutgoingCall.setOnError(object : OnError {
- override fun onError(context: Context, e: CometChatException) {
- // Your Exception Handling code.
- }
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setOnEndCallClick(OnClick {
+ // Your custom end-call logic
})
```
-
-
-
-##### setOnEndCallClick
-
-The `setOnEndCallClick` action is typically triggered when the end call button is clicked, carrying out default actions. However, with the following code snippet, you can effortlessly customize or override this default behavior to meet your specific needs.
-
-
-```java
+```java YourActivity.java lines
cometchatOutgoingCall.setOnEndCallClick(new OnClick() {
@Override
public void onClick() {
- //TODO
+ // Your custom end-call logic
}
});
```
-
-
-
-```kotlin
-cometchatOutgoingCall.setOnEndCallClick(OnClick {
- //TODO
-})
-```
-
-
-
-***
-
-### Filters
-
-**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK.
-
-The OutgoingCall component does not have any exposed filters.
-
-***
-
-### Events
-
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed.
-
-Events emitted by the Outgoing call component are as follows.
+> **What this does:** Replaces the default end-call button behavior. When the user taps the end-call button, your custom `OnClick` lambda executes instead of the built-in call cancellation.
-| Event | Description |
-| -------------------------- | -------------------------------------------- |
-| **onOutgoingCallAccepted** | Triggers when the outgoing call is accepted. |
-| **onOutgoingCallRejected** | Triggers when the outgoing call is rejected. |
+#### `setOnError`
-##### Add CometChatCallEvents
+Fires on internal errors (network failure, auth issue, SDK exception).
-
-```java
-CometChatCallEvents.addListener("UNIQUE_ID", new CometChatCallEvents() {
- @Override
- public void ccCallAccepted(Call call) {
- super.ccCallAccepted(call);
+
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setOnError(object : OnError {
+ override fun onError(context: Context, e: CometChatException) {
+ // Your error handling logic
}
+})
+```
+
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setOnError(new OnError() {
@Override
- public void ccCallRejected(Call call) {
- super.ccCallRejected(call);
+ public void onError(CometChatException cometchatException) {
+ // Your error handling logic
}
-
});
```
-
+
+> **What this does:** Registers an error callback on the `CometChatOutgoingCall` instance. When an error occurs within the component, the `onError` method is invoked with the `CometChatException` containing error details.
+
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap end-call, cause an error) and confirm your custom logic executes instead of the default behavior.
+
+### Global UI Events (CometChatCallEvents)
+
+`CometChatCallEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed.
+
+| Event | Fires when | Payload |
+| --- | --- | --- |
+| `ccCallAccepted` | The outgoing call is accepted by the receiver | `Call` |
+| `ccCallRejected` | The outgoing call is rejected by the receiver | `Call` |
+
+
-```kotlin
-CometChatCallEvents.addListener("UNIQUE_ID", object : CometChatCallEvents() {
+```kotlin Add Listener lines
+CometChatCallEvents.addListener("LISTENER_TAG", object : CometChatCallEvents() {
override fun ccCallAccepted(call: Call) {
super.ccCallAccepted(call)
}
@@ -295,135 +280,102 @@ CometChatCallEvents.addListener("UNIQUE_ID", object : CometChatCallEvents() {
})
```
-
+Remove Listener
-
-
-***
-
-##### Remove CometChatCallEvents
-
-
-
-```java
-CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER");
```
-
-
-
-
-```kotlin
-CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER")
+CometChatCallEvents.removeListener("LISTENER_TAG")
```
-
-
-
-***
-
-## Customization
-
-To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
-
-### Style
-
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
-
-
-
-
-
-```xml themes.xml
-
-
-```
-
-
-```java
-cometChatOutgoingCall.setStyle(R.style.CustomOutgoingCall);
+```java Add Listener lines
+CometChatCallEvents.addListener("LISTENER_TAG", new CometChatCallEvents() {
+ @Override
+ public void ccCallAccepted(Call call) {
+ super.ccCallAccepted(call);
+ }
+
+ @Override
+ public void ccCallRejected(Call call) {
+ super.ccCallRejected(call);
+ }
+});
```
-
+Remove Listener
-
-```kotlin
-cometChatOutgoingCall.setStyle(R.style.CustomOutgoingCall)
```
-
+CometChatCallEvents.removeListener("LISTENER_TAG");
+```
-
-***
+### SDK Events
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_outgoing_call.xml).
-
-### Functionality
+The component listens to SDK call events internally. No manual attachment needed unless additional side effects are required.
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements.
+| SDK Listener | Internal behavior |
+| --- | --- |
+| `onOutgoingCallAccepted` | Transitions to the ongoing call screen |
+| `onOutgoingCallRejected` | Finishes the activity or invokes the back-press handler |
-Below is a list of customizations along with corresponding code snippets
+## Functionality
-| Methods | Description | Code |
-| -------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
-| **setCall** | Used to set the Call object against which we need to display the outgoing screen | `.setCall(Call call)` |
-| **setCallSettingsBuilder** | Sets the CallSettingsBuilder for the outgoing call configuration. | `setCallSettingsBuilder(CometChatCalls.CallSettingsBuilder callSettingsBuilder)` |
-| **disableSoundForCalls** | used to enable/disable sound for outgoing call , default false | `.disableSoundForMessages(false);` |
-| **setCustomSoundForCalls** | used to set custom sound for outgoing calls | `.setCustomSoundForMessages(@RawRes resource);` |
+Small functional customizations for sound and call behavior.
-***
+| Method | Description | Code |
+| --- | --- | --- |
+| `disableSoundForCall` | Enables or disables the outgoing call ringtone | `.disableSoundForCall(true);` |
+| `setCustomSoundForCalls` | Sets a custom sound resource for the outgoing call ringtone | `.setCustomSoundForCalls(R.raw.custom_ringtone);` |
-### Advanced
+- **Verify**: After calling `disableSoundForCall(true)`, initiate an outgoing call and confirm no ringtone plays.
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
+## Custom View Slots
-#### setTitleView
+Each slot replaces a section of the default UI. All view slots accept a `Function2` that receives the current context and `Call` object and returns a custom `View`.
-Allows setting a custom list item view to be rendered for each conversation in the fetched call list.
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Title view | `setTitleView(Function2)` | Name / title text |
+| Subtitle view | `setSubtitleView(Function2)` | Subtitle text (e.g., "Calling...") |
+| Avatar view | `setAvatarView(Function2)` | Avatar / profile picture area |
+| End-call view | `setEndCallView(Function2)` | End-call button |
-Use Cases:
+### `setTitleView`
-* Display the contact’s name in a unique style.
-* Show a call type indicator (Voice Call, Video Call).
-* Add status text like "Calling..." or "Ringing...".
+Replace the name / title text area.
-
-```java YourActivity.java
-cometchatOutgoingCall.setTitleView((context, call) -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setTitleView(object : Function2 {
+ override fun apply(context: Context?, call: Call?): View? {
+ return null
+ }
+})
```
-
-
-```kotlin YourActivity.kt
-cometchatOutgoingCall.setTitleView(object : Function3 {
- override fun apply(context: Context?, call: Call?): View? {
-
- }
- })
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setTitleView((context, call) -> {
+ return null;
+});
```
-
-
-Example:
+> **What this does:** Registers a callback that receives the `Context` and `Call` object and returns a custom `View` to replace the default title area on the outgoing call screen.
+
+Example with sender and receiver names:
-```xml custom_title_view.xml
+Create a `custom_title_view.xml` layout:
+
+```xml custom_title_view.xml lines
-
-```java YourActivity.java
-cometchatOutgoingCall.setTitleView(new Function2() {
- @Override
- public View apply(Context context, Call call) {
- View titleView = LayoutInflater.from(context).inflate(R.layout.custom_title_view, null);
- TextView tvTitle = titleView.findViewById(R.id.title_text);
- User user = (User) call.getCallReceiver();
- tvTitle.setText(user.getName() + " <> " + call.getSender().getUid());
- return titleView;
- }
- });
-```
-
-
-
-```kotlin YourActivity.kt
-
+```kotlin YourActivity.kt lines
cometchatOutgoingCall.setTitleView(object : Function2 {
- override fun apply(context: Context?, call: Call?): View? {
- val titleView: View = LayoutInflater.from(context).inflate(R.layout.custom_title_view, null)
- val tvTitle = titleView.findViewById(R.id.title_text)
- val user = call?.callReceiver as User
- tvTitle.text = user.name + " <> " + call.sender.uid
- return titleView
- }
- })
+ override fun apply(context: Context?, call: Call?): View? {
+ val titleView: View = LayoutInflater.from(context).inflate(R.layout.custom_title_view, null)
+ val tvTitle = titleView.findViewById(R.id.title_text)
+ val user = call?.callReceiver as User
+ tvTitle.text = user.name + " <> " + call.sender.uid
+ return titleView
+ }
+})
```
-
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setTitleView(new Function2() {
+ @Override
+ public View apply(Context context, Call call) {
+ View titleView = LayoutInflater.from(context).inflate(R.layout.custom_title_view, null);
+ TextView tvTitle = titleView.findViewById(R.id.title_text);
+ User user = (User) call.getCallReceiver();
+ tvTitle.setText(user.getName() + " <> " + call.getSender().getUid());
+ return titleView;
+ }
+});
+```
+
-***
-
-#### setSubtitleView
+> **What this does:** Inflates the `custom_title_view` layout, retrieves the call receiver's name and the sender's UID, and sets the title text to display them separated by `" <> "`.
-Enables customizing the subtitle view, typically used for additional call details.
+### `setSubtitleView`
-Use Cases:
-
-* Display call duration if available.
-* Show network strength indicators.
-* Include a custom message like "Connecting...".
+Replace the subtitle text below the title.
-
-```java YourActivity.java
-cometchatOutgoingCall.setSubtitleView((context, call) -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setSubtitleView(object : Function2 {
+ override fun apply(context: Context?, call: Call?): View? {
+ return null
+ }
+})
```
-
-
-```kotlin YourActivity.kt
-cometchatOutgoingCall.setSubtitleView(object : Function3 {
- override fun apply(context: Context?, call: Call?): View? {
-
- }
- })
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setSubtitleView((context, call) -> {
+ return null;
+});
```
-
-
-Example:
+> **What this does:** Registers a callback that receives the `Context` and `Call` object and returns a custom `View` to replace the default subtitle area on the outgoing call screen.
+
+Example with call-type icon and "Calling...." text:
-```html custom_subtitle_view.xml
+Create a `custom_subtitle_view.xml` layout:
+
+```xml custom_subtitle_view.xml lines
-
```
-
-```java YourActivity.java
-cometchatOutgoingCall.setSubtitleView(new Function2() {
- @Override
- public View apply(Context context, Call call) {
- View subtitleView = LayoutInflater.from(context).inflate(R.layout.custom_subtitle_view, null);
- TextView tvTitle = subtitleView.findViewById(R.id.subtitle_text);
- tvTitle.setText("Calling....");
- ImageView ivCall = subtitleView.findViewById(R.id.call_iv);
-
- if (CometChatConstants.CALL_TYPE_AUDIO.equals(call.getType())) {
- ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_voice);
- } else {
- ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_video);
- }
-
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- );
- layoutParams.gravity = Gravity.CENTER_VERTICAL;
- subtitleView.setLayoutParams(layoutParams);
- return subtitleView;
- }
- });
-```
-
-
-
-```kotlin YourActivity.kt
-
+```kotlin YourActivity.kt lines
cometchatOutgoingCall.setSubtitleView(object : Function2 {
- override fun apply(context: Context?, call: Call?): View? {
- val subtitleView: View = LayoutInflater.from(context).inflate(R.layout.custom_title_view, null)
- val tvTitle = subtitleView.findViewById(R.id.subtitle_text)
- tvTitle.text = "Calling...."
- val ivCall = subtitleView.findViewById(R.id.call_iv)
-
- if (CometChatConstants.CALL_TYPE_AUDIO == call.type) {
- ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_voice)
- } else {
- ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_video)
- }
-
- val layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- layoutParams.gravity = Gravity.CENTER_VERTICAL
- subtitleView.layoutParams = layoutParams
- return subtitleView
- }
- })
+ override fun apply(context: Context?, call: Call?): View? {
+ val subtitleView: View = LayoutInflater.from(context).inflate(R.layout.custom_subtitle_view, null)
+ val tvTitle = subtitleView.findViewById(R.id.subtitle_text)
+ tvTitle.text = "Calling...."
+ val ivCall = subtitleView.findViewById(R.id.call_iv)
+
+ if (CometChatConstants.CALL_TYPE_AUDIO == call?.type) {
+ ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_voice)
+ } else {
+ ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_video)
+ }
+
+ val layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ layoutParams.gravity = Gravity.CENTER_VERTICAL
+ subtitleView.layoutParams = layoutParams
+ return subtitleView
+ }
+})
```
-
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setSubtitleView(new Function2() {
+ @Override
+ public View apply(Context context, Call call) {
+ View subtitleView = LayoutInflater.from(context).inflate(R.layout.custom_subtitle_view, null);
+ TextView tvTitle = subtitleView.findViewById(R.id.subtitle_text);
+ tvTitle.setText("Calling....");
+ ImageView ivCall = subtitleView.findViewById(R.id.call_iv);
+
+ if (CometChatConstants.CALL_TYPE_AUDIO.equals(call.getType())) {
+ ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_voice);
+ } else {
+ ivCall.setImageResource(com.cometchat.chatuikit.R.drawable.cometchat_ic_call_video);
+ }
+
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ );
+ layoutParams.gravity = Gravity.CENTER_VERTICAL;
+ subtitleView.setLayoutParams(layoutParams);
+ return subtitleView;
+ }
+});
+```
+
-***
-
-#### setAvatarView
-
-Allows setting a custom leading view, usually used for the contact’s profile picture or avatar.
+> **What this does:** Inflates the `custom_subtitle_view` layout, sets the subtitle text to "Calling....", and displays a voice call icon if the call type is `CALL_TYPE_AUDIO`, or a video call icon otherwise.
-Use Cases:
+### `setAvatarView`
-* Show a profile picture with an online indicator.
-* Display a custom icon based on the call type (Voice/Video).
-* Use an animated ring effect around the avatar when calling.
+Replace the avatar / profile picture area.
-
-```java YourActivity.java
-cometchatOutgoingCall.setAvatarView((context, call) -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setAvatarView(object : Function2 {
+ override fun apply(context: Context?, call: Call?): View? {
+ return null
+ }
+})
```
-
-
-```kotlin YourActivity.kt
-cometchatOutgoingCall.setAvatarView(object : Function3 {
- override fun apply(context: Context?, call: Call?): View? {
-
- }
- })
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setAvatarView((context, call) -> {
+ return null;
+});
```
-
-
-Example:
+> **What this does:** Registers a callback that receives the `Context` and `Call` object and returns a custom `View` to replace the default avatar area on the outgoing call screen.
+
+Example with admin badge:
-```xml custom_avatar_view.xml
+Create a `custom_avatar_view.xml` layout:
+
+```xml custom_avatar_view.xml lines
-
-```java YourActivity.java
-cometchatOutgoingCall.setAvatarView(new Function2() {
- @Override
- public View apply(Context context, Call call) {
- View avatarView = LayoutInflater.from(context).inflate(R.layout.custom_avatar_view, null);
- CometChatAvatar avatar = avatarView.findViewById(R.id.avatar);
- User user = (User) call.getReceiver();
- avatar.setAvatar(user.getUid(), user.getAvatar());
-
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- );
- layoutParams.gravity = Gravity.CENTER_VERTICAL;
- avatarView.setLayoutParams(layoutParams);
- return avatarView;
- }
- });
-```
-
-
-
-```kotlin YourActivity.kt
-
+```kotlin YourActivity.kt lines
cometchatOutgoingCall.setAvatarView(object : Function2 {
- override fun apply(context: Context?, call: Call?): View? {
- val avatarView: View = LayoutInflater.from(context).inflate(R.layout.custom_avatar_view, null)
- val avatar = avatarView.findViewById(R.id.avatar)
- val user = call?.receiver as User
- avatar.setAvatar(user.uid, user.avatar)
-
- val layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- layoutParams.gravity = Gravity.CENTER_VERTICAL
- avatarView.layoutParams = layoutParams
- return avatarView
- }
- })
+ override fun apply(context: Context?, call: Call?): View? {
+ val avatarView: View = LayoutInflater.from(context).inflate(R.layout.custom_avatar_view, null)
+ val avatar = avatarView.findViewById(R.id.avatar)
+ val user = call?.receiver as User
+ avatar.setAvatar(user.uid, user.avatar)
+
+ val layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ layoutParams.gravity = Gravity.CENTER_VERTICAL
+ avatarView.layoutParams = layoutParams
+ return avatarView
+ }
+})
```
-
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setAvatarView(new Function2() {
+ @Override
+ public View apply(Context context, Call call) {
+ View avatarView = LayoutInflater.from(context).inflate(R.layout.custom_avatar_view, null);
+ CometChatAvatar avatar = avatarView.findViewById(R.id.avatar);
+ User user = (User) call.getReceiver();
+ avatar.setAvatar(user.getUid(), user.getAvatar());
+
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ );
+ layoutParams.gravity = Gravity.CENTER_VERTICAL;
+ avatarView.setLayoutParams(layoutParams);
+ return avatarView;
+ }
+});
+```
+
-***
-
-#### setEndCallView
+> **What this does:** Inflates the `custom_avatar_view` layout, retrieves the call receiver's UID and avatar URL, sets them on the `CometChatAvatar` widget, and applies centered layout params.
-Defines a custom title view for the end call button, allowing modifications to the call termination UI.
+### `setEndCallView`
-Use Cases:
-
-* Customize the "End Call" button style.
-* Add a confirmation pop-up before ending the call.
-* Display different icons based on call status (Active, On Hold).
+Replace the end-call button.
-
-```java YourActivity.java
-cometchatOutgoingCall.setEndCallView((context, call) -> {
-
- });
+
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setEndCallView(object : Function2 {
+ override fun apply(context: Context?, call: Call?): View? {
+ return null
+ }
+})
```
-
-
-```kotlin YourActivity.kt
-cometchatOutgoingCall.setEndCallView(object : Function3 {
- override fun apply(context: Context?, call: Call?): View? {
-
- }
- })
+
+```java YourActivity.java lines
+cometchatOutgoingCall.setEndCallView((context, call) -> {
+ return null;
+});
```
-
-
-Example:
+> **What this does:** Registers a callback that receives the `Context` and `Call` object and returns a custom `View` to replace the default end-call button on the outgoing call screen.
+
+Example with custom end-call card:
-```xml end_call_button.xml
+Create an `end_call_button.xml` layout:
+
+```xml end_call_button.xml lines
+
+```kotlin YourActivity.kt lines
+cometchatOutgoingCall.setEndCallView(object : Function2 {
+ override fun apply(context: Context?, call: Call?): View? {
+ val endCallButtonView: View = LayoutInflater.from(context).inflate(R.layout.end_call_button, null)
+
+ endCallButtonView.setOnClickListener { Toast.makeText(context, "End call clicked", Toast.LENGTH_SHORT).show() }
+ val layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ layoutParams.bottomMargin = Utils.convertDpToPx(context, 40)
+ endCallButtonView.layoutParams = layoutParams
+ return endCallButtonView
+ }
+})
+```
+
+
-```java YourActivity.java
+```java YourActivity.java lines
cometchatOutgoingCall.setEndCallView(new Function2() {
+ @Override
+ public View apply(Context context, Call call) {
+ View endCallButtonView = LayoutInflater.from(context).inflate(R.layout.end_call_button, null);
+
+ endCallButtonView.setOnClickListener(new View.OnClickListener() {
@Override
- public View apply(Context context, Call call) {
- View endCallButtonView = LayoutInflater.from(context).inflate(R.layout.end_call_button, null);
-
- endCallButtonView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Toast.makeText(context, "End call clicked", Toast.LENGTH_SHORT).show();
- }
- });
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- );
- layoutParams.bottomMargin = Utils.convertDpToPx(context, 40);
- endCallButtonView.setLayoutParams(layoutParams);
- return endCallButtonView;
+ public void onClick(View v) {
+ Toast.makeText(context, "End call clicked", Toast.LENGTH_SHORT).show();
}
});
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ );
+ layoutParams.bottomMargin = Utils.convertDpToPx(context, 40);
+ endCallButtonView.setLayoutParams(layoutParams);
+ return endCallButtonView;
+ }
+});
```
+
+
+
+> **What this does:** Inflates the `end_call_button` layout, attaches a click listener that shows a toast message "End call clicked", sets a 40dp bottom margin, and returns the custom end-call button view.
+
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position on the outgoing call screen and that the data binding populates correctly.
+
+## Common Patterns
+### Silent outgoing call
+
+
+
+```kotlin lines
+cometchatOutgoingCall.disableSoundForCall(true)
+```
+
+
+
+```java lines
+cometchatOutgoingCall.disableSoundForCall(true);
+```
+
+### Custom ringtone
+
+
-```kotlin YourActivity.kt
+```kotlin lines
+cometchatOutgoingCall.setCustomSoundForCalls(R.raw.custom_ringtone)
+```
+
-cometchatOutgoingCall.setEndCallView(object : Function2 {
- override fun apply(context: Context?, call: Call?): View? {
- val endCallButtonView: View = LayoutInflater.from(context).inflate(R.layout.end_call_button, null)
-
- endCallButtonView.setOnClickListener { Toast.makeText(context, "End call clicked", Toast.LENGTH_SHORT).show() }
- val layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- layoutParams.bottomMargin = Utils.convertDpToPx(context, 40)
- endCallButtonView.layoutParams = layoutParams
- return endCallButtonView
- }
- })
+
+```java lines
+cometchatOutgoingCall.setCustomSoundForCalls(R.raw.custom_ringtone);
+```
+
+
+
+### Custom call settings for ongoing call
+
+
+
+```kotlin lines
+val callSettingsBuilder = CometChatCalls.CallSettingsBuilder(this, true)
+ .setDefaultAudioMode("SPEAKER")
+cometchatOutgoingCall.setCallSettingsBuilder(callSettingsBuilder)
+```
+
+
+
+```java lines
+CometChatCalls.CallSettingsBuilder callSettingsBuilder = new CometChatCalls.CallSettingsBuilder(this, true)
+ .setDefaultAudioMode("SPEAKER");
+cometchatOutgoingCall.setCallSettingsBuilder(callSettingsBuilder);
+```
+
+
+
+### Handle end-call with custom navigation
+
+
+
+```kotlin lines
+cometchatOutgoingCall.setOnEndCallClick(OnClick {
+ finish() // navigate back instead of default SDK rejection
+})
+```
+
+
+
+```java lines
+cometchatOutgoingCall.setOnEndCallClick(() -> {
+ finish(); // navigate back instead of default SDK rejection
+});
+```
+
+
+
+## Advanced Methods
+
+### `setCall`
+
+Sets the call object and extracts the receiver `User` automatically. Use this when you have a `Call` object from the SDK.
+
+
+
+```kotlin lines
+cometChatOutgoingCall.setCall(call)
+```
+
+
+
+```java lines
+cometChatOutgoingCall.setCall(call);
+```
+
+
+
+> `setCall` internally extracts the receiver from the `Call` object and calls `setUser` with it. The component then displays the receiver's name and avatar.
+
+### `setUser`
+
+Sets the user directly when you don't have a `Call` object. The `uid`, `name`, and `avatar` fields are required.
+
+
+
+```kotlin lines
+cometChatOutgoingCall.setUser(user)
+```
+
+
+
+```java lines
+cometChatOutgoingCall.setUser(user);
+```
+
+
+
+### `setCallSettingsBuilder`
+
+Configures the ongoing call settings (audio mode, video settings, etc.) that apply once the call is accepted.
+
+
+
+```kotlin lines
+val callSettingsBuilder = CometChatCalls.CallSettingsBuilder(this, true)
+ .setIsAudioOnly(true)
+cometChatOutgoingCall.setCallSettingsBuilder(callSettingsBuilder)
+```
+
+
+
+```java lines
+CometChatCalls.CallSettingsBuilder callSettingsBuilder = new CometChatCalls.CallSettingsBuilder(this, true)
+ .setIsAudioOnly(true);
+cometChatOutgoingCall.setCallSettingsBuilder(callSettingsBuilder);
+```
+
+
+
+### `setCustomSoundForCalls`
+
+Sets a custom ringtone sound that plays while the outgoing call is ringing.
+
+
+
+```kotlin lines
+cometChatOutgoingCall.setCustomSoundForCalls(R.raw.custom_ringtone)
+```
+
+
+
+```java lines
+cometChatOutgoingCall.setCustomSoundForCalls(R.raw.custom_ringtone);
```
+
+
+### `disposeObservers`
+
+Removes lifecycle observers manually. Normally handled automatically when the view detaches from the window.
+
+
+
+```kotlin lines
+cometChatOutgoingCall.disposeObservers()
+```
+
+```java lines
+cometChatOutgoingCall.disposeObservers();
+```
+
-***
+### Internal Access
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getViewModel()` | `OutgoingViewModel` | The ViewModel managing call state and SDK listeners |
+
+> Use this only when the standard API is insufficient. Directly manipulating the ViewModel may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatOutgoingCallStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
+
+```xml themes.xml lines
+
+
+```
+
+
+
+```kotlin lines
+cometChatOutgoingCall.setStyle(R.style.CustomOutgoingCall)
+```
+
+
+
+```java lines
+cometChatOutgoingCall.setStyle(R.style.CustomOutgoingCall);
+```
+
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_outgoing_call.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setTitleTextColor` | `@ColorInt int` | Title text color |
+| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance |
+| `setSubtitleTextColor` | `@ColorInt int` | Subtitle text color |
+| `setSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance |
+| `setEndCallIcon` | `Drawable` | Custom end-call button icon |
+| `setEndCallIconTint` | `@ColorInt int` | Tint color for the end-call icon |
+| `setEndCallButtonBackgroundColor` | `@ColorInt int` | Background color for the end-call button |
+| `setAvatarStyle` | `@StyleRes int` | Style for the avatar |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component |
+| `setStrokeWidth` | `@Dimension int` | Stroke width of the component border |
+| `setStrokeColor` | `@ColorInt int` | Stroke color of the component border |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Set the call object | Activity/Fragment | `setCall(Call)` | `.setCall(call)` |
+| Set the user directly | Activity/Fragment | `setUser(User)` | `.setUser(user)` |
+| Override end-call behavior | Activity/Fragment | `setOnEndCallClick(OnClick)` | See `setOnEndCallClick` code above |
+| Handle errors | Activity/Fragment | `setOnError(OnError)` | See `setOnError` code above |
+| Disable outgoing call sound | Activity/Fragment | `disableSoundForCall(boolean)` | `.disableSoundForCall(true);` |
+| Set custom outgoing call sound | Activity/Fragment | `setCustomSoundForCalls(@RawRes int)` | `.setCustomSoundForCalls(R.raw.custom_ringtone);` |
+| Configure ongoing call settings | Activity/Fragment | `setCallSettingsBuilder(CallSettingsBuilder)` | `.setCallSettingsBuilder(builder)` |
+| Title view | Activity/Fragment | `setTitleView(Function2)` | See `setTitleView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(Function2)` | See `setSubtitleView` code above |
+| Avatar view | Activity/Fragment | `setAvatarView(Function2)` | See `setAvatarView` code above |
+| End-call button view | Activity/Fragment | `setEndCallView(Function2)` | See `setEndCallView` code above |
+| Avatar style (corner radius, background) | `themes.xml` | `CometChatOutgoingCallStyle` with `cometchatOutgoingCallAvatarStyle` | `8dp` |
+| Apply a custom style | Activity/Fragment | `setStyle(@StyleRes int)` | `cometChatOutgoingCall.setStyle(R.style.CustomOutgoingCall);` |
+| Title text color | Activity/Fragment | `setTitleTextColor(@ColorInt int)` | `.setTitleTextColor(Color.WHITE);` |
+| Subtitle text color | Activity/Fragment | `setSubtitleTextColor(@ColorInt int)` | `.setSubtitleTextColor(Color.GRAY);` |
+| End-call icon | Activity/Fragment | `setEndCallIcon(Drawable)` | `.setEndCallIcon(drawable);` |
+| End-call icon tint | Activity/Fragment | `setEndCallIconTint(@ColorInt int)` | `.setEndCallIconTint(Color.WHITE);` |
+| End-call button background | Activity/Fragment | `setEndCallButtonBackgroundColor(@ColorInt int)` | `.setEndCallButtonBackgroundColor(Color.RED);` |
+| Background color | Activity/Fragment | `setBackgroundColor(@ColorInt int)` | `.setBackgroundColor(Color.BLACK);` |
+| Corner radius | Activity/Fragment | `setCornerRadius(@Dimension int)` | `.setCornerRadius(16);` |
+| Stroke width | Activity/Fragment | `setStrokeWidth(@Dimension int)` | `.setStrokeWidth(2);` |
+| Stroke color | Activity/Fragment | `setStrokeColor(@ColorInt int)` | `.setStrokeColor(Color.GRAY);` |
+
+## Accessibility
+
+The component renders a full-screen outgoing call view. The end-call button responds to tap gestures. The avatar image includes the user name as content description. The title and subtitle text views are readable by screen readers.
+
+For custom views provided via `setTitleView`, `setSubtitleView`, `setAvatarView`, or `setEndCallView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load. |
+| Outgoing call screen is blank | Verify that you set a `User` object with `setUser(user)` or a `Call` object with `setCall(call)` on the `CometChatOutgoingCall` instance. The `uid`, `name`, and `avatar` fields are required on the `User` object. |
+| End-call button does not respond | If you set `setOnEndCallClick` with a custom `OnClick`, ensure your callback contains the call cancellation logic. The default behavior is replaced when you override this action. |
+| Call events not received | Ensure you call `CometChatCallEvents.addListener` with a unique string ID. If you reuse the same ID as another listener, the previous one is replaced. |
+| Call events still firing after screen is closed | Call `CometChatCallEvents.removeListener("YOUR_LISTENER_ID")` in your Activity's `onDestroy` or Fragment's `onDestroyView` to unsubscribe from events. |
+| Custom style not visible | Verify the style parent is `CometChatOutgoingCallStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| Sound still plays after disabling | Ensure you call `disableSoundForCall` before the component starts the outgoing call. If called after the call is initiated, it may not take effect. |
+| Custom avatar view not centered | Set `LinearLayout.LayoutParams` with `Gravity.CENTER_VERTICAL` on your custom view, as shown in the `setAvatarView` example. |
+
+## FAQ
+
+**Q: Do I need a `User` object or a `Call` object to use `CometChatOutgoingCall`?**
+**A:** You need one or the other. Use `setUser(user)` if you have a `User` object with `uid`, `name`, and `avatar` set. Use `setCall(call)` if you have a `Call` object from the CometChat SDK.
+
+**Q: Can I use `CometChatOutgoingCall` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, create the instance and call `setContentView(cometchatOutgoingCall)`. In a Fragment, create the instance and return it from `onCreateView`.
+
+**Q: How do I listen for when the outgoing call is accepted or rejected?**
+**A:** Use `CometChatCallEvents.addListener("YOUR_ID", ...)` and override `ccCallAccepted` and `ccCallRejected`. Call `CometChatCallEvents.removeListener("YOUR_ID")` to unsubscribe.
+
+**Q: How do I customize the end-call button appearance?**
+**A:** Use `setEndCallView` to provide a custom layout. Inflate your XML layout, attach a click listener, and return the view from the callback.
+
+**Q: Does the outgoing call component support filters?**
+**A:** No. The `CometChatOutgoingCall` component does not have any exposed filters.
+
+## Next Steps
+
+- [Incoming Call component](/ui-kit/android/incoming-call)
+- [Call Buttons component](/ui-kit/android/call-buttons)
+- [Call Logs component](/ui-kit/android/call-logs)
\ No newline at end of file
diff --git a/ui-kit/android/overview.mdx b/ui-kit/android/overview.mdx
index 82e6f306c..6d6786645 100644
--- a/ui-kit/android/overview.mdx
+++ b/ui-kit/android/overview.mdx
@@ -44,7 +44,7 @@ Get started with the **CometChat UI Kit** on your mobile device:
## **Getting Started**
-Before integrating the CometChat UI Kit, familiarize yourself with the key concepts and features offered by CometChat’s platform.
+Before integrating the CometChat UI Kit, familiarize yourself with the key concepts and features of CometChat’s platform.
* Review the [Key Concepts](/fundamentals/key-concepts) to understand essential terminology and features.
* Follow the [Getting Started Guide](/ui-kit/android/getting-started) for detailed steps on initial setup and integration.
diff --git a/ui-kit/android/property-changes.mdx b/ui-kit/android/property-changes.mdx
index aec1a2f74..f0eecd8e9 100644
--- a/ui-kit/android/property-changes.mdx
+++ b/ui-kit/android/property-changes.mdx
@@ -206,7 +206,7 @@ title: "Property Changes"
| setOnSelection | setOnSelect | Method | Sets selection listener for users |
| setSubtitle | setSubtitleView | Method | Sets custom subtitle view |
| setTail | setTailView | Method | Sets custom tail view (renamed to setTrailingView) |
-| setListItemView | seItemView | Method | Sets custom item view |
+| setListItemView | setItemView | Method | Sets custom item view |
| getConversationsAdapter | getUsersAdapter | Method | Gets the users adapter |
### Removed Properties
diff --git a/ui-kit/android/search.mdx b/ui-kit/android/search.mdx
index 5377979aa..70e11e056 100644
--- a/ui-kit/android/search.mdx
+++ b/ui-kit/android/search.mdx
@@ -2,27 +2,178 @@
title: "Search"
---
-## Overview
+`CometChatSearch` is a composite component that provides a real-time search interface for finding conversations and messages, with support for filters, scopes, and customization options.
+
+## AI Agent Component Spec
+
+
+
+```json
+{
+ "component": "CometChatSearch",
+ "package": "com.cometchat.chatuikit.search",
+ "xmlElement": "",
+ "description": "Real-time search interface for finding conversations and messages with filters, scopes, and customization options.",
+ "primaryOutput": {
+ "conversationClicked": {
+ "method": "setOnConversationClicked",
+ "type": "OnItemClick"
+ },
+ "messageClicked": {
+ "method": "setOnMessageClicked",
+ "type": "OnItemClick"
+ }
+ },
+ "methods": {
+ "data": {
+ "setConversationsRequestBuilder": {
+ "type": "ConversationsRequest.ConversationsRequestBuilder",
+ "default": "SDK default",
+ "note": "Pass the builder, not the result of .build()"
+ },
+ "setMessagesRequestBuilder": {
+ "type": "MessagesRequest.MessagesRequestBuilder",
+ "default": "SDK default",
+ "note": "Pass the builder, not the result of .build()"
+ }
+ },
+ "callbacks": {
+ "setOnConversationClicked": "OnItemClick",
+ "setOnMessageClicked": "OnItemClick",
+ "setOnBackPressListener": "OnBackPress",
+ "setOnError": "OnError",
+ "setOnEmpty": "OnEmpty",
+ "setOnLoadMessages": "OnLoad",
+ "setOnLoadConversations": "OnLoad"
+ },
+ "visibility": {
+ "setEmptyStateVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" },
+ "setErrorStateVisibility": { "type": "int", "default": "View.VISIBLE" }
+ },
+ "functionality": {
+ "setUid": { "type": "String", "note": "Scope search to a specific user conversation" },
+ "setGuid": { "type": "String", "note": "Scope search to a specific group conversation" },
+ "setSearchFilters": { "type": "List", "note": "Filters rendered as chips" },
+ "setInitialSearchFilter": { "type": "UIKitConstants.SearchFilter", "note": "Default active filter on load" },
+ "setSearchIn": { "type": "List", "note": "Entities to search in" },
+ "setHideGroupType": { "type": "boolean", "default": "false" },
+ "setHideUserStatus": { "type": "boolean", "default": "false" }
+ },
+ "viewSlots": {
+ "setConversationItemView": "ConversationsSearchViewHolderListener — entire conversation item row",
+ "setTextMessageItemView": "MessagesSearchViewHolderListener — text message item",
+ "setImageMessageItemView": "MessagesSearchViewHolderListener — image message item",
+ "setAudioMessageItemView": "MessagesSearchViewHolderListener — audio message item",
+ "setVideoMessageItemView": "MessagesSearchViewHolderListener — video message item",
+ "setDocumentMessageItemView": "MessagesSearchViewHolderListener — document message item",
+ "setLinkMessageItemView": "MessagesSearchViewHolderListener — link message item",
+ "setInitialView": "@LayoutRes int — initial state before search",
+ "setEmptyView": "@LayoutRes int — empty state",
+ "setLoadingView": "View — loading state",
+ "setErrorView": "View — error state"
+ },
+ "advanced": {
+ "setTextFormatters": "List — custom text formatters",
+ "setDateTimeFormatter": "DateTimeFormatterCallback — custom date/time formatting",
+ "setMentionAllLabelId": "String id, String mentionAllLabel — custom mention-all label",
+ "setHintText": "String — search bar hint text"
+ },
+ "style": {
+ "setStyle": {
+ "type": "@StyleRes int",
+ "parent": "CometChatSearchStyle"
+ }
+ }
+ },
+ "events": [],
+ "sdkListeners": []
+}
+```
-The `CometChatSearch` component is a powerful and customizable search interface that allows users to search across conversations and messages in real time. It supports a wide variety of filters, scopes, and customization options. `CometChatSearch` helps users find messages, conversations, media, and more through an intuitive and filterable search experience. It can be embedded in multiple contexts — as part of the conversation list, message header, or as a full-screen search experience.
+
-
-
-
+## Where It Fits
-***
+`CometChatSearch` is a composite search component. It searches across conversations and messages in real time and emits the selected result via `setOnConversationClicked` or `setOnMessageClicked`. Wire it to navigation so tapping a conversation opens the message view, or tapping a message scrolls to it in context.
-## Usage
+
+
+```kotlin ChatActivity.kt lines
+class ChatActivity : AppCompatActivity() {
+
+ private lateinit var search: CometChatSearch
+ private lateinit var messageHeader: CometChatMessageHeader
+ private lateinit var messageList: CometChatMessageList
+ private lateinit var messageComposer: CometChatMessageComposer
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_chat)
+
+ search = findViewById(R.id.cometchat_search)
+ messageHeader = findViewById(R.id.message_header)
+ messageList = findViewById(R.id.message_list)
+ messageComposer = findViewById(R.id.message_composer)
+
+ search.setOnConversationClicked { view, position, conversation ->
+ val user = conversation.conversationWith as? User
+ user?.let {
+ messageHeader.setUser(it)
+ messageList.setUser(it)
+ messageComposer.setUser(it)
+ }
+ }
-### Integration
+ search.setOnMessageClicked { view, position, baseMessage ->
+ // Navigate to the message in context
+ }
+ }
+}
+```
+
-`CometChatSearch`, as a composite Component, offers flexible integration options, allowing it to be launched directly via button clicks or any user-triggered action.
+
+```java ChatActivity.java lines
+public class ChatActivity extends AppCompatActivity {
-The following code snippet exemplifies how you can seamlessly integrate the GroupMembers component into your application.
+ private CometChatSearch search;
+ private CometChatMessageHeader messageHeader;
+ private CometChatMessageList messageList;
+ private CometChatMessageComposer messageComposer;
-
-
-```xml
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ search = findViewById(R.id.cometchat_search);
+ messageHeader = findViewById(R.id.message_header);
+ messageList = findViewById(R.id.message_list);
+ messageComposer = findViewById(R.id.message_composer);
+
+ search.setOnConversationClicked((view, position, conversation) -> {
+ if (conversation.getConversationWith() instanceof User) {
+ User user = (User) conversation.getConversationWith();
+ messageHeader.setUser(user);
+ messageList.setUser(user);
+ messageComposer.setUser(user);
+ }
+ });
+
+ search.setOnMessageClicked((view, position, baseMessage) -> {
+ // Navigate to the message in context
+ });
+ }
+}
+```
+
+
+
+## Quick Start
+
+Add the component to your layout XML:
+
+```xml activity_search.xml lines
```
-
+
+
+
-
+Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.
-If you're defining the Group members within the XML code, you'll need to extract them and set them on the Group object using the appropriate method.
+To add programmatically in an Activity:
+
+```kotlin SearchActivity.kt lines
+class SearchActivity : AppCompatActivity() {
+ private lateinit var binding: ActivitySearchBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivitySearchBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ }
+}
+```
+
+
-```java
+```java SearchActivity.java lines
public class SearchActivity extends AppCompatActivity {
private ActivitySearchBinding binding;
@@ -61,587 +228,974 @@ public class SearchActivity extends AppCompatActivity {
}
}
```
-
+
-
-```kotlin
-class SearchActivity : AppCompatActivity() {
- private lateinit var binding: ActivitySearchBinding
+## Actions and Events
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivitySearchBinding.inflate(layoutInflater)
- setContentView(binding.root)
- }
+### Callback Methods
+
+#### `setOnConversationClicked`
+
+Fires when a user taps a conversation from the search results. Primary navigation hook — set the active conversation and render the message view.
+
+
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setOnConversationClicked { view, position, conversation ->
+ Log.i(TAG, "onCreate: Conversation Clicked !")
}
```
-
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnConversationClicked((view, position, conversation) -> {
+ Log.d(TAG, "onCreate: Conversation Clicked !");
+});
+```
+
-***
-
-### Actions
-
-[Actions](/ui-kit/android/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs.
+> **What this does:** Replaces the default conversation-click behavior. When a user taps a conversation item, your custom lambda executes. The callback receives the view, position, and `Conversation` object.
-#### 1. setOnConversationClicked
+#### `setOnMessageClicked`
-`setOnConversationClicked` is triggered when you click on a Conversation from the search result. The `onConversationClicked` action doesn't have a predefined behavior. You can override this action using the following code snippet.
+Fires when a user taps a message from the search results. Use to navigate to the message in context.
-
-```java SearchActivity.java
- binding.cometchatSearch.setOnConversationClicked((view, position, conversation) -> {
- Log.d(TAG, "onCreate: Conversation Clicked !");
- });
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setOnMessageClicked { view, position, baseMessage ->
+ Log.i(TAG, "onCreate: Message Clicked !")
+}
```
-
-
-```kotlin SearchActivity.kt
- binding.cometchatSearch.setOnConversationClicked { view, position, conversation ->
- Log.i(TAG, "onCreate: Conversation Clicked !")
- }
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnMessageClicked((view, position, baseMessage) -> {
+ Log.d(TAG, "onCreate: Message Clicked !");
+});
```
-
-
-***
+> **What this does:** Registers a callback that fires when the user taps a message in the search results. The callback receives the view, position, and `BaseMessage` object.
-#### 2. setOnMessageClicked
+#### `setOnBackPressListener`
-`setOnMessageClicked` is triggered when you click on a Message from the search result. The `onMessageClicked` action doesn't have a predefined behavior. You can override this action using the following code snippet.
+Fires when the user presses the back button in the search bar. Default: no predefined behavior.
-
-```java SearchActivity.java
- binding.cometchatSearch.setOnMessageClicked((view, position, baseMessage) -> {
- Log.d(TAG, "onCreate: Message Clicked !");
- });
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setOnBackPressListener {
+ Log.i(TAG, "onCreate: Back Pressed !")
+}
```
-
-
-```kotlin SearchActivity.kt
- binding.cometchatSearch.setOnMessageClicked { view, position, baseMessage ->
- Log.i(TAG, "onCreate: Message Clicked !")
- }
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnBackPressListener(() -> {
+ Log.d(TAG, "onCreate: Back Pressed !");
+});
```
-
-
-***
-
-#### 3. setOnBackPressListener
+#### `setOnError`
-'setOnBackPressListener' is triggered when you click on the back button of the search component.
+Fires on internal errors (network failure, auth issue, SDK exception).
-
-```java SearchActivity.java
- binding.cometchatSearch.setOnBackPressListener {
- Log.i(TAG, "onCreate: Back Pressed !")
- }
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.onError = OnError {
+ Log.i(TAG, "onCreate: Error Occurred ! ${it.message}")
+}
```
-
-
-```kotlin SearchActivity.kt
- binding.cometchatSearch.setOnBackPressListener(()-> {
- Log.d(TAG, "onCreate: Back Pressed !");
- });
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnError((e -> {
+ Log.e(TAG, "onCreate: ", e);
+}));
```
-
-
-***
-
-#### 4. setOnError
+#### `setOnLoadMessages`
-This action doesn't change the behavior of the component but rather listens for any errors that occur in the Search component.
+Fires when the message list is successfully fetched and loaded, helping track when message search results are ready.
-
-```java SearchActivity.java
- binding.cometchatSearch.setOnError((e -> {
- Log.e(TAG, "onCreate: ", e);
- // Handle Error
- }));
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setOnLoadMessages(OnLoad { list ->
+ Log.i(TAG, "Messages loaded: ${list.size}")
+})
```
-
-
-```kotlin SearchActivity.kt
- binding.cometchatSearch.onError = OnError {
- Log.i(TAG, "onCreate: Error Occurred ! ${it.message}")
- }
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnLoadMessages(list -> {
+ Log.d(TAG, "Messages loaded: " + list.size());
+});
```
-
-
-***
+#### `setOnLoadConversations`
-#### 5. setOnEmpty
-
-This action doesn't change the behavior of the component but rather listens for the empty state of the Search component.
+Fires when the conversation list is successfully fetched and loaded, helping track when conversation search results are ready.
-
-```java SearchActivity.java
- binding.cometchatSearch.setOnEmpty(()-> {
- Log.d(TAG, "onCreate: Empty Result !");
- });
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setOnLoadConversations(OnLoad { list ->
+ Log.i(TAG, "Conversations loaded: ${list.size}")
+})
```
+
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnLoadConversations(list -> {
+ Log.d(TAG, "Conversations loaded: " + list.size());
+});
+```
+
+#### `setOnEmpty`
+
+Fires when the search returns no results, enabling custom handling such as showing a placeholder.
+
+
-```kotlin SearchActivity.kt
- binding.cometchatSearch.onEmpty = OnEmpty {
- Log.i(TAG, "onCreate: No Results Found !")
- }
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.onEmpty = OnEmpty {
+ Log.i(TAG, "onCreate: No Results Found !")
+}
```
-
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setOnEmpty(() -> {
+ Log.d(TAG, "onCreate: Empty Result !");
+});
+```
+
-### Filters
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap a conversation result, tap a message result, press back, cause an error, or search for a term with no results) and confirm your custom logic executes.
-#### 1. ConversationsRequestBuilder
+### Global UI Events
-You can set the `ConversationsRequestBuilder` in the Search Component to filter the search result. You can modify the builder as per your specific requirements with multiple options available to know more refer to [ConversationRequestBuilder](/sdk/android/retrieve-conversations).
+The `CometChatSearch` component does not produce any global UI events.
-
-
-```java SearchActivity.java
- binding.cometchatSearch.setConversationsRequestBuilder(
- new ConversationsRequest.ConversationsRequestBuilder().setLimit(10)
- );
-```
+### SDK Events (Real-Time, Automatic)
-
+The `CometChatSearch` component does not listen to any SDK events internally. Search results are fetched on demand when the user types a query.
-
-```kotlin SearchActivity.kt
- binding.cometchatSearch.setConversationsRequestBuilder(
- ConversationsRequest.ConversationsRequestBuilder().setLimit(10)
- )
-```
+## Functionality
-
+Small functional customizations such as toggling visibility of UI elements and configuring search scope.
-
+| Methods | Description | Code |
+| --- | --- | --- |
+| `setEmptyStateVisibility` | Hides the empty state when search returns no results | `.setEmptyStateVisibility(View.GONE);` |
+| `setErrorStateVisibility` | Hides the error state on search failure | `.setErrorStateVisibility(View.GONE);` |
+| `setSearchFilters` | List of filters rendered as chips in the search component | `.setSearchFilters(filters);` |
+| `setInitialSearchFilter` | The filter which will be active by default on load | `.setInitialSearchFilter(UIKitConstants.SearchFilter.MESSAGES);` |
+| `setSearchIn` | List of entities in which the search should be performed | `.setSearchIn(scopes);` |
+| `setHideGroupType` | Hides the group type icon in conversation leading view | `.setHideGroupType(true);` |
+| `setHideUserStatus` | Hides the user's online/offline status indicator | `.setHideUserStatus(true);` |
-***
+- **Verify**: After calling a visibility or functionality method, confirm the corresponding UI element is shown or hidden, or the search scope is correctly applied.
-#### 2. MessagesRequestBuilder
+## Custom View Slots
-You can set the `MessagesRequestBuilder` in the Search Component to filter the search result. You can modify the builder as per your specific requirements with multiple options available to know more refer to [MessagesRequestBuilder](/sdk/android/additional-message-filtering).
+Each slot replaces a section of the default UI. Conversation item slots use the `ConversationsSearchViewHolderListener` pattern (`createView` + `bindView`). Message item slots use the `MessagesSearchViewHolderListener` pattern.
-
-
-```java SearchActivity.java
- binding.cometchatSearch.setMessagesRequestBuilder(
- new MessagesRequest.MessagesRequestBuilder().setLimit(5)
- );
-```
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Conversation item view | `setConversationItemView(ConversationsSearchViewHolderListener)` | Entire conversation item row |
+| Text message item | `setTextMessageItemView(MessagesSearchViewHolderListener)` | Text message item |
+| Image message item | `setImageMessageItemView(MessagesSearchViewHolderListener)` | Image message item |
+| Audio message item | `setAudioMessageItemView(MessagesSearchViewHolderListener)` | Audio message item |
+| Video message item | `setVideoMessageItemView(MessagesSearchViewHolderListener)` | Video message item |
+| Document message item | `setDocumentMessageItemView(MessagesSearchViewHolderListener)` | Document message item |
+| Link message item | `setLinkMessageItemView(MessagesSearchViewHolderListener)` | Link message item |
+| Initial view | `setInitialView(@LayoutRes int)` | Initial state before search |
+| Empty view | `setEmptyView(@LayoutRes int)` | Empty state |
+| Loading view | `setLoadingView(View)` | Loading spinner |
+| Error view | `setErrorView(View)` | Error state |
-
+### `setConversationItemView`
+
+Replace the entire conversation item row in search results.
+
-```kotlin SearchActivity.kt
- binding.cometchatSearch.setMessagesRequestBuilder(
- MessagesRequest.MessagesRequestBuilder().setLimit(5)
- )
-```
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setConversationItemView(object : ConversationsSearchViewHolderListener() {
+ override fun createView(context: Context?, listItem: View?): View? {
+ return layoutInflater.inflate(R.layout.custom_conversation_search_item, null)
+ }
+ override fun bindView(
+ context: Context?,
+ createdView: View?,
+ conversation: Conversation?,
+ holder: RecyclerView.ViewHolder?,
+ conversationList: List?,
+ position: Int
+ ) {
+ val titleTv = createdView?.findViewById(R.id.tv_title)
+ conversation?.let {
+ if (it.conversationType == CometChatConstants.CONVERSATION_TYPE_USER) {
+ titleTv?.text = (it.conversationWith as User).name
+ } else {
+ titleTv?.text = (it.conversationWith as Group).name
+ }
+ }
+ }
+})
+```
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setConversationItemView(new ConversationsSearchViewHolderListener() {
+ @Override
+ public View createView(Context context, View listItem) {
+ LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ return layoutInflater.inflate(R.layout.custom_conversation_search_item, null);
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List conversationList, int position) {
+ android.widget.TextView titleTv = createdView.findViewById(R.id.tv_title);
+ if (conversation != null) {
+ if (conversation.getConversationType().equals(CometChatConstants.CONVERSATION_TYPE_USER)) {
+ titleTv.setText(((User) conversation.getConversationWith()).getName());
+ } else {
+ titleTv.setText(((Group) conversation.getConversationWith()).getName());
+ }
+ }
+ }
+});
+```
+
-***
+> **What this does:** Registers a `ConversationsSearchViewHolderListener` for conversation items in search results. The `createView` method inflates a custom layout, and `bindView` populates it with the conversation name based on whether it's a user or group conversation.
-### Events
+### `setTextMessageItemView`
-[Events](/ui-kit/android/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in multiple locations and are capable of being added or removed.
+Replace the text message item view in search results.
-The `CometChatSearch` component does not produce any events.
+Define a custom layout XML:
-***
+```xml custom_message_item_view.xml lines
+
+
+
+
+
+
+
+```
+
+
+
+```kotlin SearchActivity.kt lines
+binding.cometchatSearch.setTextMessageItemView(object : MessagesSearchViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: View?
+ ): View? {
+ return layoutInflater.inflate(R.layout.custom_message_item_view, null)
+ }
+
+ override fun bindView(
+ context: Context?,
+ createdView: View?,
+ message: TextMessage?,
+ holder: RecyclerView.ViewHolder?,
+ messagesList: List?,
+ position: Int
+ ) {
+ val titleTv = createdView?.findViewById(R.id.tv_sender_name)
+ val messageTv = createdView?.findViewById(R.id.tv_message)
+
+ titleTv?.text = message?.sender?.name
+ messageTv?.text = message?.text
+ }
+})
+```
+
-## Customization
+
+```java SearchActivity.java lines
+binding.cometchatSearch.setTextMessageItemView(new MessagesSearchViewHolderListener() {
+ @Override
+ public View createView(Context context, View listItem) {
+ LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ return layoutInflater.inflate(R.layout.custom_message_item_view, null);
+ }
-To fit your app's design requirements, you can customize the appearance of the `CometChatSearch` component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs.
+ @Override
+ public void bindView(Context context, View createdView, TextMessage message, RecyclerView.ViewHolder holder, List messagesList, int position) {
+ android.widget.TextView titleTv = createdView.findViewById(R.id.tv_sender_name);
+ android.widget.TextView messageTv = createdView.findViewById(R.id.tv_message);
-### Style
+ if (message != null) {
+ titleTv.setText(message.getSender().getName());
+ messageTv.setText(message.getText());
+ }
+ }
+});
+```
+
+
-Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component.
+> **What this does:** Registers a `MessagesSearchViewHolderListener` for text messages. The `createView` method inflates the custom layout, and `bindView` populates the sender name and message text from the `TextMessage` object.
-
+
-```xml themes.xml
-
+
+
+```kotlin lines
+binding.cometchatSearch.setInitialView(R.layout.your_initial_view)
+```
+
-
+
+```java lines
+binding.cometchatSearch.setInitialView(R.layout.your_initial_view);
```
+
+
+
+### `setEmptyView`
+
+Configures a custom view displayed when the search returns no results.
-
-```java
-binding.cometchatSearch.setStyle(R.style.CustomSearchStyle)
+
+```kotlin lines
+binding.cometchatSearch.setEmptyView(R.layout.your_empty_view)
```
+
+
+```java lines
+binding.cometchatSearch.setEmptyView(R.layout.your_empty_view);
+```
+
+
+### `setLoadingView`
+
+Sets a custom loading view displayed when search results are being fetched.
+
-```kotlin
-binding.cometchatSearch.setStyle(R.style.CustomSearchStyle)
+```kotlin lines
+binding.cometchatSearch.setLoadingView(loadingView)
```
-
+
+```java lines
+binding.cometchatSearch.setLoadingView(loadingView);
+```
+
-***
+### `setErrorView`
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_search.xml).
+Defines a custom error state view that appears when an issue occurs while searching.
-### Functionality
+
+
+```kotlin lines
+binding.cometchatSearch.setErrorView(errorView)
+```
+
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can toggle the visibility of UI elements.
+
+```java lines
+binding.cometchatSearch.setErrorView(errorView);
+```
+
+
-Below is a list of customizations along with corresponding code snippets
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the search result items, and the data binding populates correctly for each result.
-| Property | Description | Code |
-| ------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
-| **User** | The UID of the user in whose conversation the search will be performed. | `.setUid(String uid)` |
-| **Group** | The GUID of the group in whose conversation the search will be performed. | `.setGuid(String guid)` |
-| **Hide User Status** | Hides the user's online/offline status indicator. | `.setHideUserStatus(boolean bool)` |
-| **Hide Group Type** | Hides the group type icon in conversation leading view. | `.setHideGroupType(boolean hide)` |
-| **Search Filters** | List of filters to be rendered in the Search component. | `.setSearchFilters(List filters)` |
-| **Initial Search Filter** | The filter which will be active by default on load. | `.setInitialSearchFilter(UIKitConstants.SearchFilter initialSearchFilter)` |
-| **Search In** | List of entities in which the search should be performed. | `.setSearchIn(List scopes)` |
-| **Initial View** | Custom view to be shown when CometChat Search is rendered & no search is performed. | `.setInitialView(@LayoutRes int initialView)` |
-| **Loading View** | A custom component to display during the loading state. | `.setLoadingView(View loadingView)` |
-| **Empty View** | A custom component to display when there are no conversations available. | `.setEmptyView(@LayoutRes int emptyView)` |
-| **Error View** | A custom component to display when an error occurs. | `.setErrorView(View errorView)` |
+## Common Patterns
-### Advanced
+### Messages-only search
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
+
+
+```kotlin lines
+binding.cometchatSearch.setSearchFilters(
+ listOf(UIKitConstants.SearchFilter.MESSAGES)
+)
+binding.cometchatSearch.setInitialSearchFilter(UIKitConstants.SearchFilter.MESSAGES)
+```
+
-***
+
+```java lines
+binding.cometchatSearch.setSearchFilters(
+ Arrays.asList(UIKitConstants.SearchFilter.MESSAGES)
+);
+binding.cometchatSearch.setInitialSearchFilter(UIKitConstants.SearchFilter.MESSAGES);
+```
+
+
-#### ConversationItemView
+### Filter by message type
-With this function, you can assign a custom list item view to an conversation in the search result. For more information, refer to the [itemView](/ui-kit/android/conversations#itemview) prop of the `CometChatConversations` component.
+
+
+```kotlin lines
+binding.cometchatSearch.setMessagesRequestBuilder(
+ MessagesRequest.MessagesRequestBuilder().setLimit(10)
+)
+```
+
-#### ConversationLeadingView
+
+```java lines
+binding.cometchatSearch.setMessagesRequestBuilder(
+ new MessagesRequest.MessagesRequestBuilder().setLimit(10)
+);
+```
+
+
-With this function, you can assign a custom leading view of an conversation in the search result. For more information, refer to the [leadingView](/ui-kit/android/conversations#leadingview) prop of the `CometChatConversations` component.
+### Scope search to a specific user
-#### ConversationTitleView
+
+
+```kotlin lines
+binding.cometchatSearch.setUid("user123")
+```
+
-With this function, you can assign a custom title view to an conversation in the search result. For more information, refer to the [titleView](/ui-kit/android/conversations#titleview) prop of the `CometChatConversations` component.
+
+```java lines
+binding.cometchatSearch.setUid("user123");
+```
+
+
-#### ConversationSubtitleView
+### Scope search to a specific group
-With this function, you can assign a custom subtitle view to an conversation in the search result. For more information, refer to the [subtitleView](/ui-kit/android/conversations#subtitleview) prop of the `CometChatConversations` component.
+
+
+```kotlin lines
+binding.cometchatSearch.setGuid("group123")
+```
+
-#### ConversationTrailingView
+
+```java lines
+binding.cometchatSearch.setGuid("group123");
+```
+
+
-With this function, you can assign a custom trailing view to an conversation in the search result. For more information, refer to the [trailingView](/ui-kit/android/conversations#trailingview) prop of the `CometChatConversations` component.
+## Advanced Methods
-#### MessageItemView
+### Search Scope
-With message item view functions, you can assign custom views to different types of messages in the search result. For more information, refer to the [itemView](/ui-kit/android/messages#itemview) prop of the `CometChatMessages` component.
+#### `setUid`
-Here's how you can override the default message item view with a custom one for text messages:
+Scopes the search to a specific user's conversation.
-
-```xml
-
-
-
-
-
-
-
+
+```kotlin lines
+binding.cometchatSearch.setUid("user123")
```
-
+
+```java lines
+binding.cometchatSearch.setUid("user123");
+```
+
+#### `setGuid`
+
+Scopes the search to a specific group's conversation.
+
+
+```kotlin lines
+binding.cometchatSearch.setGuid("group123")
+```
+
+
-```java
- binding.cometchatSearch.setTextMessageItemView(new MessagesSearchViewHolderListener() {
- @Override
- public View createView(Context context, View listItem) {
- // Inflate the custom message item view
- LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- return layoutInflater.inflate(R.layout.custom_message_item_view, null);
- }
+```java lines
+binding.cometchatSearch.setGuid("group123");
+```
+
+
- @Override
- public void bindView(Context context, View createdView, TextMessage message, RecyclerView.ViewHolder holder, List messagesList, int position) {
- // Find the TextView elements
- android.widget.TextView titleTv = createdView.findViewById(R.id.tv_sender_name);
- android.widget.TextView messageTv = createdView.findViewById(R.id.tv_message);
-
- // Bind the message data to the views
- if (message != null) {
- titleTv.setText(message.getSender().getName());
- messageTv.setText(message.getText());
- }
- }
- });
+### Request Builders
+
+#### `setConversationsRequestBuilder`
+
+Sets a `ConversationsRequest.ConversationsRequestBuilder` to filter conversation search results. Pass the builder instance — not the result of `.build()`. For all available builder options, refer to the [ConversationRequestBuilder](/sdk/android/retrieve-conversations) documentation.
+
+
+
+```kotlin lines
+binding.cometchatSearch.setConversationsRequestBuilder(
+ ConversationsRequest.ConversationsRequestBuilder().setLimit(10)
+)
```
+
+
+```java lines
+binding.cometchatSearch.setConversationsRequestBuilder(
+ new ConversationsRequest.ConversationsRequestBuilder().setLimit(10)
+);
+```
+
+
+#### `setMessagesRequestBuilder`
+Sets a `MessagesRequest.MessagesRequestBuilder` to filter message search results. For all available builder options, refer to the [MessagesRequestBuilder](/sdk/android/additional-message-filtering) documentation.
+
+
-```kotlin
- binding.cometchatSearch.setTextMessageItemView(object : MessagesSearchViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: View?
- ): View? {
- return layoutInflater.inflate(R.layout.custom_message_item_view, null)
- }
+```kotlin lines
+binding.cometchatSearch.setMessagesRequestBuilder(
+ MessagesRequest.MessagesRequestBuilder().setLimit(5)
+)
+```
+
- override fun bindView(
- context: Context?,
- createdView: View?,
- message: TextMessage?,
- holder: RecyclerView.ViewHolder?,
- messagesList: List?,
- position: Int
- ) {
- val titleTv = createdView?.findViewById(R.id.tv_sender_name)
- val messageTv = createdView?.findViewById(R.id.tv_message)
-
- titleTv?.text = message?.sender?.name
- messageTv?.text = message?.text
- }
- })
+
+```java lines
+binding.cometchatSearch.setMessagesRequestBuilder(
+ new MessagesRequest.MessagesRequestBuilder().setLimit(5)
+);
```
-It should look like this in the app:
+### Text Formatters
-
-
-
+#### `setTextFormatters`
-Bellow is the list of message item view functions available for customization:
+Enables developers to define and apply text formatters that dynamically modify or transform message content before rendering it in the UI. Text formatters can be used for:
-| Function | Message Type |
-| -------------------------------- | ---------------------|
-| **setTextMessageItemView** | Text Message |
-| **setImageMessageItemView** | Image Message |
-| **setVideoMessageItemView** | Video Message |
-| **setAudioMessageItemView** | Audio Message |
-| **setDocumentMessageItemView** | Document Message |
-| **setLinkMessageItemView** | Link Message |
+* Automatically converting URLs into clickable links
+* Applying Markdown or rich text styling
+* Replacing certain words or patterns with emojis or predefined text
+* Censoring specific words for moderation
-#### DateTime Formatters
+For implementation details, refer to the [MentionsFormatter Guide](/ui-kit/android/mentions-formatter-guide).
-#### setDateTimeFormatter
+### Date/Time Formatting
-By providing a custom implementation of the DateTimeFormatterCallback, you can configure how time and date values are displayed. This ensures consistent formatting for labels such as "Today", "Yesterday", "X minutes ago", and more.
+#### `setDateTimeFormatter`
-Each method in the interface corresponds to a specific case:
+Provides a custom implementation of `DateTimeFormatterCallback` to configure how time and date values are displayed in search results.
-`time(long timestamp)` → Custom full timestamp format
+
+
+```kotlin lines
+import java.text.SimpleDateFormat
+import java.util.*
+
+binding.cometchatSearch.setDateTimeFormatter(object : DateTimeFormatterCallback {
-`today(long timestamp)` → Called when a message is from today
+ private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
+ private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
-`yesterday(long timestamp)` → Called for yesterday’s messages
+ override fun time(timestamp: Long): String {
+ return fullTimeFormatter.format(Date(timestamp))
+ }
-`lastWeek(long timestamp)` → Messages from the past week
+ override fun today(timestamp: Long): String {
+ return "Today"
+ }
-`otherDays(long timestamp)` → Older messages
+ override fun yesterday(timestamp: Long): String {
+ return "Yesterday"
+ }
-`minute(long timestamp)` / `hour(long timestamp)` → Exact time unit
+ override fun lastWeek(timestamp: Long): String {
+ return "Last Week"
+ }
-`minutes(long diffInMinutesFromNow, long timestamp)` → e.g., "5 minutes ago"
+ override fun otherDays(timestamp: Long): String {
+ return dateFormatter.format(Date(timestamp))
+ }
-`hours(long diffInHourFromNow, long timestamp)` → e.g., "2 hours ago"
+ override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String {
+ return "$diffInMinutesFromNow mins ago"
+ }
+
+ override fun hours(diffInHourFromNow: Long, timestamp: Long): String {
+ return "$diffInHourFromNow hrs ago"
+ }
+})
+```
+
-
-```java
+```java lines
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
+binding.cometchatSearch.setDateTimeFormatter(new DateTimeFormatterCallback() {
-cometChatSearch.setDateTimeFormatter(new DateTimeFormatterCallback() {
+ private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault());
+ private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault());
- private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault());
- private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault());
-
- @Override
- public String time(long timestamp) {
- return fullTimeFormatter.format(new Date(timestamp));
- }
+ @Override
+ public String time(long timestamp) {
+ return fullTimeFormatter.format(new Date(timestamp));
+ }
- @Override
- public String today(long timestamp) {
- return "Today";
- }
+ @Override
+ public String today(long timestamp) {
+ return "Today";
+ }
- @Override
- public String yesterday(long timestamp) {
- return "Yesterday";
- }
+ @Override
+ public String yesterday(long timestamp) {
+ return "Yesterday";
+ }
- @Override
- public String lastWeek(long timestamp) {
- return "Last Week";
- }
+ @Override
+ public String lastWeek(long timestamp) {
+ return "Last Week";
+ }
- @Override
- public String otherDays(long timestamp) {
- return dateFormatter.format(new Date(timestamp));
- }
+ @Override
+ public String otherDays(long timestamp) {
+ return dateFormatter.format(new Date(timestamp));
+ }
- @Override
- public String minutes(long diffInMinutesFromNow, long timestamp) {
- return diffInMinutesFromNow + " mins ago";
- }
+ @Override
+ public String minutes(long diffInMinutesFromNow, long timestamp) {
+ return diffInMinutesFromNow + " mins ago";
+ }
- @Override
- public String hours(long diffInHourFromNow, long timestamp) {
- return diffInHourFromNow + " hrs ago";
- }
- });
+ @Override
+ public String hours(long diffInHourFromNow, long timestamp) {
+ return diffInHourFromNow + " hrs ago";
+ }
+});
```
-
+
-
-```kotlin
-import java.text.SimpleDateFormat
-import java.util.*
+> **What this does:** Provides a custom date/time formatter that displays "Today", "Yesterday", "Last Week" for recent messages, a "dd MMM yyyy" format for older messages, and relative time strings like "5 mins ago" or "2 hrs ago" for recent activity.
-cometChatSearch.setDateTimeFormatterCallback(object : DateTimeFormatterCallback {
+### Other Advanced Methods
- private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
- private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
+| Method | Type | Description |
+| --- | --- | --- |
+| `setMentionAllLabelId` | `String id, String mentionAllLabel` | Sets a custom label for the "mention all" feature for a specific ID |
+| `setHintText` | `String` | Sets the hint text displayed in the search bar |
- override fun time(timestamp: Long): String {
- return fullTimeFormatter.format(Date(timestamp))
- }
+## Style
- override fun today(timestamp: Long): String {
- return "Today"
- }
+The component uses XML theme styles. Define a custom style with parent `CometChatSearchStyle` in `themes.xml`, then apply with `setStyle()`.
- override fun yesterday(timestamp: Long): String {
- return "Yesterday"
- }
+
+
+
- override fun lastWeek(timestamp: Long): String {
- return "Last Week"
- }
+```xml themes.xml lines
+
-#### Text Formatters
+
+```
-#### setTextFormatters
+> **What this does:** Defines a custom search style that sets a light purple background color (`#EDEAFA`) for the search component, conversation items, and message items, and applies a Times New Roman font to all text elements including filter chips, section headers, conversation titles/subtitles, message titles/subtitles, timestamps, "see more" text, and the search bar.
-This method enables developers to define and apply text formatters that dynamically modify or transform message content before rendering it in the UI. Text formatters can be used for purposes such as:
+
+
+```kotlin lines
+binding.cometchatSearch.setStyle(R.style.CustomSearchStyle)
+```
+
-* Automatically converting URLs into clickable links
-* Applying Markdown or rich text styling
-* Replacing certain words or patterns with emojis or predefined text
-* Censoring specific words for moderation
+
+```java lines
+binding.cometchatSearch.setStyle(R.style.CustomSearchStyle);
+```
+
+
-By utilizing this method, developers can enhance readability, usability, and compliance with content guidelines. [MentionsFormatter Guide](/ui-kit/android/mentions-formatter-guide)
\ No newline at end of file
+To view all available style attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_search.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+**Search Bar**
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setSearchBarBackgroundColor` | `@ColorInt int` | Background color of the search bar |
+| `setSearchBarStrokeWidth` | `@Dimension int` | Stroke width of the search bar border |
+| `setSearchBarStrokeColor` | `@ColorInt int` | Stroke color of the search bar border |
+| `setSearchBarCornerRadius` | `@Dimension int` | Corner radius of the search bar |
+| `setSearchBarTextColor` | `@ColorInt int` | Text color of the search bar input |
+| `setSearchBarTextAppearance` | `@StyleRes int` | Text appearance of the search bar input |
+| `setSearchBarHintTextColor` | `@ColorInt int` | Hint text color of the search bar |
+| `setBackIcon` | `Drawable` | Custom back icon drawable |
+| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon |
+| `setClearIcon` | `Drawable` | Custom clear icon drawable |
+| `setClearIconTint` | `@ColorInt int` | Tint color for the clear icon |
+| `setSearchIcon` | `Drawable` | Custom search icon drawable |
+| `setSearchIconTint` | `@ColorInt int` | Tint color for the search icon |
+
+**Filter Chips**
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setFilterChipBackgroundColor` | `@ColorInt int` | Background color of filter chips |
+| `setFilterChipSelectedBackgroundColor` | `@ColorInt int` | Background color of selected filter chips |
+| `setFilterChipTextColor` | `@ColorInt int` | Text color of filter chips |
+| `setFilterChipSelectedTextColor` | `@ColorInt int` | Text color of selected filter chips |
+| `setFilterChipTextAppearance` | `@StyleRes int` | Text appearance of filter chips |
+| `setFilterChipStrokeColor` | `@ColorInt int` | Stroke color of filter chips |
+| `setFilterChipSelectedStrokeColor` | `@ColorInt int` | Stroke color of selected filter chips |
+| `setFilterChipStrokeWidth` | `@Dimension int` | Stroke width of filter chips |
+| `setFilterChipCornerRadius` | `@Dimension int` | Corner radius of filter chips |
+
+**Section Headers**
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSectionHeaderTextColor` | `@ColorInt int` | Text color for section headers |
+| `setSectionHeaderTextAppearance` | `@StyleRes int` | Text appearance for section headers |
+| `setSectionHeaderBackgroundColor` | `@ColorInt int` | Background color for section headers |
+
+**Conversation Items**
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setConversationItemBackgroundColor` | `@ColorInt int` | Background color for conversation items |
+| `setConversationTitleTextColor` | `@ColorInt int` | Text color for conversation titles |
+| `setConversationTitleTextAppearance` | `@StyleRes int` | Text appearance for conversation titles |
+| `setConversationSubtitleTextColor` | `@ColorInt int` | Text color for conversation subtitles |
+| `setConversationSubtitleTextAppearance` | `@StyleRes int` | Text appearance for conversation subtitles |
+| `setConversationTimestampTextColor` | `@ColorInt int` | Text color for conversation timestamps |
+| `setConversationTimestampTextAppearance` | `@StyleRes int` | Text appearance for conversation timestamps |
+
+**Message Items**
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setMessageItemBackgroundColor` | `@ColorInt int` | Background color for message items |
+| `setMessageTitleTextColor` | `@ColorInt int` | Text color for message titles |
+| `setMessageTitleTextAppearance` | `@StyleRes int` | Text appearance for message titles |
+| `setMessageSubtitleTextColor` | `@ColorInt int` | Text color for message subtitles |
+| `setMessageSubtitleTextAppearance` | `@StyleRes int` | Text appearance for message subtitles |
+| `setMessageTimestampTextColor` | `@ColorInt int` | Text color for message timestamps |
+| `setMessageTimestampTextAppearance` | `@StyleRes int` | Text appearance for message timestamps |
+| `setMessageLinkTextColor` | `@ColorInt int` | Text color for links in messages |
+| `setMessageLinkTextAppearance` | `@StyleRes int` | Text appearance for links in messages |
+
+**Other Style Properties**
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setAvatarStyle` | `@StyleRes int` | Style for avatars in search results |
+| `setBadgeStyle` | `@StyleRes int` | Style for badges in search results |
+| `setSeeMoreTextColor` | `@ColorInt int` | Text color for "See more" links |
+| `setSeeMoreTextAppearance` | `@StyleRes int` | Text appearance for "See more" links |
+| `setDateSeparatorTextColor` | `@ColorInt int` | Text color for date separators |
+| `setDateSeparatorBackgroundColor` | `@ColorInt int` | Background color for date separators |
+| `setDateSeparatorTextAppearance` | `@StyleRes int` | Text appearance for date separators |
+| `setEmptyStateTextColor` | `@ColorInt int` | Title text color for the empty state |
+| `setEmptyStateTextAppearance` | `@StyleRes int` | Title text appearance for the empty state |
+| `setEmptyStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the empty state |
+| `setEmptyStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the empty state |
+| `setEmptyStateIcon` | `Drawable` | Icon for the empty state |
+| `setEmptyStateIconTint` | `@ColorInt int` | Tint for the empty state icon |
+| `setErrorStateTextColor` | `@ColorInt int` | Title text color for the error state |
+| `setErrorStateTextAppearance` | `@StyleRes int` | Title text appearance for the error state |
+| `setErrorStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the error state |
+| `setErrorStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the error state |
+| `setErrorStateIcon` | `Drawable` | Icon for the error state |
+| `setErrorStateIconTint` | `@ColorInt int` | Tint for the error state icon |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override behavior on conversation tap | Activity/Fragment | `setOnConversationClicked` | `setOnConversationClicked { v, pos, conv -> ... }` |
+| Override behavior on message tap | Activity/Fragment | `setOnMessageClicked` | `setOnMessageClicked { v, pos, msg -> ... }` |
+| Override back press behavior | Activity/Fragment | `setOnBackPressListener` | `setOnBackPressListener { ... }` |
+| Scope search to a user | Activity/Fragment | `setUid(String)` | `.setUid("user123")` |
+| Scope search to a group | Activity/Fragment | `setGuid(String)` | `.setGuid("group123")` |
+| Hide user online status | Activity/Fragment | `setHideUserStatus(boolean)` | `.setHideUserStatus(true)` |
+| Hide group type icon | Activity/Fragment | `setHideGroupType(boolean)` | `.setHideGroupType(true)` |
+| Set search filters | Activity/Fragment | `setSearchFilters(List)` | `.setSearchFilters(filters)` |
+| Set initial active filter | Activity/Fragment | `setInitialSearchFilter(SearchFilter)` | `.setInitialSearchFilter(UIKitConstants.SearchFilter.MESSAGES)` |
+| Set search scope | Activity/Fragment | `setSearchIn(List)` | `.setSearchIn(scopes)` |
+| Filter conversation results | Activity/Fragment | `setConversationsRequestBuilder` | See Request Builders code above |
+| Filter message results | Activity/Fragment | `setMessagesRequestBuilder` | See Request Builders code above |
+| Custom conversation item view | Activity/Fragment | `setConversationItemView(ConversationsSearchViewHolderListener)` | See `setConversationItemView` code above |
+| Custom text message item view | Activity/Fragment | `setTextMessageItemView(MessagesSearchViewHolderListener)` | See `setTextMessageItemView` code above |
+| Custom image message item view | Activity/Fragment | `setImageMessageItemView(MessagesSearchViewHolderListener)` | See `setTextMessageItemView` pattern |
+| Custom video message item view | Activity/Fragment | `setVideoMessageItemView(MessagesSearchViewHolderListener)` | See `setTextMessageItemView` pattern |
+| Custom audio message item view | Activity/Fragment | `setAudioMessageItemView(MessagesSearchViewHolderListener)` | See `setTextMessageItemView` pattern |
+| Custom document message item view | Activity/Fragment | `setDocumentMessageItemView(MessagesSearchViewHolderListener)` | See `setTextMessageItemView` pattern |
+| Custom link message item view | Activity/Fragment | `setLinkMessageItemView(MessagesSearchViewHolderListener)` | See `setTextMessageItemView` pattern |
+| Custom initial view | Activity/Fragment | `setInitialView(@LayoutRes int)` | `.setInitialView(R.layout.your_initial_view)` |
+| Custom loading view | Activity/Fragment | `setLoadingView(View)` | `.setLoadingView(loadingView)` |
+| Custom empty view | Activity/Fragment | `setEmptyView(@LayoutRes int)` | `.setEmptyView(R.layout.your_empty_view)` |
+| Custom error view | Activity/Fragment | `setErrorView(View)` | `.setErrorView(errorView)` |
+| Empty state visibility | Activity/Fragment | `setEmptyStateVisibility(int)` | `.setEmptyStateVisibility(View.GONE)` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE)` |
+| Change colors, fonts, spacing | `themes.xml` | `CometChatSearchStyle` | `#EDEAFA` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `binding.cometchatSearch.setStyle(R.style.CustomSearchStyle)` |
+| Search bar background | Activity/Fragment | `setSearchBarBackgroundColor` | `.setSearchBarBackgroundColor(color)` |
+| Filter chip colors | Activity/Fragment | `setFilterChip*` methods | `.setFilterChipBackgroundColor(color)` |
+| Section header style | Activity/Fragment | `setSectionHeader*` methods | `.setSectionHeaderTextColor(color)` |
+| Conversation item style | Activity/Fragment | `setConversation*` methods | `.setConversationTitleTextColor(color)` |
+| Message item style | Activity/Fragment | `setMessage*` methods | `.setMessageTitleTextColor(color)` |
+| Date/time formatting | Activity/Fragment | `setDateTimeFormatter(DateTimeFormatterCallback)` | See `setDateTimeFormatter` code above |
+| Text formatters | Activity/Fragment | `setTextFormatters(List)` | See Text Formatters section |
+| Search bar hint text | Activity/Fragment | `setHintText(String)` | `.setHintText("Search...")` |
+| Mention-all label | Activity/Fragment | `setMentionAllLabelId(String, String)` | `.setMentionAllLabelId(id, label)` |
+| Callback on messages loaded | Activity/Fragment | `setOnLoadMessages(OnLoad)` | `.setOnLoadMessages { list -> ... }` |
+| Callback on conversations loaded | Activity/Fragment | `setOnLoadConversations(OnLoad)` | `.setOnLoadConversations { list -> ... }` |
+
+## Accessibility
+
+The component renders a search bar with filter chips and scrollable result lists for conversations and messages. The search input is focusable and supports keyboard input. Filter chips respond to tap gestures and announce their selected state.
+
+For custom views provided via `setConversationItemView` or message item view setters, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Search returns no results despite existing data | Verify that a user is logged in with `CometChatUIKit.login()` before displaying the component. The component fetches data for the logged-in user only. |
+| Search scoped to wrong conversation | If you called `setUid()` or `setGuid()`, verify the UID or GUID matches an existing user or group. If both are set, the last one called takes precedence. |
+| Custom style not visible | Verify the style parent is `CometChatSearchStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| `setOnConversationClicked` not firing | Ensure you set the listener before the component loads data. If the listener is set after results are displayed, it may not attach to existing items. |
+| `setOnMessageClicked` not firing | Ensure you set the listener before the component loads data. If the listener is set after results are displayed, it may not attach to existing items. |
+| Filters not applied to search results | Ensure you call `setConversationsRequestBuilder()` or `setMessagesRequestBuilder()` on the `CometChatSearch` instance after creating and configuring the builder. |
+| Custom message item view not rendering | Ensure `createView` in your `MessagesSearchViewHolderListener` returns a valid inflated `View`, not `null`. If `createView` returns `null`, the default view is used. |
+| Date/time format not changing | Use `setDateTimeFormatter()` to provide a custom `DateTimeFormatterCallback`. Verify you are calling the method on the correct component instance. |
+| Initial view not showing | Ensure you pass a valid `@LayoutRes` resource ID to `setInitialView()`. The view displays only when no search has been performed. |
+
+## FAQ
+
+**Q: Can I scope the search to a specific user or group conversation?**
+**A:** Yes. Call `setUid(String uid)` to scope search to a specific user's conversation, or `setGuid(String guid)` to scope search to a specific group's conversation.
+
+**Q: Does `CometChatSearch` emit any events?**
+**A:** No. The `CometChatSearch` component does not produce any events. Use the action callbacks (`setOnConversationClicked`, `setOnMessageClicked`, etc.) to respond to user interactions.
+
+**Q: How do I customize the view for a specific message type in search results?**
+**A:** Use the corresponding message item view setter (e.g., `setTextMessageItemView`, `setImageMessageItemView`) with a `MessagesSearchViewHolderListener` that implements `createView` and `bindView`.
+
+**Q: How do I filter which conversations or messages appear in search results?**
+**A:** Use `setConversationsRequestBuilder()` with a configured `ConversationsRequest.ConversationsRequestBuilder` for conversation results, and `setMessagesRequestBuilder()` with a configured `MessagesRequest.MessagesRequestBuilder` for message results.
+
+**Q: How do I customize conversation items in the search results?**
+**A:** Use `setConversationItemView` with a `ConversationsSearchViewHolderListener` that implements `createView` and `bindView` to replace the entire conversation item row.
+
+## Next Steps
+
+- [Conversations component](/ui-kit/android/conversations)
+- [Users component](/ui-kit/android/users)
+- [Groups component](/ui-kit/android/groups)
+- [Message list component](/ui-kit/android/message-list)
\ No newline at end of file
diff --git a/ui-kit/android/shortcut-formatter-guide.mdx b/ui-kit/android/shortcut-formatter-guide.mdx
index 2f3f006aa..64917698e 100644
--- a/ui-kit/android/shortcut-formatter-guide.mdx
+++ b/ui-kit/android/shortcut-formatter-guide.mdx
@@ -2,44 +2,173 @@
title: "ShortCut Formatter"
---
-## Introduction
+`ShortCutFormatter` extends `CometChatTextFormatter` to provide a mechanism for handling message shortcuts within `CometChatMessageComposer`, enabling users to type a tracking character and receive shortcut suggestions fetched from the CometChat message-shortcuts extension.
-The ShortCutFormatter class extends the CometChatTextFormatter class to provide a mechanism for handling shortcuts within messages. This guide will walk you through the process of using ShortCutFormatter to implement shortcut extensions in your CometChat application.
+## When to Use This
-## Setup
+- You want to add shortcut text expansion to the message composer (e.g., typing `!hi` expands to a predefined message)
+- You need to fetch and display message shortcuts from the CometChat `message-shortcuts` extension
+- You want to show suggestion items in the composer when a user types a shortcut trigger character
+- You need to create a custom text formatter that extends `CometChatTextFormatter`
+- You want to integrate shortcut functionality alongside other text formatters in `CometChatMessageComposer`
-1. **Create the ShortCutFormatter Class**: Define the `ShortCutFormatter` class by extending the `CometChatTextFormatter` class.
+## Prerequisites
+
+- CometChat Android UI Kit dependency added to your project
+- `CometChatUIKit.init()` called and completed
+- A logged-in CometChat user
+- The `message-shortcuts` CometChat extension enabled on your app
+- Familiarity with the [CometChatMessageComposer](/ui-kit/android/message-composer) component
+
+## Quick Start
+
+1. Create a `ShortCutFormatter` class that extends `CometChatTextFormatter` with `'!'` as the tracking character:
+
+```kotlin
+class ShortCutFormatterKotlin : CometChatTextFormatter('!') {
+ private val messageShortcuts: HashMap = HashMap()
+ private val shortcuts: MutableList = ArrayList()
+}
+```
+
```java
- public class ShortCutFormatter extends CometChatTextFormatter {
- // Class implementation
- private HashMap messageShortcuts;
- private List shortcuts;
- }
+public class ShortCutFormatter extends CometChatTextFormatter {
+ private HashMap messageShortcuts;
+ private List shortcuts;
+}
```
+
+
+
+> **What this does:** Defines a `ShortCutFormatter` class that extends `CometChatTextFormatter` with `'!'` as the tracking character. The class declares a `HashMap` to store shortcut key-value pairs and a list to hold `SuggestionItem` objects for display.
+
+2. Add a constructor that calls `prepareShortCuts()` to fetch shortcuts from the server, and override the `search()` and `onScrollToBottom()` methods (see the Implementation section for full code).
+
+3. Initialize an instance of `ShortCutFormatter`:
+
+
+```kotlin
+val shortCutFormatter = ShortCutFormatter()
+```
+
+```java
+ShortCutFormatter shortCutFormatter = new ShortCutFormatter();
+```
+
+
+
+> **What this does:** Creates a new `ShortCutFormatter` instance. The constructor calls `prepareShortCuts()`, which fetches message shortcuts from the CometChat `message-shortcuts` extension.
+
+4. Get the existing text formatters from `CometChatUIKit.getDataSource()`, add the `ShortCutFormatter`, and pass the list to `CometChatMessageComposer` via `setTextFormatters()`:
+
```kotlin
+val cometChatMessageComposer: CometChatMessageComposer =
+ findViewById(R.id.composer)
+
+val cometChatTextFormatters = CometChatUIKit.getDataSource().getTextFormatters(this)
+cometChatTextFormatters.add(ShortCutFormatter())
+cometChatMessageComposer.setTextFormatters(cometChatTextFormatters)
+```
+
+
+```java
+CometChatMessageComposer cometChatMessageComposer = findViewById(R.id.composer);
+
+List cometChatTextFormatters = CometChatUIKit.getDataSource().getTextFormatters(this);
+cometChatTextFormatters.add(new ShortCutFormatter());
+cometChatMessageComposer.setTextFormatters(cometChatTextFormatters);
+```
+
+
+
+> **What this does:** Retrieves the default text formatters from `CometChatUIKit.getDataSource()`, adds the `ShortCutFormatter` to the list, and passes the combined list to `CometChatMessageComposer` via `setTextFormatters()`. The composer now supports both the default formatters and the shortcut formatter.
+
+## Core Concepts
+
+### The Text Formatter Extension Pattern
+
+`ShortCutFormatter` extends `CometChatTextFormatter`, which is the base class for all text formatters in the CometChat UI Kit. By extending this class, you can create custom formatters that plug into any component accepting text formatters via `setTextFormatters()`.
+
+The key elements of the extension pattern:
+
+- **Tracking character**: The constructor passes a character (in this case `'!'`) to `CometChatTextFormatter`. When the user types this character in the composer, the formatter activates and begins matching input against registered shortcuts.
+- **`search()` method**: Override this method to define how the formatter matches user input against available shortcuts. The method receives the current query string and updates the suggestion list.
+- **`SuggestionItem` list**: The formatter populates a list of `SuggestionItem` objects and passes them to the UI via `setSuggestionItemList()` (Java) or `suggestionItemList.value` (Kotlin). The composer displays these as selectable suggestions.
+- **`onScrollToBottom()` method**: Override this method to handle scroll-to-bottom events in the suggestion list. This is required by the `CometChatTextFormatter` base class.
+
+### How Shortcuts Work
+
+1. On initialization, `prepareShortCuts()` calls `CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", ...)` to fetch shortcut key-value pairs from the server.
+2. The fetched shortcuts are stored in a `HashMap` where keys are shortcut triggers (e.g., `!hi`) and values are the expanded text.
+3. When the user types the tracking character `'!'` followed by text, the `search()` method checks if the combined string matches a key in the shortcuts map.
+4. If a match is found, a `SuggestionItem` is created showing the shortcut and its expansion (e.g., `!hi => Hello, how are you?`), and the suggestion list is updated.
+
+## Implementation
+
+### Class Creation
+
+What you are changing: Creating the `ShortCutFormatter` class that extends `CometChatTextFormatter` to handle message shortcuts.
+
+- **Where**: A new class file in your project (e.g., `ShortCutFormatter.java` or `ShortCutFormatterKotlin.kt`)
+- **Applies to**: `CometChatMessageComposer` (via `setTextFormatters()`)
+- **Default behavior**: Without this class, the message composer has no shortcut expansion functionality
+- **Override**: Create a class extending `CometChatTextFormatter` with `'!'` as the tracking character, and declare a `HashMap` for shortcuts and a `List` for `SuggestionItem` objects
+
+**Code:**
+
+
+
+```kotlin lines
class ShortCutFormatterKotlin : CometChatTextFormatter('!') {
// Class implementation
private val messageShortcuts: HashMap = HashMap()
private val shortcuts: MutableList = ArrayList()
}
```
-
-
+
+```java lines
+ public class ShortCutFormatter extends CometChatTextFormatter {
+ // Class implementation
+ private HashMap messageShortcuts;
+ private List shortcuts;
+ }
+```
+
-2. **Constructor**: Initialize the `messageShortcuts` map and `shortcuts` list in the constructor.
+> **What this does:** Defines the `ShortCutFormatter` class extending `CometChatTextFormatter` with `'!'` as the tracking character. It declares a `HashMap` to store shortcut key-value pairs and a `List` to hold suggestion items displayed in the composer.
+
+- **Verify**: The class compiles without errors and extends `CometChatTextFormatter` with the `'!'` character passed to the superclass constructor.
+
+### Constructor
+
+What you are changing: Initializing the shortcuts map and list, and triggering the server fetch for shortcuts.
+
+- **Where**: The constructor of `ShortCutFormatter` (Java) or the `init` block of `ShortCutFormatterKotlin` (Kotlin)
+- **Applies to**: `ShortCutFormatter` / `ShortCutFormatterKotlin`
+- **Default behavior**: Without the constructor, the `messageShortcuts` map and `shortcuts` list are not initialized, and shortcuts are not fetched from the server
+- **Override**: In Java, initialize `messageShortcuts` and `shortcuts` in the constructor and call `prepareShortCuts()`. In Kotlin, call `prepareShortCuts()` in the `init` block (properties are initialized at declaration)
+
+**Code:**
+
+```kotlin lines
+ init {
+ prepareShortCuts()
+ }
+```
+
-```java
+```java lines
public ShortCutFormatter() {
super('!');
messageShortcuts = new HashMap<>();
@@ -47,57 +176,27 @@ class ShortCutFormatterKotlin : CometChatTextFormatter('!') {
shortcuts = new ArrayList<>();
}
```
-
-
-
-
-```kotlin
- init {
- prepareShortCuts()
- }
-```
-
-
-3. **Prepare Shortcuts**: Implement the `prepareShortCuts()` method to fetch shortcuts from the server using CometChat extension.
+> **What this does:** In Kotlin, the `init` block calls `prepareShortCuts()` to fetch shortcuts from the server on initialization. In Java, the constructor calls `super('!')` to set the tracking character, initializes the `messageShortcuts` HashMap and `shortcuts` ArrayList, and calls `prepareShortCuts()` to fetch shortcuts.
-
-
-```java
-private void prepareShortCuts() {
- // Implementation to fetch shortcuts from server
- CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", null, new CometChat.CallbackListener() {
- @Override
- public void onSuccess(JSONObject responseObject) {
+- **Verify**: After constructing a `ShortCutFormatter` instance, the `prepareShortCuts()` method is called, which initiates a network request to fetch message shortcuts from the CometChat `message-shortcuts` extension.
- Iterator keysItr;
- try {
- JSONObject shortcutObject = responseObject.getJSONObject("data").getJSONObject("shortcuts");
- keysItr = shortcutObject.keys();
+### Prepare Shortcuts
- while (keysItr.hasNext()) {
- String key = keysItr.next();
- String value = shortcutObject.getString(key);
- messageShortcuts.put(key, value);
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
+What you are changing: Implementing the method that fetches shortcut key-value pairs from the CometChat `message-shortcuts` extension.
- @Override
- public void onError(CometChatException e) {
- }
- });
-}
-```
+- **Where**: The `prepareShortCuts()` method inside `ShortCutFormatter` / `ShortCutFormatterKotlin`
+- **Applies to**: `ShortCutFormatter` / `ShortCutFormatterKotlin`
+- **Default behavior**: Without this method, the `messageShortcuts` map remains empty and no shortcuts are available for matching
+- **Override**: Implement `prepareShortCuts()` to call `CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", ...)` and populate the `messageShortcuts` map from the JSON response
-
+**Code:**
+
-```kotlin
+```kotlin lines
private fun prepareShortCuts() {
CometChat.callExtension(
"message-shortcuts",
@@ -125,34 +224,57 @@ private fun prepareShortCuts() {
})
}
```
-
+
+```java lines
+private void prepareShortCuts() {
+ // Implementation to fetch shortcuts from server
+ CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", null, new CometChat.CallbackListener() {
+ @Override
+ public void onSuccess(JSONObject responseObject) {
-
+ Iterator keysItr;
+ try {
+ JSONObject shortcutObject = responseObject.getJSONObject("data").getJSONObject("shortcuts");
+ keysItr = shortcutObject.keys();
-4. **Override Search Method**: Override the `search()` method to search for shortcuts based on the entered query.
+ while (keysItr.hasNext()) {
+ String key = keysItr.next();
+ String value = shortcutObject.getString(key);
+ messageShortcuts.put(key, value);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
-
-
-```java
-@Override
-public void search(@NonNull Context context, String queryString) {
- // Implementation to search for shortcuts
- String query = getTrackingCharacter() + queryString;
- shortcuts.clear();
- if (messageShortcuts.containsKey(query)) {
- SuggestionItem suggestionItem = new SuggestionItem("", query + " => " + messageShortcuts.get(query), null, null, messageShortcuts.get(query), null, null);
- suggestionItem.setHideLeadingIcon(true);
- shortcuts.add(suggestionItem);
- }
- setSuggestionItemList(shortcuts);
+ @Override
+ public void onError(CometChatException e) {
+ }
+ });
}
```
-
+
+
+> **What this does:** Calls the CometChat `message-shortcuts` extension via `CometChat.callExtension()` with a GET request to `/v1/fetch`. On success, it parses the JSON response to extract the `shortcuts` object from `data`, iterates over its keys, and stores each shortcut key-value pair in the `messageShortcuts` HashMap.
+
+- **Verify**: After the extension call completes, the `messageShortcuts` HashMap contains the shortcut key-value pairs fetched from the server (e.g., `"!hi"` → `"Hello, how are you?"`). If the extension is not enabled or the request fails, the `onError` callback is invoked and the map remains empty.
+
+### Override Search Method
+
+What you are changing: Implementing the logic that matches user input against stored shortcuts and updates the suggestion list.
+- **Where**: The `search()` method override inside `ShortCutFormatter` / `ShortCutFormatterKotlin`
+- **Applies to**: `CometChatMessageComposer` (the composer calls `search()` when the user types after the tracking character)
+- **Default behavior**: The base `CometChatTextFormatter.search()` does nothing — no suggestions are shown
+- **Override**: Override `search()` to combine the tracking character with the query string, check if the combined string exists as a key in `messageShortcuts`, and if so, create a `SuggestionItem` and update the suggestion list
+
+**Code:**
+
+
-```kotlin
+```kotlin lines
override fun search(context: Context, queryString: String?) {
val query = trackingCharacter.toString() + queryString
shortcuts.clear()
@@ -172,85 +294,87 @@ public void search(@NonNull Context context, String queryString) {
suggestionItemList.value = shortcuts
}
```
-
-
+
+```java lines
+@Override
+public void search(@NonNull Context context, String queryString) {
+ // Implementation to search for shortcuts
+ String query = getTrackingCharacter() + queryString;
+ shortcuts.clear();
+ if (messageShortcuts.containsKey(query)) {
+ SuggestionItem suggestionItem = new SuggestionItem("", query + " => " + messageShortcuts.get(query), null, null, messageShortcuts.get(query), null, null);
+ suggestionItem.setHideLeadingIcon(true);
+ shortcuts.add(suggestionItem);
+ }
+ setSuggestionItemList(shortcuts);
+}
+```
+
-5. **Handle Scroll to Bottom**: Override the `onScrollToBottom()` method if needed.
+> **What this does:** Combines the tracking character (`'!'`) with the user's query string to form the full shortcut key. Clears the current suggestions list, then checks if the `messageShortcuts` map contains the key. If a match is found, it creates a `SuggestionItem` displaying the shortcut and its expansion (e.g., `!hi => Hello, how are you?`), hides the leading icon, and updates the suggestion list so the composer displays the match.
-
-
-```java
- @Override
- public void onScrollToBottom() {
- // Implementation if needed
- }
-```
+- **Verify**: When the user types `!` followed by a valid shortcut key (e.g., `!hi`) in the message composer, a suggestion item appears showing the shortcut and its expanded text. If the typed text does not match any shortcut key, no suggestions are displayed.
-
+### Handle Scroll to Bottom
+
+What you are changing: Providing the required `onScrollToBottom()` override for the `CometChatTextFormatter` base class.
+
+- **Where**: The `onScrollToBottom()` method override inside `ShortCutFormatter` / `ShortCutFormatterKotlin`
+- **Applies to**: `ShortCutFormatter` / `ShortCutFormatterKotlin`
+- **Default behavior**: The base class requires this method to be overridden
+- **Override**: Override `onScrollToBottom()` with an empty implementation or a placeholder, since shortcut suggestions do not require scroll-to-bottom handling
+
+**Code:**
+
-```kotlin
+```kotlin lines
override fun onScrollToBottom() {
TODO("Not yet implemented")
}
```
-
-
+
+```java lines
+ @Override
+ public void onScrollToBottom() {
+ // Implementation if needed
+ }
+```
+
-## Usage
+> **What this does:** Provides the required override of `onScrollToBottom()` from the `CometChatTextFormatter` base class. In this implementation, the method body is left as a placeholder because shortcut suggestions do not require scroll-to-bottom handling.
-1. **Initialization**: Initialize an instance of `ShortCutFormatter` in your application.
+- **Verify**: The class compiles without errors with the `onScrollToBottom()` override in place.
-
-
-```java
-ShortCutFormatter shortCutFormatter = new ShortCutFormatter();
-```
+### Integration with MessageComposer
-
+What you are changing: Adding the `ShortCutFormatter` to `CometChatMessageComposer` so that shortcut suggestions appear when the user types the tracking character.
-
-```kotlin
- val shortCutFormatter = ShortCutFormatter()
-```
-
-
+- **Where**: Your Activity or Fragment where you configure `CometChatMessageComposer`
+- **Applies to**: `CometChatMessageComposer`
+- **Default behavior**: Without adding the `ShortCutFormatter`, the message composer does not display shortcut suggestions when the user types `'!'`
+- **Override**: Add a `CometChatMessageComposer` to your XML layout, then in your Activity or Fragment, get the existing text formatters from `CometChatUIKit.getDataSource().getTextFormatters()`, add a `ShortCutFormatter` instance, and call `setTextFormatters()` on the composer
-
+**Code:**
-2. **Integration**: Integrating the `ShortCutFormatter` into your CometChat application involves incorporating it within your project to handle message shortcuts. Use [MessageComposer](/ui-kit/android/message-composer) component, you can seamlessly integrate the ShortCutFormatter to manage shortcut functionalities within your application.
+**XML Layout:**
-
-
-```xml
+```xml lines
```
-
-
-
+> **What this does:** Adds a `CometChatMessageComposer` widget to your XML layout with the id `composer`, set to fill the parent width and height.
-
-```java
-CometChatMessageComposer cometChatMessageComposer = findViewById(R.id.composer);
-
-List cometChatTextFormatters = CometChatUIKit.getDataSource().getTextFormatters(this);
-cometChatTextFormatters.add(new ShortCutFormatter());
-cometChatMessageComposer.setTextFormatters(cometChatTextFormatters);
-```
-
-
-
-```kotlin
+```kotlin lines
val cometChatMessageComposer: CometChatMessageComposer =
findViewById(R.id.composer)
@@ -258,13 +382,55 @@ val cometChatTextFormatters = CometChatUIKit.getDataSource().getTextFormatters(t
cometChatTextFormatters.add(ShortCutFormatter())
cometChatMessageComposer.setTextFormatters(cometChatTextFormatters)
```
-
+
+```java lines
+CometChatMessageComposer cometChatMessageComposer = findViewById(R.id.composer);
+List cometChatTextFormatters = CometChatUIKit.getDataSource().getTextFormatters(this);
+cometChatTextFormatters.add(new ShortCutFormatter());
+cometChatMessageComposer.setTextFormatters(cometChatTextFormatters);
+```
+
-## Example
+> **What this does:** Finds the `CometChatMessageComposer` view by its id, retrieves the default text formatters list from `CometChatUIKit.getDataSource().getTextFormatters()`, adds a new `ShortCutFormatter` instance to the list, and passes the combined list to the composer via `setTextFormatters()`. The composer now supports shortcut suggestions alongside any default formatters.
+
+- **Verify**: After running the app, typing `!` followed by a valid shortcut key in the message composer displays a suggestion item showing the shortcut and its expanded text. Selecting the suggestion inserts the expanded text into the composer.
+
+## Common Pitfalls and Fixes
+
+| Pitfall | Fix |
+| ------- | --- |
+| Shortcut suggestions do not appear when typing `!` | Confirm that the `ShortCutFormatter` instance is added to the formatters list and that `setTextFormatters()` is called on the `CometChatMessageComposer` instance. |
+| Formatter created but not added to the formatters list | Call `cometChatTextFormatters.add(new ShortCutFormatter())` (Java) or `cometChatTextFormatters.add(ShortCutFormatter())` (Kotlin) before calling `setTextFormatters()`. If the formatter is not in the list, `setTextFormatters()` has no effect on shortcut handling. |
+| Called `setTextFormatters()` with an empty list | Add at least one formatter to the list before calling `setTextFormatters()`. Retrieve the default formatters via `CometChatUIKit.getDataSource().getTextFormatters(this)` and add the `ShortCutFormatter` to that list. |
+| `prepareShortCuts()` does not populate the shortcuts map | Confirm that the `message-shortcuts` CometChat extension is enabled on your CometChat dashboard. The `CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", ...)` call returns an empty or error response if the extension is not enabled. |
+| Shortcuts fetched but `search()` does not find matches | The `search()` method combines the tracking character `'!'` with the query string to form the lookup key. Confirm that the keys stored in `messageShortcuts` include the `'!'` prefix (e.g., `"!hi"`, not `"hi"`). |
+| `CometChatMessageComposer` not found in layout | Confirm that your XML layout includes `` with the correct `android:id` matching the `findViewById()` call. |
+
+## FAQ
+
+**Q: What tracking character does `ShortCutFormatter` use?**
+A: `ShortCutFormatter` uses `'!'` as the tracking character, passed to the `CometChatTextFormatter` superclass constructor. When the user types `!` in the message composer, the formatter activates and begins matching input against stored shortcuts.
+
+**Q: Where does `ShortCutFormatter` fetch shortcuts from?**
+A: Shortcuts are fetched from the CometChat `message-shortcuts` extension via `CometChat.callExtension("message-shortcuts", "GET", "/v1/fetch", null, ...)`. The response JSON contains a `data.shortcuts` object with key-value pairs.
+
+**Q: Can I use `ShortCutFormatter` alongside other text formatters like `CometChatMentionsFormatter`?**
+A: Yes. Retrieve the default formatters list via `CometChatUIKit.getDataSource().getTextFormatters(this)`, add the `ShortCutFormatter` to the list, and pass the combined list to `CometChatMessageComposer` via `setTextFormatters()`. All formatters in the list are active simultaneously.
+
+**Q: Do I need to implement `onScrollToBottom()` with actual logic?**
+A: The `CometChatTextFormatter` base class requires the `onScrollToBottom()` override. For `ShortCutFormatter`, the method body can be left as a placeholder because shortcut suggestions do not require scroll-to-bottom handling.
+
+**Q: What happens if the `message-shortcuts` extension is not enabled?**
+A: If the extension is not enabled, the `CometChat.callExtension()` call triggers the `onError` callback, and the `messageShortcuts` map remains empty. The `search()` method finds no matches, so no suggestions are displayed.
+
+## Next steps
+
+- [Message Composer component](/ui-kit/android/message-composer) — configure the composer where `ShortCutFormatter` is integrated via `setTextFormatters()`
+- [Mentions Formatter guide](/ui-kit/android/mentions-formatter-guide) — another text formatter implementation using `CometChatMentionsFormatter` for @mention handling
\ No newline at end of file
diff --git a/ui-kit/android/sound-manager.mdx b/ui-kit/android/sound-manager.mdx
index c57d4466b..27356c65b 100644
--- a/ui-kit/android/sound-manager.mdx
+++ b/ui-kit/android/sound-manager.mdx
@@ -2,69 +2,198 @@
title: "Sound Manager"
---
-## Overview
-
-The SoundManager is a helper class responsible for managing and playing various types of audio in the CometChat UI Kit. This includes sound events for incoming and outgoing messages and calls.
-
-Before you can use the SoundManager, it must be initialized:
+Use `CometChatSoundManager` to play UI Kit audio cues for calls and messages.
+
+## When to use this
+- You want audible feedback for incoming or outgoing calls and messages.
+- You need custom sounds for specific chat events.
+- You want to pause or stop sound playback programmatically.
+
+## Prerequisites
+- CometChat UI Kit for Android is installed and initialized.
+- You have access to an Android `Context`.
+- Optional: You have sound files in `app/src/main/res/raw` for custom playback.
+
+## Quick start
+
+
+Instantiate `CometChatSoundManager` using a valid `Context`.
+
+
+Call `play(Sound)` for built-in UI Kit sounds.
+
+
+Call `play(Sound, int)` with a file from `res/raw`.
+
+
+Call `pause()` when you need to stop sound playback.
+
+
+Run the app and confirm the expected sound plays for each event.
+
+
+
+## Core concepts
+- `CometChatSoundManager`: Manages playback of UI Kit sounds.
+- `Sound`: Enum of supported sound events such as `incomingCall`, `outgoingMessage`, and `incomingMessageFromOther`.
+- `R.raw`: Android raw resource IDs used for custom sounds.
+
+### Available methods
+- `play(Sound sound)`: Plays the default UI Kit sound for the given event.
+- `play(Sound sound, int res)`: Plays a custom raw resource for the given event.
+- `pause()`: Pauses any sound currently playing.
+
+## Implementation
+
+### Initialize `CometChatSoundManager`
+What you're changing: Creating a sound manager instance.
+
+- **Where to change it**: Any class where you have access to a `Context`.
+
+- **Applies to**: All UI Kit sound playback.
+
+- **Default behavior**: Sounds are not managed until you create the instance.
+
+- **Override**: Instantiate `CometChatSoundManager` with a valid `Context`.
+
+- **Code**:
-
-```java
-CometChatSoundManager soundManager = new CometChatSoundManager(context);
+
+```kotlin SoundManagerHelper.kt lines
+import android.content.Context
+import com.cometchat.chatuikit.shared.resources.soundmanager.CometChatSoundManager
+
+fun createSoundManager(context: Context): CometChatSoundManager {
+ return CometChatSoundManager(context)
+}
```
-
-```kotlin
-val soundManager = CometChatSoundManager(context)
+
+```java SoundManagerHelper.java lines
+import android.content.Context;
+import com.cometchat.chatuikit.shared.resources.soundmanager.CometChatSoundManager;
+
+public final class SoundManagerHelper {
+ public static CometChatSoundManager createSoundManager(Context context) {
+ return new CometChatSoundManager(context);
+ }
+}
```
-## Methods
+- **What this does**: Creates a sound manager you can reuse across your UI Kit screens.
+
+- **Verify**: Call a play method and confirm audio plays.
+
+### Play default and custom sounds
+What you're changing: Triggering sound playback for chat events.
+
+- **Where to change it**: The class that handles your chat or call UI logic.
-### Play Sound
+- **Applies to**: Message and call events you choose to handle.
-The SoundManager plays pre-defined or custom sounds based on user interactions with the chat interface. If no custom sound file is provided, the default sound is played.
+- **Default behavior**: UI Kit plays its built-in sounds when triggered.
-Here are the available methods for triggering sound playback:
+- **Override**: Use `play(Sound, int)` to play a custom raw resource.
-* `play(Sound sound)`: This method plays different types of sounds for incoming and outgoing calls and messages.
+- **Code**:
-* `play(Sound sound, int res)`: This method is capable of playing a custom sound for a particular raw file passed in this method.
+
+
+```kotlin SoundManagerUsage.kt lines
+import android.content.Context
+import com.cometchat.chatuikit.shared.resources.soundmanager.CometChatSoundManager
+import com.cometchat.chatuikit.shared.resources.soundmanager.Sound
+
+fun playSounds(context: Context) {
+ val soundManager = CometChatSoundManager(context)
+
+ // Default sounds
+ soundManager.play(Sound.incomingCall)
+ soundManager.play(Sound.outgoingCall)
+ soundManager.play(Sound.incomingMessage)
+ soundManager.play(Sound.outgoingMessage)
+ soundManager.play(Sound.incomingMessageFromOther)
+
+ // Custom sounds
+ soundManager.play(Sound.incomingCall, R.raw.incoming_call)
+ soundManager.play(Sound.outgoingCall, R.raw.outgoing_call)
+ soundManager.play(Sound.incomingMessage, R.raw.incoming_message)
+ soundManager.play(Sound.outgoingMessage, R.raw.outgoing_message)
+ soundManager.play(Sound.incomingMessageFromOther, R.raw.incoming_message_other)
+
+ // Pause playback
+ soundManager.pause()
+}
+```
+
+
-### Pause Sound
+
+```java SoundManagerUsage.java lines
+import android.content.Context;
+import com.cometchat.chatuikit.shared.resources.soundmanager.CometChatSoundManager;
+import com.cometchat.chatuikit.shared.resources.soundmanager.Sound;
+
+public class SoundManagerUsage {
+ public static void playSounds(Context context) {
+ CometChatSoundManager soundManager = new CometChatSoundManager(context);
+
+ // Default sounds
+ soundManager.play(Sound.incomingCall);
+ soundManager.play(Sound.outgoingCall);
+ soundManager.play(Sound.incomingMessage);
+ soundManager.play(Sound.outgoingMessage);
+ soundManager.play(Sound.incomingMessageFromOther);
+
+ // Custom sounds
+ soundManager.play(Sound.incomingCall, R.raw.incoming_call);
+ soundManager.play(Sound.outgoingCall, R.raw.outgoing_call);
+ soundManager.play(Sound.incomingMessage, R.raw.incoming_message);
+ soundManager.play(Sound.outgoingMessage, R.raw.outgoing_message);
+ soundManager.play(Sound.incomingMessageFromOther, R.raw.incoming_message_other);
+
+ // Pause playback
+ soundManager.pause();
+ }
+}
+```
-The SoundManager can pause different types of sounds for incoming and outgoing calls and messages using the following method:
+
-* `pause()`: This method pauses any sound currently being played.
+
-## Usage
+- **What this does**: Plays default and custom sounds, then pauses playback.
-Here is how to use CometChatSoundManager:
+- **Verify**: You hear the expected sound for each call and message event.
-```java
-// Initialize SoundManager
-val soundManager = CometChatSoundManager(context)
+## Customization matrix
+| What you want to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Create sound manager | `app/src/main/java//SoundManagerHelper.kt` | `CometChatSoundManager(Context)` | `val soundManager = CometChatSoundManager(context)` |
+| Play default sounds | `app/src/main/java//SoundManagerUsage.kt` | `play(Sound)` | `soundManager.play(Sound.incomingCall)` |
+| Play custom sounds | `app/src/main/java//SoundManagerUsage.kt` | `play(Sound, int)` | `soundManager.play(Sound.incomingCall, R.raw.incoming_call)` |
+| Pause playback | `app/src/main/java//SoundManagerUsage.kt` | `pause()` | `soundManager.pause()` |
-// Play sound with default sound:
-soundManager.play(Sound.incomingCall) //To play incoming call sound
-soundManager.play(Sound.outgoingCall) //To play outgoing call sound
-soundManager.play(Sound.incomingMessage) //To play incoming message sound
-soundManager.play(Sound.outgoingMessage) //To play outgoing message sound
+## Common pitfalls and fixes
+- No sound plays: Ensure `CometChatSoundManager` is created with a valid `Context`.
+- Custom sounds not found: Place audio files in `app/src/main/res/raw` and reference them as `R.raw.`.
+- Sound plays once only: Reuse the same `CometChatSoundManager` instance instead of creating one per event.
+- Silent device: Check device volume and ringer mode.
+- No sound on specific devices: Verify the audio file format is supported by Android.
-// Play sound with custom sound
-soundManager.play(Sound.incomingCall, R.raw.incoming_call) //To play incoming call sound
-soundManager.play(Sound.outgoingCall, R.raw.outgoing_call) //To play outgoing call sound
-soundManager.play(Sound.incomingMessage, R.raw.incoming_message) //To play incoming message sound
-soundManager.play(Sound.outgoingMessage, R.raw.outgoing_message) //To play outgoing message sound
+## FAQ
+**Q**: Do I need to initialize SoundManager before each play call?
+**A**: No. Create one instance and reuse it while the screen is active.
-// Pause Sound:
-soundManager.pause()
-```
+**Q**: Can I use my own audio files?
+**A**: Yes. Place them in `res/raw` and call `play(Sound, int)` with your `R.raw` resource ID.
-By using the CometChatSoundManager, you can enhance the user experience in your chat application by integrating audible cues for chat interactions.
+**Q**: How do I stop a sound that is playing?
+**A**: Call `pause()` on the sound manager instance.
\ No newline at end of file
diff --git a/ui-kit/android/theme-introduction.mdx b/ui-kit/android/theme-introduction.mdx
index 3e36cc70e..287a8f73a 100644
--- a/ui-kit/android/theme-introduction.mdx
+++ b/ui-kit/android/theme-introduction.mdx
@@ -2,68 +2,252 @@
title: "Introduction"
---
-## Overview
+Create and apply a global CometChat UI Kit theme that matches your brand across light and dark modes.
+
+## When to use this
+- You want a single UI Kit theme that matches your app branding.
+- You need light and dark mode support with consistent colors.
+- You want to customize primary, background, or text colors across UI Kit.
+- You want a different UI Kit theme for a specific activity.
+
+## Prerequisites
+- CometChat UI Kit for Android is installed and initialized.
+- You can edit `app/src/main/res/values/themes.xml`.
+- You can edit `AndroidManifest.xml`.
+- Optional: You can create `app/src/main/res/values-night/themes.xml` for dark mode overrides.
+
+## Quick start
+
+
+File: `app/src/main/res/values/themes.xml`. Extend `CometChatTheme.DayNight` as the base theme.
+
+
+File: `AndroidManifest.xml`. Set `android:theme` on the `` element.
+
+
+File: `AndroidManifest.xml`. Set `android:theme` on a specific `` if needed.
+
+
+File: `app/src/main/res/values/themes.xml`. Update `cometchatPrimaryColor` and other attributes.
+
+
+File: `app/src/main/res/values-night/themes.xml`. Override attributes for dark mode.
+
+
+Run the app and confirm UI Kit screens use your colors in light and dark mode.
+
+
+
+## Core concepts
+- `CometChatTheme.DayNight`: Base UI Kit theme built on `Theme.MaterialComponents.DayNight.NoActionBar`.
+- Theme attributes: `cometchatPrimaryColor`, `cometchatBackgroundColor1`, `cometchatTextColorPrimary`, and others.
+- `values-night`: Android resource folder for dark mode overrides.
+
+## Implementation
+
+### Create an app theme that extends `CometChatTheme.DayNight`
+What you're changing: The base theme used by UI Kit components.
+
+- **Where to change it**: `app/src/main/res/values/themes.xml`.
+- **Applies to**: All UI Kit components.
+- **Default behavior**: UI Kit uses `CometChatTheme.DayNight`.
+- **Override**: Define your app theme and set `parent="CometChatTheme.DayNight"`.
+- **Code**:
+
+```xml themes.xml lines
+
+
+
+```
-Theming in CometChat allows you to create visually consistent and customizable user interfaces that align with your application's branding. With the `CometChatTheme.DayNight` style which is built on `Theme.MaterialComponents.DayNight.NoActionBar` and acts as a global theme applied across all components, you can seamlessly integrate light and dark modes, define custom colors, typography, and component-specific styles, and enhance user experience across all CometChat components.
+- **What this does**: Creates an app theme that inherits all UI Kit styling.
+- **Verify**: UI Kit screens render correctly after the theme is applied.
-## Using Theming in Your Project
+### Apply the theme to your application
+What you're changing: The theme applied to the entire app.
-Set the `CometChatTheme.DayNight` as the parent theme for your application in the `themes.xml` file. You can extend it with your custom theme as needed:
+- **Where to change it**: `AndroidManifest.xml`.
-```html
-
-
-```
+- **Applies to**: All activities unless overridden.
-In your AndroidManifest.xml file, set the theme for your application or activity:
+- **Default behavior**: The application theme is not set to your UI Kit theme.
-```html
-
+- **Override**: Set `android:theme` on the `` element.
+
+- **Code**:
+
+```xml AndroidManifest.xml lines
-
+ android:name=".YourApplication"
+ android:theme="@style/AppTheme"
+ ...>
+
```
-If you need to apply specific styles to a particular activity, override the theme as follows:
+- **What this does**: Applies `AppTheme` to every activity by default.
+
+- **Verify**: Launch any UI Kit screen and confirm the theme is applied.
+
+
+
+
+
+### Apply a theme to a specific activity
+What you're changing: The theme for a single activity.
+
+- **Where to change it**: `AndroidManifest.xml`.
-```html
-
+- **Applies to**: Only the targeted activity.
+
+- **Default behavior**: Activities inherit the application theme.
+
+- **Override**: Set `android:theme` on the `` element.
+
+- **Code**:
+
+```xml AndroidManifest.xml lines
-
+ android:theme="@style/AppTheme"
+ ...>
-
-
+
```
-
-
-
+- **What this does**: Applies `ChatTheme` only to `ChatActivity`.
-## Customization
+- **Verify**: Open `ChatActivity` and confirm the theme differs from the rest of the app.
-To customize the primary color in your app, you can override the cometchatPrimaryColor attribute in your theme. Here's how:
+### Change the primary color
+What you're changing: The primary brand color used across UI Kit.
-```html
-
-
```
-To know more such attributes, visit the [theme attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_theme.xml).
+- **What this does**: Replaces the UI Kit primary color with your brand color.
+
+- **Verify**: Buttons and highlights use the new color.
+
+### Customize common theme attributes
+What you're changing: Background, text, and stroke colors.
+
+- **Where to change it**: `app/src/main/res/values/themes.xml`.
+
+- **Applies to**: All UI Kit components that use these attributes.
+
+- **Default behavior**: UI Kit uses its default theme values.
+
+- **Override**: Define the attributes in your app theme.
+
+- **Code**:
+
+```xml themes.xml lines
+
+```
+
+- **What this does**: Updates common UI Kit colors in one place.
+
+- **Verify**: Backgrounds, text, and dividers reflect the new values.
+
+### Add dark mode overrides
+What you're changing: Theme values used in dark mode.
+
+- **Where to change it**: `app/src/main/res/values-night/themes.xml`.
+
+- **Applies to**: Dark mode only.
+
+- **Default behavior**: Dark mode uses the same values as light mode.
+
+- **Override**: Create `values-night/themes.xml` and override the attributes.
+
+- **Code**:
+
+```xml values-night/themes.xml lines
+
+
+
+```
+
+- **What this does**: Applies dark mode colors when the system uses night mode.
+
+- **Verify**: Toggle dark mode on the device and confirm UI Kit colors update.
+
+
+For a complete list of theme attributes, visit the [theme attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_theme.xml) on GitHub.
+
+
+## Customization matrix
+| What you want to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Base UI Kit theme | `app/src/main/res/values/themes.xml` | `parent="CometChatTheme.DayNight"` | `
-
+The component listens to SDK events internally via its ViewModel. No manual attachment needed.
-
+| SDK Listener | Internal behavior |
+| --- | --- |
+| Message edited | Updates the parent message bubble if the parent message is edited |
+| Message deleted | Updates the parent message bubble if the parent message is deleted |
+| Reply count changed | Updates the reply count indicator when new replies are added |
+
+> Automatic: parent message changes and reply count updates reflect in real time.
+
+## Functionality
+
+Small functional customizations such as toggling visibility of UI elements and configuring alignment.
+
+| Method | Description | Code |
+| --- | --- | --- |
+| `setReactionVisibility` | Shows or hides reactions on the parent message bubble | `.setReactionVisibility(View.GONE)` |
+| `setAvatarVisibility` | Shows or hides the avatar in the thread header | `.setAvatarVisibility(View.GONE)` |
+| `setReceiptsVisibility` | Shows or hides read receipts on the parent message bubble | `.setReceiptsVisibility(View.GONE)` |
+| `setReplyCountVisibility` | Shows or hides the reply count text | `.setReplyCountVisibility(View.GONE)` |
+| `setReplyCountBarVisibility` | Shows or hides the reply count bar/layout | `.setReplyCountBarVisibility(View.GONE)` |
+| `setMaxHeight` | Sets the maximum height limit for the thread header in pixels | `.setMaxHeight(500)` |
+| `setAlignment` | Sets bubble alignment: STANDARD (left/right by message type) or LEFT_ALIGNED (all left) | `.setAlignment(UIKitConstants.MessageListAlignment.LEFT_ALIGNED)` |
+
+- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden.
+
+## Custom View Slots
+
+`CometChatThreadHeader` does not use the traditional `ViewHolderListener` pattern for view slots. Instead, it uses `CometChatMessageTemplate` to customize how the parent message bubble is rendered.
+
+### `setTemplates`
+
+Replaces the default list of message templates used to render the parent message bubble.
+
+
+
+```kotlin lines
+val customTemplates: List = listOf(myCustomTemplate)
+threadHeader.setTemplates(customTemplates)
+```
+
+
+
+```java lines
+List customTemplates = Arrays.asList(myCustomTemplate);
+threadHeader.setTemplates(customTemplates);
+```
+
+
+
+> **What this does:** Replaces the entire set of message templates. The parent message bubble renders using the custom template configuration. If you pass an empty list, no message bubble renders.
+
+### `addTemplate`
+
+Adds a single message template to the existing list without replacing defaults.
+
+
+
+```kotlin lines
+threadHeader.addTemplate(myCustomTemplate)
+```
+
+
+
+```java lines
+threadHeader.addTemplate(myCustomTemplate);
+```
+
+
+
+> **What this does:** Appends a new `CometChatMessageTemplate` to the existing template list. Use this when you want to support an additional message type without removing the built-in templates.
+
+- **Verify**: After calling `setTemplates` or `addTemplate`, confirm the parent message bubble renders using the custom template configuration.
+
+## Common Patterns
+
+### Hide reactions on the parent message
+
+
+
+```kotlin lines
+threadHeader.setReactionVisibility(View.GONE)
+```
+
+
+
+```java lines
+threadHeader.setReactionVisibility(View.GONE);
```
+
+
+
+### Left-align all message bubbles
+
+```kotlin lines
+threadHeader.setAlignment(UIKitConstants.MessageListAlignment.LEFT_ALIGNED)
+```
+
+
-```java
-cometChatThreadHeader.setStyle(R.style.CustomThreadHeaderStyle);
+```java lines
+threadHeader.setAlignment(UIKitConstants.MessageListAlignment.LEFT_ALIGNED);
+```
+
+
+
+### Custom time format
+
+
+
+```kotlin lines
+threadHeader.setTimeFormat(SimpleDateFormat("hh:mm a", Locale.getDefault()))
```
+
+
+```java lines
+threadHeader.setTimeFormat(new SimpleDateFormat("hh:mm a", Locale.getDefault()));
+```
+
+
+### Hide reply count and reply count bar
+
-```kotlin
-cometChatThreadHeader.setStyle(R.style.CustomThreadHeaderStyle)
+```kotlin lines
+threadHeader.setReplyCountVisibility(View.GONE)
+threadHeader.setReplyCountBarVisibility(View.GONE)
+```
+
+
+
+```java lines
+threadHeader.setReplyCountVisibility(View.GONE);
+threadHeader.setReplyCountBarVisibility(View.GONE);
```
+
+
+
+## Advanced Methods
+### `setParentMessage`
+
+Sets the parent message for the thread header. This is required — the component will not render without it.
+
+
+
+```kotlin lines
+threadHeader.setParentMessage(baseMessage)
+```
+
+```java lines
+threadHeader.setParentMessage(baseMessage);
+```
+
-***
+### `setTemplates`
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_thread_header.xml).
+Replaces the default list of message templates used to render the parent message bubble.
-### Functionality
+
+
+```kotlin lines
+threadHeader.setTemplates(customTemplateList)
+```
+
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements.
+
+```java lines
+threadHeader.setTemplates(customTemplateList);
+```
+
+
+
+### `addTemplate`
+
+Adds a single message template to the existing list.
+
+```kotlin lines
+threadHeader.addTemplate(customTemplate)
+```
+
+
-```java
-CometChatThreadHeader cometChatThreadHeader = findViewById(R.id.threaded_header);
+```java lines
+threadHeader.addTemplate(customTemplate);
```
+
+
+
+### `setTextFormatters`
+Adds custom text formatters to the current list of formatters used in the thread header.
+
+
+
+```kotlin lines
+threadHeader.setTextFormatters(listOf(myCustomFormatter))
+```
+
+
+
+```java lines
+threadHeader.setTextFormatters(Arrays.asList(myCustomFormatter));
+```
+
+### `setTimeFormat`
+
+Sets a custom time format for the parent message display.
+
+
-```kotlin
-val threadedMessages = findViewById(R.id.threaded_messages)
+```kotlin lines
+threadHeader.setTimeFormat(SimpleDateFormat("hh:mm a", Locale.getDefault()))
```
+
+
+```java lines
+threadHeader.setTimeFormat(new SimpleDateFormat("hh:mm a", Locale.getDefault()));
+```
+
+
+
+### `setAlignment`
+
+Sets the bubble alignment for the parent message.
+
+
+
+```kotlin lines
+threadHeader.setAlignment(UIKitConstants.MessageListAlignment.LEFT_ALIGNED)
+```
+
+```java lines
+threadHeader.setAlignment(UIKitConstants.MessageListAlignment.LEFT_ALIGNED);
+```
+
-Below is a list of customizations along with corresponding code snippets
+> In `STANDARD` mode, the bubble appears on the left or right based on whether the message is incoming or outgoing. In `LEFT_ALIGNED` mode, all bubbles appear on the left.
+
+### Internal Access
+
+These methods provide direct access to internal components for advanced use cases.
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getRecyclerView()` | `RecyclerView` | The RecyclerView used for the parent message bubble |
+| `getBinding()` | `CometchatThreadHeaderBinding` | The ViewBinding for the component's root layout |
+| `getThreadedHeaderViewModel()` | `ThreadHeaderViewModel` | The ViewModel managing thread header state |
+| `getAdapter()` | `MessageAdapter` | The adapter powering the parent message RecyclerView |
+
+### Bubble Style Methods
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setIncomingMessageBubbleStyle` | `@StyleRes int` | Sets the style for incoming message bubbles |
+| `setOutgoingMessageBubbleStyle` | `@StyleRes int` | Sets the style for outgoing message bubbles |
+
+> Use internal access methods only when the standard API is insufficient. Directly manipulating the adapter or ViewModel may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatThreadHeaderStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
-| Methods | Description | Code |
-| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
-| **setParentMessage** | Used to to set the message for which the replies need to be fetched | `.setParentMessage(BaseMessage)` |
-| **setIncomingMessageBubbleStyle** | Used to set Incoming Bubble style | `.setIncomingMessageBubbleStyle(@StyleRes int)` |
-| **setOutgoingMessageBubbleStyle** | Used to set Outgoing Bubble style | `.setOutgoingMessageBubbleStyle(@StyleRes int)` |
-| **setReceiptsVisibility** | Used to hide Receipt from Message Bubble | `setReceiptsVisibility(View.GONE)` |
-| **setReplyCountVisibility** | Used to hide reply count from the component | `setReplyCountVisibility(View.GONE)` |
-| **setReplyCountBarVisibility** | Used to hide reply count bar from component | `setReplyCountBarVisibility(View.GONE)` |
-| **setAlignment** | Used to set the bubble alignment: either leftAligned or standard. If set to standard, the bubble will appear on the left or right based on the message type (incoming or outgoing). If set to leftAligned, all message bubbles will appear on the left regardless of their type. | `setAlignment(UIKitConstants.MessageListAlignment alignment)` |
-| **setAvatarVisibility** | Shows or hides the avatar in the Thread Header. | `setAvatarVisibility(true)` |
-| **setDateFormat** | Sets the date pattern for displaying message dates in the Thread Header. | `setDateFormat(new SimpleDateFormat("MMM dd, yyyy",Locale.getDefault()))` |
-| **setTimeFormat** | Sets the date pattern for displaying message dates in the Thread Header. | `setDateFormat(new SimpleDateFormat("hh:mm a",Locale.getDefault()))` |
-| **addTemplate** | Adds a new message template to the existing list of templates to the Thread Header. | `addTemplate(CometChatMessageTemplate template)` |
-| **setTemplates** | Replace the default list of message template and sets a new list. | `setTemplates(List cometchatMessageTemplates)` |
-| **setTextFormatters** | This method allows the addition of custom text formatters to the current list of formatters used in the Thread Header. | `setTextFormatters(List cometchatTextFormatters)` |
+```xml themes.xml lines
+
+
-***
+
+```
-### Advanced
+
+
+```kotlin lines
+threadHeader.setStyle(R.style.CustomThreadHeaderStyle)
+```
+
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
+
+```java lines
+threadHeader.setStyle(R.style.CustomThreadHeaderStyle);
+```
+
+
-#### setTemplates
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_thread_header.xml).
-The setTemplates method is used to configure and set a list of templates for message bubbles. It allows for dynamic customization of message appearance, content, or other predefined settings based on the templates provided. This method can be called to update or apply a new set of templates to the message handling system.
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setReplyCountBackgroundColor` | `@ColorInt int` | Background color of the reply count view |
+| `setReplyCountTextColor` | `@ColorInt int` | Text color of the reply count view |
+| `setReplyCountTextAppearance` | `@StyleRes int` | Text appearance of the reply count view |
+| `setIncomingMessageBubbleStyle` | `@StyleRes int` | Style for incoming message bubbles |
+| `setOutgoingMessageBubbleStyle` | `@StyleRes int` | Style for outgoing message bubbles |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Parent message | Activity/Fragment | `setParentMessage(BaseMessage)` | `threadHeader.setParentMessage(baseMessage)` |
+| Reaction visibility | Activity/Fragment | `setReactionVisibility(int)` | `.setReactionVisibility(View.GONE)` |
+| Avatar visibility | Activity/Fragment | `setAvatarVisibility(int)` | `.setAvatarVisibility(View.GONE)` |
+| Receipt visibility | Activity/Fragment | `setReceiptsVisibility(int)` | `.setReceiptsVisibility(View.GONE)` |
+| Reply count visibility | Activity/Fragment | `setReplyCountVisibility(int)` | `.setReplyCountVisibility(View.GONE)` |
+| Reply count bar visibility | Activity/Fragment | `setReplyCountBarVisibility(int)` | `.setReplyCountBarVisibility(View.GONE)` |
+| Max height | Activity/Fragment | `setMaxHeight(int)` | `.setMaxHeight(500)` |
+| Bubble alignment | Activity/Fragment | `setAlignment(MessageListAlignment)` | `.setAlignment(UIKitConstants.MessageListAlignment.LEFT_ALIGNED)` |
+| Time format | Activity/Fragment | `setTimeFormat(SimpleDateFormat)` | `.setTimeFormat(new SimpleDateFormat("hh:mm a", Locale.getDefault()))` |
+| Text formatters | Activity/Fragment | `setTextFormatters(List)` | `.setTextFormatters(formatterList)` |
+| Message templates (replace) | Activity/Fragment | `setTemplates(List)` | `.setTemplates(templateList)` |
+| Message templates (add) | Activity/Fragment | `addTemplate(CometChatMessageTemplate)` | `.addTemplate(template)` |
+| Outgoing bubble style | `themes.xml` | `cometchatThreadHeaderOutgoingMessageBubbleStyle` | `@style/CustomOutgoingStyle` |
+| Incoming bubble style | `themes.xml` | `cometchatThreadHeaderIncomingMessageBubbleStyle` | `@style/CustomIncomingStyle` |
+| Header background color | `themes.xml` | `cometchatThreadHeaderBackgroundColor` | `#FEEDE1` |
+| Reply count text color | `themes.xml` | `cometchatThreadHeaderReplyCountTextColor` | `#F76808` |
+| Reply count background color | `themes.xml` | `cometchatThreadHeaderReplyCountBackgroundColor` | `#FEEDE1` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `threadHeader.setStyle(R.style.CustomThreadHeaderStyle)` |
+| Incoming bubble style (programmatic) | Activity/Fragment | `setIncomingMessageBubbleStyle(int)` | `.setIncomingMessageBubbleStyle(R.style.CustomIncomingStyle)` |
+| Outgoing bubble style (programmatic) | Activity/Fragment | `setOutgoingMessageBubbleStyle(int)` | `.setOutgoingMessageBubbleStyle(R.style.CustomOutgoingStyle)` |
+| Reply count background (programmatic) | Activity/Fragment | `setReplyCountBackgroundColor(int)` | `.setReplyCountBackgroundColor(Color.parseColor("#FEEDE1"))` |
+| Reply count text color (programmatic) | Activity/Fragment | `setReplyCountTextColor(int)` | `.setReplyCountTextColor(Color.parseColor("#F76808"))` |
+| Reply count text appearance (programmatic) | Activity/Fragment | `setReplyCountTextAppearance(int)` | `.setReplyCountTextAppearance(R.style.CustomTextAppearance)` |
+| Internal adapter access | Activity/Fragment | `getAdapter()` | Advanced use only |
+
+## Accessibility
+
+The component renders a `RecyclerView` containing the parent message bubble. The reply count text is readable by screen readers. Avatar images include content descriptions derived from the sender's name.
+
+For custom message templates provided via `setTemplates` or `addTemplate`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default templates handle this automatically.
+
+Reaction indicators and read receipts are visual-only by default. If screen reader descriptions are needed, provide them via custom templates with appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| Thread header shows no message | Ensure you call `setParentMessage(baseMessage)` with a valid `BaseMessage` object. If no parent message is set, the thread header has no message to display. |
+| Custom style not visible | Verify the style parent is `CometChatThreadHeaderStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| Reply count not showing | Ensure `setReplyCountVisibility` is not set to `View.GONE`. If the parent message has no replies, the reply count may not appear. |
+| Bubble alignment not changing | Ensure you pass a valid `UIKitConstants.MessageListAlignment` value to `setAlignment`. If set to STANDARD, the bubble position depends on whether the message is incoming or outgoing. |
+| Message bubble style not applied | If you set `setIncomingMessageBubbleStyle` or `setOutgoingMessageBubbleStyle` programmatically, ensure the style resource ID points to a valid style with parent `CometChatIncomingMessageBubbleStyle` or `CometChatOutgoingMessageBubbleStyle`. |
+| Date or time format not changing | Ensure you pass a valid `SimpleDateFormat` object to `setTimeFormat`. If the format pattern is invalid, the default format is used. |
+| Custom templates not rendering | If you call `setTemplates` with an empty list, no message bubble renders. Ensure the list contains at least one valid `CometChatMessageTemplate`. |
+
+## FAQ
+
+**Q: How do I set the parent message for the thread header?**
+**A:** Call `setParentMessage(baseMessage)` on the `CometChatThreadHeader` instance, passing a valid `BaseMessage` object that represents the parent message of the thread.
+
+**Q: How do I hide the reply count and reply count bar?**
+**A:** Call `setReplyCountVisibility(View.GONE)` to hide the reply count text, and call `setReplyCountBarVisibility(View.GONE)` to hide the reply count bar.
+
+**Q: How do I customize the message bubble colors in the thread header?**
+**A:** Define custom styles with parents `CometChatOutgoingMessageBubbleStyle` and `CometChatIncomingMessageBubbleStyle` in `themes.xml`, reference them in a `CometChatThreadHeaderStyle`, and apply with `setStyle()`.
+
+**Q: How do I change the bubble alignment so all bubbles appear on the left?**
+**A:** Call `setAlignment` with `UIKitConstants.MessageListAlignment.LEFT_ALIGNED`. If set to STANDARD, the bubble position depends on whether the message is incoming or outgoing.
+
+**Q: Can I add custom message templates to the thread header?**
+**A:** Yes. Use `addTemplate(CometChatMessageTemplate template)` to add a single template to the existing list, or use `setTemplates(List)` to replace the entire template list.
+
+## Next Steps
+
+- [Message list component](/ui-kit/android/message-list)
+- [Message header component](/ui-kit/android/message-header)
+- [Message composer component](/ui-kit/android/message-composer)
diff --git a/ui-kit/android/upgrading-from-v4.mdx b/ui-kit/android/upgrading-from-v4.mdx
index 7047bcb7b..b58b87384 100644
--- a/ui-kit/android/upgrading-from-v4.mdx
+++ b/ui-kit/android/upgrading-from-v4.mdx
@@ -68,7 +68,7 @@ The reliance on Context for theming introduced several challenges. Customizing t
-```java
+```java lines
Palette palette = Palette.getInstance();
palette.primary(Color.parseColor("#YourPrimaryColor"));
palette.secondary(Color.parseColor("#YourSecondaryColor"));
@@ -82,7 +82,7 @@ typography.setName(R.style.font);
-```kotlin
+```kotlin lines
val palette = Palette.getInstance()
palette.primary(Color.parseColor("#YourPrimaryColor"))
palette.secondary(Color.parseColor("#YourSecondaryColor"))
@@ -102,7 +102,7 @@ In v5, theming has been completely revamped to align with standard Android devel
The new theming system is **declarative, XML-based, and follows Android conventions**. Developers now define themes in `themes.xml` by extending `CometChatTheme.DayNight` and overriding specific attributes. For example, changing the primary color is as simple as overriding the `cometchatPrimaryColor` attribute — no need to instantiate objects or write programmatic theming logic.
**themes.xml:**
-```xml
+```xml lines
-
+}
```
+
-
-```java
-cometChatUsers.setStyle(R.style.CustomUsersStyle);
-```
-
-
+```java YourActivity.java lines
+cometchatUsers.setOnError(cometchatException -> {
-
-```kotlin
-cometChatUsers.setStyle(R.style.CustomUsersStyle)
+});
```
-
-
-***
-
-To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_users.xml).
-
-### Functionality
-
-These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can toggle the visibility of UI elements.
-
-Below is a list of customizations along with corresponding code snippets
-
-| Methods | Description | Code |
-| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
-| setBackIconVisibility | Used to toggle visibility for back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` |
-| setToolbarVisibility | Used to toggle visibility for back button in the app bar | `.setToolbarVisibility(View.GONE);` |
-| setStickyHeaderVisibility | Used to toggle visibility for back button in the app bar | `.setStickyHeaderVisibility(View.GONE);` |
-| setErrorStateVisibility | Used to hide error state on fetching Users | `.setErrorStateVisibility(View.GONE);` |
-| setEmptyStateVisibility | Used to hide empty state on fetching Users | `.setEmptyStateVisibility(View.GONE);` |
-| setLoadingStateVisibility | Used to hide loading state while fetching Users | `.setLoadingStateVisibility(View.GONE);` |
-| setSeparatorVisibility | Used to control visibility of Separators in the list view | `.setSeparatorVisibility(View.GONE);` |
-| setUsersStatusVisibility | Used to control visibility of status indicator shown if user is online | `.setUsersStatusVisibility(View.GONE);` |
-| setSelectionMode | This method determines the selection mode for Users, enabling users to select either a single User or multiple Users at once. | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
-| setSearchkeyword | Used for fetching users matching the passed keywords | `.setSearchkeyword("anything");` |
-| setSearchBoxVisibility | Used to hide search box shown in the tool bar | `.setSearchBoxVisibility(View.GONE);` |
-
-***
+#### `setOnLoad`
-### Advanced
-
-For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component.
-
-***
-
-#### setOptions
-
-This method sets a predefined list of actions that users can perform when they long press a user in the list. These options typically include:
-
-* Muting notifications for a specific user
-
-By customizing these options, developers can provide a streamlined and contextually relevant user experience.
+Fires when the list is successfully fetched and loaded.
-
-```java
-cometchatUsers.setOptions((context, user) -> Collections.emptyList());
-```
+
+```kotlin YourActivity.kt lines
+cometchatUsers.setOnLoad(object : OnLoad {
+ override fun onLoad(list: MutableList?) {
+ }
+})
+```
-
-```kotlin
-cometchatUsers.options = Function2?> { context, user -> emptyList() }
-```
+
+```java YourActivity.java lines
+cometchatUsers.setOnLoad(list -> {
+});
+```
-
-***
-
-#### addOptions
+#### `setOnEmpty`
-This method extends the existing set of actions available when users long press a user item. Unlike setOptionsDefines, which replaces the default options, addOptionsAdds allows developers to append additional actions without removing the default ones. Example use cases include:
-
-* Adding a "Report Spam" action
-* Introducing a "Save to Notes" option
-* Integrating third-party actions such as "Share to Cloud Storage"
-
-This method provides flexibility in modifying user interaction capabilities.
+Fires when the list is empty, enabling custom handling such as showing a placeholder.
-
-```java
-cometchatUsers.addOptions((context, user) -> Collections.emptyList());
+
+```kotlin YourActivity.kt lines
+cometchatUsers.setOnEmpty {
+
+}
```
-
-
-```kotlin
-cometchatUsers.addOptions { context, user -> emptyList() }
+
+```java YourActivity.java lines
+cometchatUsers.setOnEmpty(() -> {
+
+});
```
-
-
-***
-
-#### setLoadingView
+- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap, long-press, back, select) and confirm your custom logic executes instead of the default behavior.
-This method allows developers to set a custom loading view that is displayed when data is being fetched or loaded within the component. Instead of using a default loading spinner, a custom animation, progress bar, or branded loading screen can be displayed.
+### Global UI Events
-Use cases:
+`CometChatUserEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed.
-* Showing a skeleton loader for users while data loads
-* Displaying a custom progress indicator with branding
-* Providing an animated loading experience for a more engaging UI
+| Event | Fires when | Payload |
+| --- | --- | --- |
+| `ccUserBlocked` | The logged-in user blocks another user | `User` |
+| `ccUserUnblocked` | The logged-in user unblocks another user | `User` |
-
-```java
-cometchatUsers.setLoadingView(R.layout.your_loading_view);
+
+```kotlin Add Listener lines
+CometChatUserEvents.addUserListener("LISTENER_TAG", object : CometChatUserEvents() {
+ override fun ccUserBlocked(user: User?) {
+ super.ccUserBlocked(user)
+ }
+
+ override fun ccUserUnblocked(user: User?) {
+ super.ccUserUnblocked(user)
+ }
+})
```
-
+Remove Listener
-
-```kotlin
-cometchatUsers.loadingView = R.layout.your_loading_view
```
-
+CometChatUserEvents.removeListener("LISTENER_TAG")
+```
-
-
-***
-
-#### setEmptyView
-
-Configures a custom view to be displayed when there are no users. This improves the user experience by providing meaningful content instead of an empty screen.
-
-Examples:
-
-* Displaying a message like "No users yet. Start a new chat!"
-* Showing an illustration or animation to make the UI visually appealing
-* Providing a button to start a new user
-
-
-```java
-cometchatUsers.setEmptyView(R.layout.your_empty_view);
+```java Add Listener lines
+CometChatUserEvents.addUserListener("LISTENER_TAG", new CometChatUserEvents() {
+ @Override
+ public void ccUserBlocked(User user) {
+ super.ccUserBlocked(user);
+ }
+
+ @Override
+ public void ccUserUnblocked(User user) {
+ super.ccUserUnblocked(user);
+ }
+});
```
-
+Remove Listener
-
-```kotlin
-cometchatUsers.emptyView = R.layout.your_empty_view
```
-
+CometChatUserEvents.removeListener("LISTENER_TAG");
+```
-
-***
+### SDK Events (Real-Time, Automatic)
-#### setErrorView
+The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.
-Defines a custom error state view that appears when an issue occurs while loading users or messages. This enhances the user experience by displaying friendly error messages instead of generic system errors.
+| SDK Listener | Internal behavior |
+| --- | --- |
+| `onUserOnline` | Updates online status indicator for the user |
+| `onUserOffline` | Updates offline status indicator for the user |
-Common use cases:
+> Automatic: user presence changes update the status indicator in real time.
-* Showing "Something went wrong. Please try again." with a retry button
-* Displaying a connection issue message if the user is offline
-* Providing troubleshooting steps for the error
+## Functionality
-
-
-```java
-cometchatUsers.setErrorView(R.layout.your_empty_view);
-```
+Small functional customizations such as toggling visibility of UI elements and configuring selection modes.
-
+| Methods | Description | Code |
+| --- | --- | --- |
+| `setBackIconVisibility` | Toggles visibility for the back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` |
+| `setToolbarVisibility` | Toggles visibility for the toolbar in the app bar | `.setToolbarVisibility(View.GONE);` |
+| `setStickyHeaderVisibility` | Toggles visibility for the alphabetical sticky header | `.setStickyHeaderVisibility(View.GONE);` |
+| `setLoadingStateVisibility` | Hides the loading state while fetching users | `.setLoadingStateVisibility(View.GONE);` |
+| `setErrorStateVisibility` | Hides the error state on fetching users | `.setErrorStateVisibility(View.GONE);` |
+| `setEmptyStateVisibility` | Hides the empty state on fetching users | `.setEmptyStateVisibility(View.GONE);` |
+| `setSeparatorVisibility` | Controls visibility of separators in the list view | `.setSeparatorVisibility(View.GONE);` |
+| `setUserStatusVisibility` | Controls visibility of the online status indicator | `.setUserStatusVisibility(View.GONE);` |
+| `setSearchBoxVisibility` | Controls visibility of the search box in the toolbar | `.setSearchBoxVisibility(View.GONE);` |
+| `setSelectionMode` | Determines the selection mode (single or multiple) | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| `setSearchKeyword` | Programmatically triggers a search with the given keyword | `.setSearchKeyword("john");` |
+| `setTitleText` | Sets a custom title in the toolbar | `.setTitleText("Contacts");` |
+| `setSearchPlaceholderText` | Sets the placeholder text for the search input | `.setSearchPlaceholderText("Find users...");` |
-
-```kotlin
-cometchatUsers.errorView = R.layout.your_error_view
-```
+- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden.
-
+## Custom View Slots
-
+Each slot replaces a section of the default UI. Slots that accept a `User` parameter receive the user object for that row via the `UsersViewHolderListener` pattern (`createView` + `bindView`).
-***
+| Slot | Method | Replaces |
+| --- | --- | --- |
+| Leading view | `setLeadingView(UsersViewHolderListener)` | Avatar / left section |
+| Title view | `setTitleView(UsersViewHolderListener)` | Name / title text |
+| Subtitle view | `setSubtitleView(UsersViewHolderListener)` | Subtitle text below name |
+| Trailing view | `setTrailingView(UsersViewHolderListener)` | Right section |
+| Item view | `seItemView(UsersViewHolderListener)` | Entire list item row (note: typo in SDK) |
+| Loading view | `setLoadingView(@LayoutRes int)` | Loading spinner |
+| Empty view | `setEmptyView(@LayoutRes int)` | Empty state |
+| Error view | `setErrorView(@LayoutRes int)` | Error state |
+| Overflow menu | `setOverflowMenu(View)` | Toolbar menu |
+| Options (replace) | `setOptions(Function2)` | Long-press context menu (replaces defaults) |
+| Options (append) | `addOptions(Function2)` | Long-press context menu (appends to defaults) |
-#### setLeadingView
-This method allows developers to set a custom leading view element that appears at the beginning of each user item. Typically, this space is used for profile pictures, avatars, or user badges.
+### `setLeadingView`
-Use Cases:
-
-* Profile Pictures & Avatars – Display user profile images with online/offline indicators.
-* Custom Icons or Badges – Show role-based badges (Admin, VIP, Verified) before the user name.
-* Status Indicators – Add an active status ring or colored border based on availability.
+Replace the avatar / left section.
-
-```java
-cometchatUsers.setLeadingView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-
- }
- });
-```
-
-
-
-```kotlin
-cometchatUsers.setLeadingView(object: UsersViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatUsers.setLeadingView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, user: User, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
}
})
```
-
-
+
+```java lines
+cometchatUsers.setLeadingView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
-***
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-#### setTitleView
+ }
+});
+```
+
+
-This method customizes the title view of each user item, which typically displays the user’s name. It allows for styling modifications, additional metadata, or inline action buttons.
+> **What this does:** Registers a `UsersViewHolderListener` that provides a custom view for the leading (left) area of each user item. `createView` inflates your layout, and `bindView` populates it with user data.
-Use Cases:
+### `setTitleView`
-* Styled Usernames – Customize fonts, colors, or text sizes for the name display.
-* Additional Metadata – Show extra details like username handles or job roles.
-* Inline Actions – Add a follow button or verification checkmark next to the name.
+Replace the name / title text.
-
-```java
-cometchatUsers.setTitleView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-
- }
- });
-```
-
-
-
-```kotlin
-cometchatUsers.setTitleView(object: UsersViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatUsers.setTitleView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, user: User, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
}
})
```
-
+
+```java lines
+cometchatUsers.setTitleView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+
+ }
+});
+```
+
+Inline role badge example:
+
-You can indeed create a custom layout file named `custom_user_title_view.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `UsersViewHolderListener`. The inflation process prepares the layout for use in your application:
+Create a `custom_user_title_view.xml` layout:
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the User object:
-
-```xml custom_user_title_view.xml
+```xml custom_user_title_view.xml lines
-
-```java
-cometchatUsers.setTitleView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_user_title_view, null);
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
- LinearLayout layout = createdView.findViewById(R.id.user_layout);
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- layout.setLayoutParams(layoutParams);
- TextView name = createdView.findViewById(R.id.title);
- name.setText(user.getName());
- View role = createdView.findViewById(R.id.role);
- if ("teacher".equals(user.getRole())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.teacher, null));
- } else if ("student".equals(user.getRole())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.student, null));
- } else if ("close_friend".equals(user.getRole())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.close_friend, null));
- } else {
- role.setVisibility(View.GONE);
- }
+
+```kotlin lines
+cometchatUsers.setTitleView(object : UsersViewHolderListener() {
+ override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_user_title_view, null)
+ }
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
+ val layout = createdView.findViewById(R.id.user_layout)
+ val layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ layout.layoutParams = layoutParams
+ val name = createdView.findViewById(R.id.title)
+ name.text = user.name
+ val role = createdView.findViewById(R.id.role)
+ when (user.role) {
+ "teacher" -> {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.teacher, null)
}
- });
+ "student" -> {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.student, null)
+ }
+ "close_friend" -> {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.close_friend, null)
+ }
+ else -> role.visibility = View.GONE
+ }
+ }
+})
```
+
+
+
+```java lines
+cometchatUsers.setTitleView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_user_title_view, null);
+ }
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+ LinearLayout layout = createdView.findViewById(R.id.user_layout);
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ layout.setLayoutParams(layoutParams);
+ TextView name = createdView.findViewById(R.id.title);
+ name.setText(user.getName());
+ View role = createdView.findViewById(R.id.role);
+ if ("teacher".equals(user.getRole())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.teacher, null));
+ } else if ("student".equals(user.getRole())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.student, null));
+ } else if ("close_friend".equals(user.getRole())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.close_friend, null));
+ } else {
+ role.setVisibility(View.GONE);
+ }
+ }
+});
+```
+
+
+### `setSubtitleView`
+
+Replace the subtitle text below the user's name.
+
-```kotlin
-cometchatUsers.setTitleView(object : UsersViewHolderListener() {
- override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_user_title_view, null)
- }
+```kotlin lines
+cometchatUsers.setSubtitleView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
+ return null
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- user: User,
- holder: RecyclerView.ViewHolder,
- userList: List,
- position: Int
- ) {
- val layout = createdView.findViewById(R.id.user_layout)
- val layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- layout.layoutParams = layoutParams
- val name = createdView.findViewById(R.id.title)
- name.text = user.name
- val role = createdView.findViewById(R.id.role)
- if ("teacher" == user.role) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.teacher, null)
- } else if ("student" == user.role) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.student, null)
- } else if ("close_friend" == user.role) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.close_friend, null)
- } else {
- role.visibility = View.GONE
- }
- }
- })
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
+ }
+})
```
-
-
-
-***
+
+```java lines
+cometchatUsers.setSubtitleView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
-#### setTrailingView
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-This method allows developers to customize the trailing (right-end) section of each user item, typically used for actions like buttons, icons, or extra information.
+ }
+});
+```
+
+
-Use Cases:
+Example with last-active timestamp:
-* Quick Actions – Add a follow/unfollow button.
-* Notification Indicators – Show unread message counts or alert icons.
-* Custom Info Display – Display last active time or mutual connections.
+
+
+
-
-```java
-cometchatUsers.setTrailingView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
+
+```kotlin lines
+cometchatUsers.setSubtitleView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View {
+ return TextView(context)
+ }
+
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
+ val tvSubtitle = createdView as TextView
+ tvSubtitle.text =
+ "Last Active at: " + SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(user.lastActiveAt * 1000)
+ tvSubtitle.setTextColor(Color.BLACK)
+ }
+})
+```
+
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+
+```java lines
+cometchatUsers.setSubtitleView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return new TextView(context);
+ }
- }
- });
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+ TextView tvSubtitle = (TextView) createdView;
+ tvSubtitle.setText("Last Active at: " + new SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(user.getLastActiveAt() * 1000));
+ tvSubtitle.setTextColor(Color.BLACK);
+ }
+});
```
-
+
+
+### `setTrailingView`
+
+Replace the right section of each user item.
+
-```kotlin
-cometchatUsers.setTrailingView(object: UsersViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatUsers.setTrailingView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, user: User, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
}
})
```
-
+
+```java lines
+cometchatUsers.setTrailingView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+
+ }
+});
+```
+
+Role tag badge example:
+
-You can indeed create a custom layout file named `custom_user_tail_view.xml` for more complex or unique list items.
-
-Once this layout file is made, you would inflate it inside the `createView()` method of the `UsersViewHolderListener`. The inflation process prepares the layout for use in your application:
+Create a `custom_user_tail_view.xml` layout:
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the User object:
-
-```xml custom_user_tail_view.xml
+```xml custom_user_tail_view.xml lines
-
-```java
-cometchatUsers.setTrailingView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_user_tail_view, null);
- }
+
+```kotlin lines
+cometchatUsers.setTrailingView(object : UsersViewHolderListener() {
+ override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
+ return LayoutInflater.from(context).inflate(R.layout.custom_user_tail_view, null)
+ }
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
- View role = createdView.findViewById(R.id.tag);
- if ("pro".equals(user.getRole())) {
- role.setVisibility(View.VISIBLE);
- role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.teacher, null));
- } else {
- role.setVisibility(View.GONE);
- }
- }
- });
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
+ val role = createdView.findViewById(R.id.tag)
+ if ("pro" == user.role) {
+ role.visibility = View.VISIBLE
+ role.background = ResourcesCompat.getDrawable(resources, R.drawable.teacher, null)
+ } else {
+ role.visibility = View.GONE
+ }
+ }
+})
```
-
-
-```kotlin
-cometchatUsers.setTrailingView(object : UsersViewHolderListener() {
- override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
- return LayoutInflater.from(context).inflate(R.layout.custom_user_tail_view, null)
- }
+
+```java lines
+cometchatUsers.setTrailingView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_user_tail_view, null);
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- user: User,
- holder: RecyclerView.ViewHolder,
- userList: List,
- position: Int
- ) {
- val role = createdView.findViewById(R.id.tag)
- if ("pro" == user.role) {
- role.visibility = View.VISIBLE
- role.background = ResourcesCompat.getDrawable(resources, R.drawable.teacher, null)
- } else {
- role.visibility = View.GONE
- }
- }
- })
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+ View role = createdView.findViewById(R.id.tag);
+ if ("pro".equals(user.getRole())) {
+ role.setVisibility(View.VISIBLE);
+ role.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.teacher, null));
+ } else {
+ role.setVisibility(View.GONE);
+ }
+ }
+});
```
-
-
-***
-
-#### setItemView
+### `setItemView`
-This method allows developers to assign a fully custom ListItem layout to the Users component, replacing the default design. It provides complete control over the appearance and structure of each user item in the list.
+Replace the entire list item row.
-Use Cases:
-
-* Customizing User Display – Modify how user information (name, avatar, status) is presented.
-* Adding Action Buttons – Include follow, message, or call buttons directly in the item view.
-* Highlighting User Roles – Display user badges such as Admin, Moderator, or VIP.
+
+The Java method name is `seItemView` (note the missing 't'). This is a known typo in the SDK. In Kotlin, property access syntax normalizes this.
+
-
-```java
- cometchatUsers.seItemView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
-
- }
- });
-```
-
-
-
-```kotlin
-cometchatUsers.setItemView(object: UsersViewHolderListener {
- override fun createView(context: Context, cometChatListItem: CometChatListItem): View? {
+```kotlin lines
+cometchatUsers.seItemView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View? {
return null
}
- override fun bindView(context: Context, view: View, user: User, viewHolder: RecyclerView.ViewHolder, list: List, i: Int) {
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
}
})
```
-
+
+```java lines
+cometchatUsers.seItemView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return null;
+ }
+
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+
+ }
+});
+```
+
-**Example**
+Example with online status background:
-You can indeed create a custom layout file named `custom_list_item_view.xml` for more complex or unique list items.
+Create a `custom_list_item_view.xml` layout:
-Once this layout file is made, you would inflate it inside the `createView()` method of the `UsersViewHolderListener`. The inflation process prepares the layout for use in your application:
-
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the User object:
-
-```xml custom_list_item_view.xml
+```xml custom_list_item_view.xml lines
-
-
-```java YourActivity.java
-binding.users.setListItemView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return LayoutInflater.from(context).inflate(R.layout.custom_list_item_view, null, false);
- }
-
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
- CometChatAvatar avatar = createdView.findViewById(R.id.custom_avatar);
- TextView title = createdView.findViewById(R.id.tvName);
- LinearLayout parentLayout = createdView.findViewById(R.id.parent_lay);
- String name = user.getName();
- title.setText(name);
- avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle);
- avatar.setAvatarPlaceHolderTextAppearance(com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold);
- avatar.setAvatar(name,user.getAvatar());
- if(user.getStatus().equals(UIKitConstants.UserStatus.ONLINE)) {
- parentLayout.setBackgroundColor(Color.parseColor("#E6F4ED"));
- } else {
- parentLayout.setBackgroundColor(Color.parseColor("#00000000"));
- }
+
+```kotlin lines
+cometchatUsers.seItemView(object : UsersViewHolderListener() {
+ override fun createView(
+ context: Context?,
+ listItem: CometchatListBaseItemsBinding?
+ ): View {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.custom_list_item_view, null, false)
+ }
- }
- });
+ override fun bindView(
+ context: Context,
+ createdView: View,
+ user: User,
+ holder: RecyclerView.ViewHolder,
+ userList: List,
+ position: Int
+ ) {
+ val avatar = createdView.findViewById(R.id.custom_avatar)
+ val title = createdView.findViewById(R.id.tvName)
+ val parentLayout = createdView.findViewById(R.id.parent_lay)
+ val name = user.name
+ title.text = name
+ avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle)
+ avatar.avatarPlaceHolderTextAppearance =
+ com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold
+ avatar.setAvatar(name, user.avatar)
+ if (user.status == UIKitConstants.UserStatus.ONLINE) {
+ parentLayout.setBackgroundColor(Color.parseColor("#E6F4ED"))
+ } else {
+ parentLayout.setBackgroundColor(Color.parseColor("#00000000"))
+ }
+ }
+})
```
-
-
-```kotlin YourActivity.kt
-users.setListItemView(object : UsersViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatListBaseItemsBinding?
- ): View {
- return LayoutInflater.from(context)
- .inflate(R.layout.custom_list_item_view, null, false)
- }
+
+```java lines
+cometchatUsers.seItemView(new UsersViewHolderListener() {
+ @Override
+ public View createView(Context context, CometchatListBaseItemsBinding listItem) {
+ return LayoutInflater.from(context).inflate(R.layout.custom_list_item_view, null, false);
+ }
- override fun bindView(
- context: Context,
- createdView: View,
- user: User,
- holder: RecyclerView.ViewHolder,
- userList: List,
- position: Int
- ) {
- val avatar = createdView.findViewById(R.id.custom_avatar)
- val title = createdView.findViewById(R.id.tvName)
- val parentLayout = createdView.findViewById(R.id.parent_lay)
- val name = user.name
- title.text = name
- avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle)
- avatar.avatarPlaceHolderTextAppearance =
- com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold
- avatar.setAvatar(name, user.avatar)
- if (user.status == UIKitConstants.UserStatus.ONLINE) {
- parentLayout.setBackgroundColor(Color.parseColor("#E6F4ED"))
- } else {
- parentLayout.setBackgroundColor(Color.parseColor("#00000000"))
- }
- }
- })
+ @Override
+ public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+ CometChatAvatar avatar = createdView.findViewById(R.id.custom_avatar);
+ TextView title = createdView.findViewById(R.id.tvName);
+ LinearLayout parentLayout = createdView.findViewById(R.id.parent_lay);
+ String name = user.getName();
+ title.setText(name);
+ avatar.setStyle(com.cometchat.chatuikit.R.style.CometChatAvatarStyle);
+ avatar.setAvatarPlaceHolderTextAppearance(com.cometchat.chatuikit.R.style.CometChatTextAppearanceHeading4_Bold);
+ avatar.setAvatar(name, user.getAvatar());
+ if (user.getStatus().equals(UIKitConstants.UserStatus.ONLINE)) {
+ parentLayout.setBackgroundColor(Color.parseColor("#E6F4ED"));
+ } else {
+ parentLayout.setBackgroundColor(Color.parseColor("#00000000"));
+ }
+ }
+});
```
-
-
-***
+### `setOptions`
+
+Replace the long-press context menu entirely.
-#### setSubtitleView
+
+
+```kotlin lines
+cometchatUsers.setOptions { context, user -> emptyList() }
+```
+
-This method customizes the subtitle view of each user item, typically shown below the user's name. It can display additional details such as user status, last seen time, or a brief bio.
+
+```java lines
+cometchatUsers.setOptions((context, user) -> Collections.emptyList());
+```
+
+
-Use Cases:
+### `addOptions`
-* Last Active Time – Show "Online Now", "Last seen 2 hours ago".
-* User Status – Display status messages like "Offine", "Available".
+Append to the long-press context menu without removing defaults.
+
+```kotlin lines
+cometchatUsers.addOptions { context, user -> emptyList() }
+```
+
+
-```java
-cometChatUsers.setSubtitleView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return null;
- }
+```java lines
+cometchatUsers.addOptions((context, user) -> Collections.emptyList());
+```
+
+
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
+### `setLoadingView`
- }
- });
+Sets a custom loading view displayed when data is being fetched.
+
+
+
+```kotlin lines
+cometchatUsers.loadingView = R.layout.your_loading_view
```
+
+
+```java lines
+cometchatUsers.setLoadingView(R.layout.your_loading_view);
+```
+
+
+### `setEmptyView`
+
+Configures a custom view displayed when there are no users in the list.
+
-```kotlin
-cometChatUsers.setSubtitleView(object : UsersViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatListBaseItemsBinding?
- ): View? {
- return null
- }
+```kotlin lines
+cometchatUsers.emptyView = R.layout.your_empty_view
+```
+
- override fun bindView(
- context: Context,
- createdView: View,
- user: User,
- holder: RecyclerView.ViewHolder,
- userList: List,
- position: Int
- ) {
- }
- })
+
+```java lines
+cometchatUsers.setEmptyView(R.layout.your_empty_view);
```
+
+
+
+### `setErrorView`
+
+Defines a custom error state view that appears when an issue occurs while loading users.
+
+
+```kotlin lines
+cometchatUsers.errorView = R.layout.your_error_view
+```
+
+```java lines
+cometchatUsers.setErrorView(R.layout.your_error_view);
+```
+
-**Example**
+### `setOverflowMenu`
+
+Replace the toolbar overflow menu.
-
+
-You can indeed create a custom layout file named `subtitle_layout.xml` for more complex or unique list items.
+
+
+```kotlin lines
+val imageView = ImageView(requireContext())
+imageView.setImageResource(R.drawable.ic_user_menu)
+cometchatUsers.setOverflowMenu(imageView)
+```
+
-Once this layout file is made, you would inflate it inside the `createView()` method of the `UsersViewHolderListener`. The inflation process prepares the layout for use in your application:
+
+```java lines
+ImageView imageView = new ImageView(requireContext());
+imageView.setImageResource(R.drawable.ic_user_menu);
+cometchatUsers.setOverflowMenu(imageView);
+```
+
+
-Following this, you would use the `bindView()` method to initialize and assign values to your individual views. This could include setting text on TextViews, images on ImageViews, and so on based on the properties of the User object:
+- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the user list item, and the data binding populates correctly for each user.
-
-
-```java
-cometChatUsers.setSubtitleView(new UsersViewHolderListener() {
- @Override
- public View createView(Context context, CometchatListBaseItemsBinding listItem) {
- return new TextView(context);
- }
+## Common Patterns
- @Override
- public void bindView(Context context, View createdView, User user, RecyclerView.ViewHolder holder, List userList, int position) {
- TextView tvSubtitle = (TextView) createdView;
- tvSubtitle.setText("Last Active at: "+new SimpleDateFormat("dd/mm/yyyy, HH:MM:SS").format(user.getLastActiveAt() * 1000));
- tvSubtitle.setTextColor(Color.BLACK);
- }
- });
+### Hide all chrome — minimal list
+
+
+
+```kotlin lines
+cometChatUsers.setUserStatusVisibility(View.GONE)
+cometChatUsers.setSeparatorVisibility(View.GONE)
+cometChatUsers.setToolbarVisibility(View.GONE)
+cometChatUsers.setStickyHeaderVisibility(View.GONE)
```
+
+
+```java lines
+cometChatUsers.setUserStatusVisibility(View.GONE);
+cometChatUsers.setSeparatorVisibility(View.GONE);
+cometChatUsers.setToolbarVisibility(View.GONE);
+cometChatUsers.setStickyHeaderVisibility(View.GONE);
+```
+
+### Friends-only list
+
+
-```kotlin
-cometChatUsers.setSubtitleView(object : UsersViewHolderListener() {
- override fun createView(
- context: Context?,
- listItem: CometchatListBaseItemsBinding?
- ): View {
- return TextView(context)
- }
+```kotlin lines
+val builder = UsersRequest.UsersRequestBuilder()
+ .friendsOnly(true)
+cometChatUsers.setUsersRequestBuilder(builder)
+```
+
- override fun bindView(
- context: Context,
- createdView: View,
- user: User,
- holder: RecyclerView.ViewHolder,
- userList: List,
- position: Int
- ) {
- val tvSubtitle = createdView as TextView
- tvSubtitle.text =
- "Last Active at: " + SimpleDateFormat("dd/mm/yyyy, HH:MM:SS").format(user.lastActiveAt * 1000)
- tvSubtitle.setTextColor(Color.BLACK)
- }
- })
+
+```java lines
+UsersRequest.UsersRequestBuilder builder = new UsersRequest.UsersRequestBuilder()
+ .friendsOnly(true);
+cometChatUsers.setUsersRequestBuilder(builder);
```
+
+
+
+### Online users only
+
+
+```kotlin lines
+val builder = UsersRequest.UsersRequestBuilder()
+ .setUserStatus(CometChatConstants.USER_STATUS_ONLINE)
+cometChatUsers.setUsersRequestBuilder(builder)
+```
+
+```java lines
+UsersRequest.UsersRequestBuilder builder = new UsersRequest.UsersRequestBuilder()
+ .setUserStatus(CometChatConstants.USER_STATUS_ONLINE);
+cometChatUsers.setUsersRequestBuilder(builder);
+```
+
-***
-#### setOverflowMenu
+## Advanced Methods
-This method customizes the overflow menu, typically appearing as a three-dot (⋮) icon, allowing additional options for each user in the list.
+### Programmatic Selection
-Use Cases:
+#### `selectUser`
-* User Management Actions – "Block User", "Report", "Add to Favorites".
-* Friendship & Communication – "Send Message", "Follow/Unfollow".
-* Profile Settings – "View Profile", "Edit Contact Info".
+Programmatically selects or deselects a user. Works with both `SINGLE` and `MULTIPLE` selection modes.
-
-```java
-users.setOverflowMenu(v);
+
+```kotlin lines
+// Select a user in single-select mode
+cometChatUsers.selectUser(user, UIKitConstants.SelectionMode.SINGLE)
+
+// Select a user in multi-select mode
+cometChatUsers.selectUser(user, UIKitConstants.SelectionMode.MULTIPLE)
```
+
+
+
+```java lines
+// Select a user in single-select mode
+cometChatUsers.selectUser(user, UIKitConstants.SelectionMode.SINGLE);
+// Select a user in multi-select mode
+cometChatUsers.selectUser(user, UIKitConstants.SelectionMode.MULTIPLE);
+```
+
+
+> In `SINGLE` mode, selecting a new user replaces the previous selection. In `MULTIPLE` mode, calling this on an already-selected user deselects it (toggle behavior).
+
+#### `clearSelection`
+Clears all selected users and resets the selection UI.
+
+
-```kotlin
-users.setOverflowMenu(v)
+```kotlin lines
+cometChatUsers.clearSelection()
```
-
+
+```java lines
+cometChatUsers.clearSelection();
+```
+
-**Example**
+#### `getSelectedUsers`
-
-
-
+Returns the list of currently selected `User` objects.
-
-```java
- ImageView imageView = new ImageView(requireContext());
- imageView.setImageResource(R.drawable.ic_user_menu);
- users.setOverflowMenu(imageView);
+
+```kotlin lines
+val selected = cometChatUsers.selectedUsers
```
+
+
+```java lines
+List selected = cometChatUsers.getSelectedUsers();
+```
+
-
-```kotlin
- val imageView = ImageView(requireContext())
- imageView.setImageResource(android.R.drawable.ic_user_menu)
- users.setOverflowMenu(imageView)
+### Selected Users List
+
+When using multi-select mode, a horizontal list of selected users can be shown above the main list.
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSelectedUsersListVisibility` | `int (View.VISIBLE / View.GONE)` | Show or hide the selected users strip |
+| `setSelectedUserAvatarStyle` | `@StyleRes int` | Avatar style for selected user chips |
+| `setSelectedUserItemTextColor` | `@ColorInt int` | Text color for selected user names |
+| `setSelectedUserItemTextAppearance` | `@StyleRes int` | Text appearance for selected user names |
+| `setSelectedUserItemRemoveIcon` | `Drawable` | Icon for the remove button on each chip |
+| `setSelectedUserItemRemoveIconTint` | `@ColorInt int` | Tint color for the remove icon |
+
+### Search Input Customization
+
+The built-in search box can be customized programmatically:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setSearchPlaceholderText` | `String` | Sets the placeholder text for the search input |
+| `setSearchInputTextColor` | `@ColorInt int` | Text color of the search input |
+| `setSearchInputTextAppearance` | `@StyleRes int` | Text appearance of the search input |
+| `setSearchInputPlaceHolderTextColor` | `@ColorInt int` | Placeholder text color |
+| `setSearchInputPlaceHolderTextAppearance` | `@StyleRes int` | Placeholder text appearance |
+| `setSearchInputIcon` | `Drawable` | Leading icon in the search box |
+| `setSearchInputIconTint` | `@ColorInt int` | Tint for the leading icon |
+| `setSearchInputEndIcon` | `Drawable` | Trailing icon in the search box |
+| `setSearchInputEndIconTint` | `@ColorInt int` | Tint for the trailing icon |
+| `setSearchInputStrokeWidth` | `@Dimension int` | Stroke width of the search box border |
+| `setSearchInputStrokeColor` | `@ColorInt int` | Stroke color of the search box border |
+| `setSearchInputBackgroundColor` | `@ColorInt int` | Background color of the search box |
+| `setSearchInputCornerRadius` | `@Dimension int` | Corner radius of the search box |
+
+### Internal Access
+
+These methods provide direct access to internal components for advanced use cases.
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getBinding()` | `CometchatUserListBinding` | The ViewBinding for the component's root layout |
+| `getViewModel()` | `UsersViewModel` | The ViewModel managing user data and state |
+| `getUsersAdapter()` | `UsersAdapter` | The adapter powering the RecyclerView |
+| `setAdapter(UsersAdapter)` | `void` | Replaces the default adapter with a custom one |
+
+> Use these only when the standard API is insufficient. Directly manipulating the adapter or ViewModel may conflict with the component's internal state management.
+
+## Style
+
+The component uses XML theme styles. Define a custom style with parent `CometChatUsersStyle` in `themes.xml`, then apply with `setStyle()`.
+
+
+
+
+
+```xml themes.xml lines
+
+
```
+
+
+```kotlin lines
+cometChatUsers.setStyle(R.style.CustomUsersStyle)
+```
+
+```java lines
+cometChatUsers.setStyle(R.style.CustomUsersStyle);
+```
+
+
+To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_users.xml).
+
+### Programmatic Style Properties
+
+In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setBackgroundColor` | `@ColorInt int` | Background color of the component |
+| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon |
+| `setBackIcon` | `Drawable` | Custom back icon drawable |
+| `setTitleTextColor` | `@ColorInt int` | Title text color in the toolbar |
+| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance in the toolbar |
+| `setItemTitleTextColor` | `@ColorInt int` | Text color for user item titles |
+| `setItemTitleTextAppearance` | `@StyleRes int` | Text appearance for user item titles |
+| `setItemBackgroundColor` | `@ColorInt int` | Background color for list items |
+| `setItemSelectedBackgroundColor` | `@ColorInt int` | Background color for selected list items |
+| `setSeparatorColor` | `@ColorInt int` | Color of list item separators |
+| `setStrokeColor` | `@ColorInt int` | Stroke color of the component border |
+| `setStrokeWidth` | `@Dimension int` | Stroke width of the component border |
+| `setCornerRadius` | `@Dimension int` | Corner radius of the component |
+| `setStickyTitleColor` | `@ColorInt int` | Text color for sticky alphabetical headers |
+| `setStickyTitleAppearance` | `@StyleRes int` | Text appearance for sticky headers |
+| `setStickyTitleBackgroundColor` | `@ColorInt int` | Background color for sticky headers |
+| `setEmptyStateTextColor` | `@ColorInt int` | Title text color for the empty state |
+| `setEmptyStateTextAppearance` | `@StyleRes int` | Title text appearance for the empty state |
+| `setEmptyStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the empty state |
+| `setEmptyStateSubTitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the empty state |
+| `setErrorStateTextColor` | `@ColorInt int` | Title text color for the error state |
+| `setErrorStateTextAppearance` | `@StyleRes int` | Title text appearance for the error state |
+| `setErrorStateSubtitleColor` | `@ColorInt int` | Subtitle text color for the error state |
+| `setErrorStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the error state |
+| `setRetryButtonTextColor` | `@ColorInt int` | Text color for the retry button |
+| `setRetryButtonTextAppearance` | `@StyleRes int` | Text appearance for the retry button |
+| `setRetryButtonBackgroundColor` | `@ColorInt int` | Background color for the retry button |
+| `setRetryButtonStrokeColor` | `@ColorInt int` | Stroke color for the retry button |
+| `setRetryButtonStrokeWidth` | `@Dimension int` | Stroke width for the retry button |
+| `setRetryButtonCornerRadius` | `@Dimension int` | Corner radius for the retry button |
+| `setAvatarStyle` | `@StyleRes int` | Style for user avatars |
+| `setStatusIndicatorStyle` | `@StyleRes int` | Style for online/offline status indicators |
+
+### Checkbox Style Properties (Selection Mode)
+
+When using `SINGLE` or `MULTIPLE` selection mode, checkboxes appear on each item:
+
+| Method | Type | Description |
+| --- | --- | --- |
+| `setCheckBoxStrokeWidth` | `@Dimension int` | Stroke width of the checkbox border |
+| `setCheckBoxCornerRadius` | `@Dimension int` | Corner radius of the checkbox |
+| `setCheckBoxStrokeColor` | `@ColorInt int` | Stroke color of the checkbox border |
+| `setCheckBoxBackgroundColor` | `@ColorInt int` | Background color of unchecked checkbox |
+| `setCheckBoxCheckedBackgroundColor` | `@ColorInt int` | Background color of checked checkbox |
+| `setCheckBoxSelectIcon` | `Drawable` | Icon shown when checkbox is checked |
+| `setCheckBoxSelectIconTint` | `@ColorInt int` | Tint for the checkbox select icon |
+| `setDiscardSelectionIcon` | `Drawable` | Icon for the discard selection button |
+| `setDiscardSelectionIconTint` | `@ColorInt int` | Tint for the discard selection icon |
+| `setSubmitSelectionIcon` | `Drawable` | Icon for the submit selection button |
+| `setSubmitSelectionIconTint` | `@ColorInt int` | Tint for the submit selection icon |
+
+## Customization Matrix
+
+| What to change | Where | Property/API | Example |
+| --- | --- | --- | --- |
+| Override behavior on user interaction | Activity/Fragment | `setOn` callbacks | `setOnItemClick((v, pos, u) -> { ... })` |
+| Filter which users appear | Activity/Fragment | `setUsersRequestBuilder` | `setUsersRequestBuilder(builder)` |
+| Customize search results | Activity/Fragment | `setSearchRequestBuilder` | `setSearchRequestBuilder(builder)` |
+| Toggle visibility of UI elements | Activity/Fragment | `setVisibility(int)` | `setUserStatusVisibility(View.GONE)` |
+| Replace a section of the list item | Activity/Fragment | `setView` | `setLeadingView(listener)` |
+| Change colors, fonts, spacing | `themes.xml` | `CometChatUsersStyle` | `#F76808` |
+| Avatar style (corner radius, background) | `themes.xml` | `cometchatUsersAvatarStyle` | `8dp` |
+| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometChatUsers.setStyle(R.style.CustomUsersStyle);` |
+| Back button visibility | Activity/Fragment | `setBackIconVisibility(int)` | `.setBackIconVisibility(View.VISIBLE);` |
+| Toolbar visibility | Activity/Fragment | `setToolbarVisibility(int)` | `.setToolbarVisibility(View.GONE);` |
+| Sticky header visibility | Activity/Fragment | `setStickyHeaderVisibility(int)` | `.setStickyHeaderVisibility(View.GONE);` |
+| Error state visibility | Activity/Fragment | `setErrorStateVisibility(int)` | `.setErrorStateVisibility(View.GONE);` |
+| Empty state visibility | Activity/Fragment | `setEmptyStateVisibility(int)` | `.setEmptyStateVisibility(View.GONE);` |
+| Loading state visibility | Activity/Fragment | `setLoadingStateVisibility(int)` | `.setLoadingStateVisibility(View.GONE);` |
+| Separator visibility | Activity/Fragment | `setSeparatorVisibility(int)` | `.setSeparatorVisibility(View.GONE);` |
+| User online status visibility | Activity/Fragment | `setUserStatusVisibility(int)` | `.setUserStatusVisibility(View.GONE);` |
+| Selection mode (single/multiple) | Activity/Fragment | `setSelectionMode(SelectionMode)` | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
+| Search keyword | Activity/Fragment | `setSearchKeyword(String)` | `.setSearchKeyword("john");` |
+| Search box visibility | Activity/Fragment | `setSearchBoxVisibility(int)` | `.setSearchBoxVisibility(View.GONE);` |
+| Custom toolbar title | Activity/Fragment | `setTitleText(String)` | `.setTitleText("Contacts");` |
+| Search placeholder | Activity/Fragment | `setSearchPlaceholderText(String)` | `.setSearchPlaceholderText("Find users...");` |
+| Long-press options (replace) | Activity/Fragment | `setOptions(Function2)` | See `setOptions` code above |
+| Long-press options (append) | Activity/Fragment | `addOptions(Function2)` | See `addOptions` code above |
+| Loading view | Activity/Fragment | `setLoadingView(int)` | `.setLoadingView(R.layout.your_loading_view);` |
+| Empty view | Activity/Fragment | `setEmptyView(int)` | `.setEmptyView(R.layout.your_empty_view);` |
+| Error view | Activity/Fragment | `setErrorView(int)` | `.setErrorView(R.layout.your_error_view);` |
+| Leading view (avatar area) | Activity/Fragment | `setLeadingView(UsersViewHolderListener)` | See `setLeadingView` code above |
+| Title view | Activity/Fragment | `setTitleView(UsersViewHolderListener)` | See `setTitleView` code above |
+| Trailing view | Activity/Fragment | `setTrailingView(UsersViewHolderListener)` | See `setTrailingView` code above |
+| Entire list item | Activity/Fragment | `seItemView(UsersViewHolderListener)` | See `setItemView` code above |
+| Subtitle view | Activity/Fragment | `setSubtitleView(UsersViewHolderListener)` | See `setSubtitleView` code above |
+| Overflow menu | Activity/Fragment | `setOverflowMenu(View)` | `cometChatUsers.setOverflowMenu(view);` |
+| Programmatic selection | Activity/Fragment | `selectUser(User, SelectionMode)` | `.selectUser(user, SelectionMode.SINGLE);` |
+| Clear selection | Activity/Fragment | `clearSelection()` | `.clearSelection();` |
+| Selected users strip | Activity/Fragment | `setSelectedUsersListVisibility(int)` | `.setSelectedUsersListVisibility(View.VISIBLE);` |
+| Internal adapter access | Activity/Fragment | `getUsersAdapter()` / `setAdapter()` | Advanced use only |
+
+## Accessibility
+
+The component renders a scrollable `RecyclerView` of interactive user items. Each user row responds to tap and long-press gestures. Avatar images include the user name as content description. The alphabetical sticky headers provide section navigation for screen readers.
+
+For custom views provided via `setLeadingView`, `setTitleView`, `setTrailingView`, or `seItemView`, ensure you set `android:contentDescription` on visual-only elements so TalkBack can announce them. The default views handle this automatically.
+
+Online/offline status dots are visual-only by default. If screen reader descriptions are needed, provide them via a custom view with appropriate `contentDescription` attributes.
+
+## Common Pitfalls & Fixes
+
+| Pitfall | Fix |
+| --- | --- |
+| Component does not render | Ensure `CometChatUIKit.init()` is called and awaited before using any UI Kit component. If `init()` has not completed, the component will not load data. |
+| User list is empty despite having users | Verify that a user is logged in with `CometChatUIKit.login()` before displaying the component. The component fetches users for the logged-in user only. |
+| Filters not applied | Ensure you call `setUsersRequestBuilder(builder)` on the `CometChatUsers` instance after creating and configuring the builder. |
+| Custom style not visible | Verify the style parent is `CometChatUsersStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. |
+| `setOnItemClick` not firing | If you set `setSelectionMode` to `MULTIPLE`, item clicks may be consumed by the selection logic. Set the selection mode to `NONE` if you need standard click behavior. |
+| Event listener not receiving events | Ensure you call `CometChatUserEvents.addUserListener` with a unique tag. If you use the same tag as another listener, the previous one is replaced. |
+| Search not working with custom filter | If you set a `UsersRequestBuilder` via `setUsersRequestBuilder`, the search may use different parameters. Use `setSearchRequestBuilder` to control search behavior separately. |
+| Custom view returns null in `createView` | If `createView` returns `null`, the default view is used. Return a valid inflated `View` to replace the default. |
+| Sticky header not showing | Ensure `setStickyHeaderVisibility` is set to `View.VISIBLE`. If set to `View.GONE`, the alphabetical sticky headers will not appear. |
+| Online status indicator not visible | Ensure `setUserStatusVisibility` is set to `View.VISIBLE`. If set to `View.GONE`, the online/offline status indicator will not appear next to user avatars. |
+
+## FAQ
+
+**Q: How do I show only friends in the user list?**
+**A:** Create a `UsersRequest.UsersRequestBuilder`, call `friendsOnly(true)`, and pass it to `setUsersRequestBuilder`.
+
+**Q: How do I filter users by role?**
+**A:** Create a `UsersRequest.UsersRequestBuilder`, call `setRoles(List)` with the desired role names, and pass it to `setUsersRequestBuilder`.
+
+**Q: How do I listen for user blocked/unblocked events outside the component?**
+**A:** Use `CometChatUserEvents.addUserListener("YOUR_TAG", ...)` and override `ccUserBlocked` and `ccUserUnblocked`. Call `CometChatUserEvents.removeListener("YOUR_TAG")` to unsubscribe.
+
+**Q: How do I customize the avatar style in the user list?**
+**A:** Define a custom style with parent `CometChatAvatarStyle` in `themes.xml`, reference it in a `CometChatUsersStyle` using `cometchatUsersAvatarStyle`, and apply with `setStyle()`.
+
+**Q: How do I add custom long-press options without removing the defaults?**
+**A:** Use `addOptions` instead of `setOptions`. `addOptions` appends your custom `MenuItem` objects to the existing default options.
+
+**Q: Can I use `CometChatUsers` in both an Activity and a Fragment?**
+**A:** Yes. In an Activity, call `setContentView(new CometChatUsers(this))`. In a Fragment, return `new CometChatUsers(getContext())` from `onCreateView`.
+
+## Next Steps
+
+- [Conversations component](/ui-kit/android/conversations)
+- [Groups component](/ui-kit/android/groups)
+- [Message list component](/ui-kit/android/message-list)