ChatMessagesAdapter for Android

QuickBlox simple to use UI library for showing quickblox chat messages inside android application.

Features

Screenshots

Chat Message Adapter 

Chat Message Adapter

Dependencies

Just add to your build.gradle

dependencies {

compile 'com.quickblox:chat-message-adapter:2.0'

}

Getting started

Example is included in repository. Try it out to see how chat message adapter works.
For now QBMessagesAdapter works with RecycleView.

The following code example demonstrates how to add the QBMessagesAdapter to show chat messages:

Steps to customize QBMessagesAdapter to your Chat app:

  1. Create a subclass of QBMessagesAdapter.
  2. In your subclass define and override methods that you need (such as displayAvatarImage() and obtainAvatarUrl()).
  3. Also you can adjust predefined styles for the next:
    * size of the avatar image view
    * message view container size
    * attachment view container size
    * bubble background for message
    * for all layouts and views set paddings, margins, etc.

Main listeners

Chat Adapter main event listeners.

QBChatMessageLinkClickListener - interface used to handle Clicks and Long clicks on the TextView and taps on the phone, web, mail links inside of TextView.
QBChatAttachClickListener - interface used to handle Clicks on any attachments: image, location, audio, video.

Usage:

messagesAdapter.setAttachLocationClickListener(new QBChatAttachClickListener{

        @Override
        public void onLinkClicked(QBAttachment qbAttachment, int i) {
            MapsActivity.start(context, qbAttachment.getData());
        }
    });

messagesAdapter.setMessageTextViewLinkClickListener(messagesTextViewLinkClickListener, false);
messagesAdapter.setAttachImageClickListener(imageAttachClickListener);

Style configuration

ChatMessagesAdapter has a flexible configuration system for displaying any view elements. For example:

To change bubble for left side opponent you can just create

    <style name="BubbleTextFrame.Left">
        <item name="android:background">@drawable/left_bubble</item>
    </style>

To change Avatar cell size

    <style name="AvatarImageViewStyle.Left">
        <item name="android:layout_width">@dimen/image_view_small_avatar_layout_width</item>
        <item name="android:layout_height">@dimen/image_view_small_avatar_layout_height</item>
    </style>

To change some margin or padding

    <style name="ImageViewAttach.Left">
        <item name="android:layout_marginLeft">@dimen/padding_common</item>
    </style>

Some styles namespaces:

Configure QBMessagesAdapter

You can modify layout resource files, that used in QBMessagesAdapter by creating them with the same namespaces.

In addition, you can add your own widget, just create the layout resource file.
For example, create layout with namespace list_item_text_right with any layout, e.g. text_widget_owner:

<com.quickblox.ui.kit.chatmessage.adapter.widget.MessageTextViewRight
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"

    android:id="@+id/msg_message_text_view_right"
    style="@style/ListItemTextMessage.Right"
    custom:widget_id="@layout/text_widget_owner">

</com.quickblox.ui.kit.chatmessage.adapter.widget.MessageTextViewRight>

Then you can extends QBMessagesAdapter and define your own logic for every item view - plain text message, message with attachment or your custom item view:

    @Override
    protected void onBindViewMsgRightHolder(TextMessageHolder holder, QBChatMessage chatMessage, int position) {
        //update logic for showing your own plain text message
        TextView view = (TextView) holder.itemView.findViewById(R.id.custom_text_view);
        view.setText(currentUser.getFullName());
        super.onBindViewMsgRightHolder(holder, chatMessage, position);
    }
    @Override
    protected void onBindViewMsgLeftHolder(TextMessageHolder holder, QBChatMessage chatMessage, int position) {
        super.onBindViewMsgLeftHolder(holder, chatMessage, position);
        //update logic for showing plain text message from opponent
    }
    @Override
    protected void onBindViewAttachLeftHolder(ImageAttachHolder holder, QBChatMessage chatMessage, int position) {
        super.onBindViewAttachLeftHolder(holder, chatMessage, position);
        //update logic for showing message with image attachment from opponent
    }

There are 8 predefined view types:

To create your own non predefined view type for chat message use code:

Also you can override methods to display attach images

    @Override
    protected void displayAttachment(QBMessageViewHolder holder, int position) {
       super.displayAttachment(holder, position);
       ...add own logic
    }

override methods to display avatars

    @Override
    public void displayAvatarImage(String url, ImageView imageView) {
       ...
    }

    @Override
    public String obtainAvatarUrl(int valueType, QBChatMessage chatMessage) {
        return currentUser.getId().equals(chatMessage.getSenderId()) ?
                currentUserData.getUserAvatar() : opponentUserData.getUserAvatar();
    }

and etc.

Audio and video attachment integration.

Starting from version 2.0 ChatAdapter has ability to record audio attachment, a.k.a. - voice message.
AudioRecorder is intended for this purpose. Just use it like this:

        audioRecorder = AudioRecorder.newBuilder()
                // Required
                .useInBuildFilePathGenerator(this) // or setFilePath(filePath)
                .build();
                // Optional
