Conversation

Pre-built customizable chat UI - Conversation

This section will guide you in using our ready-made UI. If you are looking to build your own UI using our features, you can refer to Custom UI section.

Initiate Chat

For starting the messaging activity:

Launch Chat list screen

Intent intent = new Intent(this, ConversationActivity.class);            
startActivity(intent);
val conversationsIntent = Intent(context, ConversationActivity::class.java)
context.startActivity(conversationsIntent)

For starting individual conversation thread, set "userId" in intent:

Intent intent = new Intent(this, ConversationActivity.class);            
intent.putExtra(ConversationUIService.USER_ID, "receiveruserid123");   
intent.putExtra(ConversationUIService.DISPLAY_NAME, "Receiver display name"); //put it for displaying the title.
intent.putExtra(ConversationUIService.TAKE_ORDER,true); //Skip chat list for showing on back press 
startActivity(intent);
val individualConversationIntent = Intent(context, ConversationActivity::class.java)
individualConversationIntent.putExtra(ConversationUIService.USER_ID, <RECEIVER_USER_ID>)
individualConversationIntent.putExtra(ConversationUIService.DISPLAY_NAME, <DISPLAY_NAME>) //Pass the display name for the title.
individualConversationIntent.putExtra(ConversationUIService.TAKE_ORDER, true)
startActivity(individualConversationIntent)

Launch group Chat conversation with groupId or channelKey

AlGroupInformationAsyncTask.GroupMemberListener taskListener = new AlGroupInformationAsyncTask.GroupMemberListener() {
  @Override
  public void onSuccess(Channel channel, Context context) {
   Intent chatIntent = new Intent(context, ConversationActivity.class);
   chatIntent.putExtra(ConversationUIService.GROUP_ID, channel.getKey());
   chatIntent.putExtra(ConversationUIService.GROUP_NAME, channel.getName());
   chatIntent.putExtra(ConversationUIService.TAKE_ORDER, true);
   context.startActivity(chatIntent);
  }

  @Override
  public void onFailure(Channel channel, Exception e, Context context) {

  }
 };
 AlGroupInformationAsyncTask groupInfoTask = new AlGroupInformationAsyncTask( < Your Context > , < GroupID > , taskListener);
 AlTask.execute(groupInfoTask);
val taskListener: AlGroupInformationAsyncTask.GroupMemberListener = object : AlGroupInformationAsyncTask.GroupMemberListener {
        override fun onSuccess(channel: Channel, context: Context?) {
            val groupConversationIntent = Intent(context, ConversationActivity::class.java)
            groupConversationIntent.putExtra(ConversationUIService.GROUP_ID, channel.key)
            groupConversationIntent.putExtra(ConversationUIService.GROUP_NAME, channel.name)
            groupConversationIntent.putExtra(ConversationUIService.TAKE_ORDER, true)
            context?.startActivity(groupConversationIntent)
        }

        override fun onFailure(channel: Channel?, e: Exception?, context: Context?) {
            // Got some exception
        }
}
val groupInfoTask = AlGroupInformationAsyncTask(context, groupId, taskListener)
AlTask.execute(groupInfoTask)

Parameter

Value

Description

Context

this, activity context

Pass the context in the AlGroupInformationAsyncTask

groupId/channelKey

Integer

This is the groupId of the group you can get the groupId/channelKey from Channel object Example : channel.getKey()

🚧

Note for older versions:

For SDK versions lesser than v5.95 use groupInfoTask.execute(); instead.

Launching a chat with Client groupId

