> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-rn-guide-message-privately.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Threaded Messages

> Add threaded messages in CometChat Android UI Kit with parent message context, reply views, composers, and thread navigation.

<Accordion title="AI Integration Quick Reference">
  | Field          | Value                                                                                                                                                                                                                  |
  | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | Package        | `com.cometchat:chat-uikit-android`                                                                                                                                                                                     |
  | Key components | `CometChatThreadHeader`, `CometChatMessageList`, `CometChatMessageComposer`                                                                                                                                            |
  | Purpose        | Implement threaded replies so users can respond to specific messages in a focused sub-conversation.                                                                                                                    |
  | Related        | [Threaded Messages Header](/ui-kit/android/threaded-messages-header), [Message List](/ui-kit/android/message-list), [Message Composer](/ui-kit/android/message-composer), [All Guides](/ui-kit/android/guide-overview) |
</Accordion>

Implement threaded replies in your Android chat app using CometChat’s UI Kit, enabling users to reply to specific messages in a focused sub-conversation.

## Overview

Threaded replies allow users to respond directly to a specific message in one-on-one or group chats, improving context and readability:

* Organizes related replies into a dedicated thread view.
* Mirrors functionality in Slack, Discord, and WhatsApp.
* Maintains clarity in active conversations.

Users tap a message → open thread screen → view parent message + replies → compose within thread.

## Prerequisites

* Android project in Android Studio.
* CometChat Android UI Kit v5 added to your `build.gradle`.
* Valid CometChat **App ID**, **Auth Key**, and **Region** initialized.
* `<uses-permission android:name="android.permission.INTERNET"/>` in `AndroidManifest.xml`.
* Logged-in user via `CometChat.login()`.
* Existing `MessagesActivity` using `CometChatMessageList`.

## Components

| Component                     | Role                                                        |
| ----------------------------- | ----------------------------------------------------------- |
| `activity_thread_message.xml` | Defines thread UI: header, message list, composer, unblock. |
| `ThreadMessageActivity`       | Hosts thread screen; initializes UI & ViewModel.            |
| `ThreadMessageViewModel`      | Fetches parent message & thread replies; manages state.     |
| `CometChatMessageList`        | Displays threaded replies when given parent message ID.     |
| `CometChatMessageComposer`    | Composes and sends replies with `parentMessageId`.          |
| `CometChatMessageOption`      | Defines “Message Privately” in message context menus.       |
| `UserDetailActivity`          | Handles blocked-user UI; hides composer & shows unblock.    |

## Integration Steps

### Step 1: Add Thread Layout

Create `res/layout/activity_thread_message.xml`:

```xml activity_thread_message.xml lines theme={null}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.cometchat.chatuikit.threadheader.CometChatThreadHeader
        android:id="@+id/threadHeader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <com.cometchat.chatuikit.messagelist.CometChatMessageList
        android:id="@+id/threadMessageList"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <LinearLayout
        android:id="@+id/unblockLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="12dp"
        android:visibility="gone">

        <Button
            android:id="@+id/unblockBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Unblock" />
    </LinearLayout>

    <com.cometchat.chatuikit.messagecomposer.CometChatMessageComposer
        android:id="@+id/threadComposer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
```

**File reference:**\
[`activity_thread_message.xml`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/res/layout/activity_thread_message.xml)

### Step 2: Set up ThreadMessageActivity

Initialize UI & handle blocked-user flows:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    class ThreadMessageActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_thread_message)
            val header = findViewById<CometChatThreadHeader>(R.id.threadHeader)
            val messageList = findViewById<CometChatMessageList>(R.id.threadMessageList)
            val composer = findViewById<CometChatMessageComposer>(R.id.threadComposer)
            val unblock = findViewById<View>(R.id.unblockLayout)

            val rawMessage = intent.getStringExtra("raw_json")
            val viewModel = ViewModelProvider(this)[ThreadMessageViewModel::class.java]
            if (rawMessage != null) {
                val parentMessage = BaseMessage.processMessage(JSONObject(rawMessage))
                viewModel.setParentMessage(parentMessage)
            }
            viewModel.parentMessage.observe(this) { msg ->
                header.setParentMessage(msg)
                messageList.setParentMessage(msg.id)
                composer.setParentMessageId(msg.id)
            }

            // Handle blocked user
            if (isBlockedByMe) {
                composer.visibility = View.GONE
                unblock.visibility = View.VISIBLE
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    public class ThreadMessageActivity extends AppCompatActivity {
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread_message);
        CometChatThreadHeader header = findViewById(R.id.threadHeader);
        CometChatMessageList messageList = findViewById(R.id.threadMessageList);
        CometChatMessageComposer composer = findViewById(R.id.threadComposer);
        View unblock = findViewById(R.id.unblockLayout);

        String rawMessage = getIntent().getStringExtra("raw_json");
        ThreadMessageViewModel viewModel = new ViewModelProvider(this).get(ThreadMessageViewModel.class);
        if (rawMessage != null) {
          BaseMessage parentMessage = BaseMessage.processMessage(new JSONObject(rawMessage));
          viewModel.setParentMessage(parentMessage);
        }
        viewModel.getParentMessage().observe(this, msg -> {
          header.setParentMessage(msg);
          messageList.setParentMessage(msg.getId());
          composer.setParentMessageId(msg.getId());
        });

        // Handle blocked user
        if (isBlockedByMe) {
          composer.setVisibility(View.GONE);
          unblock.setVisibility(View.VISIBLE);
        }
      }
    }
    ```
  </Tab>
</Tabs>

**File reference:**\
[`ThreadMessageActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/ThreadMessageActivity.java)

