PubNub Logo Docs
Support Contact Sales Login Try Our APIs

›ANDROID

Collapse all
Dark mode

Back to Home

Overview

  • In-App Chat

Chat Components

  • Overview
  • REACT

    • React Components

    ANDROID

    • Getting Started
    • UI Components
    • Data Components
    • Chat Provider

    IOS

    • Getting Started
    • UI Components
    • Data Components
    • Chat Provider

SDKs

  • Overview
  • USERS

    • Setup
    • Metadata
    • Permissions
    • Presence
    • Mentions

    CHANNELS

    • Types and Names
    • Metadata
    • Subscriptions
    • Memberships

    MESSAGES

    • Sending Messages
    • Message Storage
    • Unread Counts
    • File Upload
    • Typing Indicators
    • Read Receipts
    • Emoji Reactions
    • Update Messages
    • Delete Messages
    • Message Webhooks

    PUSH NOTIFICATIONS

    • Overview

    MODERATION

    • Profanity Filters
    • Flag Messages
    • Ban Users
    • Mute Users
    • Spam Prevention

    INTEGRATIONS

    • Overview
    • Content Moderation
    • Image Moderation
    • Language Translation
    • Chatbots
    • GIFs
    • Stickers

Moderation Dashboard

  • Overview
  • Getting Started
  • FEATURES

    • Automatic Text Moderation
    • Automatic Image Moderation
    • Manual Message Moderation
    • Manual User Moderation
    • User Management
    • Channel Management
  • Required Configuration

Debug Console
Network Status

UI components

PubNub Chat Components for Android provide easy-to-use building blocks to create chat applications for various use cases with different functionalities and customizable looks.

Available components include:

  • ChannelList
  • MemberList
  • MessageList
  • MessageInput

Component theming

The default theme implementation provides both light and dark theme for any component. If you want to change them, there are different ways of customizing how the components look.

Override material theme

Since the component theme is based on application material theme, you can override values or create a new theme for an application. The result will be similar to PubNub's light and dark theme implementation. For more information, refer to the Android guide.

Create custom component theme

Another option of customizing the look of a component is to create a custom theme for the component. Once created, you can pass it to the {ComponentName}Theme function, for example ChannelListTheme, or directly to CompositionLocalProvider.

Create custom renderer

You can also create a custom renderer that extends the corresponding component's interface and pass it via the renderer parameter. Each component has different customization options which you can find under the Theming heading in the component's description. The renderer is responsible for drawing the component on the screen. If you need to change the structure of the view, you can provide a custom implementation of the renderer. Check the renderer interfaces or default implementations to see the available data.

Predefined theme classes

Source of data classes used for theming are included below. Use them to define custom styles for components.

class ButtonTheme(
    elevation: ButtonElevation?,
    shape: Shape,
    border: BorderStroke?,
    colors: ButtonColors,
    contentPadding: PaddingValues,
    text: TextTheme,
    modifier: Modifier
)

class IconTheme(
    icon: ImageVector,
    shape: Shape,
    tint: Color,
    modifier: Modifier
)

class InputTheme(
    shape: Shape,
    colors: TextFieldColors,
)

class ShapeTheme(
    shape: Shape,
    tint: Color,
    padding: PaddingValues,
    modifier: Modifier
)

class TextTheme(
    modifier: Modifier,
    color: Color,
    fontSize: TextUnit,
    fontStyle: FontStyle?,
    fontWeight: FontWeight?,
    fontFamily: FontFamily?,
    letterSpacing: TextUnit,
    textDecoration: TextDecoration?,
    textAlign: TextAlign?,
    lineHeight: TextUnit,
    overflow: TextOverflow,
    softWrap: Boolean,
    maxLines: Int,
    style: TextStyle,
)