AlGroupInformationAsyncTask.GroupMemberListener taskListener = new AlGroupInformationAsyncTask.GroupMemberListener() {
 @Override
 public void onSuccess(Channel channel, Context context) {
  Intent chatIntent = new Intent(context, ConversationActivity.class);
  chatIntent.putExtra(ConversationUIService.GROUP_ID, channel.getKey());
  chatIntent.putExtra(ConversationUIService.GROUP_NAME, channel.getName());
  chatIntent.putExtra(ConversationUIService.TAKE_ORDER, true);
  context.startActivity(chatIntent);
 }

 @Override
 public void onFailure(Channel channel, Exception e, Context context) {

 }
};
AlGroupInformationAsyncTask groupInfoTask = new AlGroupInformationAsyncTask( < Your Context > , < ClientGroupId > , taskListener);
val taskListener: AlGroupInformationAsyncTask.GroupMemberListener = object : AlGroupInformationAsyncTask.GroupMemberListener {
        override fun onSuccess(channel: Channel, context: Context?) {
            val groupConversationIntent = Intent(context, ConversationActivity::class.java)
            groupConversationIntent.putExtra(ConversationUIService.GROUP_ID, channel.key)
            groupConversationIntent.putExtra(ConversationUIService.GROUP_NAME, channel.name)
            groupConversationIntent.putExtra(ConversationUIService.TAKE_ORDER, true)
            context?.startActivity(groupConversationIntent)
        }

        override fun onFailure(channel: Channel?, e: Exception?, context: Context?) {
            // Got some exception
        }
}
val groupInfoTask = AlGroupInformationAsyncTask(context, < ClientGroupId >, taskListener)

Then execute the task using:

AlTask.execute(groupInfoTask);
AlTask.execute(groupInfoTask)

🚧

Note for older versions:

For SDK versions lesser than v5.95 use groupInfoTask.execute(); instead.

Delete Conversation thread

If you want to delete all the messages with a user or group chat you can check the below code

One to one :

Pass the RECEIVER_USERID in the below method and context can be this or application context to delete the one to one chats.

// Getting the contact object from RECEIVER_USERID
 AppContactService contactService = new AppContactService(context); 
 Contact contact = contactService.getContactById(<RECEIVER_USERID>);
 
// Calling user conversation delete task 
 AlTask.execute(new DeleteConversationAsyncTask(new MobiComConversationService(context), contact, null, null, context));
// Getting the contact object from RECEIVER_USERID
val contactService = AppContactService(context);
val contact = contactService.getContactById(< RECEIVER_USERID >)

// Calling user conversation delete task 
AlTask.execute(DeleteConversationAsyncTask(MobiComConversationService(context), contact, null, null, context))

Group conversation :

Pass the RECEIVER_USERID in the below method and context can be this or application context to delete the group chats.

// Getting the channel object from group id or channelKey 
Channel channel = ChannelService.getInstance(this).getChannel(groupId);

// Calling group conversation delete task 
AlTask.execute(new DeleteConversationAsyncTask(new MobiComConversationService(context), null, channel, null, context));
// Getting the channel object from group id or channelKey
val channel: Channel = ChannelService.getInstance(context).getChannel(groupId)

// Calling group conversation delete task
AlTask.execute(DeleteConversationAsyncTask(MobiComConversationService(context), null, channel, null, context))

📘

NOTE: Delete conversation will show a dialog during the deleting process if you want to go with without progress dialog then you can check out the new MobiComConversationService(context).deleteSync(***, **, null); you will need to call this method in async task

Context Based Chat

Here are the steps to enable context based chat:

  • Add the setting in UserLoginTask's onSuccess method as below:
ApplozicClient.getInstance(context).setContextBasedChat(true);
ApplozicClient.getInstance(context).isContextBasedChat = true
  • When starting ConversationActivity add CONTEXT_BASED_CHAT flag in intent as below:
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationUIService.CONTEXT_BASED_CHAT,true);
startActivity(intent);
val individualConversationIntent = Intent(context, ConversationActivity::class.java)
individualConversationIntent.putExtra(ConversationUIService.CONTEXT_BASED_CHAT,true)
startActivity(individualConversationIntent)

Follow the below steps to create a Context Based Chat:

private Conversation buildConversation() {

       //Title and subtitles are required if you are enabling the view for particular context.

        TopicDetail topic = new TopicDetail();
        topic.setTitle("Hyundai i20");//Your Topic title
        topic.setSubtitle("May be your car model");//Put Your Topic subtitle
        topic.setLink("Topic Image link if any");

       //You can set two Custom key-value pair which will appear on context view .

        topic.setKey1("Mileage  : ");
        topic.setValue1("18 kmpl");
        topic.setKey2("Price :");
        topic.setValue2("RS. 5.7 lakh");

        //Create Conversation.

        Conversation conversation = new Conversation();

        //SET UserId for which you want to launch chat or conversation

        conversation.setTopicId("Your Topic Id //unique ");
        conversation.setUserId("RECEIVER USERID");
        conversation.setTopicDetail(topic.getJson());
        return conversation;
    }
