# Embed the Message Center

Embed the Message Center directly in your app's navigation, create custom implementations with full control over design and functionality, and filter messages by named user.

This guide covers how to embed the Message Center directly in your app's navigation instead of displaying it as an overlay, create custom implementations, and filter messages.

## Handling Display Requests

To use a custom Message Center implementation or navigate to your embedded Message Center instead of the default overlay activity, set a listener to handle display requests:


#### Kotlin


```kotlin
Airship.messageCenter.setOnShowMessageCenterListener { messageId: String? ->
    // Navigate to your custom Message Center UI
    // messageId is optional - null means show the full message list
    
    // Return true to prevent the default SDK display
    true
}
```



#### Java


```java
MessageCenter.shared().setOnShowMessageCenterListener(messageId -> {
    // Navigate to your custom Message Center UI
    // messageId is optional - null means show the full message list
    
    // Return true to prevent the default SDK display
    return true;
});
```




## Embedding with Jetpack Compose

When embedding Message Center composables, you can choose between an all-in-one screen with a customizable top bar and a content-only Message Center view, without a top bar.

Both composables must be wrapped in a `MessageCenterTheme`, which allows the theme to be customized.

**MessageCenterScreen**

```kotlin
MessageCenterTheme {
    MessageCenterScreen()
}
```


**MessageCenterContent**

```kotlin
MessageCenterTheme {
    MessageCenterContent()
}
```


**Customizing the theme**

```kotlin
val lightColors = MessageCenterColors.lightDefaults(
    background = Color(0xDEDEDE),
    surface = Color(0xFFFFFF),
    accent = Color(0x6200EE),
)

val darkColors = MessageCenterColors.darkDefaults(
    background = Color(0x121212),
    surface = Color(0x1E1E1E),
    accent = Color(0xBB86FC),
)

val typography = MessageCenterTypography.defaults(
    fontFamily = FontFamily(context.resources.getFont(R.font.roboto_regular))
)

MessageCenterTheme(
    colors = if (isSystemInDarkTheme()) darkColors else lightColors,
    typography = typography
) {
    // MessageCenterScreen OR MessageCenterContent
}
```


## Embedding with XML Views

The Message Center UI can be embedded in any `FragmentActivity` or `Fragment` using `MessageCenterFragment`. When embedding the MessageCenterFragment, either use a `FragmentContainerView` or create the fragment directly.

### Using FragmentContainerView

Add the `MessageCenterFragment` directly in your layout XML:

```xml
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragment_container_view"
    android:name="com.urbanairship.messagecenter.ui.MessageCenterFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```


### Creating Fragment Programmatically

Alternatively, create and add the fragment programmatically:


#### Kotlin


```kotlin
val fragment = MessageCenterFragment.newInstance()
```



#### Java


```java
MessageCenterFragment fragment = MessageCenterFragment.newInstance();
```