object TextThemeDefaults {
    @Composable
    fun title(
        modifier: Modifier = Modifier,
        color: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.high),
        fontSize: TextUnit = 16.sp,
        fontStyle: FontStyle? = null,
        fontWeight: FontWeight? = FontWeight.Normal,
        fontFamily: FontFamily? = null,
        letterSpacing: TextUnit = TextUnit.Unspecified,
        textDecoration: TextDecoration? = null,
        textAlign: TextAlign? = null,
        lineHeight: TextUnit = TextUnit.Unspecified,
        overflow: TextOverflow = TextOverflow.Ellipsis,
        softWrap: Boolean = true,
        maxLines: Int = 1,
        style: TextStyle = LocalTextStyle.current,
    ) = TextTheme(
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        style
    )

    @Composable
    fun subtitle(
        modifier: Modifier = Modifier,
        color: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.medium),
        fontSize: TextUnit = 14.sp,
        fontStyle: FontStyle? = null,
        fontWeight: FontWeight? = null,
        fontFamily: FontFamily? = null,
        letterSpacing: TextUnit = TextUnit.Unspecified,
        textDecoration: TextDecoration? = null,
        textAlign: TextAlign? = null,
        lineHeight: TextUnit = TextUnit.Unspecified,
        overflow: TextOverflow = TextOverflow.Ellipsis,
        softWrap: Boolean = true,
        maxLines: Int = 1,
        style: TextStyle = LocalTextStyle.current,
    ) = TextTheme(
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        style
    )

    @Composable
    fun header(
        modifier: Modifier = Modifier
            .background(MaterialTheme.colors.surface)
            .padding(16.dp, 24.dp, 16.dp, 16.dp)
            .fillMaxWidth(),
        color: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.high),
        fontSize: TextUnit = 18.sp,
        fontStyle: FontStyle? = null,
        fontWeight: FontWeight? = FontWeight.Normal,
        fontFamily: FontFamily? = null,
        letterSpacing: TextUnit = TextUnit.Unspecified,
        textDecoration: TextDecoration? = null,
        textAlign: TextAlign? = null,
        lineHeight: TextUnit = TextUnit.Unspecified,
        overflow: TextOverflow = TextOverflow.Ellipsis,
        softWrap: Boolean = true,
        maxLines: Int = 1,
        style: TextStyle = LocalTextStyle.current,
    ) = TextTheme(
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        style
    )

}

The ThemeDefaults class contains the default implementation of a component's style.

object ThemeDefaults {

    @Composable
    fun messageInput(
        modifier: Modifier = Modifier
            .fillMaxWidth(),
        input: InputTheme = input(),
        button: ButtonTheme = button(),
    ) = MessageInputTheme(modifier, input, button)

    @Composable
    fun typingIndicator(
        modifier: Modifier = Modifier
            .fillMaxWidth()
            .padding(12.dp),
        icon: IconTheme = icon(tint = MaterialTheme.colors.primaryVariant.copy(alpha = ContentAlpha.medium)),
        text: TextTheme = text(
            fontSize = 12.sp,
            color = MaterialTheme.colors.onSurface.copy(alpha = 0.54f)
        ),
    ) = TypingIndicatorTheme(modifier, icon, text)

    @Composable
    fun channelList(
        modifier: Modifier = Modifier.fillMaxWidth(),
        title: TextTheme = TextThemeDefaults.title(),
        description: TextTheme = TextThemeDefaults.subtitle(),
        image: Modifier = Modifier
            .padding(16.dp, 8.dp, 16.dp, 8.dp)
            .size(36.dp),
        icon: IconTheme = icon(Icons.Default.Logout),
        header: TextTheme = TextThemeDefaults.header(),
    ) = ChannelListTheme(modifier, title, description, image, icon, header)

    @Composable
    fun memberList(
        modifier: Modifier = Modifier.fillMaxWidth(),
        name: TextTheme = TextThemeDefaults.title(),
        description: TextTheme = TextThemeDefaults.subtitle(),
        image: Modifier = Modifier
            .padding(16.dp, 8.dp, 16.dp, 8.dp)
            .size(36.dp),
        icon: IconTheme = icon(Icons.Default.Logout),
        header: TextTheme = TextThemeDefaults.header(),
    ) = MemberListTheme(modifier, name, description, image, icon, header)

    // region Message
    @Composable
    fun messageList(
        modifier: Modifier = Modifier.fillMaxWidth(),
        arrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
        message: MessageTheme = message(),
        messageOwn: MessageTheme = message(
            title = messageTitle(MaterialTheme.colors.primary),
            shape = messageBackgroundShape(color = MaterialTheme.colors.primary.copy(alpha = 0.4f))
        ),
        separator: TextTheme = separator(),
    ) = MessageListTheme(modifier, arrangement, message, messageOwn, separator)

    @Composable
    fun message(
        modifier: Modifier = Modifier
            .padding(16.dp, 12.dp)
            .fillMaxWidth(),
        title: TextTheme = messageTitle(),
        date: TextTheme = messageDate(),
        text: TextTheme = messageText(),
        profileImage: ProfileImageTheme = profileImage(),
        shape: ShapeTheme = messageBackgroundShape(),
        previewShape: ShapeTheme = linkPreviewShape(),
        previewImageShape: ShapeTheme = linkPreviewImageShape(),
        verticalAlignment: Alignment.Vertical = Alignment.Top,
    ) = MessageTheme(
        modifier,
        title,
        date,
        text,
        profileImage,
        shape,
        previewShape,
        previewImageShape,
        verticalAlignment
    )