private fun buildConversation(): Conversation? {

        //Title and subtitles are required if you are enabling the view for particular context.
        val topic = TopicDetail()
        topic.title = "Hyundai i20" //Your Topic title
        topic.subtitle = "May be your car model" //Put Your Topic subtitle
        topic.link = "Topic Image link if any"

        //You can set two Custom key-value pair which will appear on context view .
        topic.key1 = "Mileage  : "
        topic.value1 = "18 kmpl"
        topic.key2 = "Price :"
        topic.value2 = "RS. 5.7 lakh"

        //Create Conversation.
        val conversation = Conversation()

        //SET UserId for which you want to launch chat or conversation
        conversation.topicId = "Your Topic Id //unique "
        conversation.userId = "RECEIVER USERID"
        conversation.topicDetail = topic.json
        return conversation
}
  • Create an AlAsyncTask (basically a background running task):
ApplozicConversationCreateTask applozicConversationCreateTask = null;

   ApplozicConversationCreateTask.ConversationCreateListener conversationCreateListener =  new ApplozicConversationCreateTask.ConversationCreateListener() {
            @Override
            public void onSuccess(Integer conversationId, Context context) {

                //For launching the  one to one  chat
                Intent intent = new Intent(context, ConversationActivity.class);
                intent.putExtra("takeOrder", true);
                intent.putExtra(ConversationUIService.USER_ID, "userId");//RECEIVER USERID
                intent.putExtra(ConversationUIService.DEFAULT_TEXT, "Hello I am interested in this car, Can we chat?");
                intent.putExtra(ConversationUIService.DISPLAY_NAME,"display name");
                intent.putExtra(ConversationUIService.CONTEXT_BASED_CHAT,true);
                intent.putExtra(ConversationUIService.CONVERSATION_ID,conversationId);
                startActivity(intent);
            }

            @Override
            public void onFailure(Exception e, Context context) {

            }
        };
    Conversation conversation = buildConversation(); //From Step 1 
applozicConversationCreateTask = new ApplozicConversationCreateTask(context,conversationCreateListener,conversation);
var applozicConversationCreateTask: ApplozicConversationCreateTask? = null
        val conversationCreateListener: ConversationCreateListener = object : ConversationCreateListener {
            override fun onSuccess(conversationId: Int, context: Context?) {

                //For launching the  one to one  chat
                if (context != null) {
                    val intent = Intent(context, ConversationActivity::class.java)
                    intent.putExtra("takeOrder", true)
                    intent.putExtra(ConversationUIService.USER_ID, "userId") //RECEIVER USERID
                    intent.putExtra(ConversationUIService.DEFAULT_TEXT, "Hello I am interested in this car, Can we chat?")
                    intent.putExtra(ConversationUIService.DISPLAY_NAME, "display name")
                    intent.putExtra(ConversationUIService.CONTEXT_BASED_CHAT, true)
                    intent.putExtra(ConversationUIService.CONVERSATION_ID, conversationId)
                    startActivity(intent) 
                }
              
            }

            override fun onFailure(e: java.lang.Exception?, context: Context?) {}
        }
 val conversation: Conversation = buildConversation() //From Step 1 
applozicConversationCreateTask = ApplozicConversationCreateTask(context, conversationCreateListener, conversation)
  • Then execute the task to start the chat:
AlTask.execute(applozicConversationCreateTask);
AlTask.execute(applozicConversationCreateTask)

🚧

Note for older versions:

For SDK versions lesser than v5.95 use applozicConversationCreateTask.execute((Void)null); instead.

Build your UI from scratch - Conversation

This doc will guide you on how to get the messages for the list and individual group/user messages

Latest message list

The latest message list is used to display the messages to the logged in user based on the communication time. This list contains only the latest messages for each user or group that the logged in user has interacted with, sorted in descending order of the communication time. The latest message would be the first in the list.

ApplozicConversation.getLatestMessageList(context, isScroll, new MessageListHandler() {
            
            @Override
            public void onResult(List<Message> messageList, ApplozicException e) {
                if(e == null){
                // do something
                }else{
                //Error in fetching messages. 
                e.printStrackTrace();
            }
           }
        });
