Data components for PubNub Chat Components for Android

Data components are responsible for managing data between the UI Components and the persistence layer. They also interact with the PubNub service by sending and receiving messages and signals.

Available components include:

Overview

PubNub Chat Components for Android utilize several layers of configurable data to drive the functionality found in the UI Components. The goal of the data layer is to provide a simple and robust foundation that can be used across any chat implementation. The two main forms of data used by the components are persistent and network objects.

Persistent data

All the data is stored as entities in a local database using Room, an abstraction layer over SQLite. Room provides the following benefits:

  • Compile-time verification of SQL queries.
  • Convenience annotations that minimize repetitive and error-prone boilerplate code.
  • Streamlined database migration paths.

You can find the default implementation of the database in ChatProvider. It contains data entities, data access objects, and database implementation. Additionally, ChatProvider uses the repository design pattern that allows for separation of concerns by abstracting the data persistence logic.

To learn more about Room, refer to the official Android docs.

Network data

Network objects are most commonly used when interacting with PubNub APIs. Those objects exist only at the network layer and need to be converted with Data Mappers to be used in the application.

UI data

The UI Components don't use persistent or network data but extra UI data objects are created for them instead. These UI data objects contain only user-readable information. For example, to display a timetoken, it must be converted to a date string first.

Data Mappers

The role of Data Mappers is to convert one data type to another to allow developers to swap between Persistent, Network, and UI data objects. For example, when the NetworkMessage is received by MessageService, the data is converted to DBMessage and stored in the database. Similarly to the previous example, when the user sends a message, the MessageUi.Data object is converted to DBMessage and stored in the local database. At the same time, the object is converted to NetworkMessagePayload and published in PubNub.

View models

The ViewModel class is designed to store and manage UI-related data by communicating with services and repositories.

For more information on view models, refer to the official Android docs.

Services

The role of services is to communicate with PubNub APIs, add, get, or update objects and store them using local repositories. The default implementation of services exists in the ChatProvider composition tree.

Data flow

The typical data flow through the components revolves around storing incoming data in the Room database instance and updating that data automatically in UI Components if the data matches the UI Components population query.

Component Data Flow

  1. The PubNub APIs and events return network data that can be stored directly in the Room database using the repositories declared in ChatProvider.

  2. The UI Components use specific view models to connect with the database (persistent data) through repositories and Data Access Object instances. If the returned type of the ViewModel method is declared as Flow, it automatically updates the component's data source if the new matching data is added, updated, or removed.

  3. The UI Components provide actions that can be configured to call PubNub APIs through DataProvider or update existing objects and store the result.

Data payloads

PubNub Chat Components for Android enforce you to use the unified JSON schemas (data models) for such common entity types as users, channels, and messages when transferring data over the PubNub network. These common data payloads allow you to create cross-platform applications and ensure that such applications developed in different technologies (Swift, Kotlin, or JavaScript) communicate with one another properly, avoiding any unexpected errors.

Validate your payload

To avoid any parsing errors, validate the data payload you prepared for users, channels, and messages in an online validator.

Users