    @Composable
    fun separator(
        modifier: Modifier = Modifier.padding(16.dp, 4.dp),
        color: Color = MaterialTheme.colors.primaryVariant,
        fontSize: TextUnit = 14.sp,
        fontStyle: FontStyle? = null,
        fontWeight: FontWeight? = FontWeight.Normal,
        fontFamily: FontFamily? = null,
        letterSpacing: TextUnit = TextUnit.Unspecified,
        textDecoration: TextDecoration? = null,
        textAlign: TextAlign? = null,
        lineHeight: TextUnit = TextUnit.Unspecified,
        overflow: TextOverflow = TextOverflow.Ellipsis,
        softWrap: Boolean = true,
        maxLines: Int = 1,
        style: TextStyle = LocalTextStyle.current,
    ) = TextTheme(
        modifier = modifier,
        color = color,
        fontSize = fontSize,
        fontStyle = fontStyle,
        fontWeight = fontWeight,
        fontFamily = fontFamily,
        letterSpacing = letterSpacing,
        textDecoration = textDecoration,
        textAlign = textAlign,
        lineHeight = lineHeight,
        overflow = overflow,
        softWrap = softWrap,
        maxLines = maxLines,
        style = style,
    )

    @Composable
    fun profileImage(
        modifier: Modifier = Modifier
            .padding(0.dp, 0.dp, 12.dp, 0.dp)
            .size(32.dp),
        indicator: IndicatorTheme = indicator(),
    ) = ProfileImageTheme(modifier, indicator)

    @Composable
    fun indicator(
        modifier: Modifier = Modifier.size(16.dp),
        alignment: Alignment = Alignment.BottomEnd,
        activeColor: Color = Color(0xFFb8e986),
        inactiveColor: Color = Color(0xFF9b9b9b),
        borderStroke: BorderStroke = BorderStroke(2.dp, Color.White),
    ) = IndicatorTheme(modifier, alignment, activeColor, inactiveColor, borderStroke)


    @Composable
    fun shape(
        modifier: Modifier = Modifier,
        color: Color = TextFieldDefaults.textFieldColors().backgroundColor(true).value,
        padding: PaddingValues = PaddingValues(0.dp),
        shape: Shape,
    ) = ShapeTheme(shape, color, padding, modifier)

    @Composable
    fun linkPreviewShape(
        shape: Shape = RoundedCornerShape(0.dp, 0.dp, 8.dp, 8.dp),
        color: Color = MaterialTheme.colors.surface,
        padding: PaddingValues = PaddingValues(8.dp),
    ) = shape(shape = shape, padding = padding, color = color)

    @Composable
    fun linkPreviewImageShape(
        modifier: Modifier = Modifier
            .defaultMinSize(minHeight = 100.dp)
            .fillMaxWidth(),
        shape: Shape = RoundedCornerShape(0.dp, 8.dp, 0.dp, 0.dp),
        color: Color = MaterialTheme.colors.surface,
        padding: PaddingValues = PaddingValues(0.dp),
    ) = shape(modifier = modifier, shape = shape, padding = padding, color = color)

    @Composable
    fun messageBackgroundShape(
        shape: Shape = RoundedCornerShape(0.dp),
        color: Color = MaterialTheme.colors.background,
        padding: PaddingValues = PaddingValues(0.dp, 6.dp, 0.dp, 0.dp),
    ) = shape(shape = shape, padding = padding, color = color)

    @Composable
    private fun messageTitle(
        color: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.high),
    ) = text(
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp,
        color = color,
        overflow = TextOverflow.Ellipsis,
        maxLines = 1,
        modifier = Modifier,
    )

    @Composable
    private fun messageDate(
        color: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.medium),
    ) = text(
        fontWeight = FontWeight.Light,
        fontSize = 12.sp,
        color = color,
        overflow = TextOverflow.Ellipsis,
        maxLines = 1,
        modifier = Modifier.paddingFromBaseline(bottom = 4.sp)
    )

    @Composable
    private fun messageText(
        color: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.high),
    ) = text(
        fontWeight = FontWeight.Normal,
        fontSize = 14.sp,
        color = color,
        modifier = Modifier,
    )
    // endregion

    @Composable
    fun input(
        shape: Shape = MaterialTheme.shapes.medium,
        colors: TextFieldColors = TextFieldDefaults.textFieldColors(
            textColor = MaterialTheme.colors.contentColorFor(MaterialTheme.colors.background), // Workaround for text color not changes after theme switch
        ),
    ) = InputTheme(shape, colors)

    @Composable
    fun button(
        elevation: ButtonElevation? = ButtonDefaults.elevation(),
        shape: Shape = MaterialTheme.shapes.small,
        border: BorderStroke? = null,
        colors: ButtonColors = ButtonDefaults.buttonColors(),
        contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
        text: TextTheme = text(),
        modifier: Modifier = Modifier
    ) = ButtonTheme(elevation, shape, border, colors, contentPadding, text, modifier)

    @Composable
    fun icon(
        icon: ImageVector? = null,
        shape: Shape = CircleShape,
        tint: Color = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.medium),//LocalContentColor.current.copy(alpha = ContentAlpha.medium),
        modifier: Modifier = Modifier
            .size(40.dp)
            .padding(8.dp),
    ) = IconTheme(icon, shape, tint, modifier)

    @Composable
    fun text(
        modifier: Modifier = Modifier,
        color: Color = Color.Unspecified,
        fontSize: TextUnit = TextUnit.Unspecified,
        fontStyle: FontStyle? = null,
        fontWeight: FontWeight? = null,
        fontFamily: FontFamily? = null,
        letterSpacing: TextUnit = TextUnit.Unspecified,
        textDecoration: TextDecoration? = null,
        textAlign: TextAlign? = null,
        lineHeight: TextUnit = TextUnit.Unspecified,
        overflow: TextOverflow = TextOverflow.Clip,
        softWrap: Boolean = true,
        maxLines: Int = Int.MAX_VALUE,
        style: TextStyle = LocalTextStyle.current,
    ) = TextTheme(
        modifier,
        color,
        fontSize,
        fontStyle,
        fontWeight,
        fontFamily,
        letterSpacing,
        textDecoration,
        textAlign,
        lineHeight,
        overflow,
        softWrap,
        maxLines,
        style
    )
}