ApplozicConversation.getLatestMessageList(context, isScroll) { messageList, e ->
      if (e == null) {
         // do something with the messageList
      } else {
         // Error in fetching messages.
      }                                                       
}

Just pass the isScroll flag as false.

You can create a list/recycler view to set this messageList. The Message object has fields contactIds and groupIds which helps to determine if the message is for a one-to-one chat or group chat respectively.

You will need to get the Contact and the Channel object for that particular message in your Adapter's getView()/onBindView() method.

You can check if the message is for a group or 1-to-1 chat using the below code:

Contact contact = null;
Channel channel = null;
if(message.getGroupId == null){
  //this is a 1-to-1 message. Get the contact object and display its fields in the item view of your adapter
   contact = new AppContactService(context).getContactById(message.getContactIds());
   displayNameTextView.setText(contact.getDisplayName());
   unreadCountTextView.setText(contact.getUnreadCount());
   loadImage(profileImageView, contact.getImageUrl());
}else {
  //this message is for a group. Get the Channel to display its fields
  channel = ChannelService.getInstance(context).getChannelInfo(message.getGroupId());
   displayNameTextView.setText(channel.getName());
   unreadCountTextView.setText(channel.getUnreadCount());
   loadImage(profileImageView, channel.getImageUrl());
}
var contact: Contact? = null
var channel: Channel? = null
 if (message.groupId == null) {
  //this is a 1-to-1 message. Get the contact object and display its fields in the item view of your adapter
   contact = AppContactService(context).getContactById(message.contactIds)
   displayNameTextView.setText(contact.displayName)
   unreadCountTextView.setText(contact.unreadCount)
   loadImage(profileImageView, contact.imageURL)
} else {
  //this message is for a group. Get the Channel to display its fields
  channel = ChannelService.getInstance(context).getChannelInfo(message.groupId)
  displayNameTextView.setText(channel.getName())
  unreadCountTextView.setText(channel.getUnreadCount())
  loadImage(profileImageView, channel.getImageUrl())
}

Where displayNameTextView is the TextView defined to display the name in your adapter's item view
unreadCountTextView is the TextView defined to display the count of unread messages in your adapter's item view
loadImage is the image loader you are using to load images from a url and
profileImageView is the ImageView to display the image for a user or group.

To display the message use the below code:

if(message.getMessage() != null){
  messageTextView.setText(message.getMessage());
}

if(message.hasAttachment()){
  messageTextView.setText("Attachment");
}
if (message.message != null) {
   messageTextView.setText(message.message);
}

if (message.hasAttachment()) {
   messageTextView.setText("Attachment");
}

To display the Message time use the below code:

messageTimeTextView.setText(DateUtils.getFormattedDateAndTime(message.getCreatedAtTime()));
messageTimeTextView.setText(DateUtils.getFormattedDateAndTime(context, message.createdAtTime, R.string.JUST_NOW, com.applozic.mobicomkit.uiwidgets.R.plurals.MINUTES, R.plurals.HOURS))

Paste the below strings in your strings.xml file

<string name="JUST_NOW">Just now</string>

 <plurals name="HOURS">
 <item quantity="one">%d hr</item>
 <item quantity="other">%d hrs</item>
 </plurals>

  <plurals name="MINUTES">
  <item quantity="one">%d min</item>
   <item quantity="other">%d mins</item>
  </plurals>

Handling pagination in message list

The list will only fetch the top 60 messages in one call. If the user has more than 60 conversations, then a next call must be made for the next batch of messages. Usually the call is made if the user reaches the end of the list while scrolling. You just need to set the isScroll flag as true and make the call for message list, the next batch of messages would be fetched.

📘

Note

The onResult method would not give a concatenated messageList on next call. It would return a new messageList. You need to handle the concatenation yourself. It is recommended to use a global List<Message> mList variable and add the list from onReceive method to this master list. The master list should be passed to your adapter. So on pagination you can directly add the messageList to the mList using addAll method on mList and then notify your adapter.

Message list for a particular thread

The previous section explained how to create the outer message list that displays the latest messages for a particular logged in user. But what happens if the user clicks on the message in the list ? The user should see a detailed list of messages with that user/group. This section will guide you through the same.

Use the below code to get the message list for a particular user:

ApplozicConversation.getMessageListForContact(context, userId, createdAtTime, new MessageListHandler() {
            @Override
            public void onResult(List<Message> messageList, ApplozicException e) {
                if(e == null){
                // do something
                }else{
                //error in fetching messages
                }
            }
        });
ApplozicConversation.getMessageListForContact(this, userId, null, MessageListHandler { messageList, e ->
       if (e == null) {
          // do something
       } else {
          // error in fetching messages
       }
 })

The call takes userId , createdAtTime and a callback handler as arguments. Pass the userId of the User to get the latest 50 messages. For the first call you can pass createdAtTime as null.
You can get the userId from a message object as below:

String userId = message.getContactIds();
val userId = message.contactIds

Use the below code to get the message list for a particular group:

ApplozicConversation.getMessageListForChannel(context, channelKey, createdAtTime, new MessageListHandler() {
            @Override
            public void onResult(List<Message> messageList, ApplozicException e) {
                if(e == null){
                // do something
                }else{
                //error in fetching messages
                }
            }
        });
ApplozicConversation.getMessageListForChannel(context, channelKey, createdAtTime, MessageListHandler { messageList, e ->
       if (e == null) {
          // do something
       } else {
          //error in fetching messages
       }
})

The call takes channelKey , createdAtTime and a callback handler as arguments. Pass the userId of the User to get the latest 50 messages. For the first call you can pass createdAtTime as null.
You can get the channelKey from message object as below:

Integer channelKey = message.getGroupId();
val channelKey = message.groupId

In both of the above cases the list is sorted in ascending order. The latest message would be last in the list.

Handling pagination

You can get the batch of next 50 messages for a particular user/group by passing the createdAtTime of the first message from the previous messageList.
The below code explains handling the pagination for a particular group.

List<Message> mList = new ArrayList(); //global varibale
YourListAdapet adapter;

//call this method inside onCreate of activity or onCreateView of fragment
ApplozicConversation.getMessageListForChannel(context, channelKey, createdAtTime, new MessageListHandler() {
            @Override
            public void onResult(List<Message> messageList, ApplozicException e) {
                if(e == null){
                 mList.addAll(messageList);
                 adapter.setList(mList);
                 adapter.notifyDatasetChanged();
                }
            }
        });
val mList: MutableList<Message> = ArrayList() //global varibale

var adapter: YourListAdapet

//call this method inside onCreate of activity or onCreateView of fragment
ApplozicConversation.getMessageListForChannel(context, channelKey, createdAtTime, MessageListHandler { messageList, e ->
       if (e == null) {
          if (messageList != null &&
                        messageList.size > 0) {
              mList.addAll(messageList)
              adapter.setList(mList)
              adapter.notifyDatasetChanged()
          }
        }
})

Now if the user has scrolled to the first message on the top of the list, you will need to load older messages. You could use swipeRefreshLayout or Scroll handlers for the list view to determine this.

loadNextList(){
  ApplozicConversation.getMessageListForChannel(context, channelKey, mList.get(0).getCreatedAtTime(), new MessageListHandler() {
            @Override
            public void onResult(List<Message> messageList, ApplozicException e) {
                if(e == null){
                 mList.addAll(messageList);
                 adapter.notifyDatasetChanged();
                }
            }
        });
}
fun loadNextList() {
ApplozicConversation.getMessageListForChannel(context, channelKey, mList.get(0).getCreatedAtTime(), MessageListHandler { messageList, e ->
       if (e == null) {
           mList.addAll(messageList)
           adapter.notifyDatasetChanged()
       }
   })
}

Date type messages:

In the message list for particular threads you would also get the date type messages. Date type message holds the date differences between two messages if they are created on two different dates. They have messageType of 100. You would need to create a different ViewHolder to render these messages. For e.g. If a message is created at 11:55 PM on 7th Sept and the next message after that is created at 12:01 AM on 8th Sept then a date type message would be created between these two messages. Its up to you how you display the date on the UI.

Understanding Applozic Message class

All messages communicated through applozic are instance of the Message class. To render the messages in a list for a single thread, you will need to understand the properties of this class.
Please refer to this Class level doc for the details.

Rendering the message in the list

Now that we have the individual thread's message list and the required information about the message class, we can render it on the list view.

Define your list view and individual list item for the same.

