Stream's Chat SDK for Android provides a way for you to add reactions in your application in a matter of minutes.
The SDK has a free trial, and it's free to use for small companies and hobby projects with a Maker Account.
In this tutorial, you're going to learn how to do the following with the low-level Android client library:
- Add reactions to a message
- Delete a reaction from a message
- Use cumulative reactions
- Paginate reactions
Then, using the Android UI components:
- Add custom reactions
- Style the reactions UI
Note: This tutorial assumes you already know the basic knowledge of the Stream API. To get started, check out the Android In-App Messaging Tutorial, and take a look at the Android SDK on GitHub.
Adding a Reaction
Reactions are on most social media apps and there's many of them, for example:
- Like
- Favourite/Love
- Sad/Angry
- Clap
They're used to represent common, quick reactions that users can have after seeing a piece of content. Using the Stream Chat SDK, you can add reactions to your messages in a very easy way.
You'll find the sample app for this tutorial on GitHub. This is how the app looks:
The app has a TextView
which has a Sample message text. It has a favourite ImageButton
beside it and a VIEW CHANNEL
Button. You'll see the channel functionalities later on in this tutorial.
Tap on the favourite ImageButton
. The following BottomSheet
modal will appear:
This is the UI for adding your reaction. It has buttons for selecting the reaction type. There are other buttons for adding or reducing the score for your reaction. Once you set everything it should be as follows:
Now that you've seen the UI part, to save your reaction, first, you have to create a Reaction
object which has the properties of your reaction.
123456val reaction = Reaction( messageId = sentMessage.id, type = reactionType, score = score, extraData = mutableMapOf("customField" to 1), )
In the code above:
- You're providing the
messageId
of the message that you want to react to. - You specify the type of the reaction. The type is from the one you selected on the app.
- Here, you're also adding the score for the reaction. The value for the score is the one you set on the UI.
- Lastly, you add any arbitrary extra information using extra data.
You have your reaction object ready. Next, you'll be seeing how to send that reaction using the Stream Client.
To send a message reaction, you need a ChannelClient
. A ChannelClient
enables you to:
- Create channels
- Add users to channels
- Send messages to channels
- React to messages
- And a lot more!
On the sample app, you declare the client at the top of the file as:
1private lateinit var channelClient: ChannelClient
It's initialised in your onCreate
method as follows:
1channelClient = client.channel(channelType = "messaging", channelId = "general")
The logic to save a reaction is on the ReactionsBottomSheet
. You'll need to pass the sentMesage
and channelCient
to the class as shown below:
12val modalbottomSheetFragment = ReactionsBottomSheet(channelClient, sentMessage) modalbottomSheetFragment.show(supportFragmentManager,modalbottomSheetFragment.tag)
Now that you have everything set, to send your reaction object, you need the following code:
12345678910channelClient.sendReaction(reaction).enqueue { result -> if (result.isSuccess) { val sentReaction = result.data() reactionViewModel.setMessageId(reaction.messageId) Log.d("Message","Message Reaction score is: ${sentReaction.score}") dismiss() } else { requireContext().toast("Adding reaction Failed") } }
Here, you send your reaction object to Stream Client. You're also handling the success and failure states from the callback response. Depending on the result, you handle the states according to your app's needs.
-
If the call succeeds, you call the
setMessageId()
method in the ViewModel. You pass the id of the reaction which has been saved so that you observe it on your activity. -
Show a
Toast
when saving the reactions fails.
When the reaction is saved, you'll see the following image:
Congratulations! You've learned how to add your first message reaction. With Stream's Android SDK, this was simple. Let's see what else you can do with reactions.
Removing a Reaction
To remove a reaction, you only need the messageId
and reactionType
. The code to remove is as follows:
12345678910channelClient.deleteReaction( messageId = reaction.messageId, reactionType = reaction.type, ).enqueue { result -> if (result.isSuccess) { Log.d("Reaction Deleted","Reaction ${reaction.type} has been deleted") } else { showSnackBar("Delete Failed") } }
This method is like the one for adding reactions. The difference is that you're calling the deleteReaction
method to delete the reaction. You're also passing the messageId
and reactionType
for the reaction that you want to remove. You're also handling the success and error states.
Cumulative Reactions
Another commonly used reaction is the clap reaction or enabling a user to react more than once. This is useful in blogs and articles. Stream's Android SDK allows this functionality out of the box as well. You do this by specifying the score
in your reaction model as shown below:
123456val reaction = Reaction( messageId = sentMessage.id, type = reactionModel.name, score = reactionModel.score, extraData = mutableMapOf("customField" to 1), )
Here you specify the score
for your reaction. The value for the score
is the one from the input on the UI. From here, you can send the reaction in the same way as before:
1channelClient.sendReaction(reaction).enqueue { result -> ... }
When quering reactions with scores, the API will return the sum of all reaction scores as well as each reaction's individual scores. For example, it will tell you that you've received 420 claps in total, and Sam clapped 15 times.
Paginating Reactions
In social apps, a message or a post can get many, many reactions - thousands, at times. In such cases, you can not display all these reactions in your app. To handle this case, the SDK allows you to paginate reactions as you fetch them. In this way, you specify the number that you want to fetch according to the UI of your app.
Here's how an example of to fetch reactions with pagination:
1234567891011121314channelClient.getReactions( messageId = messageId, offset = 0, limit = 10, ).enqueue { result -> if (result.isSuccess) { val reactions: List<Reaction> = result.data() binding.rvReactions.visibility = View.VISIBLE reactionsAdapter.submitList(reactions) binding.rvReactions.adapter = reactionsAdapter } else { showSnackBar("Getting Reactions Failed: ${result.error().message}") } }
The getReactions()
method takes in three parameters:
messageId
- ID of the message whose reactions you want to fetch.offset
- The position at which you want to start fetching your reactions. This is usually the number of reactions that you've already loaded. For this case, it's 0 since you want to fetch from the first one (so no offset is required).limit
- This specifies the number of reactions you want to fetch at a single time. This number can be set based on your UI's needs.
From the sample project, here's how the reactions are:
The API offers a lot of flexibility according to your needs. In the next section you'll be looking and the reactions UI provided by the Stream SDK and how you can customize it.
Reactions with Stream's UI Components
Stream's Android SDK has UI components for reactions built-in. They're useful in case you don't need custom ones as you've been learning in the sections above. This is how they look:
The UI offers a couple of commons reactions for example love, like, and thumbs up. This makes it easy to get started with if you want to use them in your app.
However, at times the requirement for your app can be different. Can I remove the default reactions? Can I add custom reactions? Can I apply my app's style to the reactions? Those are some of the questions you might ask yourself.
And the good news is.... drum rolls 🙂 Yes, you can do all that! You can customize all that in the SDK, and you'll be learning how to do that next.
Customizing the Reactions UI
To customize the reactions, you'll be using the SupportedReactions
class, which allows you to define a set of reactions. It accepts two parameters in its constructor:
context
- App context for loading resources.reactions
- This is a Map of keys which hold the reaction type and aReactionDrawable
. This is the parameter you use to add your custom reactions. If you don't provide any reactions, by default it'll use the standard reactions.
A ReactionDrawable
is an object that describes the reaction icon. It handles the different states for the icon: it has different drawables for active and inactive states.
To define your own custom reaction, create a ReactionDrawable
as follows:
1234567fun clapDrawable(context: Context): SupportedReactions.ReactionDrawable { val drawableInactive = ContextCompat.getDrawable(context, R.drawable.ic_clapping)!! val drawableActive = ContextCompat.getDrawable(context, R.drawable.ic_clapping)!!.apply { setTint(ContextCompat.getColor(context,android.R.color.holo_red_dark )) } return SupportedReactions.ReactionDrawable(drawableInactive, drawableActive) }
This function assembles a ReactionDrawable
after loading the drawableInactive
and drawableActive
icons. The active icon here is a tinted version of the inactive icon.
In the sample project, you can check on the ReactionDrawables.kt
file under the utils package for more custom drawables.
Now, you have the drawables ready for use. Next is to create a map of reactions types and their corresponding drawables as follows:
1234567val reactions: Map<String, SupportedReactions.ReactionDrawable> = mapOf( "like" to likeDrawable(applicationContext), "clap" to clapDrawable(applicationContext), "wondering" to wonderingDrawable(applicationContext), "brilliant" to brilliantDrawable(applicationContext), "handshake" to handShakeDrawable(applicationContext), )
Here you have all your custom reactions and their icons. This is all you need. After defining this, the final thing to do is to make sure your app uses the custom reactions that you've created.
You do this by adding this to your initialization code:
1ChatUI.supportedReactions = SupportedReactions(applicationContext, reactions)
Here you're passing your reactions to the Stream's Android SDK. And now this is how your reactions will look like inside the UI components:
Woohoo! As you can now see, all the reactions are custom ones and with different colors!.
In the next section, you'll see how to customize the colors of the reaction card.
Adding your Custom Styling to Reactions
At times you need the UI for the reactions to adapt to the styling of your app. Stream's Android SDK also supports this in a simple and straightforward way. For the title text, you can add the following in your themes.xml
file:
12345<item name="streamUiUserReactionsTitleTextColor">@color/white</item> <item name="streamUiUserReactionsTitleTextSize">18sp</item> <item name="streamUiUserReactionsTitleTextFont">@font/benton_sans_book</item> <item name="streamUiUserReactionsTitleTextStyle">italic</item> <item name="streamUiUserReactionsBackgroundColor">@color/purple_200</item>
From the above attributes you can see you that you're able to change:
- Color
- Text Size
- Font
- Style
- Card Background.
This is how the final results look like with the above settings:
Albeit yours will be different depending on your app colors and styling requirements.
Conclusion
You've learned how to add, remove, paginate and add cumulative reactions in this tutorial. In the process, you've also learned how you can create your custom reactions, including integrating them with Stream's UI Components. You've also seen how to customize reactions in the Stream SDK, and also add your custom reactions.
To learn more about Stream's Android SDK, go to the GitHub repository which is a great starting point to all the available docs and samples.
You can get the full sample project with the examples shown in this tutorial here.