ChannelList

The ChannelList component is responsible for displaying provided channels. It can represent all channels of the application, only channels joined by the current user, or all available channels. Also, it allows you to define actions for UI interactions.

Parameters

You can configure the ChannelList component using the following parameters.

Required parameters

Required parameters don't have default values. If a parameter has a default value, it's optional.

ParameterTypeDefault valueDescription
channelsList<ChannelUi.Data> or Map<String?, List<ChannelUi.Data>> or Flow<PagingData<ChannelUi>>n/aA paged flow of channels, list of channels, or a map of group name and channel list.
onSelected(ChannelUi.Data) -> Unit{ channel: ChannelUi.Data -> }An action called on channel tap. It's used to navigate to the discussion in a selected channel.
onAdd(() -> Unit)?{}An action called after add button tap. It's used to create a new channel. Available only with groups of channels.
onLeave((ChannelUi.Data) -> Unit)?nullAn action called on channel leave icon tap. It's used to leave a channel. The Leave icon is visible only if the onLeave action is not null.
header@Composable (LazyItemScope) -> Unit{ scope: LazyItemScope -> }A composable function to draw above the list. Can be used for a search box.
footer@Composable (LazyItemScope) -> Unit{ scope: LazyItemScope -> }A composable function to draw below the list. You can use it to draw a typing indicator.
rendererChannelRendererDefaultChannelRendererA renderer used for the channel list and its items.

View model

The ChannelViewModel class is designed to store and manage UI-related data. It contains the logic for getting the list of channels from the repository. The returned object is mapped to UI data and contains only the data needed to be displayed.

You can initialize ChannelViewModel with default values using the ChannelViewModel.default() constructor.

Default constructor

ParameterTypeDefault valueDescription
idUserIdLocalPubNub.current.configuration.uuidCurrent user ID
repositoryDefaultChannelRepositoryLocalChannelRepository.currentThe ChannelRepository implementation responsible for CRUD operations (Create, Read, Update, Delete) on channel objects in the database.
dbMapperMapper<DBChannelWithMembers, ChannelUi.Data>DBChannelMapper()Database object to UI object mapper
@Composable
fun default(
    id: UserId = LocalPubNub.current.configuration.uuid,
    repository: DefaultChannelRepository = LocalChannelRepository.current,
    dbMapper: Mapper<DBChannelWithMembers, ChannelUi.Data> = DBChannelMapper(),
): ChannelViewModel

Get channel by ID

This method returns the representation of ChannelUi.Data for the specified channelId. If the channel doesn't exist, this method returns null.

fun get(id: ChannelId): ChannelUi.Data?
ParameterTypeDefault valueDescription
idChannelIdn/aID of the channel.
Example
get("my-channel")

Get paged list of channels

This method returns the paged list of the ChannelUi data, containing both the ChannelUi.Data and ChannelUi.Header items. Channels are grouped by type and extra ChannelUi.Header separator is inserted to the list based on the channel type. The result is updated every time the channel data changes in the database.

fun getAll(filter: Query? = null, sorted: Array<Sorted> = emptyArray()): Flow<PagingData<ChannelUi>>
ParameterTypeDefault valueDescription
filterQuery?n/aQuery filter for the database.
sortedArray<Sorted>emptyArray()Array of sorted objects.
Example
getAll()
getAll(filter = Query("type LIKE ?", listOf("direct")))
getAll(sorted = arrayOf(Sorted("type", Sorted.Direction.ASC)))

Get map of grouped channels

This method is similar to the get paged list of channels (getAll()) method. The main difference is that this method returns groups of channels with titles. Like in the previous method, the channels are grouped by type.