Mostly you would need to show the received message on the left side and the sent message on the right side. To check if the message is sent or received use the below code in your adapter's getView()/onBindView() method:

if(message.isTypeOutBox()){
  //This is a sent message, show this on right side
}else{
  //This is a received message, show this on left side
}
if (message.isTypeOutbox) {
   //This is a sent message, show this on right side
} else {
  //This is a received message, show this on left side
}

To get the message text from the message use the below code:

if(message.getMessage() != null){
  messageTextView.setText(message.getMessage());
}
if (!TextUtils.isEmpty(message.message)) {
   messageTextView.setText(message.message);
}

To check the message's content type, use the below code in your adapter's getView()/onBindView() method:

if(Message.ContentType.LOCATION.getValue().equals(message.getContentType())){
        String latitude = "0";
        String longitude = "0";

        try {
            JSONObject locationObject = new JSONObject(message);
            latitude = locationObject.getString("lat");
            longitude = locationObject.getString("lon");
          //do something with this lat/long, you could load a static map.
        } catch (JSONException e) {
            e.printStackTrace();
        }
}else if(Message.ContentType.ATTCHMENT.getValue().equals(message.getContentType())){
   if(message.isAttachmentDownloaded()){
     String filePath = message.getFilePaths().get(0);
     //do something with this filePath, you could use image loader to display this on an image view.
   }
}
if (Message.ContentType.LOCATION.value.equals(message.contentType)) {
    var latitude = "0"
    var longitude = "0"
    try {
        val locationObject = JSONObject(message.message)
        latitude = locationObject.getString("lat")
        longitude = locationObject.getString("lon")
        //do something with this lat/long, you could load a static map.
    } catch (e: JSONException) {
             e.printStackTrace()
     }
} else if (Message.ContentType.ATTCHMENT.getValue().equals(message.contentType)) {
   if (message.isAttachmentDownloaded) {
      val filePath = message.filePaths[0]
  //do something with this filePath, you could use image loader to display this on an image view.
    }
 }

Similarly you can check for other content types. If the message has attachment and the attachment is downloaded, you can directly set it to a view from the filePath as described above.

If the message has attachment and the attachment is not downloaded, then you will need to display a download option in your view for that message.

Checking the attachment type

The Message class provides getAttachmentType() method to determine the attachment type for a message. This would return the attachment type irrespective of wether the attachment has been downloaded or not.
Following are the types determined:

  • Message.IMAGE
  • Message.VIDEO
  • Message.AUDIO
  • Message.LOCATION
  • Message.CONTACT

Applozic does not put restrictions on the attchment types sent. So any attachment that does not fall under the above mentioned categories will come under Message.OTHER.

You can check for an attachment type using the below code:

if(message.hasAttachment()){
  if(message.getAttachmentType().equals(Message.VIDEO)){
    //the message has a video attachment. Display it as video.
  }
}
if (message.hasAttachment()) {
   if (message.attachmentType == Message.VIDEO) {
     //the message has a video attachment. Display it as video.
   }
}

📘

Note

There is no separate contentType for Image unlike video, audio etc. The image will come under contentType ATTACHMENT. If a video, audio etc is attached with contentType as ATTACHMENT, you are recommended to check the attachmentType for that message using the above method.

Setting the status for a message

You can set the status for a message using the below code

if(Message.Status.SENT.getValue().equals(message.getStaus)){
  //show the sent status for that message
}else if(Message.Status.DELIVERED.getValue().equals(message.getStaus)){
  //show the delivered status for that message
}
//similarly for other status, Refer to the Status enum in the Message class
if (Message.Status.SENT.value == message.status) {
    //show the sent status for that message
   } else if (Message.Status.DELIVERED.value == message.status) {
    //show the delivered status for that message
}
//similarly for other status, Refer to the Status enum in the Message class

Marking the chat thread as read

You can update the read status of a complete conversation thread by calling the below method:

ApplozicConversation.markAsRead(context, userId, groupId);
//userId : String
//groupId : Integer
ApplozicConversation.markAsRead(context, userId, groupId)
//userId : String
//groupId : Integer

Basically you would want to call this method whenever a user opens a chat thread with a user or with a group. You will need to pass the userId in case the chat is opened with a user or groupId if the chat is opened with a group.


What’s Next
Did this page help you?