You will need to [set up display request handling](#handling-display-requests) to navigate to your embedded fragment instead of letting Airship launch the `MessageCenterActivity`.

### Integrating with Navigation

For more control over the UI, `MessageCenterListFragment` and `MessageCenterMessageFragment` can be used to embed the list and message views separately, each maintaining its own `Toolbar`.

This example assumes that Jetpack Navigation is being used to navigate between the list and message views, but any navigation method can be used.

### Custom Message List Fragment

```kotlin
class CustomMessageListFragment() : MessageCenterListFragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
        toolbar.inflateMenu(messageCenterR.menu.ua_message_center_list_pane_menu)

        // Set up the toolbar, if desired.
        setupWithNavController(toolbar, findNavController())

        onMessageClickListener = OnMessageClickListener {
            // Handle message clicks by navigating to the message fragment 
            // (or replace with custom navigation logic).
            findNavController().navigate(
                R.id.action_messageCenterFragment_to_messageFragment, bundleOf(
                    MessageCenterMessageFragment.ARG_MESSAGE_ID to it.id,
                    MessageCenterMessageFragment.ARG_MESSAGE_TITLE to it.title
                )
            )
        }
    }
}
```


### Custom Message Fragment

```kotlin
class CustomMessageFragment : MessageCenterMessageFragment(R.layout.fragment_inbox_message) {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        toolbar?.run {
            // Inflate the default menu
            inflateMenu(messageCenterR.menu.ua_message_center_message_pane_menu)

            // Set up the toolbar, if desired.
            setupWithNavController(toolbar, findNavController(view))
        }

        // Handle message deletion from the message view
        onMessageDeletedListener = OnMessageDeletedListener {
            // Handle message deletion by navigating back to the message list fragment 
            // (or replace with custom navigation logic).
            findNavController().popBackStack()

            // Optionally show a toast confirmation message
            context?.run {
                val msg = getQuantityString(messageCenterR.plurals.ua_mc_description_deleted, 1, 1)
                Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
            }
        }
    }
}
```


These custom fragments can then be embedded into your app UI using `FragmentContainerView` or by using `FragmentManager` programmatically. You will need to [set up display request handling](#handling-display-requests) to navigate to your custom message list fragment instead of letting Airship launch the `MessageCenterActivity`.

## Layout Support

The Message Center provides automatic support for both single-pane and two-pane layouts, when on large display sizes or foldable devices. In two-pane mode, the selected message is highlighted in the list and displayed in the detail pane. Right-to-left (RTL) layout is also supported when `android:supportsRtl="true"` is set in your application manifest.

## Message Center Filtering

Sometimes it can be useful to filter the contents of the Message Center according to some predetermined pattern. To facilitate this, use the shared `MessageCenter` instance to set a predicate. Once set, only messages that match the predicate will be displayed.

### Filter by Named User

Filter messages to show only those for the current named user:


#### Kotlin


```kotlin
MessageCenter.shared().predicate = Predicate { message ->
    val namedUserID = Airship.shared().contact.namedUserID
    if (namedUserID == null) {
        return@Predicate false
    }
    
    // Check if message has matching named_user_id in extras
    val extras = message.extras
    val messageNamedUserID = extras?.get("named_user_id") as? String
    messageNamedUserID == namedUserID
}
```



#### Java


```java
MessageCenter.shared().setPredicate(message -> {
    String namedUserID = Airship.shared().getContact().getNamedUserID();
    if (namedUserID == null) {
        return false;
    }
    
    // Check if message has matching named_user_id in extras
    Map<String, String> extras = message.getExtras();
    String messageNamedUserID = extras != null ? extras.get("named_user_id") : null;
    return messageNamedUserID != null && messageNamedUserID.equals(namedUserID);
});
```




### Custom Filtering

Create custom predicates for any filtering logic:


#### Kotlin


```kotlin
MessageCenter.shared().predicate = Predicate { message ->
    // Example: Only show messages with "cool" in the title
    message.title.contains("cool")
}
```



#### Java


```java
MessageCenter.shared().setPredicate(message -> 
    // Example: Only show messages with "cool" in the title
    message.getTitle().contains("cool")
);
```




## Custom Message Center Implementation

For complete control over Message Center placement and navigation, create a custom implementation using the Message Center components.

### Key Components

**MessageCenter**
: The main entry point for fetching messages and handling callbacks. Access via `MessageCenter.shared()`.

**Inbox**
: Provides an interface for retrieving messages asynchronously and accessing the local message array. Access via `MessageCenter.shared().inbox`.

> **Note:** The message list uses a local database. Message objects are refreshed with the list. Don't hold onto individual message instances indefinitely.


**Message**
: Model object representing an individual message. Instances don't contain the message body—they point to authenticated URLs that should be displayed in a webview.

**Display Callbacks**
: Set `MessageCenter.shared().setOnShowMessageCenterListener()` to handle when messages should be displayed.