fun getList(): Map<String?, List<ChannelUi.Data>>
Example
getList()

Theming

The default implementation is available in the ThemeDefaults.kt file:

@Composable
fun channelList(
  modifier: Modifier = Modifier.fillMaxWidth(),
  title: TextTheme = TextThemeDefaults.title(),
  description: TextTheme = TextThemeDefaults.subtitle(),
  image: Modifier = Modifier
      .size(54.dp)
      .padding(8.dp),
  icon: IconTheme = icon(Icons.Default.Logout),
) = ChannelListTheme(modifier, title, description, image, icon)

The customization allows you to change the position on screen (modifiers), colors, text sizes, and icons. The default values are taken from Android native components implementations.

To apply the newly created theme, you can use PubNub's helper which propagates the style onto its child elements.

val customTheme = ThemeDefaults.channelList(modifier = Modifier.width(200.dp))
ChannelListTheme(customTheme) {
   ChannelList(channels)
}

// the helper

@Composable
fun ChannelListTheme(
    theme: ChannelListTheme,
    content: @Composable() () -> Unit,
){
    CompositionLocalProvider(LocalChannelListTheme provides theme) {
        content()
    }
}

Channel custom renderer

The default implementation is available in the DefaultChannelRenderer.kt file. You can implement the following functions:

FunctionDefault valueDescription
Channel(name: String, description: String, profileUrl: String, onClick: (() -> Unit)?, onLeave: (() -> Unit)?, modifier: Modifier)n/aA composable function to draw a channel item.
Separator(title: String?, onClick: (() -> Unit)? = null)n/aA composable function to draw a separator for channel types.
Placeholder()n/aA composable placeholder used during data loading.
renderSeparator(scope: LazyListScope, title: String?, onClick: (() -> Unit)? = null)n/aA renderer used for sticky headers.

Actions

This component supports the following UI interactions:

  • On channel tap - onSelected will be called.
  • On group add button tap - onAdd will be called. Available only with groups of channels.
  • On leave icon tap - onLeave will be called. Available if the onLeave action is not null.

Example

The following example shows how to set an action. onSelected navigates to the defined route with the MessageList component from the selected channel. For more information about navigating in Jetpack Compose, refer to the official guide.

val navController = rememberNavController()
val viewModel: ChannelViewModel = ChannelViewModel.default()

ChannelList(
  channels = viewModel.getAll(),
  onSelected = { id ->
    navController.navigate("channel/${id}")
  },
)

MemberList

The MemberList component is responsible for displaying provided members. It can represent all the members of the application or members who joined the selected channel. Also, it allows you to define actions for UI interactions.

Parameters

Required parameters

Required parameters don't have default values. If a parameter has a default value, it's optional.

ParameterTypeDefault valueDescription
membersList<MemberUi.Data> or Map<String?, List<MemberUi.Data>> or Flow<PagingData<MemberUi>>n/aA paged flow of members, list of members, or a map of group name and member list.
presencePresence?nullA Presence object which holds the online state of users.
onSelected(MemberUi.Data) -> Unit{ member: MemberUi.Data -> }An action to be called on member tap. You can use it to navigate to the user profile.
header@Composable (LazyItemScope) -> Unit{ scope: LazyItemScope -> }A composable function to draw above the list. Can be used for a search box.
footer@Composable (LazyItemScope) -> Unit{ scope: LazyItemScope -> }A composable function to draw after the list. You can use it for the Invite button.
rendererMemberRendererDefaultMemberRendererA renderer used for the member list and its items.

View model

The MemberViewModel class is designed to store and manage UI-related data. It contains the logic for getting the list of members from the repository and getting members online state. The returned object is mapped to UI data and contains only the data needed to be displayed.

You can initialize the MemberViewModel with default values using the MemberViewModel.default() constructor.

Default constructor

ParameterTypeDefault valueDescription
pubNubPubNubLocalPubNub.currentPubNub instance
repositoryDefaultMemberRepositoryLocalMemberRepository.currentMemberRepository implementation, responsible for CRUD operations (Create, Read, Update, Delete) on member objects in database.
occupancyServiceOccupancyServiceLocalOccupancyService.currentOccupancyService implementation, responsible for resolving occupancy for channels.
dbMapperMapper<DBMemberWithChannels, MemberUi.Data>DBMemberMapper()Database object to UI object mapper
@Composable
fun default(
    pubNub: PubNub = LocalPubNub.current,
    repository: DefaultMemberRepository = LocalMemberRepository.current,
    occupancyService: OccupancyService = LocalOccupancyService.current,
    dbMapper: Mapper<DBMemberWithChannels, MemberUi.Data> = DBMemberMapper(),
): MemberViewModel

Get member by ID

This method returns the representation of MemberUi.Data for the specified user id. If the member doesn't exist, this method returns null.