### Step 3: Create ThreadMessageViewModel

Store parent message and expose LiveData:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    class ThreadMessageViewModel : ViewModel() {
        val parentMessage = MutableLiveData<BaseMessage>()
        var id: Long = 0
            private set

        fun setParentMessage(message: BaseMessage?) {
            if (message != null) {
                id = message.id
                parentMessage.value = message
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    public class ThreadMessageViewModel extends ViewModel {
      private MutableLiveData<BaseMessage> parentMessage = new MutableLiveData<>();
      private long id;

      public void setParentMessage(BaseMessage message) {
        if (message != null) {
          this.id = message.getId();
          parentMessage.setValue(message);
        }
      }

      public long getId() { return id; }

      public LiveData<BaseMessage> getParentMessage() {
        return parentMessage;
      }
    }
    ```
  </Tab>
</Tabs>

**File reference:**\
[`ThreadMessageViewModel.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/viewmodels/ThreadMessageViewModel.java)

### Step 4: Hook Thread Entry from Message List

In your `MessagesActivity`, capture thread icon taps:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    messageList.setOnThreadRepliesClick { context, baseMessage, template ->
        val intent = Intent(context, ThreadMessageActivity::class.java)
        intent.putExtra("raw_json", baseMessage.rawMessage.toString())
        intent.putExtra("reply_count", baseMessage.replyCount)
        context.startActivity(intent)
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    messageList.setOnThreadRepliesClick((context, baseMessage, template) -> {
      Intent intent = new Intent(context, ThreadMessageActivity.class);
      intent.putExtra("raw_json", baseMessage.getRawMessage().toString());
      intent.putExtra("reply_count", baseMessage.getReplyCount());
      context.startActivity(intent);
    });
    ```
  </Tab>
</Tabs>

**File reference:**\
[`MessagesActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/MessagesActivity.java)

## Implementation Flow

1. User taps thread icon on a message.
2. `Intent` launches `ThreadMessageActivity` with raw message JSON.
3. ViewModel stores parent message and exposes via LiveData.
4. Header & `MessageList` render parent + replies.
5. Composer sends new replies under the parent message.
6. Live updates flow automatically via UI Kit.

## Customization Options

* **Styling:** Override theme attributes or call setter methods on views.
* **Header Height:** `threadHeader.setMaxHeight(...)`.
* **Hide Reactions:** `threadHeader.setReactionVisibility(View.GONE)`.

## Filtering & Edge Cases

* **Group Membership:** Verify membership before enabling composer.
* **Empty Thread:** Show placeholder if no replies.
* **Blocked Users:** Composer hidden; use unblock layout.

## Blocked-User Handling

In `UserDetailActivity`, detect and toggle UI:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    if (user.isBlockedByMe) {
        composer.visibility = View.GONE
        unblockLayout.visibility = View.VISIBLE
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    if (user.isBlockedByMe()) {
      composer.setVisibility(View.GONE);
      unblockLayout.setVisibility(View.VISIBLE);
    }
    ```
  </Tab>
</Tabs>

**File reference:**\
[`UserDetailActivity.java`](https://github.com/cometchat/cometchat-uikit-android/blob/v5/sample-app-java/src/main/java/com/cometchat/sampleapp/java/ui/activity/UserDetailsActivity.java)

## Group vs. User-Level Differences

| Scenario             | Behavior                                |
| -------------------- | --------------------------------------- |
| `ReceiverType.USER`  | Direct replies allowed if not blocked.  |
| `ReceiverType.GROUP` | Checks membership before thread access. |
| Blocked User         | Composer hidden; unblock layout shown.  |
| Not in Group         | Show option to join group first.        |

## Summary / Feature Matrix

| Feature                 | Component / Method                                    |
| ----------------------- | ----------------------------------------------------- |
| Show thread option      | `setOnThreadRepliesClick()`                           |
| Display thread messages | `messageList.setParentMessage(parentMessage.getId())` |
| Show parent message     | `header.setParentMessage(parentMessage)`              |
| Compose reply           | `composer.setParentMessageId(parentMessage.getId())`  |
| Handle blocked users    | `isBlockedByMe()`, hide composer + show unblock UI    |

## Next Steps & Further Reading

<CardGroup>
  <Card title="Android Sample App (Java)">
    Explore this feature in the CometChat SampleApp:
    [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-android/tree/v5/sample-app-java)
  </Card>

  <Card title="Android Sample App (Kotlin)">
    Explore this feature in the CometChat SampleApp:
    [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-android/tree/v5/sample-app-kotlin)
  </Card>
</CardGroup>
