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 ``` -```xml res/menu/ic_chats.xml +```xml res/drawable/ic_chats.xml lines ``` -```xml res/menu/ic_calls.xml +```xml res/drawable/ic_calls.xml lines ``` -```xml res/menu/ic_user.xml +```xml res/drawable/ic_user.xml lines ``` -```xml res/menu/ic_group.xml +```xml res/drawable/ic_group.xml lines -```kotlin ChatsFragment.kt +```kotlin ChatsFragment.kt lines import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -381,7 +398,7 @@ class ChatsFragment : Fragment() { -```java ChatsFragment.java +```java ChatsFragment.java lines import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -407,7 +424,7 @@ public class ChatsFragment extends Fragment { -```xml res/layout/fragment_chats.xml +```xml res/layout/fragment_chats.xml lines -#### Call Logs Fragment +#### **Call Logs Fragment** @@ -440,7 +457,7 @@ Make sure you’ve added the Calls SDK dependency to enable voice and video call -```kotlin CallLogsFragment.kt +```kotlin CallLogsFragment.kt lines import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -462,7 +479,7 @@ class CallLogsFragment : Fragment() { -```java CallLogsFragment.java +```java CallLogsFragment.java lines import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -486,7 +503,7 @@ public class CallLogsFragment extends Fragment { -```xml res/layout/fragment_call_logs.xml +```xml res/layout/fragment_call_logs.xml lines -#### Users Fragment +#### **Users Fragment** -```kotlin UsersFragment.kt +```kotlin UsersFragment.kt lines import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -534,7 +551,7 @@ class UsersFragment : Fragment() { -```java UsersFragment.java +```java UsersFragment.java lines import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -559,7 +576,7 @@ public class UsersFragment extends Fragment { -```xml res/layout/fragment_users.xml +```xml res/layout/fragment_users.xml lines -#### Groups Fragment +#### **Groups Fragment** -```kotlin GroupsFragment.kt +```kotlin GroupsFragment.kt lines import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -610,7 +627,7 @@ class GroupsFragment : Fragment() { -```java GroupsFragment.java +```java GroupsFragment.java lines import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -635,7 +652,7 @@ public class GroupsFragment extends Fragment { -```xml res/layout/fragment_groups.xml +```xml res/layout/fragment_groups.xml lines -```kotlin MainActivity.kt +```kotlin MainActivity.kt highlight={15-17, 19} lines +import android.content.Intent import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -683,6 +701,8 @@ 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 log in + private val uiKitSettings = UIKitSettings.UIKitSettingsBuilder() .setRegion(region) .setAppId(appID) @@ -707,7 +727,7 @@ 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 Tab-Based Chat Experience (Chats, Calls, Users, Groups) @@ -726,7 +746,7 @@ class MainActivity : ComponentActivity() { -```java MainActivity.java +```java MainActivity.java highlight={17-19, 21} lines package com.example.uikitsexamples; import android.content.Intent; @@ -747,6 +767,8 @@ 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 log in + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -774,7 +796,7 @@ 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()); @@ -798,15 +820,32 @@ 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 +```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 + + +``` + +**For Call Features**, also add: + +```xml lines + + + +``` + *** @@ -814,6 +853,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/call-buttons.mdx b/ui-kit/android/call-buttons.mdx index 9700f50de..5a9af9fe3 100644 --- a/ui-kit/android/call-buttons.mdx +++ b/ui-kit/android/call-buttons.mdx @@ -2,183 +2,312 @@ title: "Call Buttons" --- -## Overview +`CometChatCallButtons` displays voice and video call buttons that initiate calls for a given user or group. It integrates with `CometChatMessageHeader` to provide one-tap calling from any conversation. + +## AI Agent Component Spec + + + +```json +{ + "component": "CometChatCallButtons", + "package": "com.cometchat.chatuikit.calls.callbutton", + "xmlElement": "", + "description": "Voice and video call buttons that initiate calls for a given user or group.", + "primaryOutput": { + "method": "setOnVoiceCallClick / setOnVideoCallClick", + "type": "OnClick" + }, + "methods": { + "data": { + "setUser": { + "type": "User", + "default": "null", + "note": "Sets the user to call. Required for 1-on-1 calls." + }, + "setGroup": { + "type": "Group", + "default": "null", + "note": "Sets the group to call. Required for group calls." + } + }, + "callbacks": { + "setOnVoiceCallClick": "OnClick — void onClick(User user, Group group)", + "setOnVideoCallClick": "OnClick — void onClick(User user, Group group)" + }, + "visibility": { + "setVoiceCallButtonVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" }, + "setVideoCallButtonVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" }, + "setButtonTextVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" }, + "setButtonIconVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" } + }, + "viewSlots": { + "getVoiceCallButton": "CometChatButton — direct access to the voice call button for customization", + "getVideoCallButton": "CometChatButton — direct access to the video call button for customization" + }, + "advanced": { + "setOutgoingCallConfiguration": "OutgoingCallConfiguration — configures the outgoing call screen", + "setCallSettingsBuilder": "Function3 — custom call settings per call type", + "setMarginBetweenButtons": "@Dimension int — spacing between voice and video buttons", + "setVoiceButtonText": "String — custom text for the voice call button", + "setVideoButtonText": "String — custom text for the video call button", + "disposeObservers": "void — removes lifecycle observers" + }, + "style": { + "setStyle": { + "type": "@StyleRes int", + "parent": "CometChatCallButtonsStyle" + } + } + }, + "events": [ + { + "name": "CometChatCallEvents.ccOutgoingCall", + "payload": "Call", + "description": "An outgoing call was initiated" + }, + { + "name": "CometChatCallEvents.ccCallAccepted", + "payload": "Call", + "description": "A call was accepted by the recipient" + }, + { + "name": "CometChatCallEvents.ccCallRejected", + "payload": "Call", + "description": "A call was rejected by the recipient" + }, + { + "name": "CometChatCallEvents.ccCallEnded", + "payload": "Call", + "description": "A call was ended" + } + ], + "sdkListeners": [] +} +``` + + -The `CometChatCallButtons` is a [Component](/ui-kit/android/components-overview#components) provides users with the ability to make calls, access call-related functionalities, and control call settings. Clicking this button typically triggers the call to be placed to the desired recipient. +## Where It Fits - - - +`CometChatCallButtons` is a utility component. It renders voice and video call buttons and initiates calls for the bound `User` or `Group`. Wire it into a `CometChatMessageHeader` or place it anywhere a call action is needed. -*** + + +```kotlin ChatActivity.kt lines +class ChatActivity : AppCompatActivity() { -## Usage + private lateinit var messageHeader: CometChatMessageHeader + private lateinit var callButtons: CometChatCallButtons -### Integration + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_chat) -`CometChatCallButtons` can be used inside another widget or can be launched to a new screen by adding the following code snippet into the XML layout file. + messageHeader = findViewById(R.id.message_header) + callButtons = findViewById(R.id.call_buttons) - - -```xml - + // Bind the same user to both components + val user: User = intent.getParcelableExtra("user")!! + messageHeader.setUser(user) + callButtons.setUser(user) + } +} ``` - - - -If you're defining the `CometChatCallButtons` 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. - - -```java -CometChatCallButtons cometchatCallButtons = binding.callButton; // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(getLayoutInflater());` to use views like `binding.callButton` after enabling view binding. +```java ChatActivity.java lines +public class ChatActivity extends AppCompatActivity { -if (userObject != null) { -cometchatCallButtons.setUser(userObject); //Required - CometChat User object -} else if (groupObject != null) { -cometchatCallButtons.setGroup(groupObject); //Required - CometChat Group object -} -``` + private CometChatMessageHeader messageHeader; + private CometChatCallButtons callButtons; - + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_chat); - -```kotlin -val cometchatCallButtons: CometChatCallButtons = binding.callButton // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(layoutInflater)` to use views like `binding.callButton` after enabling view binding. + messageHeader = findViewById(R.id.message_header); + callButtons = findViewById(R.id.call_buttons); -if (userObject != null) { - cometchatCallButtons.setUser(userObject) //Required - CometChat User object -} else if (groupObject != null) { - cometchatCallButtons.setGroup(groupObject) //Required - CometChat Group object + // Bind the same user to both components + User user = getIntent().getParcelableExtra("user"); + messageHeader.setUser(user); + callButtons.setUser(user); + } } ``` - - -*** +## Quick Start -### Actions +Add the component to your layout XML: -[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. +```xml layout_activity.xml lines + +``` -##### setOnVoiceCallClick +Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added. -The `setOnVoiceCallClick` action is usually invoked when a voice call is initiated, executing predefined actions. However, by utilizing the provided code snippet, you can effortlessly tailor or override this default behavior to suit your unique requirements. +To add programmatically in an Activity: - -```java -cometchatCallButtons.setOnVoiceCallClick(new CometChatCallButtons.OnClick() { - @Override - public void onClick(User user, Group group) { - //TODO - } -}); + +```kotlin YourActivity.kt lines +override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val callButtons = CometChatCallButtons(this) + callButtons.setUser(user) + setContentView(callButtons) +} ``` - - -```kotlin -cometchatCallButtons.setOnVoiceCallClick(CometChatCallButtons.OnClick { user, group -> - //TODO -}) + +```java YourActivity.java lines +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + CometChatCallButtons callButtons = new CometChatCallButtons(this); + callButtons.setUser(user); + setContentView(callButtons); +} ``` - - -##### setOnVideoCallClick - -The `setOnVideoCallClick` action is typically triggered when a video call is initiated, executing default actions. However, with the provided code snippet, you have the flexibility to easily customize or override this default behavior according to your specific preferences or requirements. +Or in a Fragment: - -```java -cometchatCallButtons.setOnVideoCallClick(new CometChatCallButtons.OnClick() { - @Override - public void onClick(User user, Group group) { - //TODO - } -}); + +```kotlin YourFragment.kt lines +override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + val callButtons = CometChatCallButtons(requireContext()) + callButtons.setUser(user) + return callButtons +} ``` - - -```kotlin -cometchatCallButtons.setOnVideoCallClick(CometChatCallButtons.OnClick { user, group -> - //TODO -}) + +```java YourFragment.java lines +@Override +public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + CometChatCallButtons callButtons = new CometChatCallButtons(getContext()); + callButtons.setUser(user); + return callButtons; +} ``` - - -##### setOnError +> You must call `setUser(User)` or `setGroup(Group)` before the buttons can initiate a call. Without a target, button clicks have no effect. -You can customize this behavior by using the provided code snippet to override the `setOnError` and improve error handling. +## Actions and Events + +### Callback Methods + +#### `setOnVoiceCallClick` + +Fires when the voice call button is tapped. Replaces the default behavior of initiating an audio call. + +```kotlin YourActivity.kt lines +callButtons.setOnVoiceCallClick { user, group -> + // Custom voice call logic +} +``` + + -```java -cometchatCallButtons.setOnError(new OnError() { - @Override - public void onError(CometChatException e) { - //TODO - } +```java YourActivity.java lines +callButtons.setOnVoiceCallClick((user, group) -> { + // Custom voice call logic }); ``` - + +> **What this does:** Replaces the default voice call initiation. When a user taps the voice call button, your custom lambda executes instead of the built-in call flow. The `OnClick` interface provides `void onClick(User user, Group group)`. + +#### `setOnVideoCallClick` + +Fires when the video call button is tapped. Replaces the default behavior of initiating a video call. + + -```kotlin -cometchatCallButtons.setOnError(OnError { e -> - //TODO -}) +```kotlin YourActivity.kt lines +callButtons.setOnVideoCallClick { user, group -> + // Custom video call logic +} ``` - + +```java YourActivity.java lines +callButtons.setOnVideoCallClick((user, group) -> { + // Custom video call logic +}); +``` + -*** +- **Verify**: After setting a callback, tap the corresponding button and confirm your custom logic executes instead of the default call initiation. -### Filters +### Global UI Events (CometChatCallEvents) -**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. +`CometChatCallEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed. -The CallButton component does not have any exposed filters. +| Event | Fires when | Payload | +| --- | --- | --- | +| `ccOutgoingCall` | An outgoing call is initiated | `Call` | +| `ccCallAccepted` | A call is accepted by the recipient | `Call` | +| `ccCallRejected` | A call is rejected by the recipient | `Call` | +| `ccCallEnded` | A call is ended | `Call` | -*** + + +```kotlin Add Listener lines +CometChatCallEvents.addListener("CALL_LISTENER_TAG", object : CometChatCallEvents() { + override fun ccOutgoingCall(call: Call?) { + super.ccOutgoingCall(call) + } -### Events + override fun ccCallAccepted(call: Call?) { + super.ccCallAccepted(call) + } -[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. + override fun ccCallRejected(call: Call?) { + super.ccCallRejected(call) + } -Events emitted by the Call buttons component are as follows. + override fun ccCallEnded(call: Call?) { + super.ccCallEnded(call) + } +}) +``` -| Event | Description | -| ------------------ | -------------------------------------------- | -| **ccCallAccepted** | Triggers when the outgoing call is accepted. | -| **ccCallRejected** | Triggers when the outgoing call is rejected. | +Remove Listener -Add `CometChatCallEvents` +``` +CometChatCallEvents.removeListener("CALL_LISTENER_TAG") +``` + - -```java -CometChatCallEvents.addListener("UNIQUE_ID", new CometChatCallEvents() { +```java Add Listener lines +CometChatCallEvents.addListener("CALL_LISTENER_TAG", new CometChatCallEvents() { + @Override + public void ccOutgoingCall(Call call) { + super.ccOutgoingCall(call); + } + @Override public void ccCallAccepted(Call call) { super.ccCallAccepted(call); @@ -189,145 +318,369 @@ CometChatCallEvents.addListener("UNIQUE_ID", new CometChatCallEvents() { super.ccCallRejected(call); } + @Override + public void ccCallEnded(Call call) { + super.ccCallEnded(call); + } }); ``` - +Remove Listener - -```kotlin ``` - +CometChatCallEvents.removeListener("CALL_LISTENER_TAG"); +``` - -Remove `CometChatCallEvents` +### SDK Events - - -```java -CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER"); -``` +The component uses an internal `CallButtonsViewModel` that observes call initiation and direct call events. No manual SDK listener attachment is needed — the component handles call lifecycle internally. - +## Functionality + +Small functional customizations such as toggling visibility of UI elements and configuring button spacing. + +| Method | Description | Code | +| --- | --- | --- | +| `setVoiceCallButtonVisibility` | Toggles visibility of the voice call button | `.setVoiceCallButtonVisibility(View.GONE);` | +| `setVideoCallButtonVisibility` | Toggles visibility of the video call button | `.setVideoCallButtonVisibility(View.GONE);` | +| `setButtonTextVisibility` | Toggles visibility of text labels on both buttons | `.setButtonTextVisibility(View.GONE);` | +| `setButtonIconVisibility` | Toggles visibility of icons on both buttons | `.setButtonIconVisibility(View.GONE);` | +| `setMarginBetweenButtons` | Sets the spacing between voice and video buttons | `.setMarginBetweenButtons(24);` | + +- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden. +## Custom View Slots + +`CometChatCallButtons` exposes direct access to its two internal `CometChatButton` instances. Use these to customize icons, text, colors, and other properties on each button individually. + +| Slot | Method | Returns | +| --- | --- | --- | +| Voice call button | `getVoiceCallButton()` | `CometChatButton` | +| Video call button | `getVideoCallButton()` | `CometChatButton` | + + -```kotlin -CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") +```kotlin lines +// Access the voice call button and customize it +val voiceBtn = callButtons.getVoiceCallButton() +voiceBtn.setButtonText("Audio") + +// Access the video call button and customize it +val videoBtn = callButtons.getVideoCallButton() +videoBtn.setButtonText("Video") ``` - + +```java lines +// Access the voice call button and customize it +CometChatButton voiceBtn = callButtons.getVoiceCallButton(); +voiceBtn.setButtonText("Audio"); + +// Access the video call button and customize it +CometChatButton videoBtn = callButtons.getVideoCallButton(); +videoBtn.setButtonText("Video"); +``` + -*** +- **Verify**: After accessing a button via `getVoiceCallButton()` or `getVideoCallButton()`, confirm your customizations render correctly on the corresponding button. -## Customization +## Common Patterns -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. +### Video-only buttons -### Style + + +```kotlin lines +callButtons.setVoiceCallButtonVisibility(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. + +```java lines +callButtons.setVoiceCallButtonVisibility(View.GONE); +``` + + - - - +### Voice-only buttons -```xml themes.xml - + + +```kotlin lines +callButtons.setVideoCallButtonVisibility(View.GONE) ``` + - -```java -cometChatCallButtons.setStyle(R.style.CustomCallButtonStyle); +```java lines +callButtons.setVideoCallButtonVisibility(View.GONE); ``` - + + +### Custom button text + -```kotlin -cometChatCallButtons.setStyle(R.style.CustomCallButtonStyle) +```kotlin lines +callButtons.setVoiceButtonText("Audio Call") +callButtons.setVideoButtonText("Video Call") ``` - + +```java lines +callButtons.setVoiceButtonText("Audio Call"); +callButtons.setVideoButtonText("Video Call"); +``` + -*** +### Icon-only buttons -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_buttons.xml). + + +```kotlin lines +callButtons.setButtonTextVisibility(View.GONE) +``` + -### Functionality + +```java lines +callButtons.setButtonTextVisibility(View.GONE); +``` + + -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. +## Advanced Methods -Below is a list of customizations along with corresponding code snippets +### `setUser` / `setGroup` -| Property | Description | Code | -| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -| **setUser** | Used to set User object to the call button | `.setUser(User user)` | -| **setGroup** | Used to set Group object to the call button | `.setGroup(group)` | -| **setVideoCallButtonVisibility** | Used to hide video call button | `.setVideoCallButtonVisibility(View.GONE)` | -| **setVoiceCallButtonVisibility** | Used to hide voice call button | `.setVoiceCallButtonVisibility(View.GONE)` | -| **setCallSettingsBuilder** | Sets the call settings builder callback function. This callback is responsible for configuring the call settings based on the user, group, and call type (audio/video). | `.setCallSettingsBuilder(Function3 callSettingsBuilder)` | -| **setOutgoingCallConfiguration** | Sets the configurations for outgoing call component. | `.setOutgoingCallConfiguration(new OutgoingCallConfiguration)` | +Binds the component to a specific user or group. Required before calls can be initiated. -### Advanced + + +```kotlin lines +// For 1-on-1 calls +callButtons.setUser(user) -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. +// For group calls +callButtons.setGroup(group) +``` + -The `CometChatCallButtons` component does not provide additional functionalities beyond this level of customization. + +```java lines +// For 1-on-1 calls +callButtons.setUser(user); -*** +// For group calls +callButtons.setGroup(group); +``` + + -## Configurations +### `setOutgoingCallConfiguration` -[Configurations](/ui-kit/android/components-overview#configurations) offer the ability to customize the properties of each individual component within a Composite Component. +Configures the outgoing call screen that appears after a call is initiated. -* `Configurations` expose properties that are available in its individual components. + + +```kotlin lines +val config = OutgoingCallConfiguration() +callButtons.setOutgoingCallConfiguration(config) +``` + -*** + +```java lines +OutgoingCallConfiguration config = new OutgoingCallConfiguration(); +callButtons.setOutgoingCallConfiguration(config); +``` + + -#### Outgoing Call +### `setCallSettingsBuilder` -You can customize the properties of the Outgoing Call component by making use of the `OutgoingCallConfiguration`. You can accomplish this by employing the `OutgoingCallConfiguration` as demonstrated below: +Provides a callback to customize call settings per call. The callback receives the `User`, `Group`, and a `Boolean` indicating whether the call is audio (`true`) or video (`false`), and returns a `CometChatCalls.CallSettingsBuilder`. + +```kotlin lines +callButtons.setCallSettingsBuilder { user, group, isAudio -> + CometChatCalls.CallSettingsBuilder(this, true) + .setIsAudioOnly(isAudio) +} +``` + + -```java -OutgoingCallConfiguration outgoingCallConfiguration = new OutgoingCallConfiguration(); +```java lines +callButtons.setCallSettingsBuilder((user, group, isAudio) -> { + return new CometChatCalls.CallSettingsBuilder(this, true) + .setIsAudioOnly(isAudio); +}); +``` + + + +### `getVoiceCallButton` / `getVideoCallButton` + +Returns the internal `CometChatButton` instances for direct customization. -cometchatCallButtons.setOutgoingCallConfiguration(outgoingCallConfiguration); +| Method | Returns | Description | +| --- | --- | --- | +| `getVoiceCallButton()` | `CometChatButton` | The voice call button instance | +| `getVideoCallButton()` | `CometChatButton` | The video call button instance | + +### `disposeObservers` + +Removes lifecycle observers manually. Normally handled automatically when the view detaches from the window. + + + +```kotlin lines +callButtons.disposeObservers() ``` + + +```java lines +callButtons.disposeObservers(); +``` + - -```kotlin -val outgoingCallConfiguration = OutgoingCallConfiguration() +## Style + +The component uses XML theme styles. Define a custom style with parent `CometChatCallButtonsStyle` in `themes.xml`, then apply with `setStyle()`. -cometchatCallButtons.setOutgoingCallConfiguration(outgoingCallConfiguration) +```xml themes.xml lines + ``` + + +```kotlin lines +callButtons.setStyle(R.style.CustomCallButtonsStyle) +``` + +```java lines +callButtons.setStyle(R.style.CustomCallButtonsStyle); +``` + -All exposed properties of `OutgoingCallConfiguration` can be found under [Outgoing Call](/ui-kit/android/outgoing-call). Properties marked with the 🛑 symbol are not accessible within the Configuration Object. +### Programmatic Style Properties + +In addition to XML theme styles, the component exposes programmatic setters for fine-grained control: + +| Method | Type | Description | +| --- | --- | --- | +| `setVoiceCallIcon` | `Drawable` | Icon drawable for the voice call button | +| `setVideoCallIcon` | `Drawable` | Icon drawable for the video call button | +| `setVoiceCallIconTint` | `@ColorInt int` | Tint color for the voice call icon | +| `setVideoCallIconTint` | `@ColorInt int` | Tint color for the video call icon | +| `setVoiceCallTextColor` | `@ColorInt int` | Text color for the voice call button | +| `setVideoCallTextColor` | `@ColorInt int` | Text color for the video call button | +| `setVoiceCallTextAppearance` | `@StyleRes int` | Text appearance for the voice call button | +| `setVideoCallTextAppearance` | `@StyleRes int` | Text appearance for the video call button | +| `setVoiceCallBackgroundColor` | `@ColorInt int` | Background color for the voice call button | +| `setVideoCallBackgroundColor` | `@ColorInt int` | Background color for the video call button | +| `setVoiceCallCornerRadius` | `@Dimension int` | Corner radius for the voice call button | +| `setVideoCallCornerRadius` | `@Dimension int` | Corner radius for the video call button | +| `setVoiceCallIconSize` | `@Dimension int` | Icon size for the voice call button | +| `setVideoCallIconSize` | `@Dimension int` | Icon size for the video call button | +| `setVoiceCallStrokeWidth` | `@Dimension int` | Stroke width for the voice call button | +| `setVideoCallStrokeWidth` | `@Dimension int` | Stroke width for the video call button | +| `setVoiceCallStrokeColor` | `@ColorInt int` | Stroke color for the voice call button | +| `setVideoCallStrokeColor` | `@ColorInt int` | Stroke color for the video call button | +| `setVoiceCallButtonPadding` | `@Dimension int` | Padding for the voice call button | +| `setVideoCallButtonPadding` | `@Dimension int` | Padding for the video call button | + +## Customization Matrix + +| What to change | Where | Property/API | Example | +| --- | --- | --- | --- | +| Override voice call tap behavior | Activity/Fragment | `setOnVoiceCallClick` | `setOnVoiceCallClick((u, g) -> { ... })` | +| Override video call tap behavior | Activity/Fragment | `setOnVideoCallClick` | `setOnVideoCallClick((u, g) -> { ... })` | +| Hide voice call button | Activity/Fragment | `setVoiceCallButtonVisibility(int)` | `setVoiceCallButtonVisibility(View.GONE)` | +| Hide video call button | Activity/Fragment | `setVideoCallButtonVisibility(int)` | `setVideoCallButtonVisibility(View.GONE)` | +| Hide button text labels | Activity/Fragment | `setButtonTextVisibility(int)` | `setButtonTextVisibility(View.GONE)` | +| Hide button icons | Activity/Fragment | `setButtonIconVisibility(int)` | `setButtonIconVisibility(View.GONE)` | +| Change button spacing | Activity/Fragment | `setMarginBetweenButtons(int)` | `setMarginBetweenButtons(24)` | +| Set custom button text | Activity/Fragment | `setVoiceButtonText` / `setVideoButtonText` | `setVoiceButtonText("Audio Call")` | +| Change voice call icon | Activity/Fragment | `setVoiceCallIcon(Drawable)` | `setVoiceCallIcon(drawable)` | +| Change video call icon | Activity/Fragment | `setVideoCallIcon(Drawable)` | `setVideoCallIcon(drawable)` | +| Change icon tint colors | Activity/Fragment | `setVoiceCallIconTint` / `setVideoCallIconTint` | `setVoiceCallIconTint(Color.GREEN)` | +| Change text colors | Activity/Fragment | `setVoiceCallTextColor` / `setVideoCallTextColor` | `setVoiceCallTextColor(Color.BLACK)` | +| Change background colors | Activity/Fragment | `setVoiceCallBackgroundColor` / `setVideoCallBackgroundColor` | `setVoiceCallBackgroundColor(Color.WHITE)` | +| Change corner radius | Activity/Fragment | `setVoiceCallCornerRadius` / `setVideoCallCornerRadius` | `setVoiceCallCornerRadius(16)` | +| Change icon size | Activity/Fragment | `setVoiceCallIconSize` / `setVideoCallIconSize` | `setVoiceCallIconSize(48)` | +| Change stroke width | Activity/Fragment | `setVoiceCallStrokeWidth` / `setVideoCallStrokeWidth` | `setVoiceCallStrokeWidth(2)` | +| Change stroke color | Activity/Fragment | `setVoiceCallStrokeColor` / `setVideoCallStrokeColor` | `setVoiceCallStrokeColor(Color.GRAY)` | +| Change button padding | Activity/Fragment | `setVoiceCallButtonPadding` / `setVideoCallButtonPadding` | `setVoiceCallButtonPadding(12)` | +| Apply XML theme style | `themes.xml` | `CometChatCallButtonsStyle` | `#4CAF50` | +| Apply style programmatically | Activity/Fragment | `setStyle(int styleRes)` | `callButtons.setStyle(R.style.CustomCallButtonsStyle)` | +| Configure outgoing call screen | Activity/Fragment | `setOutgoingCallConfiguration` | `setOutgoingCallConfiguration(config)` | +| Custom call settings per call | Activity/Fragment | `setCallSettingsBuilder` | See `setCallSettingsBuilder` code above | +| Access internal buttons | Activity/Fragment | `getVoiceCallButton()` / `getVideoCallButton()` | `callButtons.getVoiceCallButton()` | + +## Accessibility + +The component renders two `CometChatButton` instances inside a `MaterialCardView`. Each button responds to tap gestures. The voice and video call icons include default content descriptions for screen readers. + +For custom icons set via `setVoiceCallIcon` or `setVideoCallIcon`, ensure you set `android:contentDescription` on the drawable or on the button view so TalkBack can announce the action. The default icons handle this automatically. + +Button text labels (when visible) provide additional context for assistive technologies. If you hide text with `setButtonTextVisibility(View.GONE)`, consider adding explicit content descriptions to the buttons via `getVoiceCallButton().setContentDescription(...)`. + +## Common Pitfalls & Fixes + +| Pitfall | Fix | +| --- | --- | +| Buttons do not initiate a call | Ensure `setUser(User)` or `setGroup(Group)` is called before the user taps a button. Without a target, the component has no recipient to call. | +| 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. | +| Custom click callback not firing | Verify you are setting `setOnVoiceCallClick` or `setOnVideoCallClick` with a non-null `OnClick` instance. Null callbacks are ignored. | +| Outgoing call screen not appearing | If you set a custom `OnClick` callback, the default call initiation is bypassed. Remove the callback or manually launch the outgoing call screen from within it. | +| `setCallSettingsBuilder` has no effect | The callback is only invoked when the default click behavior runs. If you set a custom `OnClick`, the callback is never called. | +| Style not applying | Verify the style parent is `CometChatCallButtonsStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. | +| Buttons visible but disabled after a call | The component observes call lifecycle internally. If a call is active, buttons may be disabled. Wait for the call to end or check `onAttachedToWindow` behavior. | +| Group call not working | Ensure you call `setGroup(Group)` with a valid `Group` object. Passing `null` is silently ignored. | + +## FAQ + +**Q: How do I show only the video call button?** +**A:** Call `setVoiceCallButtonVisibility(View.GONE)` to hide the voice call button. The video call button remains visible by default. + +**Q: How do I customize the call settings for audio vs. video calls?** +**A:** Use `setCallSettingsBuilder` with a `Function3`. The `Boolean` parameter is `true` for audio calls and `false` for video calls. + +**Q: Can I use `CometChatCallButtons` without embedding it in a `MessageHeader`?** +**A:** Yes. `CometChatCallButtons` is a standalone component. Place it in any layout and call `setUser(User)` or `setGroup(Group)` to bind it. + +**Q: How do I listen for call events outside the component?** +**A:** Use `CometChatCallEvents.addListener("YOUR_TAG", ...)` and override `ccOutgoingCall`, `ccCallAccepted`, `ccCallRejected`, or `ccCallEnded`. Call `CometChatCallEvents.removeListener("YOUR_TAG")` to unsubscribe. + +**Q: How do I change the spacing between the two buttons?** +**A:** Call `setMarginBetweenButtons(int)` with the desired spacing in pixels. The default is `16dp`. + +**Q: Can I access the underlying button views for advanced customization?** +**A:** Yes. Call `getVoiceCallButton()` or `getVideoCallButton()` to get the `CometChatButton` instances. You can then call any `CometChatButton` method on them directly. + +## Next Steps + +- [Call Logs component](/ui-kit/android/call-logs) +- [Message Header component](/ui-kit/android/message-header) +- [Conversations component](/ui-kit/android/conversations) diff --git a/ui-kit/android/call-features.mdx b/ui-kit/android/call-features.mdx index a5deb296e..eee8cc709 100644 --- a/ui-kit/android/call-features.mdx +++ b/ui-kit/android/call-features.mdx @@ -10,53 +10,121 @@ CometChat's Calls feature is an advanced functionality that allows you to seamle First, make sure that you've correctly integrated the UI Kit library into your project. If you haven't done this yet or are facing difficulties, refer to our [Getting Started](/ui-kit/android/getting-started) guide. This guide will walk you through a step-by-step process of integrating our UI Kit into your Android project. -Once you've successfully integrated the UI Kit, the next step is to add the CometChat Calls SDK to your project. This is necessary to enable the calling features in the UI Kit. Here's how you do it: +Once you've successfully integrated the UI Kit, the next step is to add the CometChat Calls SDK to your project. This is necessary to enable the calling features in the UI Kit. -Add the following dependency to your build.gradle file: +### Step 1: Add Calls SDK Dependency -```javascript +Add the following dependency to your `build.gradle` file: + +```gradle lines dependencies { implementation 'com.cometchat:calls-sdk-android:4.+.+' } ``` -After adding this dependency, the Android UI Kit will automatically detect it and activate the calling features. Now, your application supports both audio and video calling. You will see [CallButtons](/ui-kit/android/call-buttons) component rendered in [MessageHeader](/ui-kit/android/message-header) Component. +After adding this dependency, sync your project. The Android UI Kit will automatically detect the Calls SDK and activate the calling features. + +### Step 2: Verify Call Buttons Appear + +Once the Calls SDK is integrated, you will see the [CallButtons](/ui-kit/android/call-buttons) component automatically rendered in the [MessageHeader](/ui-kit/android/message-header) component. This provides users with quick access to initiate audio and video calls. -To start receive calls globally in your app you will need to add `CallListener`, This needs to be added before the you initialize CometChat UI kit, We sudgest you making a custom Application class and adding call listener. +### Step 3: Add Call Listener for Incoming Calls + +To receive incoming calls globally in your app, you will need to add a `CallListener`. This should be added before you initialize the CometChat UI Kit. We recommend creating a custom Application class and adding the call listener there. + +When an incoming call is received, you can display the `CometChatIncomingCall` component using the current activity context. + +```kotlin lines +class BaseApplication : Application() { + + companion object { + private val LISTENER_ID = "${BaseApplication::class.java.simpleName}${System.currentTimeMillis()}" + } + + override fun onCreate() { + super.onCreate() + + CometChat.addCallListener(LISTENER_ID, object : CometChat.CallListener { + override fun onIncomingCallReceived(call: Call) { + // Get the current activity context + val currentActivity = getCurrentActivity() // Implement this method + + currentActivity?.let { + // Create and display the incoming call component + val incomingCallView = CometChatIncomingCall(it) + incomingCallView.call = call + incomingCallView.fitsSystemWindows = true + incomingCallView.onError = OnError { exception -> + // Handle errors + } + + // Display the component (e.g., as dialog or snackbar) + } + } + + override fun onOutgoingCallAccepted(call: Call) { + // Handle outgoing call acceptance + } + + override fun onOutgoingCallRejected(call: Call) { + // Handle outgoing call rejection + } + + override fun onIncomingCallCancelled(call: Call) { + // Handle incoming call cancellation + } + }) + } +} +``` + + + -```java +```java lines public class BaseApplication extends Application { - private static String LISTENER_ID = BaseApplication.class.getSimpleName()+System.currentTimeMillis(); + private static final String LISTENER_ID = BaseApplication.class.getSimpleName() + System.currentTimeMillis(); @Override public void onCreate() { super.onCreate(); + CometChat.addCallListener(LISTENER_ID, new CometChat.CallListener() { @Override public void onIncomingCallReceived(Call call) { - CometChatCallActivity.launchIncomingCallScreen(BaseApplication.this, call, null); //pass null or IncomingCallConfiguration if need to configure CometChatIncomingCall component + // Get the current activity context + Activity currentActivity = getCurrentActivity(); // Implement this method + + if (currentActivity != null) { + // Create and display the incoming call component + CometChatIncomingCall incomingCallView = new CometChatIncomingCall(currentActivity); + incomingCallView.setCall(call); + incomingCallView.setFitsSystemWindows(true); + + // Display the component (e.g., as dialog or snackbar) + } } @Override public void onOutgoingCallAccepted(Call call) { - + // Handle outgoing call acceptance } @Override public void onOutgoingCallRejected(Call call) { - + // Handle outgoing call rejection } @Override public void onIncomingCallCancelled(Call call) { - + // Handle incoming call cancellation } }); } @@ -65,67 +133,72 @@ public class BaseApplication extends Application { - -```kotlin -class BaseApplication : Application() { - companion object { - private val LISTENER_ID = "${BaseApplication::class.java.simpleName}${System.currentTimeMillis()}" - } - - override fun onCreate() { - super.onCreate() - CometChat.addCallListener(LISTENER_ID, object : CometChat.CallListener { - override fun onIncomingCallReceived(call: Call) { - CometChatCallActivity.launchIncomingCallScreen(this@BaseApplication, call, null) - // Pass null or IncomingCallConfiguration if need to configure CometChatIncomingCall component - } + - override fun onOutgoingCallAccepted(call: Call) { - // To be implemented - } +## Call Components - override fun onOutgoingCallRejected(call: Call) { - // To be implemented - } +The CometChat Android UI Kit provides four main components for implementing calling features in your app. Each component handles a specific part of the calling experience. - override fun onIncomingCallCancelled(call: Call) { - // To be implemented - } - }) - } -} -``` +### Call Buttons - +The [Call Buttons](/ui-kit/android/call-buttons) component provides users with quick access to initiate audio and video calls. This component is automatically rendered in the [MessageHeader](/ui-kit/android/message-header) when the Calls SDK is integrated. - + + + -## Features +[Learn more about Call Buttons →](/ui-kit/android/call-buttons) ### Incoming Call -The [Incoming Call](/ui-kit/android/incoming-call) component of the CometChat UI Kit provides the functionality that lets users receive real-time audio and video calls in the app. - -When a call is made to a user, the Incoming Call component triggers and displays a call screen. This call screen typically displays the caller information and provides the user with options to either accept or reject the incoming call. +The [Incoming Call](/ui-kit/android/incoming-call) component displays when a user receives an incoming call. It provides a full-screen interface showing caller information and call controls. -### Outgoing Call +[Learn more about Incoming Call →](/ui-kit/android/incoming-call) -The [Outgoing Call](/ui-kit/android/outgoing-call) component of the CometChat UI Kit is designed to manage the outgoing call process within your application. When a user initiates an audio or video call to another user or group, this component displays an outgoing call screen, showcasing information about the recipient and the call status. +### Outgoing Call -Importantly, the Outgoing Call component is smartly designed to transition automatically into the ongoing call screen once the receiver accepts the call. This ensures a smooth flow from initiating the call to engaging in a conversation, without any additional steps required from the user. +The [Outgoing Call](/ui-kit/android/outgoing-call) component manages the outgoing call experience. It displays while waiting for the recipient to answer and automatically transitions to the active call screen once accepted. +[Learn more about Outgoing Call →](/ui-kit/android/outgoing-call) + ### Call Logs -[Call Logs](/ui-kit/android/call-logs) component provides you with the records call events such as who called who, the time of the call, and the duration of the call. This information can be fetched from the CometChat server and displayed in a structured format for users to view their past call activities. +The [Call Logs](/ui-kit/android/call-logs) component displays a history of all call activities, including missed, received, and dialed calls. Users can view call details and initiate new calls from the log. + + +[Learn more about Call Logs →](/ui-kit/android/call-logs) + +### Call Log Details + +For detailed information about individual calls, including participants, join/leave history, and recordings, see the [Call Log Details](/ui-kit/android/guide-call-log-details) guide. + +## Troubleshooting + +### Call Buttons Not Appearing + +If the call buttons don't appear in the MessageHeader: + +1. **Verify Calls SDK is added** - Check that `com.cometchat:calls-sdk-android:4.+.+` is in your `build.gradle` +2. **Sync Gradle** - Make sure you've synced your project after adding the dependency +3. **Check UI Kit version** - Ensure you're using CometChat UI Kit v5 or later +4. **Verify initialization** - Confirm CometChat is properly initialized before loading the UI + +### Incoming Calls Not Showing + +If incoming calls aren't displaying: + +1. **Check CallListener registration** - Ensure `CometChat.addCallListener()` is called in your Application class +2. **Verify Application class** - Confirm your custom Application class is registered in `AndroidManifest.xml` +3. **Test listener ID** - Make sure the listener ID is unique and not being removed elsewhere \ No newline at end of file diff --git a/ui-kit/android/call-logs.mdx b/ui-kit/android/call-logs.mdx index 6b3038497..90684ccb8 100644 --- a/ui-kit/android/call-logs.mdx +++ b/ui-kit/android/call-logs.mdx @@ -2,750 +2,952 @@ title: "Call Logs" --- -## Overview +`CometChatCallLogs` displays the list of call logs for the currently logged-in user, showing caller names, avatars, call status, and timestamps. + +## AI Agent Component Spec + + + +```json +{ + "component": "CometChatCallLogs", + "package": "com.cometchat.chatuikit.calls.calllogs", + "xmlElement": "", + "description": "Scrollable list of call logs for the logged-in user with caller names, avatars, call status, and timestamps.", + "primaryOutput": { + "method": "setOnItemClick", + "type": "OnItemClick" + }, + "methods": { + "data": { + "setCallLogRequestBuilder": { + "type": "CallLogRequest.CallLogRequestBuilder", + "default": "SDK default", + "note": "Pass the builder, not the result of .build()" + } + }, + "callbacks": { + "setOnItemClick": "OnItemClick", + "setOnItemLongClick": "OnItemLongClick", + "setOnBackPressListener": "OnBackPress", + "setOnCallIconClickListener": "OnCallIconClick", + "setOnError": "OnCallError", + "setOnLoad": "OnLoad", + "setOnEmpty": "OnEmpty" + }, + "visibility": { + "setToolbarVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.VISIBLE" }, + "setBackIconVisibility": { "type": "int", "default": "View.GONE" }, + "setLoadingStateVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setErrorStateVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setEmptyStateVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setSeparatorVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setTitleVisibility": { "type": "int", "default": "View.VISIBLE" } + }, + "viewSlots": { + "setItemView": "CallLogsViewHolderListener — entire list item row", + "setLeadingView": "CallLogsViewHolderListener — avatar / left section", + "setTitleView": "CallLogsViewHolderListener — name / title text", + "setSubtitleView": "CallLogsViewHolderListener — subtitle text below name", + "setTrailingView": "CallLogsViewHolderListener — right section", + "setLoadingView": "@LayoutRes int — loading spinner", + "setEmptyView": "@LayoutRes int — empty state", + "setErrorView": "@LayoutRes int — error state", + "setOptions": "Function2> — long-press context menu (replaces defaults)", + "setAddOptions": "Function2> — long-press context menu (appends to defaults)" + }, + "advanced": { + "refreshCallLogs": "void — re-fetches call logs from the server", + "setDateFormat": "SimpleDateFormat — legacy date format setter", + "setDateTimeFormatter": "DateTimeFormatterCallback — custom date/time formatting", + "getBinding": "CometchatCallLogsBinding — root ViewBinding", + "getViewModel": "CallLogsViewModel — internal ViewModel access", + "getAdapter": "CallLogsAdapter — internal adapter access", + "setAdapter": "CallLogsAdapter — replace the default adapter" + }, + "style": { + "setStyle": { + "type": "@StyleRes int", + "parent": "CometChatCallLogsStyle" + } + } + }, + "events": [], + "sdkListeners": [] +} +``` -`CometChatCallLogs` is a [Component](/ui-kit/android/components-overview#components) that shows the list of Call Logs available. By default, names are shown for all listed users, along with their avatars if available. + - - - +## Where It Fits -## Usage +`CometChatCallLogs` is a list component. It renders all call logs for the logged-in user and emits the selected `CallLog` via `setOnItemClick`. Wire it to a call detail screen or use `setOnCallIconClickListener` to initiate a callback. -### Integration + + +```kotlin CallDetailActivity.kt lines +class CallDetailActivity : AppCompatActivity() { -`CometChatCallLogs` being a wrapper 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. + private lateinit var callLogs: CometChatCallLogs -Since `CometChatCallLogs` can be launched by adding the following code snippet to the XML layout file. + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_call_detail) - - -```xml - -``` + callLogs = findViewById(R.id.call_log) + callLogs.setOnItemClick { view, position, callLog -> + // Navigate to call detail screen with the selected callLog + } + + callLogs.setOnCallIconClickListener { view, holder, position, callLog -> + // Initiate a call using the callLog data + } + } +} +``` - + +```java CallDetailActivity.java lines +public class CallDetailActivity extends AppCompatActivity { -If you're defining the `CometChatCallLogs` 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 CometChatCallLogs callLogs; - - -```java -CometChatCallLogs cometchatCallLogs = binding.callLog; // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(getLayoutInflater());` to use views like `binding.callLog` after enabling view binding. -``` + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_call_detail); - + callLogs = findViewById(R.id.call_log); - -```kotlin -val cometchatCallLogs: CometChatCallLogs = binding.callLog // 'binding' is a view binding instance. Initialize it with `binding = YourXmlFileNameBinding.inflate(layoutInflater)` to use views like `binding.callLog` after enabling view binding. -``` + callLogs.setOnItemClick((view, position, callLog) -> { + // Navigate to call detail screen with the selected callLog + }); + callLogs.setOnCallIconClickListener((view, holder, position, callLog) -> { + // Initiate a call using the callLog data + }); + } +} +``` - -##### Activity and Fragment +## 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, and the `cometchat-chat-uikit-android` dependency added. -You can integrate `CometChatCallLogs` into your Activity and Fragment by adding the following code snippets into the respective classes. +To add programmatically in an Activity: - -```java YourActivity.java -CometChatCallLogs cometchatCallLogs; + +```kotlin YourActivity.kt lines +override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(CometChatCallLogs(this)) +} +``` + + +```java YourActivity.java lines @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - cometchatCallLogs = new CometChatCallLogs(this); - - setContentView(cometchatCallLogs); + setContentView(new CometChatCallLogs(this)); } ``` - + - -```kotlin YourActivity.kt -private lateinit var cometchatCallLogs: CometChatCallLogs - -override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - cometchatCallLogs = CometChatCallLogs(this); +Or in a Fragment: - setContentView(cometchatCallLogs) + + +```kotlin YourFragment.kt lines +override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return CometChatCallLogs(requireContext()) } ``` - - -```java YourFragment.java -CometChatCallLogs cometchatCallLogs; - + +```java YourFragment.java lines @Override -public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - cometchatCallLogs = new CometChatCallLogs(requireContext()); - - return cometchatCallLogs; +public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return new CometChatCallLogs(getContext()); } ``` - + - -```kotlin YourFragment.kt -private lateinit var cometchatCallLogs: CometChatCallLogs - -override fun onCreateView( - inflater: LayoutInflater?, container: ViewGroup?, - savedInstanceState: Bundle? -): View { +## Filtering Call Logs - cometchatCallLogs = new CometChatCallLogs(requireContext()); +Pass a `CallLogRequest.CallLogRequestBuilder` to `setCallLogRequestBuilder`. Pass the builder instance — not the result of `.build()`. - return cometchatCallLogs -} + + +```kotlin lines +val builder = CallLogRequest.CallLogRequestBuilder() + .setLimit(20) + .setHasRecording(true) +cometchatCallLogs.setCallLogRequestBuilder(builder) ``` - + +```java lines +CallLogRequest.CallLogRequestBuilder builder = new CallLogRequest.CallLogRequestBuilder() + .setLimit(20) + .setHasRecording(true); +cometchatCallLogs.setCallLogRequestBuilder(builder); +``` + -### Actions +### Filter Recipes -[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. +| Recipe | Code | +| --- | --- | +| Limit to 20 per page | `builder.setLimit(20)` | +| Audio calls only | `builder.setCallType(CometChatCallsConstants.CALL_TYPE_AUDIO)` | +| Video calls only | `builder.setCallType(CometChatCallsConstants.CALL_TYPE_VIDEO)` | +| Missed calls only | `builder.setCallStatus(CometChatCallsConstants.CALL_STATUS_MISSED)` | +| Calls with recordings | `builder.setHasRecording(true)` | +| Incoming calls only | `builder.setCallDirection("incoming")` | +| Outgoing calls only | `builder.setCallDirection("outgoing")` | +| Filter by user UID | `builder.setUid("uid1")` | +| Filter by group GUID | `builder.setGuid("guid1")` | +| Filter by call category | `builder.setCallCategory("call")` | -##### setOnItemClick +> The component uses infinite scroll — the next page loads as the user scrolls to the bottom. -Function invoked when a call log item is clicked, typically used to open a detailed chat screen. +## Actions and Events - - -```java YourActivity.java -cometchatCallLogs.setOnItemClick((view1, position, callLog) -> { - - }); -``` +### Callback Methods - +#### `setOnItemClick` +Fires when a call log row is tapped. Primary navigation hook — use to open a call detail screen. + + -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatCallLogs.onItemClick = OnItemClick { view, position, callLog -> - } +} ``` - + +```java YourActivity.java lines +cometchatCallLogs.setOnItemClick((view1, position, callLog) -> { + +}); +``` + -*** +> **What this does:** Replaces the default item-click behavior. When a user taps a call log entry, your custom lambda executes instead of the built-in navigation. -##### setOnItemLongClick +#### `setOnItemLongClick` -Function executed when a callLog item is long-pressed, allowing additional actions like delete or select. +Fires when a call log row is long-pressed. Use for additional actions like delete or call back. - -```java YourActivity.java -cometchatCallLogs.setOnItemLongClick((view1, position, callLog) -> { - - }); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatCallLogs.onItemLongClick = OnItemLongClick({ view, position, callLog -> - }) +}) ``` - - + +```java YourActivity.java lines +cometchatCallLogs.setOnItemLongClick((view1, position, callLog) -> { -*** +}); +``` + + -##### setOnBackPressListener +#### `setOnBackPressListener` -`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. +Fires when the user presses the back button in the app bar. Default: navigates to the previous activity. - -```java YourActivity.java -cometchatCallLogs.setOnBackPressListener(() -> { - - }); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatCallLogs.onBackPressListener = OnBackPress { - } +} ``` - + +```java YourActivity.java lines +cometchatCallLogs.setOnBackPressListener(() -> { + +}); +``` + -*** +#### `setOnCallIconClickListener` -##### OnError +Fires when the user taps the audio or video call icon on a call log item. Use to initiate a call or navigate to a call screen. -This action doesn't change the behavior of the component but rather listens for any errors that occur in the callLogs component. +Interface: `void onCallIconClick(View view, CallLogsAdapter.CallLogsViewHolder holder, int position, CallLog callLog)` - -```java YourActivity.java -cometchatCallLogs.setOnError(cometchatException -> { - - }); + +```kotlin YourActivity.kt lines +cometchatCallLogs.setOnCallIconClickListener { view, holder, position, callLog -> + // Handle call icon click +} ``` - - -```kotlin YourActivity.kt -cometchatCallLogs.setOnError { - - } + +```java YourActivity.java lines +cometchatCallLogs.setOnCallIconClickListener((view, holder, position, callLog) -> { + // Handle call icon click +}); ``` - - -*** - -##### setOnLoad +#### `setOnError` -Invoked when the list is successfully fetched and loaded, helping track component readiness. +Fires on internal errors (network failure, auth issue, SDK exception). + +```kotlin YourActivity.kt lines +cometchatCallLogs.setOnError { + +} +``` + + -```java YourActivity.java -cometchatCallLogs.setOnLoad(list -> { +```java YourActivity.java lines +cometchatCallLogs.setOnError(cometchatException -> { }); ``` - + +#### `setOnLoad` + +Fires when the list is successfully fetched and loaded. + + -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatCallLogs.setOnLoad(object : OnLoad { override fun onLoad(list: MutableList?) { } }) ``` - - + +```java YourActivity.java lines +cometchatCallLogs.setOnLoad(list -> { -*** +}); +``` + + -##### setOnEmpty +#### `setOnEmpty` -Called when the list is empty, enabling custom handling such as showing a placeholder message. +Fires when the list is empty, enabling custom handling such as showing a placeholder. - -```java YourActivity.java -cometchatCallLogs.setOnEmpty(() -> { + +```kotlin YourActivity.kt lines +cometchatCallLogs.setOnEmpty { - }); +} ``` - - -```kotlin YourActivity.kt -cometchatCallLogs.setOnEmpty{ + +```java YourActivity.java lines +cometchatCallLogs.setOnEmpty(() -> { - } +}); ``` - - -*** +- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap, long-press, back, call icon) 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 `CometChatCallLogs` component does not have any exposed global UI events. -##### 1. CallLogRequestBuilder +### SDK Events (Real-Time, Automatic) -The [CallLogRequestBuilder](/sdk/android/call-logs) enables you to filter and customize the call list based on available parameters in CallLogRequestBuilder. This feature allows you to create more specific and targeted queries during the call. The following are the parameters available in [CallLogRequestBuilder](/sdk/android/call-logs) +The `CometChatCallLogs` component does not listen to any SDK events internally. Call logs are fetched on load and can be refreshed manually with `refreshCallLogs()`. -**Example** - -In the example below, we are applying a filter based on the limit and have a call recording. - - - -```java -CallLogRequest.CallLogRequestBuilder callLogRequestBuilder = new CallLogRequest.CallLogRequestBuilder() - .setLimit(20) - .setHasRecording(true); - -cometchatCallLogs.setCallLogRequestBuilder(callLogRequestBuilder); -``` +## Functionality - +Small functional customizations such as toggling visibility of UI elements. - -```kotlin -val callLogRequestBuilder = CallLogRequestBuilder() - .setLimit(20) - .setHasRecording(true) +| Methods | Description | Code | +| --- | --- | --- | +| `setToolbarVisibility` | Toggles visibility for the toolbar in the app bar | `.setToolbarVisibility(View.GONE);` | +| `setBackIconVisibility` | Toggles visibility for the back button in the app bar | `.setBackIconVisibility(View.VISIBLE);` | +| `setLoadingStateVisibility` | Hides the loading state while fetching call logs | `.setLoadingStateVisibility(View.GONE);` | +| `setErrorStateVisibility` | Hides the error state on fetching call logs | `.setErrorStateVisibility(View.GONE);` | +| `setEmptyStateVisibility` | Hides the empty state on fetching call logs | `.setEmptyStateVisibility(View.GONE);` | +| `setSeparatorVisibility` | Controls visibility of separators in the list view | `.setSeparatorVisibility(View.GONE);` | +| `setTitleVisibility` | Controls visibility of the title in the toolbar | `.setTitleVisibility(View.GONE);` | -cometchatCallLogs.setCallLogRequestBuilder(callLogRequestBuilder) -``` +- **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 `CallLog` parameter receive the call log object for that row via the `CallLogsViewHolderListener` pattern (`createView` + `bindView`). -| Property | Description | Code | -| ------------------ | --------------------------------------------------- | ----------------------------------------- | -| **Limit** | Sets the limit for the call logs request | `.setLimit(int limit)` | -| **Call Type** | Sets the call type for the call logs request | `.setCallType(String callType)` | -| **Call Status** | Sets the call status for the call logs request | `.setCallStatus(String callStatus)` | -| **Has Recording** | Sets the recording status for the call logs request | `.setHasRecording(boolean hasRecording)` | -| **Call Direction** | Sets the call direction for the call logs request | `.setCallDirection(String callDirection)` | -| **UID** | Sets the user ID for the call logs request | `.setUid(String uid)` | -| **GUID** | Sets the group ID for the call logs request | `.setGuid(String guid)` | -| **Call Category** | Sets the call category for the call logs request | `.setCallCategory(String callCategory)` | -| **Auth Token** | Sets the auth token for the call logs request | `.setAuthToken(String authToken)` | +| Slot | Method | Replaces | +| --- | --- | --- | +| Leading view | `setLeadingView(CallLogsViewHolderListener)` | Avatar / left section | +| Title view | `setTitleView(CallLogsViewHolderListener)` | Name / title text | +| Subtitle view | `setSubtitleView(CallLogsViewHolderListener)` | Subtitle text below name | +| Trailing view | `setTrailingView(CallLogsViewHolderListener)` | Right section | +| Item view | `setItemView(CallLogsViewHolderListener)` | 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 | +| Options (replace) | `setOptions(Function2)` | Long-press context menu (replaces defaults) | +| Options (append) | `setAddOptions(Function2)` | Long-press context menu (appends to defaults) | -*** +### `setLeadingView` -### Events +Replace the avatar / left section. -[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. + + +```kotlin lines +cometchatCallLogs.setLeadingView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return CometChatAvatar(context) + } -The `CometChatCallLogs` component does not have any exposed events. + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + } +}) +``` + -*** + +```java lines +cometchatCallLogs.setLeadingView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new CometChatAvatar(context); + } -## Customization + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { -To fit your app's design requirements, you can customize the appearance of the CallLog component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. + } +}); +``` + + -### Style +> **What this does:** Registers a `CallLogsViewHolderListener` that provides a custom view for the leading (left) area of each call log item. `createView` inflates your layout, and `bindView` populates it with call log data. -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. +Example with call direction icons: - + -```xml themes.xml - + + +```kotlin YourActivity.kt lines +cometchatCallLogs.setLeadingView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return CometChatAvatar(context) + } - + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + val avatar = createdView as CometChatAvatar + + if (callLog.initiator is CallUser) { + val initiator = callLog.initiator as CallUser + val isLoggedInUser = CallUtils.isLoggedInUser(initiator) + val isMissedOrUnanswered = callLog.status == CometChatCallsConstants.CALL_STATUS_UNANSWERED || (callLog + .status + == CometChatCallsConstants.CALL_STATUS_MISSED) + + if (callLog.type == CometChatCallsConstants.CALL_TYPE_AUDIO || (callLog + .type + == CometChatCallsConstants.CALL_TYPE_VIDEO) || callLog.type == CometChatCallsConstants.CALL_TYPE_AUDIO_VIDEO + ) { + if (isLoggedInUser) { + avatar.setAvatar(ResourcesCompat.getDrawable(context.resources, R.drawable.outgoing_voice_call, null)!!) + } else if (isMissedOrUnanswered) { + avatar.setAvatar(ResourcesCompat.getDrawable(context.resources, R.drawable.miss_call, null)!!) + } else { + avatar.setAvatar(ResourcesCompat.getDrawable(context.resources, R.drawable.incoming_voice_call, null)!!) + } + } + } + val layoutParams = LinearLayout.LayoutParams( + Utils.convertDpToPx(context, 50), + Utils.convertDpToPx(context, 50) + ) + avatar.layoutParams = layoutParams + } +}) ``` + - -```java -cometchatCallLogs.setStyle(R.style.CustomCallLogStyle); -``` - - +```java YourActivity.java lines +cometchatCallLogs.setLeadingView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new CometChatAvatar(context); + } - -```kotlin -cometchatCallLogs.setStyle(R.style.CustomCallLogStyle) + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { + CometChatAvatar avatar = (CometChatAvatar) createdView; + + if (callLog.getInitiator() instanceof CallUser) { + CallUser initiator = (CallUser) callLog.getInitiator(); + boolean isLoggedInUser = CallUtils.isLoggedInUser(initiator); + boolean isMissedOrUnanswered = callLog.getStatus().equals(CometChatCallsConstants.CALL_STATUS_UNANSWERED) || callLog + .getStatus() + .equals(CometChatCallsConstants.CALL_STATUS_MISSED); + + if (callLog.getType().equals(CometChatCallsConstants.CALL_TYPE_AUDIO) || callLog + .getType() + .equals(CometChatCallsConstants.CALL_TYPE_VIDEO) || callLog.getType().equals(CometChatCallsConstants.CALL_TYPE_AUDIO_VIDEO)) { + + if (isLoggedInUser) { + avatar.setAvatar(ResourcesCompat.getDrawable(context.getResources(), R.drawable.outgoing_voice_call, null)); + } else if (isMissedOrUnanswered) { + avatar.setAvatar(ResourcesCompat.getDrawable(context.getResources(), R.drawable.miss_call, null)); + } else { + avatar.setAvatar(ResourcesCompat.getDrawable(context.getResources(), R.drawable.incoming_voice_call, null)); + } + } + } + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + Utils.convertDpToPx(context, 50), + Utils.convertDpToPx(context, 50) + ); + avatar.setLayoutParams(layoutParams); + } +}); ``` - - -*** - -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_logs.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. - -| 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 Users | `.setLoadingStateVisibility(View.GONE);` | -| setErrorStateVisibility | Used to hide error state on fetching conversations | `.setErrorStateVisibility(View.GONE);` | -| setEmptyStateVisibility | Used to hide empty state on fetching conversations | `.setEmptyStateVisibility(View.GONE);` | -| setSeparatorVisibility | Used to control visibility of Separators in the list view | `.setSeparatorVisibility(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 views, layouts, and UI elements and then incorporate those into the component. +### `setTitleView` -#### setOptions +Replace the name / title text. -Defines the available actions users can perform on a call log entry, such as deleting, marking as spam, or calling back. - -Use Cases: + + +```kotlin lines +cometchatCallLogs.setTitleView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return TextView(context) + } -* Provide quick call-back options. -* Allow users to block a number. -* Enable deleting multiple call logs. + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + } +}) +``` + - -```java -cometchatConversations.setOptions((context, conversation) -> Collections.emptyList()); -``` +```java lines +cometchatCallLogs.setTitleView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new TextView(context); + } - + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { - -```kotlin -cometchatConversations.options = Function2?> { context, conversation -> emptyList() } + } +}); ``` - - -*** - -#### addOptions - -Adds custom actions to the existing call log options. - -Use Cases: +Inline call duration example: -* Add favorite/star call log option. -* Integrate a "Send Message" option. -* Provide an archive feature. + + + - -```java -cometchatConversations.addOptions((context, conversation) -> Collections.emptyList()); -``` + +```kotlin YourActivity.kt lines +cometchatCallLogs.setTitleView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return TextView(context) + } + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + val textView = createdView as TextView + textView.setTextAppearance(CometChatTheme.getTextAppearanceHeading4Regular(context)) + textView.setTextColor(CometChatTheme.getTextColorPrimary(context)) + CallUtils.getCallLogUserName(callLog) + if (callLog.totalDurationInMinutes > 0) { + val duration = callLog.totalDurationInMinutes.toString() + textView.text = CallUtils.getCallLogUserName(callLog) + " • \uD83D\uDD5A\uFE0F " + duration + .substring(0, if (duration.length > 4) 4 else 3) + " mins" + } else textView.text = CallUtils.getCallLogUserName(callLog) + } +}) +``` - -```kotlin -cometchatConversations.addOptions { context, conversation -> emptyList() } -``` + +```java YourActivity.java lines +cometchatCallLogs.setTitleView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new TextView(context); + } + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { + TextView textView = (TextView) createdView; + textView.setTextAppearance(CometChatTheme.getTextAppearanceHeading4Regular(context)); + textView.setTextColor(CometChatTheme.getTextColorPrimary(context)); + CallUtils.getCallLogUserName(callLog); + if (callLog.getTotalDurationInMinutes() > 0) { + String duration = String.valueOf(callLog.getTotalDurationInMinutes()); + textView.setText(CallUtils.getCallLogUserName(callLog) + " • \uD83D\uDD5A\uFE0F " + duration + .substring(0, duration.length() > 4 ? 4 : 3) + " mins"); + } else textView.setText(CallUtils.getCallLogUserName(callLog)); + } +}); +``` - -*** - -#### setDateTimeFormatter - -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. +### `setSubtitleView` -Each method in the interface 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 - -`minute(long timestamp)` / `hour(long timestamp)` → Exact time unit - -`minutes(long diffInMinutesFromNow, long timestamp)` → e.g., "5 minutes ago" - -`hours(long diffInHourFromNow, long timestamp)` → e.g., "2 hours ago" +Replace the subtitle text below the caller's name. - -```java -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - - -cometchatCallLogs.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"; - } + +```kotlin lines +cometchatCallLogs.setSubtitleView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return TextView(context) + } - @Override - public String hours(long diffInHourFromNow, long timestamp) { - return diffInHourFromNow + " hrs ago"; - } - }); + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + } +}) ``` - - -```kotlin -import java.text.SimpleDateFormat -import java.util.* - -cometchatCallLogs.setDateTimeFormatterCallback(object : DateTimeFormatterCallback { + +```java lines +cometchatCallLogs.setSubtitleView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new TextView(context); + } - private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault()) - private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { - override fun time(timestamp: Long): String { - return fullTimeFormatter.format(Date(timestamp)) - } + } +}); +``` + + - override fun today(timestamp: Long): String { - return "Today" - } +Example with call direction text: - override fun yesterday(timestamp: Long): String { - return "Yesterday" - } + + + - override fun lastWeek(timestamp: Long): String { - return "Last Week" - } + + +```kotlin YourActivity.kt lines +cometchatCallLogs.setSubtitleView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return TextView(context) + } - override fun otherDays(timestamp: Long): String { - return dateFormatter.format(Date(timestamp)) + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + val textView = createdView as TextView + val callUser = callLog.initiator as CallUser + val isInitiator = callUser.uid == CometChat.getLoggedInUser().uid + if (callLog.status == CometChatCallsConstants.CALL_STATUS_UNANSWERED || (callLog + .status + == CometChatCallsConstants.CALL_STATUS_MISSED) + ) { + textView.text = "Missed Call" + } else { + if (isInitiator) { + textView.text = "Outgoing Call" + } else { + textView.text = "Incoming Call" + } } + } +}) +``` + - override fun minutes(diffInMinutesFromNow: Long, timestamp: Long): String { - return "$diffInMinutesFromNow mins ago" - } + +```java YourActivity.java lines +cometchatCallLogs.setSubtitleView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new TextView(context); + } - override fun hours(diffInHourFromNow: Long, timestamp: Long): String { - return "$diffInHourFromNow hrs ago" + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { + TextView textView = (TextView) createdView; + CallUser callUser = (CallUser) callLog.getInitiator(); + boolean isInitiator = callUser.getUid().equals(CometChat.getLoggedInUser().getUid()); + if (callLog.getStatus().equals(CometChatCallsConstants.CALL_STATUS_UNANSWERED) || callLog + .getStatus() + .equals(CometChatCallsConstants.CALL_STATUS_MISSED)) { + textView.setText("Missed Call"); + } else { + if (isInitiator) { + textView.setText("Outgoing Call"); + } else { + textView.setText("Incoming Call"); + } } - }); + } +}); ``` - - -*** - -#### setLoadingView - -Allows setting a custom loading view when fetching call logs. +### `setTrailingView` -Use Cases: - -* Display a spinner animation while loading. -* Show a "Fetching Call History..." message. -* Use a shimmer effect for better UI experience. +Replace the right section of each call log item. - -```java -cometchatConversations.setLoadingView(R.layout.your_loading_view); -``` - - - -```kotlin -cometchatConversations.loadingView = R.layout.your_loading_view -``` +```kotlin lines +cometchatCallLogs.setTrailingView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return TextView(context) + } + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + } +}) +``` - - -*** - -#### setEmptyView - -Defines a custom view when no call logs are available. - -Use Cases: - -* Show a friendly message like "No calls yet!". -* Offer quick actions like "Make a Call". -* Display an illustration/image. - - -```java -cometchatConversations.setEmptyView(R.layout.your_empty_view); -``` +```java lines +cometchatCallLogs.setTrailingView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new TextView(context); + } - + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { - -```kotlin -cometchatConversations.emptyView = R.layout.your_empty_view + } +}); ``` - - -*** - -#### setErrorView - -Allows setting a custom error state view when fetching call logs fails. +Timestamp example: -Use Cases: - -* Display a retry button. -* Show a network issue message. -* Provide a troubleshooting guide. + + + - -```java -cometchatConversations.setErrorView(R.layout.your_empty_view); -``` + +```kotlin YourActivity.kt lines +cometchatCallLogs.setTrailingView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return TextView(context) + } + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + val textView = createdView as TextView + textView.text = SimpleDateFormat("dd MMM, hh:mm a").format(callLog.initiatedAt * 1000) + } +}) +``` - -```kotlin -cometchatConversations.errorView = R.layout.your_error_view -``` + +```java YourActivity.java lines +cometchatCallLogs.setTrailingView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return new TextView(context); + } + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { + TextView textView = (TextView) createdView; + textView.setText(new SimpleDateFormat("dd MMM, hh:mm a").format(callLog.getInitiatedAt() * 1000)); + } +}); +``` - -*** +### `setItemView` -#### setItemView - -Allows setting a custom layout for each call log item. - -Use Cases: - -* Customize the entire call log card. -* Display additional contact details. -* Use a two-column design for better readability. +Replace the entire list item row. - -```java - cometChatCallLog.setItemView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return super.createView(context, listItem); - } - - @Override - public void bindView(Context context, - View createdView, - CallLog call, - RecyclerView.ViewHolder holder, - List callList, - int position) { + +```kotlin lines +cometchatCallLogs.setItemView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View? { + return null + } - super.bindView(context, createdView, call, holder, callList, position); - } - }); + override fun bindView( + context: Context, + createdView: View, + callLog: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + } +}) ``` - - -```kotlin - cometChatCallLog.setItemView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + +```java lines +cometchatCallLogs.setItemView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return null; + } - } + @Override + public void bindView(Context context, View createdView, CallLog callLog, RecyclerView.ViewHolder holder, List callList, int position) { - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - } - }) + } +}); ``` - - +Example with custom call log layout: + -```xml call_log_list_item.xml +Create a `call_log_list_item.xml` custom layout file: + +```xml call_log_list_item.xml lines - @@ -782,662 +984,589 @@ Use Cases: + android:layout_height="wrap_content" /> ``` - -```java - cometChatCallLog.setItemView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return LayoutInflater.from(context).inflate(R.layout.call_log_list_item, null); - } + +```kotlin YourActivity.kt lines +cometchatCallLogs.setItemView(object : CallLogsViewHolderListener() { + override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { + return LayoutInflater.from(context).inflate(R.layout.call_log_list_item, null) + } - @Override - public void bindView(Context context, - View createdView, - CallLog call, - RecyclerView.ViewHolder holder, - List callList, - int position) { - CometChatAvatar avatar = view.findViewById(R.id.avatar); - TextView name = view.findViewById(R.id.tv_title); - TextView subTitle = view.findViewById(R.id.tv_subtitle); - TextView date = view.findViewById(R.id.tv_date_call_log); - - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT - ); - - view.setLayoutParams(layoutParams); - CallUser callUser = (CallUser) call.getInitiator(); - CallUser callUser1 = (CallUser) call.getReceiver(); - boolean isInitiator = callUser.getUid().equals(CometChat.getLoggedInUser().getUid()); - date.setText(new SimpleDateFormat("dd MMM, hh:mm a").format(call.getInitiatedAt() * 1000)); - if (call.getStatus().equals(CometChatCallsConstants.CALL_STATUS_UNANSWERED) || call - .getStatus() - .equals(CometChatCallsConstants.CALL_STATUS_MISSED)) { - avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_missed_call, null)); - subTitle.setText("Missed Call"); - } else { - if (isInitiator) { - avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_outgoing_call, null)); - subTitle.setText("Outgoing Call"); - name.setText(callUser1.getName()); - } else { - avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_incoming_call, null)); - subTitle.setText("Incoming Call"); - name.setText(callUser.getName()); - } - } + override fun bindView( + context: Context, + createdView: View, + call: CallLog, + holder: RecyclerView.ViewHolder, + callList: List, + position: Int + ) { + val avatar: CometChatAvatar = createdView.findViewById(R.id.avatar) + val name: TextView = createdView.findViewById(R.id.tv_title) + val subTitle: TextView = createdView.findViewById(R.id.tv_subtitle) + val date: TextView = createdView.findViewById(R.id.tv_date_call_log) + + val layoutParams = LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + ) + + createdView.layoutParams = layoutParams + val callUser = call.initiator as CallUser + val callUser1 = call.receiver as CallUser + val isInitiator = callUser.uid == CometChat.getLoggedInUser().uid + date.text = SimpleDateFormat("dd MMM, hh:mm a").format(call.initiatedAt * 1000) + if (call.status == CometChatCallsConstants.CALL_STATUS_UNANSWERED || (call + .status + == CometChatCallsConstants.CALL_STATUS_MISSED) + ) { + avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.ic_missed_call, null)!!) + subTitle.text = "Missed Call" + } else { + if (isInitiator) { + avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.ic_outgoing_call, null)!!) + subTitle.text = "Outgoing Call" + name.text = callUser1.name + } else { + avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.ic_incoming_call, null)!!) + subTitle.text = "Incoming Call" + name.text = callUser.name } - }); + } + } +}) ``` - - -```kotlin - cometChatCallLog.setItemView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { - return LayoutInflater.from(context).inflate(R.layout.call_log_list_item, null) - } + +```java YourActivity.java lines +cometchatCallLogs.setItemView(new CallLogsViewHolderListener() { + @Override + public View createView(Context context, CometchatCallLogsItemsBinding listItem) { + return LayoutInflater.from(context).inflate(R.layout.call_log_list_item, null); + } - override fun bindView( - context: Context, - createdView: View, - call: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - val avatar: CometChatAvatar = view.findViewById(R.id.avatar) - val name: TextView = view.findViewById(R.id.tv_title) - val subTitle: TextView = view.findViewById(R.id.tv_subtitle) - val date: TextView = view.findViewById(R.id.tv_date_call_log) - - val layoutParams = LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT - ) - - view.setLayoutParams(layoutParams) - val callUser = call.initiator as CallUser - val callUser1 = call.receiver as CallUser - val isInitiator = callUser.uid == CometChat.getLoggedInUser().uid - date.text = SimpleDateFormat("dd MMM, hh:mm a").format(call.initiatedAt * 1000) - if (call.status == CometChatCallsConstants.CALL_STATUS_UNANSWERED || (call - .status - == CometChatCallsConstants.CALL_STATUS_MISSED) - ) { - avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.ic_missed_call, null)!!) - subTitle.text = "Missed Call" - } else { - if (isInitiator) { - avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.ic_outgoing_call, null)!!) - subTitle.text = "Outgoing Call" - name.text = callUser1.name - } else { - avatar.setAvatar(ResourcesCompat.getDrawable(resources, R.drawable.ic_incoming_call, null)!!) - subTitle.text = "Incoming Call" - name.text = callUser.name - } - } + @Override + public void bindView(Context context, View createdView, CallLog call, RecyclerView.ViewHolder holder, List callList, int position) { + CometChatAvatar avatar = createdView.findViewById(R.id.avatar); + TextView name = createdView.findViewById(R.id.tv_title); + TextView subTitle = createdView.findViewById(R.id.tv_subtitle); + TextView date = createdView.findViewById(R.id.tv_date_call_log); + + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + + createdView.setLayoutParams(layoutParams); + CallUser callUser = (CallUser) call.getInitiator(); + CallUser callUser1 = (CallUser) call.getReceiver(); + boolean isInitiator = callUser.getUid().equals(CometChat.getLoggedInUser().getUid()); + date.setText(new SimpleDateFormat("dd MMM, hh:mm a").format(call.getInitiatedAt() * 1000)); + if (call.getStatus().equals(CometChatCallsConstants.CALL_STATUS_UNANSWERED) || call + .getStatus() + .equals(CometChatCallsConstants.CALL_STATUS_MISSED)) { + avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_missed_call, null)); + subTitle.setText("Missed Call"); + } else { + if (isInitiator) { + avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_outgoing_call, null)); + subTitle.setText("Outgoing Call"); + name.setText(callUser1.getName()); + } else { + avatar.setAvatar(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_incoming_call, null)); + subTitle.setText("Incoming Call"); + name.setText(callUser.getName()); } - }) + } + } +}); ``` - - -#### setTitleView +### `setOptions` -Allows setting a custom title view, typically used for the caller’s name or number. - -Use Cases: - -* Display caller’s full name. -* Show a business label for saved contacts. -* Use bold text for unknown numbers. +Replace the long-press context menu entirely. - -```java - cometChatCallLog.setTitleView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return super.createView(context, listItem); - } - - @Override - public void bindView(Context context, - View createdView, - CallLog call, - RecyclerView.ViewHolder holder, - List callList, - int position) { - - super.bindView(context, createdView, call, holder, callList, position); - } - }); + +```kotlin lines +cometchatCallLogs.setOptions { context, callLog -> emptyList() } ``` + + +```java lines +cometchatCallLogs.setOptions((context, callLog) -> Collections.emptyList()); +``` + - -```kotlin - cometChatCallLog.setTitleView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { +### `setAddOptions` - } +Append to the long-press context menu without removing defaults. - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - } - }) + + +```kotlin lines +cometchatCallLogs.setAddOptions { context, callLog -> emptyList() } ``` - + +```java lines +cometchatCallLogs.setAddOptions((context, callLog) -> Collections.emptyList()); +``` + -**Example** +### `setLoadingView` - - - +Sets a custom loading view displayed when data is being fetched. - -```java YourActivity.java - cometChatcallLog.setTitleView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return new TextView(context); - } - - @Override - public void bindView(Context context, - View createdView, - CallLog callLog, - RecyclerView.ViewHolder holder, - List callList, - int position) { - - TextView textView = (TextView) createdView; - textView.setTextAppearance(CometChatTheme.getTextAppearanceHeading4Regular(context)); - textView.setTextColor(CometChatTheme.getTextColorPrimary(context)); - CallUtils.getCallLogUserName(callLog); - if (callLog.getTotalDurationInMinutes() > 0) { - String duration = String.valueOf(callLog.getTotalDurationInMinutes()); - textView.setText(CallUtils.getCallLogUserName(callLog) + " • \uD83D\uDD5A\uFE0F " + duration - .substring(0, duration.length() > 4 ? 4 : 3) + " mins"); - } else textView.setText(CallUtils.getCallLogUserName(callLog)); - } - }); + +```kotlin lines +cometchatCallLogs.setLoadingView(R.layout.your_loading_view) ``` - - -```kotlin YourActivity.kt - cometChatCallLog.setTitleView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { - return TextView(context) - } - - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - val textView = createdView as TextView - textView.setTextAppearance(CometChatTheme.getTextAppearanceHeading4Regular(context)) - textView.setTextColor(CometChatTheme.getTextColorPrimary(context)) - CallUtils.getCallLogUserName(callLog) - if (callLog.totalDurationInMinutes > 0) { - val duration = callLog.totalDurationInMinutes.toString() - textView.text = CallUtils.getCallLogUserName(callLog) + " • \uD83D\uDD5A\uFE0F " + duration - .substring(0, if (duration.length > 4) 4 else 3) + " mins" - } else textView.text = CallUtils.getCallLogUserName(callLog) - } - }) + +```java lines +cometchatCallLogs.setLoadingView(R.layout.your_loading_view); ``` - - -*** +### `setEmptyView` -#### setLeadingView - -Customizes the leading view, usually the caller’s avatar or profile picture. - -Use Cases: - -* Display a profile picture. -* Show a call type icon (missed, received, dialed). -* Indicate call status (e.g., missed calls in red). +Configures a custom view displayed when there are no call logs in the list. - -```java - cometChatCallLog.setLeadingView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return super.createView(context, listItem); - } - - @Override - public void bindView(Context context, - View createdView, - CallLog call, - RecyclerView.ViewHolder holder, - List callList, - int position) { - - super.bindView(context, createdView, call, holder, callList, position); - } - }); + +```kotlin lines +cometchatCallLogs.setEmptyView(R.layout.your_empty_view) ``` + + +```java lines +cometchatCallLogs.setEmptyView(R.layout.your_empty_view); +``` + - -```kotlin - cometChatCallLog.setLeadingView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { +### `setErrorView` - } +Defines a custom error state view that appears when an issue occurs while loading call logs. - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - } - }) + + +```kotlin lines +cometchatCallLogs.setErrorView(R.layout.your_error_view) ``` - + +```java lines +cometchatCallLogs.setErrorView(R.layout.your_error_view); +``` + -**Example** +- **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the call log list item, and the data binding populates correctly for each call log entry. - - - +## Common Patterns - - -```java YourActivity.java -cometChatcallLog.setLeadingView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return new CometChatAvatar(context); - } +### Hide all chrome — minimal list - @Override - public void bindView(Context context, - View createdView, - CallLog callLog, - RecyclerView.ViewHolder holder, - List callList, - int position) { - CometChatAvatar avatar = (CometChatAvatar) createdView; - - if (callLog.getInitiator() instanceof CallUser) { - CallUser initiator = (CallUser) callLog.getInitiator(); - boolean isLoggedInUser = CallUtils.isLoggedInUser(initiator); - boolean isMissedOrUnanswered = callLog.getStatus().equals(CometChatCallsConstants.CALL_STATUS_UNANSWERED) || callLog - .getStatus() - .equals(CometChatCallsConstants.CALL_STATUS_MISSED); - - if (callLog.getType().equals(CometChatCallsConstants.CALL_TYPE_AUDIO) || callLog - .getType() - .equals(CometChatCallsConstants.CALL_TYPE_VIDEO) || callLog.getType().equals(CometChatCallsConstants.CALL_TYPE_AUDIO_VIDEO)) { - - if (isLoggedInUser) { - avatar.setAvatar(ResourcesCompat.getDrawable(context.getResources(), R.drawable.outgoing_voice_call, null)); - } else if (isMissedOrUnanswered) { - avatar.setAvatar(ResourcesCompat.getDrawable(context.getResources(), R.drawable.miss_call, null)); - - } else { - avatar.setAvatar(ResourcesCompat.getDrawable(context.getResources(), R.drawable.incoming_voice_call, null)); - } - } - } - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - Utils.convertDpToPx(context, 50), - Utils.convertDpToPx(context, 50) - ); - avatar.setLayoutParams(layoutParams); - } - }); + + +```kotlin lines +cometchatCallLogs.setSeparatorVisibility(View.GONE) +cometchatCallLogs.setToolbarVisibility(View.GONE) ``` + + +```java lines +cometchatCallLogs.setSeparatorVisibility(View.GONE); +cometchatCallLogs.setToolbarVisibility(View.GONE); +``` + +### Missed calls only + + -```kotlin YourActivity.kt -cometChatCallLog.setLeadingView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { - return CometChatAvatar(context) - } +```kotlin lines +val builder = CallLogRequest.CallLogRequestBuilder() + .setCallStatus(CometChatCallsConstants.CALL_STATUS_MISSED) +cometchatCallLogs.setCallLogRequestBuilder(builder) +``` + - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - val avatar = createdView as CometChatAvatar - - if (callLog.initiator is CallUser) { - val initiator = callLog.initiator as CallUser - val isLoggedInUser = CallUtils.isLoggedInUser(initiator) - val isMissedOrUnanswered = callLog.status == CometChatCallsConstants.CALL_STATUS_UNANSWERED || (callLog - .status - == CometChatCallsConstants.CALL_STATUS_MISSED) - - if (callLog.type == CometChatCallsConstants.CALL_TYPE_AUDIO || (callLog - .type - == CometChatCallsConstants.CALL_TYPE_VIDEO) || callLog.type == CometChatCallsConstants.CALL_TYPE_AUDIO_VIDEO - ) { - if (isLoggedInUser) { - avatar.setAvatar(ResourcesCompat.getDrawable(context.resources, R.drawable.outgoing_voice_call, null)!!) - } else if (isMissedOrUnanswered) { - avatar.setAvatar(ResourcesCompat.getDrawable(context.resources, R.drawable.miss_call, null)!!) - } else { - avatar.setAvatar(ResourcesCompat.getDrawable(context.resources, R.drawable.incoming_voice_call, null)!!) - } - } - } - val layoutParams = LinearLayout.LayoutParams( - Utils.convertDpToPx(context, 50), - Utils.convertDpToPx(context, 50) - ) - avatar.layoutParams = layoutParams - } - }) + +```java lines +CallLogRequest.CallLogRequestBuilder builder = new CallLogRequest.CallLogRequestBuilder() + .setCallStatus(CometChatCallsConstants.CALL_STATUS_MISSED); +cometchatCallLogs.setCallLogRequestBuilder(builder); ``` + + + +### Calls with recordings only + + +```kotlin lines +val builder = CallLogRequest.CallLogRequestBuilder() + .setHasRecording(true) +cometchatCallLogs.setCallLogRequestBuilder(builder) +``` + +```java lines +CallLogRequest.CallLogRequestBuilder builder = new CallLogRequest.CallLogRequestBuilder() + .setHasRecording(true); +cometchatCallLogs.setCallLogRequestBuilder(builder); +``` + -*** +### Audio calls only -#### setSubtitleView + + +```kotlin lines +val builder = CallLogRequest.CallLogRequestBuilder() + .setCallType(CometChatCallsConstants.CALL_TYPE_AUDIO) +cometchatCallLogs.setCallLogRequestBuilder(builder) +``` + -Enables customizing the subtitle view, usually used for additional call details. + +```java lines +CallLogRequest.CallLogRequestBuilder builder = new CallLogRequest.CallLogRequestBuilder() + .setCallType(CometChatCallsConstants.CALL_TYPE_AUDIO); +cometchatCallLogs.setCallLogRequestBuilder(builder); +``` + + -Use Cases: +## Advanced Methods -* Display call type (Missed, Received, Outgoing). -* Show network strength indicators. -* Include call duration in a more readable format. +### `refreshCallLogs` - - -```java - cometChatCallLog.setSubtitleView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return super.createView(context, listItem); - } +Forces a refresh of the call log list, re-fetching data from the server. - @Override - public void bindView(Context context, - View createdView, - CallLog call, - RecyclerView.ViewHolder holder, - List callList, - int position) { - - super.bindView(context, createdView, call, holder, callList, position); - } - }); + + +```kotlin lines +cometchatCallLogs.refreshCallLogs() ``` + + +```java lines +cometchatCallLogs.refreshCallLogs(); +``` + - -```kotlin - cometChatCallLog.setSubtitleView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { +### `setDateFormat` - } +Sets a legacy `SimpleDateFormat` for call log timestamps. - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - } - }) + + +```kotlin lines +cometchatCallLogs.setDateFormat(SimpleDateFormat("dd/MM/yyyy, HH:mm:ss", Locale.getDefault())) ``` - + +```java lines +cometchatCallLogs.setDateFormat(new SimpleDateFormat("dd/MM/yyyy, HH:mm:ss", Locale.getDefault())); +``` + -**Example** +### `setDateTimeFormatter` - - - +Provides a custom implementation of `DateTimeFormatterCallback` to configure how time and date values are displayed. Each method corresponds to a specific case: -You can create and return a view from `setSubtitleView` which will be loaded in call log item. +- `time(long timestamp)` — Custom full timestamp format +- `today(long timestamp)` — Called when a call log is from today +- `yesterday(long timestamp)` — Called for yesterday's call logs +- `lastWeek(long timestamp)` — Call logs from the past week +- `otherDays(long timestamp)` — Older call logs +- `minutes(long diffInMinutesFromNow, long timestamp)` — e.g., "5 minutes ago" +- `hours(long diffInHourFromNow, long timestamp)` — e.g., "2 hours ago" - -```java YourActivity.java - cometChatCallLog.setSubtitleView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return new TextView(context); - } + +```kotlin lines +import java.text.SimpleDateFormat +import java.util.* - @Override - public void bindView(Context context, - View createdView, - CallLog callLog, - RecyclerView.ViewHolder holder, - List callList, - int position) { - TextView textView = (TextView) createdView; - CallUser callUser = (CallUser) callLog.getInitiator(); - boolean isInitiator = callUser.getUid().equals(CometChat.getLoggedInUser().getUid()); - if (callLog.getStatus().equals(CometChatCallsConstants.CALL_STATUS_UNANSWERED) || callLog - .getStatus() - .equals(CometChatCallsConstants.CALL_STATUS_MISSED)) { - textView.setText("Missed Call"); - } else { - if (isInitiator) { - textView.setText("Outgoing Call"); - } else { - textView.setText("Incoming Call"); - } - } - } - }); -``` +cometchatCallLogs.setDateTimeFormatter(object : DateTimeFormatterCallback { - + private val fullTimeFormatter = SimpleDateFormat("hh:mm a", Locale.getDefault()) + private val dateFormatter = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) - -```kotlin YourActivity.kt - cometChatCallLog.setSubtitleView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { - return TextView(context) - } + override fun time(timestamp: Long): String { + return fullTimeFormatter.format(Date(timestamp)) + } - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - val textView = createdView as TextView - val callUser = callLog.initiator as CallUser - val isInitiator = callUser.uid == CometChat.getLoggedInUser().uid - if (callLog.status == CometChatCallsConstants.CALL_STATUS_UNANSWERED || (callLog - .status - == CometChatCallsConstants.CALL_STATUS_MISSED) - ) { - textView.text = "Missed Call" - } else { - if (isInitiator) { - textView.text = "Outgoing Call" - } else { - textView.text = "Incoming Call" - } - } - } - }) -``` + 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; -*** +cometchatCallLogs.setDateTimeFormatter(new DateTimeFormatterCallback() { -#### setTrailingView + private final SimpleDateFormat fullTimeFormatter = new SimpleDateFormat("hh:mm a", Locale.getDefault()); + private final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault()); -Customizes the trailing section, typically for call duration or actions. + @Override + public String time(long timestamp) { + return fullTimeFormatter.format(new Date(timestamp)); + } -Use Cases: + @Override + public String today(long timestamp) { + return "Today"; + } -* Display call duration. -* Add a "Call Again" button. -* Show call timestamps. + @Override + public String yesterday(long timestamp) { + return "Yesterday"; + } - - -```java - cometChatCallLog.setTrailingView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return super.createView(context, listItem); - } + @Override + public String lastWeek(long timestamp) { + return "Last Week"; + } - @Override - public void bindView(Context context, - View createdView, - CallLog call, - RecyclerView.ViewHolder holder, - List callList, - int position) { + @Override + public String otherDays(long timestamp) { + return dateFormatter.format(new Date(timestamp)); + } - super.bindView(context, createdView, call, holder, callList, position); - } - }); -``` + @Override + public String minutes(long diffInMinutesFromNow, long timestamp) { + return diffInMinutesFromNow + " mins ago"; + } + @Override + public String hours(long diffInHourFromNow, long timestamp) { + return diffInHourFromNow + " hrs ago"; + } +}); +``` + - -```kotlin - cometChatCallLog.setTrailingView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { +### Internal Access - } +These methods provide direct access to internal components for advanced use cases. - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - } - }) -``` +| Method | Returns | Description | +| --- | --- | --- | +| `getBinding()` | `CometchatCallLogsBinding` | The ViewBinding for the component's root layout | +| `getViewModel()` | `CallLogsViewModel` | The ViewModel managing call log data and state | +| `getAdapter()` | `CallLogsAdapter` | The adapter powering the RecyclerView | +| `setAdapter(CallLogsAdapter)` | `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 -**Example** +The component uses XML theme styles. Define a custom style with parent `CometChatCallLogsStyle` in `themes.xml`, then apply with `setStyle()`. - + -You can create and return a view from setTail which will be loaded in call log item. +```xml themes.xml lines + + +``` - -```java YourActivity.java - cometChatcallLog.setTrailingView(new CallLogsViewHolderListener() { - @Override - public View createView(Context context, CometchatCallLogsItemsBinding listItem) { - return new TextView(context); - } - - @Override - public void bindView(Context context, - View createdView, - CallLog callLog, - RecyclerView.ViewHolder holder, - List callList, - int position) { - TextView textView = (TextView) createdView; - textView.setText(new SimpleDateFormat("dd MMM, hh:mm a").format(callLog.getInitiatedAt() * 1000)); - } - }); + +```kotlin lines +cometchatCallLogs.setStyle(R.style.CustomCallLogStyle) ``` - - -```kotlin YourActivity.kt - cometChatCallLog.setTrailingView(object : CallLogsViewHolderListener() { - override fun createView(context: Context?, listItem: CometchatCallLogsItemsBinding?): View { - return TextView(context) - } - - override fun bindView( - context: Context, - createdView: View, - callLog: CallLog, - holder: RecyclerView.ViewHolder, - callList: List, - position: Int - ) { - val textView = createdView as TextView - textView.text = SimpleDateFormat("dd MMM, hh:mm a").format(callLog.initiatedAt * 1000) - } - }) + +```java lines +cometchatCallLogs.setStyle(R.style.CustomCallLogStyle); ``` - - + +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_logs.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` | `@Dimension int` | Corner radius of the component | +| `setStrokeColor` | `@ColorInt int` | Stroke color of the component border | +| `setStrokeWidth` | `@Dimension int` | Stroke width of the component border | +| `setBackIcon` | `Drawable` | Custom back icon drawable | +| `setBackIconTint` | `@ColorInt int` | Tint color for the back icon | +| `setTitleTextColor` | `@ColorInt int` | Title text color in the toolbar | +| `setTitleTextAppearance` | `@StyleRes int` | Title text appearance in the toolbar | +| `setItemTitleTextColor` | `@ColorInt int` | Text color for call log item titles | +| `setItemTitleTextAppearance` | `@StyleRes int` | Text appearance for call log item titles | +| `setItemSubtitleTextColor` | `@ColorInt int` | Text color for call log item subtitles | +| `setItemSubtitleTextAppearance` | `@StyleRes int` | Text appearance for call log item subtitles | +| `setSeparatorColor` | `@ColorInt int` | Color of list item separators | +| `setItemIncomingCallIcon` | `Drawable` | Icon for incoming call indicators | +| `setItemIncomingCallIconTint` | `@ColorInt int` | Tint for incoming call icon | +| `setItemOutgoingCallIcon` | `Drawable` | Icon for outgoing call indicators | +| `setItemOutgoingCallIconTint` | `@ColorInt int` | Tint for outgoing call icon | +| `setItemMissedCallIcon` | `Drawable` | Icon for missed call indicators | +| `setItemMissedCallIconTint` | `@ColorInt int` | Tint for missed call icon | +| `setItemMissedCallTitleColor` | `@ColorInt int` | Title text color for missed call entries | +| `setItemAudioCallIcon` | `Drawable` | Icon for audio call action button | +| `setItemAudioCallIconTint` | `@ColorInt int` | Tint for audio call action icon | +| `setItemVideoCallIcon` | `Drawable` | Icon for video call action button | +| `setItemVideoCallIconTint` | `@ColorInt int` | Tint for video call action icon | +| `setAvatarStyle` | `@StyleRes int` | Style for call log avatars | +| `setDateStyle` | `@StyleRes int` | Style for date/time display | +| `setEmptyStateTitleTextAppearance` | `@StyleRes int` | Title text appearance for the empty state | +| `setEmptyStateTitleTextColor` | `@ColorInt int` | Title text color for the empty state | +| `setEmptyStateSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the empty state | +| `setEmptyStateSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the empty state | +| `setErrorTitleTextAppearance` | `@StyleRes int` | Title text appearance for the error state | +| `setErrorTitleTextColor` | `@ColorInt int` | Title text color for the error state | +| `setErrorSubtitleTextAppearance` | `@StyleRes int` | Subtitle text appearance for the error state | +| `setErrorSubtitleTextColor` | `@ColorInt int` | Subtitle text color for the error state | + +## Customization Matrix + +| What to change | Where | Property/API | Example | +| --- | --- | --- | --- | +| Override behavior on user interaction | Activity/Fragment | `setOn` callbacks | `setOnItemClick((v, pos, cl) -> { ... })` | +| Filter which call logs appear | Activity/Fragment | `setCallLogRequestBuilder` | `setCallLogRequestBuilder(builder)` | +| Toggle visibility of UI elements | Activity/Fragment | `setVisibility(int)` | `setSeparatorVisibility(View.GONE)` | +| Replace a section of the list item | Activity/Fragment | `setView` | `setLeadingView(listener)` | +| Change colors, fonts, spacing | `themes.xml` | `CometChatCallLogsStyle` | `#F76808` | +| Avatar style (corner radius, background) | `themes.xml` | `cometchatCallLogsAvatarStyle` | `8dp` | +| Apply a custom style | Activity/Fragment | `setStyle(int styleRes)` | `cometchatCallLogs.setStyle(R.style.CustomCallLogStyle);` | +| Back button visibility | Activity/Fragment | `setBackIconVisibility(int)` | `.setBackIconVisibility(View.VISIBLE);` | +| Toolbar visibility | Activity/Fragment | `setToolbarVisibility(int)` | `.setToolbarVisibility(View.GONE);` | +| Title visibility | Activity/Fragment | `setTitleVisibility(int)` | `.setTitleVisibility(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);` | +| Date/time formatting | Activity/Fragment | `setDateTimeFormatter(DateTimeFormatterCallback)` | See `setDateTimeFormatter` code above | +| Legacy date format | Activity/Fragment | `setDateFormat(SimpleDateFormat)` | `setDateFormat(new SimpleDateFormat("dd/MM/yyyy, HH:mm:ss"))` | +| Long-press options (replace) | Activity/Fragment | `setOptions(Function2)` | See `setOptions` code above | +| Long-press options (append) | Activity/Fragment | `setAddOptions(Function2)` | See `setAddOptions` 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(CallLogsViewHolderListener)` | See `setLeadingView` code above | +| Title view | Activity/Fragment | `setTitleView(CallLogsViewHolderListener)` | See `setTitleView` code above | +| Subtitle view | Activity/Fragment | `setSubtitleView(CallLogsViewHolderListener)` | See `setSubtitleView` code above | +| Trailing view | Activity/Fragment | `setTrailingView(CallLogsViewHolderListener)` | See `setTrailingView` code above | +| Entire list item | Activity/Fragment | `setItemView(CallLogsViewHolderListener)` | See `setItemView` code above | +| Call icon click listener | Activity/Fragment | `setOnCallIconClickListener(OnCallIconClick)` | See `setOnCallIconClickListener` code above | +| Refresh call logs | Activity/Fragment | `refreshCallLogs()` | `.refreshCallLogs();` | +| Internal adapter access | Activity/Fragment | `getAdapter()` / `setAdapter()` | Advanced use only | + +## Accessibility + +The component renders a scrollable `RecyclerView` of interactive call log items. Each call log row responds to tap and long-press gestures. Avatar images include the caller name as content description. Call status icons (incoming, outgoing, missed) provide visual indicators for call direction. + +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. + +Call direction icons and status indicators 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. | +| Call log list is empty despite having call history | Verify that a user is logged in with `CometChatUIKit.login()` before displaying the component. The component fetches call logs for the logged-in user only. | +| Filters not applied | Ensure you call `setCallLogRequestBuilder(callLogRequestBuilder)` on the `CometChatCallLogs` instance after creating and configuring the builder. | +| Custom style not visible | Verify the style parent is `CometChatCallLogsStyle` and that you call `setStyle(R.style.YourStyle)` on the component instance. | +| `setOnItemClick` not firing | If the component is inside a parent view that intercepts touch events, ensure the parent does not consume the click. Verify the callback is set before the component loads data. | +| Custom view returns null in `createView` | If `createView` returns `null`, the default view is used. Return a valid inflated `View` to replace the default. | +| Call status icons not showing in custom leading view | Ensure you check `callLog.getStatus()` against `CometChatCallsConstants.CALL_STATUS_UNANSWERED` and `CometChatCallsConstants.CALL_STATUS_MISSED` to determine the correct icon. | +| View binding reference is null | If using view binding, initialize it with `binding = YourXmlFileNameBinding.inflate(getLayoutInflater())` before accessing `binding.callLog`. | + +## FAQ + +**Q: How do I filter call logs to show only calls with recordings?** +**A:** Create a `CallLogRequest.CallLogRequestBuilder`, call `setHasRecording(true)`, and pass it to `setCallLogRequestBuilder`. + +**Q: Can I use `CometChatCallLogs` in both an Activity and a Fragment?** +**A:** Yes. In an Activity, call `setContentView(new CometChatCallLogs(this))`. In a Fragment, return `new CometChatCallLogs(getContext())` from `onCreateView`. + +**Q: Does `CometChatCallLogs` emit any events?** +**A:** No. The `CometChatCallLogs` component does not have any exposed events. + +**Q: How do I customize the call log item to show call direction icons?** +**A:** Use `setLeadingView` with a `CallLogsViewHolderListener`. In `bindView`, check `CallUtils.isLoggedInUser(initiator)` and `callLog.getStatus()` to determine whether to show an outgoing, incoming, or missed call icon. + +**Q: How do I show call duration in the title?** +**A:** Use `setTitleView` with a `CallLogsViewHolderListener`. In `bindView`, check `callLog.getTotalDurationInMinutes()` and append the duration to the caller name from `CallUtils.getCallLogUserName(callLog)`. + +**Q: How do I add custom long-press options without removing the defaults?** +**A:** Use `setAddOptions` instead of `setOptions`. `setAddOptions` appends your custom `MenuItem` objects to the existing default options. + +## Next Steps + +- [Call Buttons component](/ui-kit/android/call-buttons) +- [Conversations component](/ui-kit/android/conversations) +- [Users component](/ui-kit/android/users) diff --git a/ui-kit/android/color-resources.mdx b/ui-kit/android/color-resources.mdx index ac2e6b556..a14360411 100644 --- a/ui-kit/android/color-resources.mdx +++ b/ui-kit/android/color-resources.mdx @@ -2,31 +2,62 @@ title: "Color Resources" --- -## Overview - -Color resources in CometChat allow you to maintain a consistent visual identity across your application, providing predefined colors for various UI elements such as text, buttons, backgrounds, alerts, and more. These color definitions adapt seamlessly to light and dark themes, ensuring an optimal user experience across different modes. - -The color resources are divided into the following categories: - -* **Primary Colors**: Define the main theme of the application. -* **Neutral Colors**: Used for backgrounds, strokes, and secondary UI elements. -* **Alert Colors**: Highlight states like success, warning, error, or information. -* **Text Colors**: Used for typography. -* **Icon Colors**: Define icon appearances. -* **Button Colors**: Customize button backgrounds, icons, and text. - -CometChat provides separate color definitions for **light mode** and **dark mode**, enabling automatic theme adaptation. - -*** - -## Usage - -### Default Colors - -CometChat includes predefined color sets for light and dark modes in the `res/values` and `res/values-night` directories, respectively. These ensure proper visual contrast and accessibility.\ -Example: Light Mode Color Resources - -```html +Use CometChat UI Kit color resources to keep a consistent visual identity in light and dark modes. + +## When to use this +- You want to review the default UI Kit color palette. +- You need consistent colors across text, buttons, backgrounds, and icons. +- You want to override the primary brand color via theming. +- You want light and dark mode color consistency. + +## Prerequisites +- CometChat UI Kit for Android is installed and initialized. +- You can edit `app/src/main/res/values/color.xml` and `app/src/main/res/values-night/color.xml`. +- You can edit `app/src/main/res/values/themes.xml`. +- Your app theme extends `CometChatTheme.DayNight`. + +## Quick start + + +File: `app/src/main/res/values/color.xml`. + + +File: `app/src/main/res/values-night/color.xml`. + + +File: `app/src/main/res/values/themes.xml`. Set `cometchatPrimaryColor`. + + +File: `AndroidManifest.xml`. Set `android:theme` on ``. + + +Run the app and confirm UI Kit screens match your palette in light and dark mode. + + + +## Core concepts +- Primary colors define the main theme of the UI. +- Neutral colors are used for backgrounds, strokes, and secondary elements. +- Alert colors highlight success, warning, error, or info states. +- Text and icon colors control typography and icon appearance. +- Light mode colors live in `res/values/color.xml` and dark mode colors in `res/values-night/color.xml`. + +## Implementation + +### Review the default light mode colors +What you're changing: The color resources used in light mode. + +- **Where to change it**: `app/src/main/res/values/color.xml`. + +- **Applies to**: Light mode only. + +- **Default behavior**: UI Kit uses its predefined light mode palette. + +- **Override**: Edit the values or reference them in your theme. + +- **Code**: + +```xml color.xml lines #6852D6 @@ -37,9 +68,24 @@ Example: Light Mode Color Resources ``` -Example: Night Mode Color Resources +- **What this does**: Shows the default light mode color definitions used by UI Kit. + +- **Verify**: Light mode UI Kit screens match these colors. -```html +### Review the default dark mode colors +What you're changing: The color resources used in dark mode. + +- **Where to change it**: `app/src/main/res/values-night/color.xml`. + +- **Applies to**: Dark mode only. + +- **Default behavior**: UI Kit uses its predefined dark mode palette. + +- **Override**: Edit the values or reference them in your theme. + +- **Code**: + +```xml values-night/color.xml lines #6852D6 @@ -50,25 +96,86 @@ Example: Night Mode Color Resources ``` -To view the complete list of colors for both light and dark modes, [Light mode colors](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/color.xml) & [Dark mode colors](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values-night/color.xml). +- **What this does**: Shows the default dark mode color definitions used by UI Kit. + +- **Verify**: Dark mode UI Kit screens match these colors. + + +To view the complete list of colors for both light and dark modes, use the [Light mode colors](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/color.xml) and [Dark mode colors](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values-night/color.xml). + + +### Override the primary color via your theme +What you're changing: The UI Kit primary color. + +- **Where to change it**: `app/src/main/res/values/themes.xml`. -## Customizing Colors +- **Applies to**: All UI Kit components. -You can override the default colors to align them with your application's branding. +- **Default behavior**: UI Kit uses the default primary color. -Example: Changing the Primary Color Define your custom color in your themes.xml: +- **Override**: Set `cometchatPrimaryColor` in your app theme. -```html +- **Code**: + +```xml themes.xml lines ``` -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 custom value. + +- **Verify**: Buttons and highlights use the new primary color. + +### Apply your theme in the manifest +What you're changing: The theme applied to your app. + +- **Where to change it**: `AndroidManifest.xml`. + +- **Applies to**: All activities unless overridden. + +- **Default behavior**: The application theme is not set to your UI Kit theme. + +- **Override**: Set `android:theme` on the `` element. + +- **Code**: + +```xml AndroidManifest.xml lines + + +``` + +- **What this does**: Applies your theme to all app activities. + +- **Verify**: UI Kit screens use your updated theme colors. + +## Customization matrix +| What you want to change | Where | Property/API | Example | +| --- | --- | --- | --- | +| Light mode palette | `app/src/main/res/values/color.xml` | `cometchat_color_primary` | `#6852D6` | +| Dark mode palette | `app/src/main/res/values-night/color.xml` | `cometchat_color_primary` | `#6852D6` | +| Primary color override | `app/src/main/res/values/themes.xml` | `cometchatPrimaryColor` | `#F76808` | +| Apply theme | `AndroidManifest.xml` | `android:theme` | `android:theme="@style/AppTheme"` | + +## Common pitfalls and fixes +- Colors do not change: Confirm your app theme extends `CometChatTheme.DayNight`. +- Dark mode colors not applied: Ensure `res/values-night/color.xml` exists. +- Custom primary color not showing: Verify `cometchatPrimaryColor` is set in your theme. +- UI Kit still uses defaults: Rebuild the app after resource changes. +- Theme not applied: Check `android:theme` in `AndroidManifest.xml`. + +## FAQ +**Q**: Can I edit the UI Kit color XML directly? +**A**: You can reference or override colors in your app resources; UI Kit will read them at runtime. + +**Q**: Do I need separate colors for dark mode? +**A**: Yes. Use `res/values-night/color.xml` for dark mode overrides. + +**Q**: Where can I see all default colors? +**A**: Use the [Light mode colors](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/color.xml) and [Dark mode colors](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values-night/color.xml). diff --git a/ui-kit/android/component-styling.mdx b/ui-kit/android/component-styling.mdx index 529c1fee9..0a25887ed 100644 --- a/ui-kit/android/component-styling.mdx +++ b/ui-kit/android/component-styling.mdx @@ -1,23 +1,102 @@ --- title: "Component Styling" +description: "Style CometChat UI Kit components in Android using XML themes and drawable overrides." --- -## Overview +This page shows how to style CometChat UI Kit components in Android by overriding XML theme attributes. It is written for Android developers customizing UI Kit v5. -CometChat UIKit enables developers to seamlessly integrate customizable components into their applications. Each component is designed to ensure a consistent user experience while offering flexibility to adapt to your app’s design system. You can modify attributes such as colors, fonts, sizes, icons, and more using XML or programmatically. Below is a detailed guide for styling individual components within the UIKit. +## When to use this -## Components +- You want UI Kit screens (lists, headers, and message UI) to match your brand colors and typography. +- You need to customize calling and AI UI components without rebuilding UI from scratch. +- You prefer centralized styling through `res/values/themes.xml`. +- You want consistent iconography by supplying your own vector drawables. +- You need a repeatable pattern that an AI coding agent can apply across components. -### Conversations +## Prerequisites -The `CometChatConversations` Component provides a list of recent chats, showing participants, message previews, and timestamps. It supports default themes while offering deep customization for text appearance, icons, and overall layout. With this component, you can create an intuitive and visually appealing chat list that matches your app’s branding. +- CometChat Android UI Kit v5 installed in your app. +- Your app theme extends `CometChatTheme.DayNight`. +- You can edit `res/values/themes.xml` in your Android module. +- You can add drawable resources to `res/drawable/` when needed. +- You rebuild or sync Gradle after updating styles. + +## Quick start + +1. Open `res/values/themes.xml`. +2. Create a custom style that extends the component's parent style (for example, `CometChatConversationsStyle`). +3. Assign your custom style to `AppTheme` using the component's theme attribute (for example, `cometchatConversationsStyle`). +4. Sync Gradle and rebuild the app. +5. Navigate to the screen that uses the component and confirm the visual change. + +```xml res/values/themes.xml lines + + + + + + + +``` + +- **What this does**: applies a custom avatar style to the Conversations list through your app theme. + +- **Verify**: open the Conversations screen and confirm the avatar background and stroke radius changed. + +## Core concepts + +- `AppTheme` is the single place where UI Kit style hooks are wired. +- Each UI Kit component has a parent style (for example, `CometChatMessageListStyle`) and a theme attribute (for example, `cometchatMessageListStyle`). +- Custom styles must extend the correct parent style to inherit default behavior. +- Drawable overrides (for example, custom icons) live in `res/drawable/` and are referenced from styles. +- Fonts can be set once at the theme level and reused across components. + +```xml res/values/themes.xml lines + + + +``` + +- **What this does**: sets UI Kit typography once so you do not repeat font assignments in every component. + +## Implementation + +Use the following sections to style each component. Each section lists what changes, where to change it, the exact code to paste, and how to verify the result. + +### Chat lists and messaging UI + +#### Conversations + +The `CometChatConversations` component renders the recent chats list. -```html - +What you're changing: avatar and badge styling in the conversation list. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatConversations` + +- **Default behavior**: UI Kit default avatar and badge styles. + +- **Override**: set `cometchatConversationsStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + -``` -```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_conversations.xml). +- **What this does**: applies custom avatar and badge styles to conversation list items. + +- **Verify**: the Conversations list shows updated avatar backgrounds and badge colors. -### Users +Attribute references: +- [Conversations attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_conversations.xml) +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) +- [Badge attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_badge.xml) -The `CometChatUsers` Component displays a scrollable list of users. It is ideal for showcasing available contacts for messaging, calls, or group creation. Developers can style elements like user avatars, status indicators, and list backgrounds to align with their design guidelines. +#### Users + +The `CometChatUsers` component renders a list of users for selection or navigation. -```html +What you're changing: user list avatar and separator styling. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatUsers` + +- **Default behavior**: UI Kit default avatar and list styling. + +- **Override**: set `cometchatUsersStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + -``` -```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_users.xml). +- **What this does**: applies avatar and separator color overrides to the user list. + +- **Verify**: the Users list shows updated avatar backgrounds and separator color. -### Groups +Attribute references: +- [Users attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_users.xml) +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) -The `CometChatGroups` Component allows you to display and interact with chat groups. Each group item highlights key details like the group name, participant count, and last active time. Customization options include avatar styles, fonts, borders, and background colors, ensuring the component blends seamlessly with your app. +#### Groups + +The `CometChatGroups` component renders group items and their summary data. -```html +What you're changing: group list avatar and typography colors. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatGroups` + +- **Default behavior**: UI Kit default group item styling. + +- **Override**: set `cometchatGroupsStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + -``` -```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_groups.xml). +- **What this does**: styles group avatars and separators in the Groups list. + +- **Verify**: the Groups list shows the updated avatar background and title color. -### Message Header +Attribute references: +- [Groups attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_groups.xml) +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) -The `CometChatMessageHeader` Component provides essential information about the active chat, such as the recipient's name, avatar, and status (online/offline). It often includes options like back navigation, search, or menu buttons. Customization options allow you to style the header background, text appearance, and icons to match your app's overall design. +#### Message Header + +The `CometChatMessageHeader` component renders the title, avatar, and action icons for a chat. -```html +What you're changing: title text color, avatar styling, and call button icons. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatMessageHeader` + +- **Default behavior**: UI Kit default header typography and icons. + +- **Override**: set `cometchatMessageHeaderStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + -``` -```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_header.xml). +- **What this does**: applies custom title color, avatar styling, and call button tints in the message header. -### Message List +- **Verify**: open a conversation and check the header text and call button icons. -The `CometChatMessageList` Component displays the sequence of messages in a conversation, supporting text, media, reactions, and more. It includes smooth scrolling, timestamps, and grouping for better readability. Developers can customize bubble colors, text appearance, timestamps, and alignment to provide a tailored chat experience. +Attribute references: +- [Message Header attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_header.xml) +- [Call Buttons attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_call_buttons.xml) + +#### Message List + +The `CometChatMessageList` component renders conversation messages and their bubble styles. -```xml themes.xml +What you're changing: message list background and outgoing bubble styling. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatMessageList` + +- **Default behavior**: UI Kit default message list background and bubble colors. + +- **Override**: set `cometchatMessageListStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + @@ -166,28 +299,41 @@ The `CometChatMessageList` Component displays the sequence of messages in a conv #FEEDE1 @style/CustomOutgoingMessageBubbleStyle -``` -```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_list.xml). +- **What this does**: changes the message list background and outgoing bubble color. + +- **Verify**: open a conversation and check outgoing message bubble colors. -### Message Composer +Attribute references: +- [Message List attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_list.xml) +- [Message Bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_bubble.xml) -The `CometChatMessageComposer` Component enables users to compose and send messages, including text, attachments, and stickers. This highly interactive component supports customization of input box styles, button appearances, and interaction feedback, ensuring it blends seamlessly with your app’s chat UI. +#### Message Composer + +The `CometChatMessageComposer` component renders the input box and action buttons. -```xml drawable/active_send_button +What you're changing: send button icon and composer icon tints. + +- **Where to change it**: `res/drawable/active_send_button.xml` and `res/values/themes.xml` + +- **Applies to**: `CometChatMessageComposer` + +- **Default behavior**: UI Kit default composer icons and send button drawable. + +- **Override**: set `cometchatMessageComposerStyle` in `AppTheme` and reference a custom drawable. + +- **Code**: +```xml res/drawable/active_send_button.xml lines ``` -```xml themes.xml +- **What this does**: defines a custom circular send button drawable. +- **Code**: +```xml res/values/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_composer.xml). +- **What this does**: applies custom icon tints and the active send button drawable to the composer. + +- **Verify**: the composer shows the custom send button and tinted icons. + +Attribute references: +- [Message Composer attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_composer.xml) -### Group Members +#### Group Members -The `CometChatGroupMembers` Component lists participants in a chat group with details like names, avatars, and roles (e.g., admin or member). It supports customizable styles for list items, fonts, and background colors, ensuring it integrates with your app's group management interface. +The `CometChatGroupMembers` component lists users inside a group. -```html - - @@ -251,33 +410,47 @@ The `CometChatGroupMembers` Component lists participants in a chat group with de #F76808 #F76808 -``` -```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_group_members.xml). +- **What this does**: applies custom avatar and separator styling to the group members list. + +- **Verify**: the group members screen shows updated avatar and separator colors. + +Attribute references: +- [Group Members attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_group_members.xml) +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) -### Thread Header +#### Thread Header -The `CometChatThreadHeader` is used in threaded message views, displaying information about the parent message and its context. It provides a seamless way to navigate between the thread and the main conversation while maintaining context. +The `CometChatThreadHeader` component renders the parent message preview in threaded views. -```xml theme.xml +What you're changing: thread header bubble colors and reply count styling. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatThreadHeader` + +- **Default behavior**: UI Kit default thread header styling. + +- **Override**: set `cometchatThreadHeaderStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + @@ -289,127 +462,418 @@ The `CometChatThreadHeader` is used in threaded message views, displaying inform #F76808 #FEEDE1 -``` -```xml themes.xml + +``` + +- **What this does**: customizes thread header bubble colors and reply count styling. + +- **Verify**: open a thread and confirm the header background and reply count colors. + +Attribute references: +- [Thread Header attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_thread_header.xml) +- [Message Bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_bubble.xml) + +#### Search + +The `CometChatSearch` component provides cross-conversation and message search UI. + + + + + +What you're changing: search background and typography styles. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatSearch` + +- **Default behavior**: UI Kit default search colors and text appearance. + +- **Override**: set `cometchatSearchStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + + + +``` + +- **What this does**: applies custom search colors and text styles across search UI sections. + +- **Verify**: open Search and check section headers, chips, and list items. + +Attribute references: +- [Search attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_search.xml) + +#### Message Information + +The `CometChatMessageInformation` component displays message metadata such as delivery and read status. + + + + + +What you're changing: message information styling for metadata views. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatMessageInformation` + +- **Default behavior**: UI Kit default metadata styling. + +- **Override**: set `cometchatMessageInformationStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + +``` + +- **What this does**: wires a custom Message Information style so you can override specific metadata attributes. + +- **Verify**: open Message Information and confirm your overrides apply. + +Attribute references: +- [Message Information attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_information.xml) + +#### Message Option Sheet + +The `CometChatMessageOptionSheet` component is the action menu for message-level actions. + + + + + +What you're changing: option sheet background and icon tint. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatMessageOptionSheet` + +- **Default behavior**: UI Kit default option sheet styling. + +- **Override**: set `cometchatPopupMenuStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + +``` + +- **What this does**: updates message option sheet icon tint and background color. + +- **Verify**: long-press a message and confirm the option sheet styling. + +Attribute references: +- [Message Option Sheet attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_option_sheet.xml) + +#### Attachment Option Sheet + +The `CometChatAttachmentOptionSheet` component renders the attachment picker. + + + + + +What you're changing: attachment option sheet background and icon tint. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatAttachmentOptionSheet` + +- **Default behavior**: UI Kit default attachment sheet styling. + +- **Override**: set `cometchatAttachmentOptionSheetStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + +``` + +- **What this does**: applies custom colors to the attachment picker sheet. + +- **Verify**: open the attachment menu and confirm background and icons. + +Attribute references: +- [Attachment Option Sheet attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_attachment_option_sheet.xml) + +#### Mentions + +The `CometChatMentions` styling controls how user mentions appear inside messages. + + + + + +What you're changing: mention text and background styles for incoming and outgoing bubbles. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatMentions` + +- **Default behavior**: UI Kit default mention styling. + +- **Override**: set `cometchatMessageBubbleMentionsStyle` in both incoming and outgoing bubble styles. + +- **Code**: +```xml res/values/themes.xml lines + + + + + + + + + + + ``` -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). +- **What this does**: customizes mention colors for incoming and outgoing message bubbles. + +- **Verify**: send a mention in a chat and check the mention highlight colors. -### Call Logs +Attribute references: +- [Mentions attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_mentions.xml) +- [Message Bubble attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_bubble.xml) -The `CometChatCallLogs` Component provides a list of recent calls (voice or video), showing details like call type, duration, participants, and timestamps. Developers can style text, icons, and background elements, making it easy to match the app’s design system. +### Calling UI + +#### Call Logs + +The `CometChatCallLogs` component renders recent call history. -```xml themes.xml +What you're changing: call log list separators and title colors. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatCallLogs` + +- **Default behavior**: UI Kit default call log styling. + +- **Override**: set `cometchatCallLogsStyle` in `AppTheme`. + +- **Code**: +```xml res/values/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_call_logs.xml). +- **What this does**: applies custom avatar and text colors to the call logs list. + +- **Verify**: open Call Logs and confirm the separator and title colors. -### Incoming Call +Attribute references: +- [Call Logs attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_call_logs.xml) -The `CometChatIncomingCall` component displays a notification for an incoming call. It typically includes caller details like name, avatar, and call type (audio/video), along with buttons to accept or decline the call. +#### Incoming Call + +The `CometChatIncomingCall` component renders the incoming call UI. -```xml themes.xml - +What you're changing: incoming call background, buttons, and avatar styling. - -``` +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatIncomingCall` + +- **Default behavior**: UI Kit default incoming call layout and colors. + +- **Override**: set `cometchatIncomingCallStyle` in `AppTheme`. + +- **Code**: +```xml res/values/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_incoming_call.xml). +- **What this does**: customizes the incoming call screen background and action buttons. + +- **Verify**: trigger an incoming call and confirm the background and button colors. + +Attribute references: +- [Incoming Call attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_incoming_call.xml) +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) -### Outgoing Call +#### Outgoing Call -The `CometChatOutgoingCall` component displays a status view for calls initiated by the user, showing the recipient's details, call type, and call status (e.g., ringing or connecting). +The `CometChatOutgoingCall` component renders the outgoing call UI. -```xml themes.xml +What you're changing: outgoing call avatar styling. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatOutgoingCall` + +- **Default behavior**: UI Kit default outgoing call styling. + +- **Override**: set `cometchatOutgoingCallStyle` in `AppTheme`. +- **Code**: +```xml res/values/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_outgoing_call.xml). +- **What this does**: applies a custom avatar style to the outgoing call screen. + +- **Verify**: place a call and confirm the avatar styling. -### Call Button +Attribute references: +- [Outgoing Call attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_outgoing_call.xml) +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) -The `CometChatCallButton` Component initiates voice or video calls with a single click. It supports various customization options for button color and icon styles, making it adaptable to different screen layouts and themes. These components further enhance the versatility of CometChat UIKit, ensuring that all aspects of messaging and calling functionality are cohesive, user-friendly, and fully customizable. +#### Call Buttons + +The `CometChatCallButton` component renders voice and video call buttons. -```xml themes.xml +What you're changing: button background, stroke, and icon tint. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatCallButtons` + +- **Default behavior**: UI Kit default call button styling. + +- **Override**: set `cometchatCallButtonsStyle` in `AppTheme`. + +- **Code**: +```xml res/values/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_call_buttons.xml). +- **What this does**: customizes call button padding, background, and icon colors. + +- **Verify**: open a chat header and confirm button styling. + +Attribute references: +- [Call Buttons attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_call_buttons.xml) + +### AI UI -### AI Assistant Chat History +#### AI Assistant Chat History -The `CometChatAIAssistantChatHistory` component displays the history of interactions with an AI assistant. It provides a seamless way to view past conversations, ensuring users can easily reference previous AI responses. +The `CometChatAIAssistantChatHistory` component renders the AI conversation history view. -```xml themes.xml +What you're changing: background, header, and list typography. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatAIAssistantChatHistory` + +- **Default behavior**: UI Kit default AI history styling. + +- **Override**: set `cometChatAIAssistantChatHistoryStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + - + ``` -```xml themes.xml - +- **What this does**: applies custom colors and font styling to the AI Assistant history screen. + +- **Verify**: open AI Assistant history and confirm background and header styling. + +Attribute references: +- [AI Assistant Chat History attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_ai_assistant_chat_history.xml) + +#### AI Option Sheet + +The `CometChatAIOptionSheet` component renders AI action options. + + + + + +What you're changing: AI option sheet background and icon tint. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatAIOptionSheet` + +- **Default behavior**: UI Kit default AI option sheet styling. + +- **Override**: set `cometchatAIOptionSheetStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + ``` -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). +- **What this does**: customizes AI option sheet colors. -### Search +- **Verify**: open AI actions and confirm the option sheet styling. -The `CometChatSearch` component allows users to search through conversations and messages. It provides a user-friendly interface for finding specific content quickly, with customizable styles for various elements such as background colors, text appearances, and section headers. +Attribute references: +- [AI Option Sheet attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_ai_option_sheet.xml) + +#### Conversation Starter + +The `CometChatConversationStarter` component renders AI-powered conversation starters. - + -```xml themes.xml - - @style/textStyleTimesNewRoman + + +``` - + + + ``` -```xml themes.xml - +- **What this does**: applies a custom background color to conversation summary cards. + +- **Verify**: open a chat summary and confirm the background color. + +Attribute references: +- [AI Conversation Summary attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_ai_conversation_summary.xml) + +#### Smart Replies + +The `CometChatSmartReplies` component renders AI-generated reply suggestions. + + + + + +What you're changing: smart reply background, item color, and stroke. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatSmartReplies` + +- **Default behavior**: UI Kit default smart replies styling. + +- **Override**: set `cometchatAISmartRepliesStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + ``` -*** +- **What this does**: customizes smart reply container and chip styling. + +- **Verify**: open a conversation with smart replies enabled and confirm chip styling. -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). +Attribute references: +- [AI Smart Replies attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_ai_smart_replies.xml) -## Base Component +### Base components -### Avatar +#### Avatar -The `CometChatAvatar` Component is used across the UIKit to represent users, groups, or placeholders visually. This highly reusable component supports various shapes (circle or square), sizes, borders, and fallback icons, allowing complete design consistency for profile or group images. +The `CometChatAvatar` component is used across lists and headers. -```xml themes.xml - -``` +What you're changing: avatar shape and background color. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatAvatar` + +- **Default behavior**: UI Kit default avatar styling. + +- **Override**: set `cometchatAvatarStyle` in `AppTheme`. + +- **Code**: +```xml res/values/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_avatar.xml). +- **What this does**: applies a consistent avatar style across UI Kit components. + +- **Verify**: open any list with avatars and confirm the style. + +Attribute references: +- [Avatar attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_avatar.xml) -### Status indicator +#### Status Indicator -The `CometChatStatusIndicator` visually represents user presence (online, offline, or custom states). It can be styled for different shapes, sizes, and colors to reflect your app’s visual preferences while maintaining clarity in conveying status information. +The `CometChatStatusIndicator` component shows user presence status. -```xml drawable/online_indicator_drawable +What you're changing: status indicator icon shape and drawable. + +- **Where to change it**: `res/drawable/online_indicator_drawable.xml` and `res/values/themes.xml` + +- **Applies to**: `CometChatStatusIndicator` + +- **Default behavior**: UI Kit default presence icon. + +- **Override**: set `cometchatStatusIndicatorStyle` in `AppTheme` and reference a custom drawable. + +- **Code**: +```xml res/drawable/online_indicator_drawable.xml lines + android:strokeColor="#ffffff" /> ``` -```xml themes.xml - -``` +- **What this does**: defines a custom online indicator drawable. + +- **Code**: +```xml res/values/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_status_indicator.xml). +- **What this does**: applies the custom status indicator drawable in UI Kit components. + +- **Verify**: check any user list to confirm the presence icon. + +Attribute references: +- [Status Indicator attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_status_indicator.xml) -### Badge +#### Badge -The `CometChatBadge` Component displays notifications or counts, such as unread messages. It can be styled for background colors, border radius, text size, and colors, allowing you to create visually distinct indicators for different notifications. +The `CometChatBadge` component shows unread or notification counts. -```xml themes.xml - -``` +What you're changing: badge background, text color, and corner radius. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatBadge` + +- **Default behavior**: UI Kit default badge styling. -```xml themes.xml - +- **Override**: set `cometchatBadgeStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + ``` -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_badge.xml). +- **What this does**: applies a custom badge appearance across UI Kit lists. + +- **Verify**: check any unread badge to confirm colors and radius. + +Attribute references: +- [Badge attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_badge.xml) -### Date +#### Date -The `CometChatDate` Component formats and displays timestamps in conversation lists and message threads. It ensures time-related information is clear and consistent. Developers can customize its text appearance, alignment, and colors to fit various contexts. +The `CometChatDate` component formats timestamps in lists and message threads. -```xml themes.xml - -``` +What you're changing: date text color. + +- **Where to change it**: `res/values/themes.xml` + +- **Applies to**: `CometChatDate` + +- **Default behavior**: UI Kit default date styling. -```xml themes.xml - +- **Override**: set `cometchatDateStyle` in `AppTheme`. + +- **Code**: +```xml res/values/themes.xml lines + + + + + ``` -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_date.xml). +- **What this does**: customizes date text color in UI Kit lists and headers. + +- **Verify**: check any timestamp and confirm the color. -### Receipts +Attribute references: +- [Date attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_date.xml) -The `CometChatReceipts` Component indicates message delivery and read statuses using intuitive icons. These can be styled for icon size, tint, and alignment, ensuring they remain clear and consistent with your app’s UI. +#### Receipts + +The `CometChatReceipts` component renders read and delivered status icons. -```xml drawable/read_receipts +What you're changing: read receipt icon drawable. + +- **Where to change it**: `res/drawable/read_receipts.xml` and `res/values/themes.xml` + +- **Applies to**: `CometChatReceipts` + +- **Default behavior**: UI Kit default receipt icons. + +- **Override**: set `cometchatMessageReceiptStyle` in `AppTheme` and reference a custom drawable. + +- **Code**: +```xml res/drawable/read_receipts.xml lines ``` -```xml themes.xml - -``` - -```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_receipt.xml). - -### Media Recorder - -The `CometChatMediaRecorder` Component facilitates the recording of audio and video messages. It supports full customization of its recording controls, including button sizes, shapes, and colors, making it an integral part of your media-rich chat experience. - - - - +- **What this does**: defines a custom read receipt icon. -```xml themes.xml -] -``` +- **Code**: +```xml res/values/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_media_recorder.xml). - -### Sticker Keyboard - -The `CometChatStickerKeyboard` simplifies the integration of sticker-based messaging. Customize the background, grid layout, and sticker display styles to align with your chat experience. This component provides a visually rich and interactive way to enhance conversations. +- **What this does**: applies the custom receipt icon to message status indicators. - - - - -```xml themes.xml - -``` - -```xml themes.xml - -``` +- **Verify**: send a message and check the receipt icon for read status. -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_keyboard.xml). +Attribute references: +- [Message Receipt attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_message_receipt.xml) -### Reaction list +#### Media Recorder -The `CometChatReactionList` Component provides a visual representation of emoji reactions on messages. It supports customization for reaction sizes, spacing, and colors, enabling you to build an engaging and personalized messaging environment. +The `CometChatMediaRecorder` component controls audio and video message recording. - + -```xml themes.xml - -``` +What you're changing: recorder icon sizes and recording button background color. -```xml themes.xml - -``` +- **Where to change it**: `res/values/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_reaction_list.xml). +- **Applies to**: `CometChatMediaRecorder` -### Conversation Starter +- **Default behavior**: UI Kit default media recorder styling. -The `CometChatConversationStarter` Component offers AI-based suggestions or reply options to initiate a chat. Developers can customize the background, text styles, and button appearances to ensure seamless integration with the app’s visual language. +- **Override**: set `cometchatMediaRecorderStyle` in `AppTheme`. - - - +- **Code**: +```xml res/values/themes.xml lines + + -```xml themes.xml - + + ``` -```xml themes.xml - -``` +- **What this does**: applies custom sizing and color to the media recorder UI. -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_conversation_starter.xml). +- **Verify**: open the recorder and check icon sizes and record button color. -### Conversation Summary +Attribute references: +- [Media Recorder attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_media_recorder.xml) -The `CometChatConversationSummary` Component highlights the essence of a conversation, including participant details, last message, and timestamp. Customize text sizes, colors, and spacing to create visually distinct summaries that improve readability and engagement. +#### Sticker Keyboard + +The `CometChatStickerKeyboard` component renders the sticker picker UI. - + -```xml themes.xml - -``` - -```xml themes.xml - -``` +What you're changing: sticker keyboard background color. -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_conversation_summary.xml). +- **Where to change it**: `res/values/themes.xml` -### Smart Replies +- **Applies to**: `CometChatStickerKeyboard` -The `CometChatSmartReplies` Component provides AI-driven suggestions for quick message replies. Fully customizable for button styles, padding, and colors, this component enables a streamlined and modern chat experience for users. +- **Default behavior**: UI Kit default sticker keyboard styling. - - - +- **Override**: set `cometchatStickerKeyboardStyle` in `AppTheme`. -```xml themes.xml - -``` +- **Code**: +```xml res/values/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_ai_smart_replies.xml). - -### Message Information +- **What this does**: applies a custom background color to the sticker keyboard. -The `CometChatMessageInformation` Component displays metadata for messages, such as delivery timestamps, sender details, and read receipts. Customization options include text styles, colors, and alignment, making it adaptable to various app layouts. +- **Verify**: open the sticker keyboard and confirm the background color. - - - - -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_information.xml). +Attribute references: +- [Sticker Keyboard attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_sticker_keyboard.xml) -### Message option sheet +#### Reaction List -The `CometChatMessageOptionSheet` Component is a context menu for performing actions on messages, such as replying, forwarding, or deleting. Developers can style its background, icons, and text to match the app’s menu system. +The `CometChatReactionList` component renders reactions on messages. - + -```xml themes.xml - -``` +What you're changing: active tab color in the reaction list. -```xml themes.xml - -``` +- **Where to change it**: `res/values/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_option_sheet.xml). +- **Applies to**: `CometChatReactionList` -### Attachment option sheet +- **Default behavior**: UI Kit default reaction list styling. -The `CometChatAttachmentOptionSheet` Component provides a sleek interface for users to attach media, documents, or other files. It supports icon and text customizations to create a cohesive attachment experience. +- **Override**: set `cometchatReactionListStyle` in `AppTheme`. - - - +- **Code**: +```xml res/values/themes.xml lines + + -```xml themes.xml - + + ``` -```xml themes.xml - -``` +- **What this does**: applies a custom active tab color in the reaction list. -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_attachment_option_sheet.xml). +- **Verify**: open reactions and confirm the active tab color. -### AIOption Sheet +Attribute references: +- [Reaction List attributes](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_reaction_list.xml) -The `CometChatAIOptionSheet` Component offers AI-powered action options, like generating replies or initiating voice-to-text commands. It allows developers to style icons, colors, and interaction elements for a polished and user-friendly interface. +## Customization matrix - - - +| What you want to change | Where | Property or API | Example | +| --- | --- | --- | --- | +| Conversations avatar and badge | `res/values/themes.xml` | `cometchatConversationsStyle` | `cometchatConversationsBadgeStyle` | +| Users list separators | `res/values/themes.xml` | `cometchatUsersStyle` | `cometchatUsersSeparatorColor` | +| Group list titles | `res/values/themes.xml` | `cometchatGroupsStyle` | `cometchatGroupsTitleTextColor` | +| Header call icons | `res/values/themes.xml` | `cometchatMessageHeaderStyle` | `cometchatMessageHeaderCallButtonsStyle` | +| Message list background | `res/values/themes.xml` | `cometchatMessageListStyle` | `cometchatMessageListBackgroundColor` | +| Composer send button | `res/drawable/active_send_button.xml` | `cometchatMessageComposerActiveSendButtonDrawable` | `@drawable/active_send_button` | +| Search UI typography | `res/values/themes.xml` | `cometchatSearchStyle` | `cometchatSearchBarTextAppearance` | +| Call buttons styling | `res/values/themes.xml` | `cometchatCallButtonsStyle` | `cometchatCallButtonsVideoCallBackgroundColor` | +| AI smart replies chip style | `res/values/themes.xml` | `cometchatAISmartRepliesStyle` | `cometchatAISmartRepliesItemStrokeColor` | +| Mentions highlight colors | `res/values/themes.xml` | `cometchatMessageBubbleMentionsStyle` | `cometchatMentionTextColor` | -```xml themes.xml - -``` +## Common pitfalls and fixes -```xml themes.xml - -``` +- Issue: styles do not apply. Fix: confirm your activity theme is `AppTheme` and extends `CometChatTheme.DayNight`. +- Issue: only some screens update. Fix: the screen might use a different theme; verify the theme in your activity or fragment. +- Issue: drawable changes not visible. Fix: rebuild the app after adding a new drawable file. +- Issue: changes apply in light mode but not dark mode. Fix: update both `values/themes.xml` and `values-night/themes.xml` if you use night resources. +- Issue: attribute name not recognized. Fix: confirm the exact attribute name in the linked attribute reference file. +- Issue: style overridden unexpectedly. Fix: check for duplicate style names in other modules or flavors. +- Issue: colors look wrong on some devices. Fix: verify color hex values include alpha when needed. +- Issue: list items still show default fonts. Fix: set UI Kit fonts in `AppTheme` once as shown in Core concepts. -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_option_sheet.xml). +## FAQ -### Mentions +**Q**: Do I need to repeat font settings in every component style? +**A**: No. Set fonts once in `AppTheme` using `cometchatFontBold`, `cometchatFontMedium`, and `cometchatFontRegular`. -The `CometChatMentions` Component highlights referenced users or groups within messages. With customizable styles for text color and background, you can ensure mentions stand out clearly in chats while maintaining a cohesive visual theme. +**Q**: Where do I find all available attributes for a component? +**A**: Use the Attribute references links under each component section. - - - +**Q**: Why do my changes not appear in a specific screen? +**A**: Confirm the screen is using the same `AppTheme` and not overriding the theme locally. + +**Q**: Can I change icons without changing the component layout? +**A**: Yes. Provide a custom vector in `res/drawable/` and reference it from the component style. -```xml themes.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_mentions.xml). +**Q**: Do I need to enable anything in the CometChat Dashboard for styling? +**A**: No. Styling is local to your Android project and does not require dashboard changes. diff --git a/ui-kit/android/components-overview.mdx b/ui-kit/android/components-overview.mdx index 5b41f2aa8..b7fc106b4 100644 --- a/ui-kit/android/components-overview.mdx +++ b/ui-kit/android/components-overview.mdx @@ -1,43 +1,112 @@ --- title: "Overview" --- - -CometChat's **UI Kit** is a set of pre-built UI components that allows you to easily craft an in-app chat with all the essential messaging features. - -## Type of Components - -UI components based on the behaviour and functionality can be categorized into three types: Base Components and Components - -### Base Components - -Base Components form the building blocks of your app's user interface (UI). They focus solely on presenting visual elements based on input data, without handling any business logic. These components provide the foundational appearance and behavior for your UI. - -### Components - -Components build upon Base Components by incorporating business logic. They not only render UI elements but also manage data loading, execute specific actions, and respond to events. This combination of visual presentation and functional capabilities makes Components essential for creating dynamic and interactive UIs. - -## Actions - -Actions direct the operational behavior of a component. They are split into two categories: Predefined Actions and User-Defined Actions. - -### Predefined Actions - -These are actions that are inherently programmed into a UI component. They are ingrained in thecomponent itself by default, and they execute automatically in response to user interaction,without needing any additional user input. - -### User-Defined Actions - -These are actions that must be explicitly specified by the user. They are not innately part ofthe component like predefined actions. Instead, they must be developed based on the unique needsof the user or the application. User-defined actions provide adaptability and allow for thecreation of custom behaviors that align with the individual needs of the application. - -To customize the behavior of a component, actions must be overridden by the user. This provides the user with control over how the component responds to specific events or interactions. - -Both Components and Composite Components expose actions to the user, which means that users can interact with these types of components through predefined or user-defined actions. On the otherhand, Base Components do not expose actions to the user as they are the foundational buildingblocks mainly responsible for rendering the user interface and do not carry any business logic oractions. - -## Events - -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. - -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. - -## Configurations - -Configurations offer the ability to customize the properties of each individual component within a Composite Component. If a Composite Component includes multiple components, each of these components will have its own set of properties that can be configured. This means multiple sets of configurations are available, one for each constituent component. This allows for fine-tuned customization of the Composite Component, enabling you to tailor its behavior and appearance to match specific requirements in a granular manner. + +Understand the CometChat UI Kit component model so you can choose the right building blocks for your chat experience. + +## When to use this +- You need to decide between Base Components and Components. +- You want to understand how actions and events affect component behavior. +- You want to know how configurations apply within composite UI flows. +- You are planning a UI Kit implementation and need the conceptual model first. + +## Prerequisites +- No additional setup is required for this conceptual overview. + +## Quick start +1. Read the definitions of Base Components and Components. +2. Decide which component type fits your screen requirements. +3. Review Actions to understand built-in vs custom behavior. +4. Review Events to understand how components communicate. +5. Review Configurations to understand per-component customization in composite UIs. + +## Core concepts +- **Base Components**: Visual building blocks that render UI without business logic. +- **Components**: UI elements that include business logic such as data loading and user actions. +- **Actions**: Behavior hooks that drive how a component responds to events. +- **Events**: Emitted signals that allow other parts of the app to react. +- **Configurations**: Per-component settings within composite screens. + +## Implementation + +### Choose between Base Components and Components +What you're changing: The type of UI Kit building block you use for a screen. + +- **Where to change it**: Your screen design and component selection (no file change on this page). +- **Applies to**: Any UI Kit screen or flow you build. +- **Default behavior**: Base Components render UI only; Components include business logic and data handling. +- **Override**: Select the component type that matches your functional needs. +- **Code**: Not applicable for this overview. +- **Verify**: You can describe why a screen uses Base Components or Components. + +### Decide on action handling +What you're changing: How a component responds to user interaction. + +- **Where to change it**: Component action configuration in your implementation (not specified on this page). +- **Applies to**: Components and composite screens that expose actions. +- **Default behavior**: Predefined actions execute automatically in the component. +- **Override**: Implement user-defined actions when you need custom behavior. +- **Code**: Not applicable for this overview. +- **Verify**: You can identify which actions are predefined vs user-defined for your screen. + +### Use events for decoupled behavior +What you're changing: How UI Kit components communicate with the rest of your app. + +- **Where to change it**: Event handling in your implementation (not specified on this page). +- **Applies to**: Components and composite components that emit events. +- **Default behavior**: Events are emitted when user interaction or state changes occur. +- **Override**: If your app needs to respond to a component event, subscribe to that event and handle it in your listener. +- **Code**: Not applicable for this overview. +- **Verify**: You can map an event to the UI change it should trigger. + +### Plan component configurations in composite screens +What you're changing: Per-component configuration inside composite screens. + +- **Where to change it**: Component configuration in your composite screen setup (not specified on this page). +- **Applies to**: Composite screens that embed multiple UI Kit components. +- **Default behavior**: Each embedded component has its own configurable properties. +- **Override**: Adjust configurations to tailor each component's behavior and appearance. +- **Code**: Not applicable for this overview. +- **Verify**: You can list the components in a composite screen and the config each one needs. + +## Component quick reference + +| Component | Purpose | Documentation | +| --- | --- | --- | +| [Conversations](/ui-kit/android/conversations) | Renders the conversation list with real-time updates | [Conversations](/ui-kit/android/conversations) | +| [Users](/ui-kit/android/users) | Displays a searchable list of users | [Users](/ui-kit/android/users) | +| [Groups](/ui-kit/android/groups) | Displays a searchable list of groups | [Groups](/ui-kit/android/groups) | +| [Group Members](/ui-kit/android/group-members) | Lists members of a group with moderation actions | [Group Members](/ui-kit/android/group-members) | +| [Message Header](/ui-kit/android/message-header) | Shows user/group info, typing indicators, and call buttons | [Message Header](/ui-kit/android/message-header) | +| [Message List](/ui-kit/android/message-list) | Renders messages with bubbles, reactions, and receipts | [Message List](/ui-kit/android/message-list) | +| [Message Composer](/ui-kit/android/message-composer) | Input field for sending text, media, and attachments | [Message Composer](/ui-kit/android/message-composer) | +| [Threaded Messages Header](/ui-kit/android/threaded-messages-header) | Displays parent message and reply count in threads | [Threaded Messages Header](/ui-kit/android/threaded-messages-header) | +| [Incoming Call](/ui-kit/android/incoming-call) | Full-screen UI for receiving calls | [Incoming Call](/ui-kit/android/incoming-call) | +| [Outgoing Call](/ui-kit/android/outgoing-call) | Full-screen UI for initiating calls | [Outgoing Call](/ui-kit/android/outgoing-call) | +| [Call Buttons](/ui-kit/android/call-buttons) | Voice and video call buttons | [Call Buttons](/ui-kit/android/call-buttons) | +| [Call Logs](/ui-kit/android/call-logs) | Displays call history | [Call Logs](/ui-kit/android/call-logs) | +| [AI Assistant Chat History](/ui-kit/android/ai-assistant-chat-history) | Shows past AI assistant conversations | [AI Assistant Chat History](/ui-kit/android/ai-assistant-chat-history) | +| [Search](/ui-kit/android/search) | Real-time search across conversations and messages | [Search](/ui-kit/android/search) | + +## Common pitfalls & fixes +- Confusing Base Components with Components: Base Components render UI only; Components include business logic. +- Expecting Base Components to emit actions: Only Components and composite components expose actions. +- Ignoring events: Events are how components notify the rest of your app about state changes. +- Overlooking per-component configs in composites: Each embedded component has its own configuration. +- Treating configurations as global: Configurations are scoped to the component they belong to. + +## FAQ +**Q**: Are Base Components enough for a full chat experience? +**A**: No. Base Components are visual building blocks; Components add business logic and data handling. + +**Q**: Do all components expose actions? +**A**: Components and composite components do. Base Components do not. + +**Q**: How do components communicate with the rest of my app? +**A**: They emit events that other parts of the app can listen to and respond to. + +## Next steps +- [Conversations](/ui-kit/android/conversations) +- [Message list](/ui-kit/android/message-list) +- [Message composer](/ui-kit/android/message-composer) +- [Component styling](/ui-kit/android/component-styling) diff --git a/ui-kit/android/conversations.mdx b/ui-kit/android/conversations.mdx index ddf400633..5573d5c60 100644 --- a/ui-kit/android/conversations.mdx +++ b/ui-kit/android/conversations.mdx @@ -2,926 +2,687 @@ title: "Conversations" --- -## Overview +`CometChatConversations` displays all conversations for the currently logged-in user, showing recent messages, user or group details, and unread counts. + +## AI Agent Component Spec + + + +```json +{ + "component": "CometChatConversations", + "package": "com.cometchat.chatuikit.conversations", + "xmlElement": "", + "description": "Scrollable list of recent one-on-one and group conversations for the logged-in user.", + "primaryOutput": { + "method": "setOnItemClick", + "type": "OnItemClick" + }, + "methods": { + "data": { + "setConversationsRequestBuilder": { + "type": "ConversationsRequest.ConversationsRequestBuilder", + "default": "SDK default (30 per page)", + "note": "Pass the builder, not the result of .build()" + }, + "setDateTimeFormatter": { + "type": "DateTimeFormatterCallback", + "default": "Component default (hh:mm a today, Yesterday, dd MMM yyyy)" + }, + "setDateFormat": { + "type": "SimpleDateFormat", + "default": "Component default" + } + }, + "callbacks": { + "setOnItemClick": "OnItemClick", + "setOnItemLongClick": "OnItemLongClick", + "setOnBackPressListener": "OnBackPress", + "setOnSelect": "OnSelection", + "setOnError": "OnError", + "setOnLoad": "OnLoad", + "setOnEmpty": "OnEmpty", + "setOnSearchClickListener": "OnSearchClick" + }, + "visibility": { + "setBackIconVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.GONE" }, + "setToolbarVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setLoadingStateVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setDeleteConversationOptionVisibility": { "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" }, + "setGroupTypeVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setReceiptsVisibility": { "type": "int", "default": "View.VISIBLE" }, + "setSearchBoxVisibility": { "type": "int", "default": "View.VISIBLE" } + }, + "sound": { + "disableSoundForMessages": { "type": "boolean", "default": false }, + "setCustomSoundForMessages": { "type": "@RawRes int", "default": "built-in" } + }, + "selection": { + "setSelectionMode": { + "type": "UIKitConstants.SelectionMode", + "values": ["NONE", "SINGLE", "MULTIPLE"], + "default": "NONE" + } + }, + "viewSlots": { + "setItemView": "ConversationsViewHolderListener — entire list item row", + "setLeadingView": "ConversationsViewHolderListener — avatar / left section", + "setTitleView": "ConversationsViewHolderListener — name / title text", + "setSubtitleView": "ConversationsViewHolderListener — last message preview", + "setTrailingView": "ConversationsViewHolderListener — timestamp / badge / 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)" + }, + "formatting": { + "setTextFormatters": { + "type": "List", + "default": "default formatters from data source" + } + }, + "advanced": { + "selectConversation": "Conversation, SelectionMode — programmatic selection", + "clearSelection": "void — clears all selected conversations", + "getSelectedConversations": "List — returns selected items", + "getRecyclerView": "RecyclerView — internal RecyclerView access", + "getViewModel": "ConversationsViewModel — internal ViewModel access", + "getConversationsAdapter": "ConversationsAdapter — internal adapter access", + "setAdapter": "ConversationsAdapter — replace the default adapter", + "getBinding": "CometchatConversationsListViewBinding — root ViewBinding", + "hideReceipts": "boolean — hide/show read receipts at adapter level", + "setMentionAllLabelId": "String id, String label — mention-all label" + }, + "style": { + "setStyle": { + "type": "@StyleRes int", + "parent": "CometChatConversationsStyle" + } + } + }, + "events": [ + { + "name": "CometChatConversationEvents.ccConversationDeleted", + "payload": "Conversation", + "description": "Conversation deleted from list" + } + ], + "sdkListeners": [ + "onTextMessageReceived", + "onMediaMessageReceived", + "onCustomMessageReceived", + "onTypingStarted", + "onTypingEnded", + "onMessagesDelivered", + "onMessagesRead", + "onMessagesDeliveredToAll", + "onMessagesReadByAll", + "onUserOnline", + "onUserOffline", + "onGroupMemberJoined", + "onGroupMemberLeft", + "onGroupMemberKicked", + "onGroupMemberBanned", + "onMemberAddedToGroup" + ], + "compositionExample": { + "description": "Sidebar conversations wired to message view", + "components": [ + "CometChatConversations", + "CometChatMessageHeader", + "CometChatMessageList", + "CometChatMessageComposer" + ], + "flow": "setOnItemClick emits Conversation -> extract User/Group via getConversationWith() -> pass to MessageHeader, MessageList, MessageComposer" + } +} +``` -The Conversations is a [Component](/ui-kit/android/components-overview#components), That shows all conversations related to the currently logged-in user, + - - - +## Where It Fits -## Usage +`CometChatConversations` is a list component. It renders recent conversations and emits the selected `Conversation` via `setOnItemClick`. Wire it to `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to build a standard chat layout. -### Integration + + +```kotlin ChatActivity.kt lines +class ChatActivity : AppCompatActivity() { -There are multiple ways in which you can use Conversations in your app. **Layout File**: To use Conversations in your \`layout\_activity.xml, use the following code snippet. + private lateinit var conversations: CometChatConversations + private lateinit var messageHeader: CometChatMessageHeader + private lateinit var messageList: CometChatMessageList + private lateinit var messageComposer: CometChatMessageComposer -```xml layout_activity.xml - + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_chat) + + conversations = findViewById(R.id.conversations) + messageHeader = findViewById(R.id.message_header) + messageList = findViewById(R.id.message_list) + messageComposer = findViewById(R.id.message_composer) + + conversations.setOnItemClick { view, position, conversation -> + if (conversation.conversationType == CometChatConstants.CONVERSATION_TYPE_USER) { + val user = conversation.conversationWith as User + messageHeader.setUser(user) + messageList.setUser(user) + messageComposer.setUser(user) + } else { + val group = conversation.conversationWith as Group + messageHeader.setGroup(group) + messageList.setGroup(group) + messageComposer.setGroup(group) + } + } + } +} ``` + -2. **Activity**: To use Conversations in your Activity, use the following code snippet. - - -```java YourActivity.java - @Override +```java ChatActivity.java lines +public class ChatActivity extends AppCompatActivity { + + private CometChatConversations conversations; + private CometChatMessageHeader messageHeader; + private CometChatMessageList messageList; + private CometChatMessageComposer messageComposer; + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(new CometChatConversations(this)); + setContentView(R.layout.activity_chat); + + conversations = findViewById(R.id.conversations); + messageHeader = findViewById(R.id.message_header); + messageList = findViewById(R.id.message_list); + messageComposer = findViewById(R.id.message_composer); + + conversations.setOnItemClick((view, position, conversation) -> { + if (CometChatConstants.CONVERSATION_TYPE_USER.equals(conversation.getConversationType())) { + User user = (User) conversation.getConversationWith(); + messageHeader.setUser(user); + messageList.setUser(user); + messageComposer.setUser(user); + } else { + Group group = (Group) conversation.getConversationWith(); + messageHeader.setGroup(group); + messageList.setGroup(group); + messageComposer.setGroup(group); + } + }); } +} ``` + + + +```xml activity_chat.xml lines + + + + + + + + + + + + + + + + +``` + + +> On phones, you'd typically use separate Activities instead of a side-by-side layout — see the [Conversation List + Message View](/ui-kit/android/android-conversation) getting started guide. + +## 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, and the `cometchat-chat-uikit-android` dependency added. +To add programmatically in an Activity: + + -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(CometChatConversations(this)) } ``` - + +```java YourActivity.java lines + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(new CometChatConversations(this)); + } +``` + -3. **Fragment**: To use `Conversations` in your `Fragment`, use the following code snippet. +Or in a Fragment: + +```kotlin YourFragment.kt lines + override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View { + return CometChatConversations(requireContext()) +} +``` + + -```java YourFragment.java +```java YourFragment.java lines @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return new CometChatConversations(getContext()); } ``` - + + +## Filtering Conversations + +Pass a `ConversationsRequest.ConversationsRequestBuilder` to `setConversationsRequestBuilder`. Pass the builder instance — not the result of `.build()`. + -```kotlin YourFragment.kt - override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View { - return CometChatConversations(requireContext()) -} -``` +```kotlin lines +val builder = ConversationsRequest.ConversationsRequestBuilder() + builder.setConversationType(CometChatConstants.CONVERSATION_TYPE_USER) + builder.setLimit(50) +cometChatConversations.setConversationsRequestBuilder(builder) +``` + +```java lines +ConversationsRequest.ConversationsRequestBuilder builder = new ConversationsRequest.ConversationsRequestBuilder(); + builder.setConversationType(CometChatConstants.CONVERSATION_TYPE_USER); + builder.setLimit(50); + +cometChatConversations.setConversationsRequestBuilder(builder); +``` + -### Actions +### Filter Recipes -[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. +| Recipe | Code | +| --- | --- | +| Only user conversations | `builder.setConversationType(CometChatConstants.CONVERSATION_TYPE_USER)` | +| Only group conversations | `builder.setConversationType(CometChatConstants.CONVERSATION_TYPE_GROUP)` | +| Limit to 10 per page | `builder.setLimit(10)` | +| With specific tags | `builder.setTags(Arrays.asList("vip"))` | +| Filter by user tags | `builder.withUserAndGroupTags(true); builder.setUserTags(Arrays.asList("premium"))` | +| Filter by group tags | `builder.withUserAndGroupTags(true); builder.setGroupTags(Arrays.asList("support"))` | -##### setOnItemClick +> Default page size is 30. The component uses infinite scroll — the next page loads as the user scrolls to the bottom. Refer to [ConversationsRequestBuilder](/sdk/android/retrieve-conversations) for the full builder API. -Function invoked when a conversation item is clicked, typically used to open a detailed chat screen. +## Actions and Events - - -```java YourActivity.java -cometchatConversations.setOnItemClick((view1, position, conversation) -> { - - }); -``` +### Callback Methods - +#### `setOnItemClick` + +Fires when a conversation row is tapped. Primary navigation hook — set the active conversation and render the message view. + -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.onItemClick = OnItemClick { view, position, conversation -> } ``` - + +```java YourActivity.java lines +cometchatConversations.setOnItemClick((view1, position, conversation) -> { + + }); +``` + -*** +> **What this does:** Replaces the default item-click behavior. When a user taps a conversation, your custom lambda executes instead of the built-in navigation. -##### setOnItemLongClick +#### `setOnItemLongClick` -Function executed when a conversation item is long-pressed, allowing additional actions like delete or select. +Fires when a conversation row is long-pressed. Use for additional actions like delete or select. - -```java YourActivity.java -cometchatConversations.setOnItemLongClick((view1, position, conversation) -> { - - }); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.onItemLongClick = OnItemLongClick({ view, position, conversation -> }) ``` - + +```java YourActivity.java lines +cometchatConversations.setOnItemLongClick((view1, position, conversation) -> { + + }); +``` + -*** +> **What this does:** Replaces the default long-press behavior. When a user long-presses a conversation, your custom lambda executes. -##### setOnBackPressListener +#### `setOnBackPressListener` -`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. +Fires when the user presses the back button in the app bar. Default: navigates to the previous activity. - -```java YourActivity.java -cometchatConversations.setOnBackPressListener(() -> { - - }); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.onBackPressListener = OnBackPress { } ``` - - - -*** - -##### setOnSearchClickListener - -`setOnSearchClickListener` is triggered when you click the search bar. It has a predefined behavior; when clicked, it opens the search screen. However, you can override this action using the following code snippet. - - -```java YourActivity.java - binding.cometchatConversations.setOnSearchClickListener(() -> { - Log.i(TAG, "onViewCreated: Search Bar Clicked"); - }); -``` - - - - -```kotlin YourActivity.kt - binding.cometchatConversations.setOnSearchClickListener { - Log.i(TAG, "onViewCreated: Search Bar Clicked") - } +```java YourActivity.java lines +cometchatConversations.setOnBackPressListener(() -> { + + }); ``` - - -*** +> **What this does:** Overrides the default back-press navigation. When the user taps the back button, your custom logic runs instead. -##### setOnSelect +#### `setOnSelect` -Called when a item from the fetched list is selected, useful for multi-selection features. +Fires when a conversation is checked/unchecked in multi-select mode. Requires `setSelectionMode` to be set. - -```java YourActivity.java -cometchatConversations.setOnSelect(t -> { - - }); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.setOnSelect(object : OnSelection { override fun onSelection(t: MutableList?) { } }) ``` - - - -*** - -##### OnError - -This action doesn't change the behavior of the component but rather listens for any errors that occur in the Conversations component. - - -```java YourActivity.java -cometchatConversations.setOnError(cometchatException -> { +```java YourActivity.java lines +cometchatConversations.setOnSelect(t -> { }); ``` - + + +> **What this does:** Registers a callback that fires when the user selects one or more conversations. The callback receives the list of selected `Conversation` objects. +#### `setOnError` + +Fires on internal errors (network failure, auth issue, SDK exception). + + -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.setOnError { } ``` - + +```java YourActivity.java lines +cometchatConversations.setOnError(cometchatException -> { + + }); +``` + -*** +> **What this does:** Registers an error listener. If the component encounters an error (e.g., network failure), your callback receives the `CometChatException`. -##### setOnLoad +#### `setOnLoad` -Invoked when the list is successfully fetched and loaded, helping track component readiness. +Fires when the list is successfully fetched and loaded. - -```java YourActivity.java -cometchatConversations.setOnLoad(list -> { - -}); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.setOnLoad(object : OnLoad { override fun onLoad(list: MutableList?) { } }) ``` - + +```java YourActivity.java lines +cometchatConversations.setOnLoad(list -> { + +}); +``` + -*** +> **What this does:** Registers a callback that fires after the conversation list is fetched and rendered. The callback receives the list of loaded `Conversation` objects. -##### setOnEmpty +#### `setOnEmpty` -Called when the list is empty, enabling custom handling such as showing a placeholder message. +Fires when the list is empty, enabling custom handling such as showing a placeholder. - -```java YourActivity.java -cometchatConversations.setOnEmpty(() -> { - - }); -``` - - - -```kotlin YourActivity.kt +```kotlin YourActivity.kt lines cometchatConversations.setOnEmpty{ } ``` - + +```java YourActivity.java lines +cometchatConversations.setOnEmpty(() -> { + + }); +``` + -*** +> **What this does:** Registers a callback that fires when the conversation list has no items. Use this to show a custom empty-state message or trigger other logic. -### Filters +#### `setOnSearchClickListener` -You can set `ConversationsRequestBuilder` in the Conversations Component to filter the conversation list. You can modify the builder as per your specific requirements with multiple options available to know more refer to [ConversationRequestBuilder](/sdk/android/retrieve-conversations). - -You can set filters using the following parameters. - -1. **Conversation Type:** Filters on type of Conversation, `User` or `Groups` -2. **Limit:** Number of conversations fetched in a single request. -3. **WithTags:** Filter on fetching conversations containing tags -4. **Tags:** Filters on specific `Tag` -5. **UserTags:** Filters on specific User `Tag` -6. **GroupTags:** Filters on specific Group `Tag` +Fires when the user taps the search icon in the toolbar. - -```java YourActivity.java -ConversationsRequest.ConversationsRequestBuilder builder = new ConversationsRequest.ConversationsRequestBuilder(); - builder.setConversationType(CometChatConstants.CONVERSATION_TYPE_USER); - builder.setLimit(50); + +```kotlin YourActivity.kt lines +cometchatConversations.setOnSearchClickListener { -cometChatConversations.setConversationsRequestBuilder(builder); + } ``` - - -```kotlin -val builder = ConversationsRequest.ConversationsRequestBuilder() - builder.setConversationType(CometChatConstants.CONVERSATION_TYPE_USER) - builder.setLimit(50) + +```java YourActivity.java lines +cometchatConversations.setOnSearchClickListener(() -> { -cometChatConversations.setConversationsRequestBuilder(builder) + }); ``` - - -*** +> **What this does:** Overrides the default search icon tap behavior. When the user taps the search icon, your custom logic runs instead. -### Events +- **Verify**: After setting an action callback, trigger the corresponding user interaction (tap, long-press, back, select, search) 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 -##### 1. ConversationDeleted +`CometChatConversationEvents` emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed. -This event will be emitted when the user deletes a conversation +| Event | Fires when | Payload | +| --- | --- | --- | +| `ccConversationDeleted` | A conversation is deleted from the list | `Conversation` | - -```ruby Add Listener -CometChatConversationEvents.addListener("YOUR_LISTENER_TAG", new CometChatConversationEvents() { - @Override - public void ccConversationDeleted(Conversation conversation) { - super.ccConversationDeleted(conversation); + +```kotlin Add Listener lines +CometChatConversationEvents.addListener("LISTENER_TAG", object : CometChatConversationEvents() { + override fun ccConversationDeleted(conversation: Conversation) { + super.ccConversationDeleted(conversation) } -}); +}) ``` Remove Listener ``` -CometChatConversationEvents.removeListener("YOUR_LISTENER_TAG"); + CometChatConversationEvents.removeListener("LISTENER_TAG"); ``` - - - - -```ruby Add Listener -CometChatConversationEvents.addListener("LISTENER_TAG", object : CometChatConversationEvents() { - override fun ccConversationDeleted(conversation: Conversation) { - super.ccConversationDeleted(conversation) - } -}) -``` - -Remove Listener - -``` - CometChatConversationEvents.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. - -##### setStyle - -You can set the styling object to the `CometChatConversations` Component to customize the styling. - - - - - -```xml themes.xml - - - - - -``` - - - -```java -cometChatConversations.setStyle(R.style.CustomConversationsStyle); -``` - - - - -```kotlin -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). - -### 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 Users | `.setLoadingStateVisibility(View.GONE);` | -| setDeleteConversationOptionVisibility | Used to toggle visibility for delete option on a long press of conversation item | `.setDeleteConversationOptionVisibility(View.GONE);` | -| setErrorStateVisibility | Used to hide error state on fetching conversations | `.setErrorStateVisibility(View.GONE);` | -| setEmptyStateVisibility | Used to hide empty state on fetching conversations | `.setEmptyStateVisibility(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);` | -| setGroupTypeVisibility | Used to control visibility of status indicator shown for the group type | `.setGroupTypeVisibility(View.GONE);` | -| setReceiptsVisibility | Used to hide receipts shown in the subtitle of the conversation item without disabling the functionality of marking messages as read and delivered. | `.setReceiptsVisibility(View.GONE);` | -| setSearchInputEndIconVisibility | Used to control the visibility for the end icon icon in the search bar of 'CometChatConversation' | `.setSearchInputEndIconVisibility(View.GONE);` | -| setSearchInputEndIconVisibility | Used to control the visibility for the end icon icon in the search bar of 'CometChatConversation' | `.setSearchInputEndIconVisibility(View.GONE);` | -| disableSoundForMessages | This method disables sound notifications for incoming messages | `.disableSoundForMessages(true);` | -| setCustomSoundForMessages | This method enables users to personalize their chat experience by setting a custom sound file for incoming message notifications. | `.setCustomSoundForMessages(com.cometchat.chatuikit.R.raw.cometchat_beep2);` | -| setSelectionMode | This method determines the selection mode for conversations, enabling users to select either a single conversation or multiple conversations at once. | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` | -| setSearchInputText | This method sets the text in the search input field. | .setSearchInputText("Sample Text"); | -| setSearchPlaceholderText | This method sets the placeholder text for the search input field. | .setSearchPlaceholderText("Enter search term"); | - -### 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. - -*** - -#### setDateTimeFormatter - -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. - -Each method in the interface 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 - -`minute(long timestamp)` / `hour(long timestamp)` → Exact time unit - -`minutes(long diffInMinutesFromNow, long timestamp)` → e.g., "5 minutes ago" - -`hours(long diffInHourFromNow, long timestamp)` → e.g., "2 hours ago" - - - -```java -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - - -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"; - } - }); -``` - - - - -```kotlin -import java.text.SimpleDateFormat -import java.util.* - -cometchatConversations.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" - } - }); -``` - - - -*** - -#### setOptions - -This method sets a predefined list of actions that users can perform when they long press a conversation in the list. These options typically include: - -* Deleting a conversation -* Marking a conversation as read or unread -* Pinning or unpinning a conversation -* Muting notifications for a specific conversation - -By customizing these options, developers can provide a streamlined and contextually relevant user experience. - - -```java -cometchatConversations.setOptions((context, conversation) -> Collections.emptyList()); -``` - - - - -```kotlin -cometchatConversations.options = Function2?> { context, conversation -> emptyList() } -``` - - - - - -Demonstration - - - - - - - -```java -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.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 - } -``` - - - - - -*** - -#### addOptions - -This method extends the existing set of actions available when users long press a conversation 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. - - - -```java -cometchatConversations.addOptions((context, conversation) -> Collections.emptyList()); -``` - - - - -```kotlin -cometchatConversations.addOptions { context, conversation -> emptyList() } -``` - - - - - -Demonstration - - - - - - - -```java -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, "Delete", 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, "Archive", 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; - }); -``` - - - - -```kotlin -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, "Delete", 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, "Archive", 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 - } -``` - - - - - -*** - -#### setLoadingView - -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. - -Use cases: - -* Showing a skeleton loader for conversations while data loads -* Displaying a custom progress indicator with branding -* Providing an animated loading experience for a more engaging UI - - - -```java -cometchatConversations.setLoadingView(R.layout.your_loading_view); -``` - - - - -```kotlin -cometchatConversations.loadingView = R.layout.your_loading_view -``` - - - - - -*** - -#### setEmptyView - -Configures a custom view to be displayed when there are no conversations or messages in the list. This improves the user experience by providing meaningful content instead of an empty screen. - -Examples: - -* Displaying a message like "No conversations yet. Start a new chat!" -* Showing an illustration or animation to make the UI visually appealing -* Providing a button to start a new conversation - - - -```java -cometchatConversations.setEmptyView(R.layout.your_empty_view); -``` - - - - -```kotlin -cometchatConversations.emptyView = R.layout.your_empty_view -``` - - - - - -*** - -#### setErrorView - -Defines a custom error state view that appears when an issue occurs while loading conversations or messages. This enhances the user experience by displaying friendly error messages instead of generic system errors. - -Common use cases: - -* 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 - - - -```java -cometchatConversations.setErrorView(R.layout.your_empty_view); -``` - - - - -```kotlin -cometchatConversations.errorView = R.layout.your_error_view -``` - - - - - -*** - -#### setLeadingView - -Allows setting a custom leading view element that appears at the beginning of each conversation item. This is typically used to modify profile pictures, avatars, or icons in the conversation list. - -Examples: - -* Displaying user avatars with online/offline status indicators -* Using initials or custom graphics instead of images - - - -```java - cometchatConversations.setLeadingView(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) { - - } - }); +```java Add Listener lines +CometChatConversationEvents.addListener("YOUR_LISTENER_TAG", new CometChatConversationEvents() { + @Override + public void ccConversationDeleted(Conversation conversation) { + super.ccConversationDeleted(conversation); + } +}); ``` +Remove Listener + +``` +CometChatConversationEvents.removeListener("YOUR_LISTENER_TAG"); +``` + +### 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 | +| --- | --- | +| `onTextMessageReceived` / `onMediaMessageReceived` / `onCustomMessageReceived` | Moves conversation to top, updates last message preview and unread count | +| `onTypingStarted` / `onTypingEnded` | Shows/hides typing indicator in the subtitle | +| `onMessagesDelivered` / `onMessagesRead` / `onMessagesDeliveredToAll` / `onMessagesReadByAll` | Updates receipt ticks (unless `setReceiptsVisibility(View.GONE)`) | +| `onUserOnline` / `onUserOffline` | Updates online/offline status dot (unless `setUserStatusVisibility(View.GONE)`) | +| `onGroupMemberJoined` / `onGroupMemberLeft` / `onGroupMemberKicked` / `onGroupMemberBanned` / `onMemberAddedToGroup` | Updates group conversation metadata | + +> Automatic: new messages, typing indicators, receipts, user presence, group membership changes. +> Manual: deleting a conversation via the SDK directly (not through the component's context menu) requires emitting `CometChatConversationEvents.ccConversationDeleted` for the UI to update. + +## Functionality + +Small functional customizations such as toggling visibility of UI elements, setting custom sounds, 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 conversations | `.setLoadingStateVisibility(View.GONE);` | +| `setDeleteConversationOptionVisibility` | Toggles visibility for the delete option on long press | `.setDeleteConversationOptionVisibility(View.GONE);` | +| `setErrorStateVisibility` | Hides the error state on fetching conversations | `.setErrorStateVisibility(View.GONE);` | +| `setEmptyStateVisibility` | Hides the empty state on fetching conversations | `.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);` | +| `setGroupTypeVisibility` | Controls visibility of the group type indicator | `.setGroupTypeVisibility(View.GONE);` | +| `setReceiptsVisibility` | Hides receipts shown in the subtitle without disabling read/delivered marking | `.setReceiptsVisibility(View.GONE);` | +| `setSearchBoxVisibility` | Controls visibility of the search box in the toolbar | `.setSearchBoxVisibility(View.GONE);` | +| `setSearchInputEndIconVisibility` | Controls visibility of the end icon in the search bar | `.setSearchInputEndIconVisibility(View.GONE);` | +| `hideReceipts` | Hides read receipts in the conversation list (adapter-level) | `.hideReceipts(true);` | +| `disableSoundForMessages` | Disables sound notifications for incoming messages | `.disableSoundForMessages(true);` | +| `setCustomSoundForMessages` | Sets a custom sound file for incoming message notifications | `.setCustomSoundForMessages(com.cometchat.chatuikit.R.raw.cometchat_beep2);` | +| `setSelectionMode` | Determines the selection mode (single or multiple) | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` | +| `setSearchInputText` | Sets the text in the search input field | `.setSearchInputText("Sample Text");` | +| `setSearchPlaceholderText` | Sets the placeholder text for the search input field | `.setSearchPlaceholderText("Enter search term");` | + +- **Verify**: After calling a visibility method, confirm the corresponding UI element is shown or hidden. After calling `disableSoundForMessages(true)`, confirm no sound plays on incoming messages. + +## Custom View Slots + +Each slot replaces a section of the default UI. Slots that accept a `Conversation` parameter receive the conversation object for that row via the `ConversationsViewHolderListener` pattern (`createView` + `bindView`). + +| Slot | Method | Replaces | +| --- | --- | --- | +| Leading view | `setLeadingView(ConversationsViewHolderListener)` | Avatar / left section | +| Title view | `setTitleView(ConversationsViewHolderListener)` | Name / title text | +| Subtitle view | `setSubtitleView(ConversationsViewHolderListener)` | Last message preview | +| Trailing view | `setTrailingView(ConversationsViewHolderListener)` | Timestamp / badge / right section | +| Item view | `setItemView(ConversationsViewHolderListener)` | 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. Typing-aware avatar example. + + -```kotlin +```kotlin lines cometchatConversations.setLeadingView(object : ConversationsViewHolderListener() { override fun createView( @@ -942,18 +703,34 @@ Examples: } }) ``` - + +```java lines + cometchatConversations.setLeadingView(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 +> **What this does:** Registers a `ConversationsViewHolderListener` that provides a custom view for the leading (left) area of each conversation item. `createView` inflates your layout, and `bindView` populates it with conversation data. -```xml drawable/chat_dots.xml +The following example shows a custom leading view with a chat-dots icon for typing indicators and an avatar with status indicator: + +```xml drawable/chat_dots.xml lines ``` -You can create an `leading_view.xml` as a custom layout file. Which we will inflate in `setLeadingView()` +> **What this does:** Defines a vector drawable of a chat bubble with three dots, used as a typing indicator icon in the custom leading view. -```html +Create a `leading_view.xml` custom layout: + +```html 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 + + +```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"> +