fun getMember(id: UserId = pubNub.configuration.uuid): MemberUi.Data?
ParameterTypeDefault valueDescription
idUserIdpubNub.configuration.uuidID of the user. The default value is the current user ID.
Example
getMember("my-user-id")

Get paged list of members

This method returns the paged list of MemberUi data containing MemberUi.Data items. When id parameter isn't set, members of all channels are returned. The result is updated every time the member data changes in the database.

fun getAll(id: ChannelId? = null, filter: Query? = null, sorted: Array<Sorted> = arrayOf(Sorted(MemberUi.Data::name.name, Sorted.Direction.ASC))): Flow<PagingData<MemberUi>>
ParameterTypeDefault valueDescription
idChannelIdnullID of the channel
filterQuery?nullQuery filter for the database
sortedArray<Sorted>arrayOf(Sorted(MemberUi.Data::name.name, Sorted.Direction.ASC)Array of sorted objects. The default value is sorted ascending by a member name.
Example
getAll()
getAll('my-channel')
getAll(filter = Query("${MemberUi.Data::name.name} LIKE ?", "Android"))
getAll(sorted = arrayOf(Sorted(MemberUi.Data::name.name, Sorted.Direction.DESC)))

Get list of members

fun getList(id: ChannelId? = null): List<MemberUi.Data>

This method returns the list of MemberUi.Data items. When the id parameter isn't set, members of all channels are returned.

ParameterTypeDefault valueDescription
idChannelIdnullID of the channel
Example
getList()
getList('my-channel')

Get grouped list of members

This method returns the map of group name and list of MemberUi.Data items. Members are grouped by the first name letter. When the id parameter isn't set, members of all channels are returned.

fun getListGroup(id: ChannelId? = null): List<MemberUi.Data>
ParameterTypeDefault valueDescription
idChannelIdnullID of the channel
Example
getListGroup()
getListGroup('my-channel')

Get user state

fun getPresence(): Presence?

This method returns the Presence object when presenceService exists, or null otherwise. The Presence object contains a map of Member ID and current online/offline state.

Example
getPresence()

Theming

The default implementation is available in the ThemeDefaults.kt file:

@Composable
fun memberList(
  modifier: Modifier = Modifier.fillMaxWidth(),
  name: TextTheme = TextThemeDefaults.title(),
  description: TextTheme = TextThemeDefaults.subtitle(),
  image: Modifier = Modifier
      .size(54.dp)
      .padding(8.dp),
  icon: IconTheme = icon(Icons.Default.Logout),
) = MemberListTheme(modifier, name, description, image, icon)

The customization allows you to change the position on screen (modifiers), colors, text sizes, and icons. The default values are taken from Android native components implementations.

To apply the newly created theme, you can use PubNub's helper which propagates the style onto its child elements.

val customTheme = ThemeDefaults.memberList(modifier = Modifier.width(200.dp))
MemberListTheme(customTheme) {
   MemberList(members)
}

// the helper

@Composable
fun MemberListTheme(
    theme: MemberListTheme,
    content: @Composable() () -> Unit,
) {
    CompositionLocalProvider(LocalMemberListTheme provides theme) {
        content()
    }
}

Member custom renderer

The default implementation is available in the DefaultMemberRenderer.kt file. You can implement the following functions:

FunctionDefault valueDescription
fun Member(name: String, description: String?, profileUrl: String, online: Boolean?, onClick: () -> Unit, modifier: Modifier)n/aA composable function to draw a member item.
Separator(title: String?, onClick: (() -> Unit)? = null)n/aA composable function to draw a separator for members.
Placeholder()n/aA composable placeholder used during data loading.
renderSeparator(scope: LazyListScope, title: String?, onClick: (() -> Unit)? = null)n/aA renderer used for sticky headers.

Actions

This component supports the following UI interactions:

  • On member tap - onSelected will be called.

Example

The following example shows how to set an action. onSelected navigates to the defined route with selected user information. For more details about navigating in Jetpack Compose, refer to the official guide.

val navController = rememberNavController()
val viewModel: MemberViewModel = MemberViewModel.default()

MemberList(
  members = viewModel.getAll(),
  presence = viewModel.getPresence(),
  onSelected = { member ->
    navController.navigate("members/${member.id}")
  }
)

MessageList

The MessageList component is responsible for displaying provided messages. It can represent all messages of the application, only messages from the provided channel, or only unread messages. Also, it allows you to define actions for UI interactions.

Parameters

You can configure the MessageList component using the following parameters:

Required parameters

Required parameters don't have default values. If a parameter has a default value, it's optional.

ParameterTypeDefault valueDescription
messagesFlow<PagingData<MessageUi>>n/aA paged flow of messages
modifierModifierModifierA modifier object which defines the on screen position.
onMemberSelected(UserId) -> Unit{ id -> }Action to be called on member profile image tap. You can use it to navigate to the user profile.
presencePresence?nullA Presence object which holds a user's online state.
rendererMessageRendererGroupMessageRendererA renderer used for message list items.

View model

The MessageViewModel class is designed to store and manage UI-related data. It contains the logic for getting the list of messages from the repository and getting members' online state. The returned object is mapped to UI data and contains only the data needed to be displayed.

You can initialize MessageViewModel with default values using the MessageViewModel.default() constructor.

Default constructor

The default constructor allows loading data only from the database. To pull the historical messages from the network, use the secondary constructor.

@Composable
fun default(
  id: ChannelId = LocalChannel.current,
  mediator: MessageRemoteMediator? = null,
): MessageViewModel
ParameterTypeDefault valueDescription
idChannelIdLocalChannel.currentID of the channel
mediatorMessageRemoteMediatornullMessageRemoteMediator implementation to pull the data from the network.

Secondary constructor

The secondary constructor allows you to use a predefined MessageRemoteMediator implementation and load messages both from the database and network.

@Composable
fun defaultWithMediator(id: ChannelId): MessageViewModel
ParameterTypeDefault valueDescription
idChannelIdLocalChannel.currentID of the channel

Get paged list of messages

This method returns the paged list of MessageUi data containing the MessageUi.Data and MessageUi.Separator items. Messages are separated by the ChannelUi.Separator item, based on the date. The result is updated every time the message data changes in the database.

fun getAll(): Flow<PagingData<MessageUi>>
Example
getAll()

Get user state

This method returns the Presence object when presenceService exists, or null otherwise. This object contains a map of Member ID and current online/offline state.

fun getPresence(): Presence?

Theming

The default implementation is available in the ThemeDefaults.kt file:

@Composable
fun messageList(
    modifier: Modifier = Modifier.fillMaxWidth(),
    arrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
    message: MessageTheme = message(),
    messageOwn: MessageTheme = message(
        title = messageTitle(MaterialTheme.colors.primary),
        shape = messageBackgroundShape(color = MaterialTheme.colors.primary.copy(alpha = 0.4f))
    ),
    separator: TextTheme = separator(),
) = MessageListTheme(modifier, arrangement, message, messageOwn, separator)

The customization allows you to change position on screen (modifiers), colors, text sizes, and icons. The default values are taken from Android native components implementations.

To apply the newly created theme, you can use PubNub's helper which propagates the style onto its child elements.

val customTheme = ThemeDefaults.messageList(modifier = Modifier.width(200.dp))
MessageListTheme(customTheme) {
   MessageList(messages, onMemberSelected)
}

// the helper

@Composable
fun MessageListTheme(
    theme: MessageListTheme,
    content: @Composable() () -> Unit,
) {
    CompositionLocalProvider(LocalMessageListTheme provides theme) {
        content()
    }
}

Message custom renderer

The default implementation is available in the GroupMessageRenderer.kt file. You can implement the following functions:

FunctionDefault valueDescription
Message(messageId: MessageId, currentUserId: UserId, userId: UserId, profileUrl: String, online: Boolean?, title: String, message: AnnotatedString?, attachments: List<Attachment>?, timetoken: Timetoken, navigateToProfile: (UserId) -> Unit)n/aA composable function to draw a message item.
Separator(title: String?, onClick: (() -> Unit)? = null)n/aA composable function to draw a separator for members.
Placeholder()n/aA composable placeholder used during data loading.

Actions

This component supports the following UI interactions:

  • On member profile image tap - onMemberSelected will be called.

Example

The following example shows to set an action. onMemberSelected navigates to the defined route with selected user information. For more details about navigating in Jetpack Compose, refer to the official guide.

val navController = rememberNavController()
val viewModel: MessageViewModel = MessageViewModel.default()

MessageList(
  messages = viewModel.getAll(),
  onMemberSelected = { id ->
    navController.navigate("members/${id}")
  },
)

MessageInput

The MessageInput component is responsible for sending messages and showing the typing indicator. Also, it allows you to define actions invoked after message sending confirmation or after receiving an error.

Parameters

Required parameters

Required parameters don't have default values. If a parameter has a default value, it's optional.

ParameterTypeDefault valueDescription
initialTextString""The initial text of the message input. Use it to load a draft message.
placeholderString"Type Message"A placeholder text which is shown when the message is empty.
typingIndicatorBooleanfalseIf set to true, displays the typing indicator above the input message.
typingIndicatorRendererTypingIndicatorRendererDefaultTypingIndicatorRendererA renderer used to show the typing indicator.
onSuccess(String, Timetoken) -> Unit{ message: String, timetoken: Timetoken -> }An action to be called after receiving confirmation that the message was sent.
onError(Exception) -> Unit{ exception: Exception -> }An action to be called after receiving an error.

View model

The MessageInputViewModel class is designed to store and send messages. It contains the logic for sending messages and setting the typing state. The data is stored in the database and sent to the PubNub service. All the methods are called automatically by the MessageInput component.

You can initialize MessageViewModel with default values using the MessageViewModel.default() constructor.

Default constructor

The default constructor allows to create a view model with custom TypingService. To use predefined TypingService, please take a look at secondary constructor.

@Composable
fun default(
  messageService: MessageService<DBMessage> = LocalMessageService.current,
  id: UserId = LocalPubNub.current.configuration.uuid,
  typingService: TypingService? = null,
): MessageInputViewModel
ParameterTypeDefault valueDescription
messageServiceMessageService<DBMessage>LocalMessageService.currentThe MessageService implementation responsible for sending and listening for messages.
idUserIdLocalPubNub.current.configuration.uuidID of the current user
typingServiceTypingService?nullThe TypingService implementation responsible for collecting and sending data about users who are typing.

Secondary constructor

The secondary constructor allows you to use a predefined TypingService implementation that displays the typing indicators.

@Composable
fun defaultWithTypingService(
  messageService: MessageService<DBMessage> = LocalMessageService.current,
  id: UserId = LocalPubNub.current.configuration.uuid,
): MessageInputViewModel
ParameterTypeDefault valueDescription
messageServiceMessageService<DBMessage>LocalMessageService.currentThe MessageService implementation responsible for sending and listening for messages.
idUserIdLocalPubNub.current.configuration.uuidID of the current user

Send messages

This method sends a message to all subscribers of the passed channel. The message is stored in the local database and its state is updated after receiving confirmation or an error.

ParameterTypeDefault valueDescription
idChannelIdn/aID of the channel
messageStringn/aMessage to send
type@NetworkMessageType StringNetworkMessage.Type.DEFAULTType of the message. Can be one of the NetworkMessage.Type values.
attachmentsList<NetworkMessage.Attachment>?nullList of attachments to send
onSuccess(String, Timetoken) -> Unit{ message, result -> }An action to be called after successfully sending a message.
onError(Exception) -> Unit{ exception -> }An action to be called after receiving an error.
fun send(
  id: ChannelId,
  message: String,
  @NetworkMessageType type: String = NetworkMessage.Type.DEFAULT,
  attachments: List<NetworkMessage.Attachment>? = null,
  onSuccess: (String, Timetoken) -> Unit = { message, result -> },
  onError: (Exception) -> Unit = { exception -> }
)
Example
send(id = "my-channel", message = "Hello world!")

Set typing state

This method sends a typing signal to all the subscribers.

fun setTyping(id: ChannelId, isTyping: Boolean)
ParameterTypeDefault valueDescription
idChannelIdn/aID of the channel
isTypingBooleann/atrue if user is typing, false otherwise
Example
setTyping(id = "my-channel", isTyping = true)

Theming

The default implementation is available in the ThemeDefaults.kt file:

@Composable
fun input(
  shape: Shape = MaterialTheme.shapes.medium,
  colors: TextFieldColors = TextFieldDefaults.textFieldColors(
    textColor = MaterialTheme.colors.contentColorFor(MaterialTheme.colors.background),
  ),
) = InputTheme(shape, colors)

The customization allows you to change position on screen (modifiers), colors, text sizes, and icons. The default values are taken from Android native components implementations.

To apply the newly created theme, you can use PubNub's helper which propagates the style onto its child elements.

val customTheme = ThemeDefaults.input(shape = RoundedCornerShape(50))
MessageInputTheme(customTheme) {
   MessageInput()
}

// the helper

@Composable
fun MessageInputTheme(
    theme: MessageInputTheme,
    content: @Composable() () -> Unit,
) {
    CompositionLocalProvider(LocalMessageInputTheme provides theme) {
        content()
    }
}

Typing indicator custom renderer

The default implementation is available in the DefaultTypingIndicatorRenderer.kt file. You can implement the following functions:

FunctionDefault valueDescription
fun TypingIndicator(data: List<Typing>)n/aA composable function to draw the typing indicator.

The Typing data contains information about user, channel, typing state, and the last signal timestamp.

data class Typing(
    val userId: UserId,
    val channelId: ChannelId,
    val isTyping: Boolean,
    val timestamp: Long = System.currentTimeMillis().timetoken,
)
←Getting StartedData Components→
  • Component theming
    • Override material theme
    • Create custom component theme
    • Create custom renderer
    • Predefined theme classes
  • ChannelList
    • Parameters
    • View model
    • Theming
    • Actions
  • MemberList
    • Parameters
    • View model
    • Theming
    • Actions
  • MessageList
    • Parameters
    • View model
    • Theming
    • Actions
  • MessageInput
    • Parameters
    • View model
    • Theming
© PubNub Inc. - Privacy Policy