Follow this schema for the user data in your apps:

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "User",
"type": "object",
"description": "User of a chat application",
"properties": {
"id": {
"description": "Unique identifier for a user",
"type": "string"
},
"name": {
"description": "Name of the user that you can display in the UI",
"type": "string"
},
"email": {
show all 58 lines

Example:

{
"id": "some-user-id",
"name": "Jane Doe",
"email": "jane.doe@example.com",
"externalId": "some-external-user-id",
"profileUrl": "https://randomuser.me/api/portraits/men/1.jpg",
"type": "default",
"status": "default",
"custom": {
"description": "Office Assistant",
},
"eTag": "AYGyoY3gre71eA",
"updated": "2020-09-23T09:23:34.598494Z"
}

Channels

Follow this schema for the channel data in your apps:

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Channel",
"description": "Channel in the chat application",
"type": "object",
"properties": {
"id": {
"description": "Unique identifier for a channel",
"type": "string"
},
"name": {
"description": "Name of the channel that you can display in the UI",
"type": "string"
},
"description": {
show all 50 lines

Example:

{
"id": "some-channel-id",
"name": "Off-topic",
"description": "Off-topic channel for random chatter and fun",
"type": "default",
"status": "default",
"custom": {
"profileUrl": "https://www.gravatar.com/avatar/149e60f311749f2a7c6515f7b34?s=256&d=identicon"
},
"eTag": "AbOx6N+6vu3zoAE",
"updated": "2020-09-23T09:23:37.175764Z"
}

Messages

Follow this schema for the message data in your apps:

Supported message types

PubNub Chat Components for Android support only text message data types.

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Message Content",
"description": "Message content in the chat application",
"type": "object",
"properties": {
"id": {
"description": "Unique identifier for a message. Use the UUID v4 algorithm.",
"type": "string"
},
"text": {
"description": "Text of the message that you can display in the UI",
"type": "string"
},
"contentType": {
show all 34 lines

Example:

{
"id": "6da72b98-e211-4724-aad4-e0fb9f08999f",
"text": "Let's sync on the topic in this thread.",
"contentType": "none",
"content": {},
"custom": {},
"createdAt": "2022-05-10T14:48:00.000Z"
}

Channel

A channel is commonly viewed as a collection of associated users with a specific purpose or goal. A channel could be created for direct communication between two or more users, a group of users, or other use case-specific scenarios.

Persistent data

The default Persistent Object Model inside the Chat Components defines an Entity named DBChannel.

If a custom Persistent Object Model is used, then an Entity must implement the Channel interface before it can be used by the Chat Components framework.

To return all the members from a selected channel, the DBChannelWithMembers object is implemented.

Default channel entity

The DBChannel entity is defined with the following attributes:

NameTypeDescription
idChannelIdUnique identifier for the object. Used as a primary key.
nameString?Name of the channel that can be displayed in the UI.
descriptionString?Channel details that can be displayed alongside the name.
typeStringFunctional type of the channel. The default value is set to "default".
statusString?Status of the channel.
customAny?Any additional custom payload (as a key-value pair) that can be stored with the channel.
profileUrlString?URL to an image that can be used to visually represent the channel.
eTagString?Caching value that changes whenever the remote object changes. It isn't used in PubNub Chat Components for Android.
updatedString?Last time the remote object was changed. It isn't used in PubNub Chat Components for Android.

The CustomDataMap typealias is a map which stores additional key-value properties.

typealias CustomDataMap = HashMap<String, Any>

Custom channel entity

To create a custom Persistent Object Model, you must implement the Channel interface.

The following properties are required:

interface Channel {
val id: ChannelId
val name: String?
val description: String?
val type: String
val status: String?
val custom: Any?
val profileUrl: String?
val eTag: String?
val updated: String?
}

Relationships

The DBChannelWithMembers entity contains the following attributes:

NameTypeDescription
channelDBChannelEntity of the channel object.
membersList<DBMember>List of members with membership in a selected channel.

Repository

PubNub Chat Components for Android use a default channel repository named DefaultChannelRepository.

If you want to use a custom Persistent Object Model, create a custom ViewModel in which your Repository implements the ChannelRepository interface before it can be used by the Chat Components framework.

Default channel repository

The DefaultChannelRepository implementation is defined with the following attributes:

NameTypeDescription
channelDaoChannelDao<DBChannel, DBChannelWithMembers>Room's data access object (DAO) for the channel entity.

The ChannelDao interface uses both DBChannel and DBChannelWithMembers types. The first one is used for CRUD operations (Create, Read, Update, Delete) and the second one defines the type of the returned object.

Custom channel repository

To create a custom channel repository, implement the ChannelRepository interface.

These are the required methods:

  • get()

    Used to get one Channel object with specified id from the database. It returns null when the object doesn't exist.

    suspend fun get(id: ChannelId): OUT?
  • getAll()

    Returns the paginated source of channels.

    fun getAll(
    id: UserId? = null,
    filter: Query? = null,
    vararg sorted: Sorted = emptyArray(),
    ): PagingSource<Int, OUT>
    NameTypeDescription
    idUserId?If specified, this method returns only channels the user is a member of.
    filterQuery?Query filter for the database.
    sortedSortedArray of sorted keys and directions.

    Example:

    val repository: DefaultChannelRepository = LocalChannelRepository.current

    val channels = remember {
    repository.getAll(
    id = "my-user-id",
    filter = Query("type LIKE ?", "group"),
    sorted = arrayOf(Sorted("type", Sorted.Direction.ASC)),
    )
    }
  • getList()

    Returns the list of all channels.

    suspend fun getList(): List<OUT>
  • insertOrUpdate()

    Sets or updates a channel object in the database.

    suspend fun insertOrUpdate(vararg channel: IN)
  • remove()

    Removes the channel object with the specified ID.

    suspend fun remove(id: ChannelId)
  • size()

    Returns the number of all channels.

    suspend fun size(): Long

Network data

The NetworkChannelMetadata class is used to communicate with PubNub APIs to send and receive channel metadata.

NameTypeDescription
idStringUnique identifier for the object.
nameString?Name of the channel.
descriptionString?Channel details that can be displayed alongside the name.
typeStringFunctional type of the channel. The default value is set to "default".
statusString?Status of the channel.
customAny?Custom key value pairs that can be stored with the channel.
profileUrlString?URL to an image that can be used to visually represent the channel.
eTagString?Caching value that changes whenever the remote object changes. It isn't used in PubNub Chat Components for Android.
updatedString?Last time the remote object was changed. It isn't used in PubNub Chat Components for Android.

Custom channel data

NetworkChannelMetadata contains the custom property. You can use it to store a custom object. In the default implementation, NetworkChannelMapper is implemented to parse the custom object to CustomDataMap.

Service

PubNub Chat Components for Android use a default service named DefaultChannelServiceImpl. This service is responsible for synchronizing PubNub APIs network channel data and storing it in the local database.

You can obtain the instance or override it using LocalChannelService in CompositionLocalProvider. If you want to use a custom service, you need to create a class that implements the ChannelService interface.

Default channel service

The DefaultChannelService implementation is defined with the following attributes:

NameTypeDescription
pubNubPubNubPubNub instance.
loggerLoggerInstance of the logging class.

Custom channel service

To create a custom channel service, implement the ChannelService interface and pass it as a parameter to the composition tree. You can do it by wrapping ChatProvider with CompositionLocalProvider.

CompositionLocalProvider(LocalChannelService provides MyChannelServiceImpl){
ChatProvider()
}

These are the required methods:

  • bind()

    Subscribes to the channels and sets listeners for channel events.

    fun bind(vararg channels: String)
  • unbind()

    Removes the listeners and unsubscribes from channels.

    fun unbind()

Member

The users that are associated with a channel are also known as its members. A user might have many channel memberships and a channel might have multiple members.

Persistent data

The default Persistent Object Model inside the Chat Components defines an Entity named DBMember.

If a custom Persistent Object Model is used, then an Entity must implement the Member interface before it can be used by the Chat Components framework.

Default member entity

The DBMember entity is defined with the following attributes:

NameTypeDescription
idUserIdA unique identifier for the object. Used as a primary key.
nameStringName of the user.
emailString?Email address of the user. It isn't used in PubNub Chat Components for Android.
externalIdString?A unique external identifier for the user. It isn't used in PubNub Chat Components for Android.
profileUrlString?Image that can be used to visually represent the user.
typeStringFunctional type of the user. The default value is set to "default".
statusString?Status of the user.
customAny?Custom object to store a description of the user.
eTagString?Caching value that changes whenever the remote object changes. It isn't used in PubNub Chat Components for Android.
updatedString?Last time the remote object was changed. It isn't used in PubNub Chat Components for Android.

Custom member entity

To create a custom Persistent Object Model, you must implement the Member interface.

The following properties are required:

interface Member {
val id: UserId
val name: String
val email: String?
val externalId: String?
val profileUrl: String?
val type: String
val status: String?
val custom: Any?
val eTag: String?
val updated: String?
}

Relationships

The DBMemberWithChannels entity contains the following attributes:

NameTypeDescription
memberDBMemberEntity of a member object.
channelsList<DBChannel>List of channels with membership.

Repository

PubNub Chat Components for Android use a default member repository named DefaultMemberRepository.

If a custom Persistent Object Model is used, then a Repository must implement the MemberRepository interface before it can be used by the Chat Components framework. Also, you must implement a custom view model.

Default member repository

The DefaultMemberRepository implementation is defined with the following attributes:

NameTypeDescription
memberDaoMemberDao<DBMember, DBMemberWithChannels>Room DAO for the member entity.

The MemberDao interface uses both DBMember and DBMemberWithChannels types. The first one is used for CRUD operations (Create, Read, Update, Delete) and the second one defines the type of the returned object.

Custom member repository

To create a custom member repository, you must implement a MemberRepository interface.

The following methods are required:

  • get()

    Used to get one member object with specified id from the database. Returns null when the object doesn't exist.

    suspend fun get(id: UserId): OUT?
  • getAll()

    Returns paginated source of members. Possible arguments are:

    fun getAll(
    id: ChannelId? = null,
    filter: Query? = null,
    vararg sorted: Sorted = emptyArray(),
    ): PagingSource<Int, OUT>
    NameTypeDescription
    idChannelId?If specified, returns all members of the channel with the specified ID.
    filterQuery?Query filter for the database.
    sortedSortedArray of sorted keys and directions.

    Example:

    val repository: DefaultMemberRepository = LocalMemberRepository.current

    val members = remember {
    repository.getAll(
    id = "channel-id",
    filter = Query("name LIKE ?", "Android"),
    sorted = arrayOf(Sorted("name", Sorted.Direction.ASC)),
    )
    }
  • getList()

    If id is specified, it returns the list of members of the specified channel. Otherwise, it returns the list of all members.

    suspend fun getList(id: ChannelId? = null): List<OUT>
  • insertOrUpdate()

    Sets or updates a member object in the database.

    suspend fun insertOrUpdate(vararg member: IN)
  • remove()

    Removes the member object with the specified ID.

    suspend fun remove(id: UserId)
  • size()

    Returns the number of all members.

    suspend fun size(): Long

Network data

The NetworkMember class is used to communicate with PubNub APIs to send and receive user metadata.

NameTypeDescription
idUserIdA unique identifier for the object. Used as a primary key.
nameStringName of the user.
emailString?Email address of the user. It isn't used in PubNub Chat Components for Android.
externalIdString?A unique external identifier for the user. It isn't used in PubNub Chat Components for Android.
profileUrlString?Image that can be used to visually represent the user.
typeStringFunctional type of the user. The default value is set to "default".
statusString?Status of the user.
customAny?Custom object to store a description of the user.
eTagString?Caching value that changes whenever the remote object changes. It isn't used in PubNub Chat Components for Android.
updatedString?Last time the remote object was changed. It isn't used in PubNub Chat Components for Android.

Custom member data

The NetworkMember contains the custom property. You can use it to store a custom object.

Message

A message is the dynamic content that a user sends to other users inside a channel.

Persistent data

The default Persistent Object Model inside the Chat Components defines an Entity named DBMessage.

If a custom Persistent Object Model is used, then an Entity must implement the Message interface before it can be used by the Chat Components framework.

Default message entity

The DBMessage entity is defined with the following attributes:

NameTypeDescription
idStringUnique identifier for the object. Used as a primary key.
textStringText of the message.
contentTypeString?If a message contains any extra content, this field describes its type. Currently, PubNub Chat Components support only text messages.
contentAny?Extra content for the message like feature-specific data like URLs to external images.
createdAtStringISO8601 date string of when the message was created.
customAny?Custom key value pairs that can be stored with the message.
publisherUserIdID of the message publisher.
channelChannelIdID of the channel the message is published on.
timetokenTimetokenTime when a message was published.
isSentBooleanInformation if a message was sent successfully.
exceptionString?Error details when an exception is thrown.

Custom message entity

To create a custom Persistent Object Model, you must implement the Message interface.

The following properties are required:

interface Message {
val id: MessageId
val text: String
val contentType: String?
val content: Any?
val createdAt: String
val custom: Any?
}

Repository

PubNub Chat Components for Android use a default message repository named DefaultMessageRepository.

If you want to use a custom Persistent Object Model, a Repository must implement the MessageRepository interface before it can be used by the Chat Components framework. Also, you must implement a custom view model.

Default message repository

The DefaultMessageRepository implementation is defined with the following attributes:

NameTypeDescription
messageDaoMessageDao<DBMessage, DBMessage>Room DAO for the message entity.

The MessageDao interface uses the DBMessage type for CRUD operations (Create, Read, Update, Delete) and to define the type of the returned object.

Custom message repository

To create a custom message repository, implement the MessageRepository interface.

The following methods are required:

  • get()

    Used to get one message object with a specified id from the database. Returns null when the object doesn't exist.

    suspend fun get(id: MessageId): OUT?
  • getList()

    Returns the list of all messages from a specified id.

    suspend fun getList(
    id: ChannelId,
    count: Int,
    before: Boolean,
    timestamp: Timetoken,
    ): List<OUT>

    These are the expected arguments:

    NameTypeDescription
    idChannelIdSpecifies a channel to return messages from.
    countIntSpecifies the number of messages to return.
    beforeBooleanRetrieves history messages before or after a specified timestamp.
    timestampTimetokenGets messages before or after a given time, based on the value in the before field.
  • getAll()

    Returns a paginated source of channels.

    fun getAll(
    id: ChannelId? = null,
    contentType: String? = null,
    filter: Query? = null,
    vararg sorted: Sorted = emptyArray(),
    ): PagingSource<Int, OUT>

    Possible arguments are:

    NameTypeDescription
    idChannelId?If specified, it returns only messages from a specified ID.
    contentTypeString?If a message contains any extra content, this field describes its type. Currently, PubNub Chat Components support only text messages.
    filterQuery?Query filter for the database.
    sortedArray<Sorted>Array of sorted keys and directions.

    Example:

    val repository: DefaultMessageRepository = LocalMessageRepository.current

    val messages = remember {
    repository.getAll(
    id = "my-channel-id",
    contentType = "default",
    filter = Query("publisher LIKE ?", "my-uuid"),
    sorted = arrayOf(Sorted("contentType", Sorted.Direction.ASC)),
    )
    }
  • getLast()

    Returns the last message from a given channel.

    suspend fun getLast(channelId: String): OUT?
  • getLastByChannel()

    Returns a flowable list of most recent messages (in a specified number) from a given channel.

    fun getLastByChannel(id: ChannelId, count: Long): Flow<List<OUT>>
    NameTypeDescription
    idStringChannels to return messages from a specified ID.
    countLongNumber of messages to return.
  • has()

    Checks if there is a message with a specified ID in the database.

    suspend fun has(id: MessageId): Boolean
  • hasMoreBefore()

    Returns true when any message with older timestamp than specified exists in the database for a given channel.

    suspend fun hasMoreBefore(id: ChannelId, timestamp: Timetoken): Boolean
  • hasMoreAfter()

    Returns true when any message with a newer timestamp than specified exists in a database for a given channel.

    suspend fun hasMoreAfter(id: ChannelId, timestamp: Timetoken): Boolean
  • remove()

    Removes a message object from the database.

    suspend fun remove(message: IN)
  • removeAll()

    Removes all messages from a given channel.

    suspend fun removeAll(id: ChannelId)
  • insertOrUpdate()

    Sets or updates a message object in the database.

    suspend fun insertOrUpdate(vararg message: IN)
  • setSent()

    Sets the message sent status.

    suspend fun setSent(
    id: MessageId,
    timestamp: Timetoken? = null,
    )
  • setSendingError()

    Sets the message error status.

    suspend fun setSendingError(
    id: MessageId,
    exception: String? = null,
    timestamp: Timetoken? = null,
    )
  • getLastTimestamp()

    Returns the last known timestamp of the message in the channel.

    suspend fun getLastTimestamp(id: ChannelId): Timetoken

Network data

The NetworkMessage class is used to communicate with PubNub APIs. The message field is mapped to the NetworkMessagePayload class:

NameTypeDescription
idStringUnique identifier for the object. Used as a primary key.
textStringText of the message.
contentTypeString?If a message contains any extra content, this field describes its type. Currently, PubNub Chat Components support only text messages.
contentAny?Extra content for the message like feature-specific data like URLs to external images.
createdAtStringISO8601 date string of when the message was created.
customAny?Custom key value pairs that can be stored with the message.

Custom message data

The NetworkMessagePayload contains the custom property. This one might be used to store custom object. In default implementation, the NetworkMessageMapper and NetworkMessageHistoryMapper are used to map it.

Service

PubNub Chat Components for Android use a default service named DefaultMessageService. This service is responsible for synchronizing PubNub APIs network message data and storing it in the local database.

You can obtain the instance or override it using LocalMessageService in CompositionLocalProvider. If you want to use a custom service, you need to create a class which implements the MessageService interface.

Default message service

The DefaultMessageService implementation is defined with the following attributes:

NameTypeDescription
pubNubPubNubPubNub instance.
userIduserIdID of the current user.
messageRepositoryMessageRepository<DBMessage, DBMessageWithActions>The messageRepository implementation responsible for CRUD operations (Create, Read, Update, Delete) on message objects in the database.
messageActionRepositoryMessageActionRepository<DBMessageAction>The messageActionRepository implementation responsible for CRUD operations (Create, Read, Update, Delete) on message action objects in the database.
networkMapperNetworkMessageMapperNetwork object to database object mapper.
networkHistoryMapperNetworkMessageHistoryMapperNetwork history object to database object mapper.
messageActionHistoryMapperNetworkMessageActionHistoryMapperNetwork message action history object to database object mapper.
loggerLoggerInstance of the logging class.
coroutineScopeCoroutineScopeScope for new coroutines.
dispatcherCoroutineDispatcherCoroutine dispatcher implementation.

Custom message service

To create a custom member service, implement the MessageService interface and pass it as a parameter to the composition tree. You can do it by wrapping ChatProvider with CompositionLocalProvider:

CompositionLocalProvider(LocalMessageService provides MyMessageServiceImpl){
ChatProvider()
}

These are the required methods:

  • bind()

    Sets listeners for message events.

    fun bind()
  • unbind()

    Removes the listeners.

    fun unbind()
  • send()

    Sends a message to a selected channel.

    suspend fun send(
    channelId: ChannelId,
    message: NetworkMessagePayload,
    meta: Any? = null,
    store: Boolean = true,
    onSuccess: (String, Timetoken) -> Unit = { _: String, _: Timetoken -> },
    onError: (Exception) -> Unit = {},
    )

    These are the expected arguments:

    NameTypeDescription
    idChannelIdSpecifies a channel to send a message to.
    messageDataMessage data object to send.
    metaAny?Additional metadata to send.
    storeBooleanThe flag denoting to store a message in history.
    onSuccess(String, Timetoken) -> UnitCallback to invoke when a message is sent successfully.
    onError(Exception) -> UnitCallback to invoke when there is an error while sending a message.
  • fetchAll()

    Pulls the messages from the PubNub History API.

    suspend fun fetchAll(
    id: ChannelId,
    start: Long?,
    end: Long?,
    count: Int,
    withActions: Boolean = false,
    withUUID: Boolean = false,
    )

    These are the expected arguments:

    NameTypeDescription
    idChannelIdSpecifies a channel to return history messages from.
    startLong?Delimits the start of a time slice (exclusive) to pull messages from.
    endLong?Delimits the end of a time slice (inclusive) to pull messages from.
    countIntSpecifies the number of historical messages to return.
    withActionsBooleanRetrieves history messages with message actions.
    withUUIDBooleanIncludes a publisher UUID with every history message.

Message reactions

A message reaction is an emoji that a user adds to a message to react to it.

Persistent data

The default Persistent Object Model inside the Chat Components defines an Entity named DBMessageAction.

If a custom Persistent Object Model is used, then an Entity must implement the MessageAction interface before it can be used by the Chat Components framework.

DBMessageWithActions

DBMessageWithActions is the relation between a message and all its actions. Both are stored independently but merged together to one data object when returned from the database. They are related through the DBMessage::timetoken and DBMessageAction::messageTimestamp entires.

data class DBMessageWithActions(
@Embedded
val message: DBMessage,

@Relation(
parentColumn = "timetoken",
entityColumn = "messageTimestamp"
)
val actions: List<DBMessageAction>,
) : Message by message
Default message reaction entity

The DBMessageAction entity is defined with the following attributes:

NameTypeDescription
channelChannelIdID of the channel on which you add a message reaction.
userUserIdID of the user who selects a reaction.
messageTimestampTimetokenTime when a message to which you react was published.
publishedTimetokenTime when a reaction was added.
typeStringThe "reaction" type of the action you made.
valueStringReaction's value.
Custom message reaction entity

To create a custom Persistent Object Model, you must implement the MessageAction interface.

The following properties are required:

interface MessageAction {
val id: String
val channel: ChannelId
val user: UserId
val messageTimestamp: Timetoken
val published: Timetoken
val type: String
val value: String
}
Repository

PubNub Chat Components for Android use a default message reaction repository named DefaultMessageActionRepository.

If you want to use a custom Persistent Object Model, a Repository must implement the MessageActionRepository interface before it can be used by the Chat Components framework. Also, you must implement a custom view model.

Default message reaction repository

The DefaultMessageActionRepository implementation is defined with the following attributes:

NameTypeDescription
messageActionDaoMessageActionDao<DBMessageAction>Room DAO for the message entity.

The MessageActionDao interface uses the DBMessageAction type for CRUD operations (Create, Read, Update, Delete) and to define the type of the returned object.

Custom message reaction repository

To create a custom message repository, implement the MessageActionRepository interface.

The following methods are required:

  • get()

    Returns a message action for the provided parameters.

    suspend fun get(
    user: UserId,
    channel: ChannelId,
    messageTimetoken: Timetoken,
    type: String,
    value: String,
    ): DB?

    These are the expected arguments:

    NameTypeDescription
    userUserIdSpecifies a user who added the reaction.
    channelChannelIdSpecifies the channel on which the reaction was added.
    messageTimetokenTimetokenRetrieves information on the time when the message a given user reacted to was sent.
    typeStringGets information on the action type ("reaction").
    valueStringGets information on the reaction value, like "\uD83D\uDC4D" which stands for "thumbs up".
  • has()

    Checks if a given message reaction exists in the database.

    suspend fun has(id: String): Boolean
    NameTypeDescription
    idStringID of a message reaction to check.
  • remove()

    Removes a given message reaction from the database.

    suspend fun remove(vararg action: DB)
    NameTypeDescription
    vararg actionDBDBMessageAction object to remove.
  • insertOrUpdate()

    Sets or updates a given DBMessageAction object in the database.

    suspend fun insertOrUpdate(vararg action: DB)
    NameTypeDescription
    vararg actionDBDBMessageAction object to add or update.
  • getLastTimetoken()

    Returns the last known timestamp of the message reaction in the channel.

    suspend fun getLastTimetoken(channel: ChannelId): Timetoken
    NameTypeDescription
    channelChannelIdChannel where a message reaction was added.

Network data

The PNMessageAction class is used to communicate with PubNub APIs to send or receive message actions (inluding reactions).

NameTypeDescription
typeStringMessage action type ("reaction" for message reactions).
valueStringMessage reaction value, like "\uD83D\uDC4D" which stands for "thumbs up".
messageTimetokenTimetokenTime when the message a given user reacted to was sent.

Service

PubNub Chat Components for Android use a default reaction service named DefaultMessageReactionService. This service is responsible for synchronizing PubNub APIs network message reaction data and storing it in the local database.

You can obtain the instance or override it using LocalMessageReactionService in CompositionLocalProvider. If you want to use a custom service, you need to create a class which implements the MessageReactionService interface.

Default message reaction service

The DefaultMessageReactionService implementation is defined with the following attributes:

NameTypeDescription
userIdUserIdID of the current user.
actionServiceActionServiceGeneric implementation of message actions. It's not solely restricted to message reactions but could also be used to implement read receipts or channel invitations. It listens for incoming message actions, adding, removing, and fetching actions from PubNub API.
messageActionRepositoryMessageActionRepository<DBMessageAction>The MessageRepository implementation responsible for CRUD operations (Create, Read, Update, Delete) on message actions objects in the database.
mapperMapper<PNMessageActionResult, DBMessageAction>Network history object to database object mapper.
loggerLoggerInstance of the logging class.
coroutineScopeCoroutineScopeScope for new coroutines.
dispatcherCoroutineDispatcherCoroutine dispatcher implementation.
Custom message reaction service

To create a custom message reaction service, implement the MessageReactionService interface and pass it as a parameter to the composition tree. You can do it by wrapping ChatProvider with CompositionLocalProvider:

CompositionLocalProvider(LocalMessageReactionService provides MyMessageReactionService){
ChatProvider()
}

These are the required methods:

  • bind()

    Sets listeners for the message reactions.

    fun bind(
    types: Array<String> = arrayOf("reaction")
    )
    NameTypeDescription
    typesArray<String> = arrayOf("reaction")Refers to the accepted message action type ("reaction") that will be stored in the database.
  • unbind()

    Stops listening for message reactions.

    fun bind()
  • synchronize()

    Synchronizes message reactions for the provided channel.

    fun synchronize(
    channel: ChannelId,
    lastTimetoken: Timetoken? = null
    )
    NameTypeDescription
    channelChannelIdID of the channel to synchronize.
    lastTimetokenTimetoken? = nullLast synchronization timestamp.
  • add()

    Adds a specific message reaction to the PubNub API and the local repository.

    suspend fun add(
    channel: ChannelId,
    messageTimetoken: Timetoken,
    type: String,
    value: String
    )
    NameTypeDescription
    channelChannelIdID of the channel where the message reaction was added.
    messageTimetokenTimetokenTime when the message a given user reacted to was sent.
    typeStringMessage action type ("reaction").
    valueStringMessage reaction value.
  • remove()

    Removes a specific message reaction from the PubNub API and the local repository.

    suspend fun remove(
    channel: ChannelId,
    messageTimetoken: Timetoken,
    published: Timetoken,
    type: String,
    value: String
    )
    NameTypeDescription
    channelChannelIdID of the channel where the message reaction was added.
    messageTimetokenTimetokenTime when the message a given user reacted to was sent.
    publishedTimetokenTime when the message reaction was added.
    typeStringMessage action type ("reaction").
    valueStringMessage reaction value.