Showcase Recipes

Typing Indicators

Typing Indicators are a staple of any chat app. They can appear as three animated dots, or simply as text to tell you who’s typing. This Recipe shows you how to quickly build and add a basic typing indicator to your chat app.

Recipe categories

  1. On-demand chat
  2. Groups
  3. Text
Platform Android
Level Intermediate
Github View on GitHub
Time Required ~ 30 mins.
Where it matters - Chatbot experiences

- Any basic chat app

Prerequisite : Get your basic project setup done by following the steps mentioned over here. Once you’re done implementing a basic chat in your app, follow the steps below.

1 Step 1

First, we need to detect when a user is typing in the message input area. To do that, add a listener to your EditText, like this:

  messageEditText.addTextChangedListener(object: TextWatcher {
      override fun afterTextChanged(s: Editable ?)
      override fun beforeTextChanged(s: CharSequence ?, start : Int, count: Int, after: Int)
      override fun onTextChanged(s: CharSequence ?, start : Int, before: Int, count: Int) {
          Toast.makeText(this @MainActivity, "User is typing", Toast.LENGTH_SHORT).show()
      }
  })

Now, if you run the app and start typing, you’ll see this:

Typing Step 2

2 Step 2

The next step is to send a typing indicator when the user starts typing. You can do that by modifying the previous block like this:

  messageEditText.addTextChangedListener(object : TextWatcher {
    override fun afterTextChanged(s: Editable?) {

    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        channels.sendTypingIndicator(
            channelId = channelId
        )
    }
  })

3 Step 3

To receive a typing indicator, you need to listen to a specific event called onTypingIndication() in your Mitter.OnPushMessageReceivedCallback. Modify your push message listener like this:

  mitter.registerOnPushMessageReceivedListener(object : Mitter.OnPushMessageReceivedCallback {
    override fun onChannelStreamData(channelId: String, streamId: String, streamData: ContextFreeMessage) 

    override fun onNewChannel(channel: Channel) 

    override fun onNewChannelTimelineEvent(channelId: String, timelineEvent: TimelineEvent) {

    }

    override fun onNewMessage(channelId: String, message: Message) {
        EventBus.getDefault().post(message)
    }

    override fun onNewMessageTimelineEvent(messageId: String, timelineEvent: TimelineEvent) {

    }

    override fun onParticipationChangedEvent(
        channelId: String,
        participantId: String,
        newStatus: ParticipationStatus,
        oldStatus: ParticipationStatus?
    ) {

    }

    override fun onTypingIndication(channelId: String, senderId: String) {
        if (mitter.getUserId() != senderId) {
        EventBus.getDefault().post(TypingIndicator())
        }
    }
  })

Here, we’ll be listening to any incoming typing indicator and then filter the indicator based on the user ID, so that we don’t interpret any typing indicator sent by the acting user.

Note : To pass messages across activities and classes, we’re using EventBus by GreenRobot. You’re free to use whatever you prefer.

4 Step 4

The only thing that’s left to do is to display a cool typing indicator within the chat window. We can do that by adding an event listener and modifying the message list.

In your main activity where you’re controlling your chat window, add the following block:

@Subscribe(threadMode = ThreadMode.MAIN)
    fun onTypingIndication(typingIndicator: TypingIndicator) {
        if (messageList.last() != "") {
            messageList.add("")
            chatRecyclerViewAdapter.notifyItemInserted(messageList.size - 1)
            chatRecyclerView.scrollToPosition(messageList.size - 1)

            Handler().postDelayed({
                messageList.remove("")
                chatRecyclerViewAdapter.notifyItemRemoved(messageList.size - 1)
                chatRecyclerView.scrollToPosition(messageList.size - 1)
            }, 3000)
        }
    }

Here, we’re showing the typing indicator for 3 seconds once it arrives. If we get another typing indication after 3 seconds, we show the typing indicator again.

With this approach, you need to modify your existing ChatRecyclerViewAdapter to accept an empty string as a chat list element and render a different view (in this case, a typing indicator) for that element.

Note: You can refer to the complete code for this in the GitHub repo mentioned below this recipe.

Final result

Try running the app now and send messages from one user to another using two devices or emulator instances. You should see the following result:
View recipe on Github