//                .setDuration(10)
//                .setAudioSource(MediaRecorder.AudioSource.MIC)
//                .setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
//                .setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
//                .setAudioSamplingRate(44100)
//                .setAudioChannels(CHANNEL_STEREO)
//                .setAudioEncodingBitRate(96000)
        audioRecorder.setMediaRecordListener(new QBMediaRecordListener());
    ...
    audioRecorder.startRecord();

and listen events with QBMediaRecordListener

public interface QBMediaRecordListener {

    void onMediaRecorded(File file);

    void onMediaRecordError(MediaRecorderException e);

    void onMediaRecordClosed();
}

QBRecordAudioButton - custom view which extends ImageButton. This view has RecordTouchEventListener:

    public interface RecordTouchEventListener {
        void onStartClick(View view);

        void onCancelClick(View view);

        void onStopClick(View view);
}

It is convenient way to make voice record. Just set setRecordTouchListener:

 recordButton.setRecordTouchListener(new RecordTouchListenerImpl());
 ...
         @Override
         public void onStartClick(View view) {
            audioRecorder.startRecord();
         }

To record Video, for example you can use:

 new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

ChatAdapter has audio and video preview integration and can play these kind attachments using ExoPlayer library.
VideoPlayerActivity - simple implementation for playing video attachments. To use it just declare VideoPlayerActivity in your AndroidManifest.xml file.

QBPlaybackControlView - custom control view for playback audio attachments, which extends PlaybackControlView from ExoPlayer.

Location attachment integration.

Starting from version 1.1.0 ChatAdapter has ability to create location JSON, that represents such fields as lat and lng:

    "attachments":[
            {
               "type":"location",
               "data":"{\"lat\":\"50.014141\",\"lng\":\"36.229058\"}"
            }
         ]

This means you can generate json location like this:

double latitude = 50.014141;
double longitude = 36.229058;
String location = LocationUtils.generateLocationJson(new Pair<>("lat", latitude),
                            new Pair<>("lng", longitude));

And then create attachment:

QBAttachment attachment = new QBAttachment("location");
attachment.setData(location);
...
chatMessage.addAttachment(attachment);

After receiving message with location ChatAdapter generates locationUrl type of google static maps api, to show it like an image.

Note, you should set google_static_maps_key in string resource(https://developers.google.com/maps/documentation/static-maps/) like this:

    <string name="google_static_maps_key" templateMergeStrategy="preserve" translatable="false">
        YOUR_KEY
    </string>

Then by clicking this item, using QBChatAttachLocationClickListener, you can get latitude and longitude to show it in your MapActivity:

    String receivedLocation = attachment.getData();
    // latitude - latLngPair.first, longitude - latLngPair.second
    Pair<Double, Double> latLngPair = LocationUtils.getLatLngFromJson(receivedLocation);

Besides, LocationUtils has defaultUrlLocationParams for location URI and it can be customized with LocationUtils.BuilderParams(), or can be changed just some parameters in string resource:

    <string name="map_zoom">15</string>
    <string name="map_size">600x300</string>
    <string name="map_type">roadmap</string>
    <string name="map_color">blue</string>

Link preview customisation

Simple customization

This chat adapter displays preview only for first link in message. If message contains only link, message's text will be hidden and link preview will be displayed. If message contains few links, link preview will be displayed only for first link and other links will be displayed as message text.

If you want to simple customize view for displaying link previews (change place, position of views etc.), you can create layout resource file widget_link_preview.xml in your module and fill it with views with next ids:

In this way your layout resource file widget_link_preview.xml must contain all this ids.

If you want use only separated ids, you should override method fillLinkPreviewLayout(View linkPreviewLayout, QBLinkPreview linkPreview, String link) for setting data to your views.

For configuration default views we prepared some styles:

Full customization

If you want fully customize link preview with own views, you should set your own custom view to MessageTextViewLeft and MessageTextViewRight (in example we use layout file with name custom_widget_link_preview.xml):

<?xml version="1.0" encoding="utf-8"?>
<com.quickblox.ui.kit.chatmessage.adapter.widget.MessageTextViewLeft
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"

    android:id="@+id/msg_message_text_view_left"
    style="@style/ListItemTextMessage.Left"
    custom:widget_id_link_preview="@layout/custom_widget_link_preview">

</com.quickblox.ui.kit.chatmessage.adapter.widget.MessageTextViewLeft>

Then need override method processLinksFromMessage(final TextMessageHolder holder, final List<String> urlsList, final int position). in this method you can find own view from parameter hollder:

    View customView = holder.linkPreviewLayout;

Sure, you can use separated views for right side bubbles (own messages) and for left side bubbles (opponent's messages). For it need set different layouts for MessageTextViewLeft and MessageTextViewRight. For example:

<!--  for left link previews-->
custom:widget_id_link_preview="@layout/custom_widget_link_preview_left"

<!--  for right link previews-->
custom:widget_id_link_preview="@layout/custom_widget_link_preview_right"

Then need override methods processLinksFromLeftMessage(TextMessageHolder holder, List<String> urlsList, int position) and processLinksFromRightMessage(TextMessageHolder holder, List<String> urlsList, int position) for

License

See LICENSE