Core SDK
This is about the data/domain layer
If you just want to query the user data and take care of the UI yourself, this part describes how to do so. For a quick start with built-in customisable UI components, you can use our Messaging UI Components.
Messaging Core SDK dependency
If you don't want the UI components, you can add a dependency only on messaging-core
instead of messaging-ui
:
implementation 'com.nabla.nabla-android:messaging-core:1.0.0-alpha06'
Watch a paginated list
Either for the list of conversations or the list of a conversation’s content, the functions watchConversations()
and watchConversationItems(conversationId: ConversationId)
will return a Flow of WatchPaginatedResponse<T>
where T
is the content to be loaded gradually, e.g. conversations or messages.
The returned flow will emit a new value whenever the concerned data changes. Change can be of any type, for instance in the case of a conversation’s content it can be:
- New messages arriving in the conversation either from the current user or distant users.
- Loaded messages changing in any way, for instance:
- their status changing from “Sending” to “Sent”;
- or their content being deleted;
- or their author changing their avatar, etc.
- New pages loaded using the
loadMore
trigger.
WatchPaginatedResponse
also provides a loadMore
callback to load more content, precisely an additional page. This callback is suspend
and its Result<Unit>
return type informs wether the operation was successful or not.
Watch conversations list
You can watch the list of conversations a user has access to. This watcher will be called every-time there's a change in those conversations and will always return all the data (You don't need to store them to perform a diff):
coroutineScope.launch {
NablaMessagingClient.getInstance().watchConversations()
.catch { error ->
// TODO: handle error
}
.collect { result ->
// You can update your UI with the list of conversations:
val conversations = result.content
// To load more conversation, you can use the loadMore callback
// It will be null if there are no more elements to load
val loadMoreCallback = result.loadMore
}
}
The loadMoreCallback
is simply a nullable suspend function you can call to load more elements.
coroutineScope.launch {
if (loadMoreCallback != null) {
loadMoreCallback()
.onFailure { error -> /* TODO: handle error */ }
.onSuccess {
/* More conversations have been loaded,
the watchConversations callback will be called
with those new conversations */
}
}
}
Don't forget to update your
loadMoreCallback
reference every-time you get a newresult.loadMore
value.
Create a new conversation
If you want your user to be able to start a new conversation, you can allow to create it into your app directly:
coroutineScope.launch {
NablaMessagingClient.getInstance().createConversation()
.onFailure { error -> /* TODO: Handle error */ }
.onSuccess { conversation ->
// Conversation is created, watchConversations will be called with that new conversation
}
}
Watch a conversation
To watch the items (message and conversation activity) of a conversation, the same pagination principles applies:
coroutineScope.launch {
NablaMessagingClient.getInstance().watchConversationItems(conversationId)
.catch { error ->
// TODO: handle error
}
.collect { result ->
// You can update your UI with the new data
val items = result.content.items
// To load more items, you can use the loadMore callback
val loadMoreCallback = result.loadMore
}
}
You can also watch for a conversation details update (like a Provider
typing status):
coroutineScope.launch {
NablaMessagingClient.getInstance().watchConversation(conversationId)
.catch { error ->
// TODO: handle error
}
.collect { result ->
// You can update your UI with the new data
val conversation = result.content
}
}
Send a new message
Creating and sending your message
The user can send a message in an existing conversation:
coroutineScope.launch {
NablaMessagingClient.getInstance()
.sendMessage(
input = MessageInput.Text(text = "Text of the message"),
conversationId = conversationId,
)
.onFailure { /* handle error */ }
.onSuccess { /* message sent successfully 🙌 */ }
}
Message sending is asynchronous
Note that here you don't need to handle failure or success directly: As soon as you call
sendMessage(..)
the new message will be locally added to the conversation: itsstatus
will beSendStatus.Sending
and its id of typeMessageId.Local
.It means that
watchConversationItems
will be called immediately after calling this method and the message will be included in the appropriate state, the SDK will then take care of sending it automatically.
Handling failure
If sending the message fails, the message will still be included in watchConversationItems
but its status
will
be SendStatus.ErrorSending
. You can then retry sending it:
val erredMessage: Message = yourMessageInErrorSendingStatus
coroutineScope.launch {
NablaMessagingClient.getInstance().retrySendingMessage(erredMessage.id, conversationId)
.onFailure { /* No-op */ }
.onSuccess { /* No-op */ }
}
Different types of messages
You can send following types of messages:
- Text
- Image
- Video
- Document
- Audio
Here is how to create each of them:
val newTextMessage = MessageInput.Text(text = "Hello world!")
val newImageMessage = MessageInput.Media.Image(
mediaSource = FileSource.Local(
FileLocal.Image(
Uri("file:///uri/from/android/img.jpg"),
fileName = "My image",
mimeType = MimeType.Image.Jpeg,
),
),
)
val newVideoMessage = MessageInput.Media.Video(
mediaSource = FileSource.Local(
FileLocal.Video(
Uri("file:///uri/from/android/video.mp4"),
fileName = "My video",
mimeType = MimeType.Video.Mp4,
),
),
)
val newDocumentMessage = MessageInput.Media.Document(
mediaSource = FileSource.Local(
FileLocal.Document(
Uri("file:///uri/from/android/file.pdf"),
fileName = "My prescription",
mimeType = MimeType.Application.Pdf,
)
),
)
val newVoiceMessage = MessageInput.Media.Audio(
mediaSource = FileSource.Local(
FileLocal.Audio(
Uri("file:///uri/from/android/audio.mp3"),
fileName = "My voice message",
mimeType = MimeType.Audio.Mp3,
estimatedDurationMs = 42_000L,
)
),
)
Updated 13 days ago