Use RecyclerView for conversation messages

This commit is contained in:
Pierre HUBERT 2018-08-15 18:59:52 +02:00
parent 80fa7567eb
commit 12bdee1617
10 changed files with 262 additions and 288 deletions

View File

@ -1,24 +1,18 @@
package org.communiquons.android.comunic.client.ui.adapters; package org.communiquons.android.comunic.client.ui.adapters;
import android.content.Context; import android.content.Context;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.communiquons.android.comunic.client.R; import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.helpers.ImageLoadHelper;
import org.communiquons.android.comunic.client.data.models.UserInfo; import org.communiquons.android.comunic.client.data.models.UserInfo;
import org.communiquons.android.comunic.client.data.models.ConversationMessage; import org.communiquons.android.comunic.client.data.models.ConversationMessage;
import org.communiquons.android.comunic.client.ui.utils.UiUtils;
import org.communiquons.android.comunic.client.ui.views.WebImageView;
import org.communiquons.android.comunic.client.ui.views.WebUserAccountImage; import org.communiquons.android.comunic.client.ui.views.WebUserAccountImage;
import java.util.ArrayList; import java.util.ArrayList;
@ -30,12 +24,18 @@ import java.util.ArrayList;
* Created by pierre on 12/18/17. * Created by pierre on 12/18/17.
*/ */
public class ConversationMessageAdapter extends ArrayAdapter<ConversationMessage> { public class ConversationMessageAdapter extends RecyclerView.Adapter {
/**
* View messages types
*/
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
/** /**
* Debug tag * Debug tag
*/ */
private static final String TAG = "ConversationMessageAdap"; private static final String TAG = ConversationMessageAdapter.class.getCanonicalName();
/** /**
* The ID of the current user * The ID of the current user
@ -47,6 +47,16 @@ public class ConversationMessageAdapter extends ArrayAdapter<ConversationMessage
*/ */
private ArrayMap<Integer, UserInfo> usersInfo; private ArrayMap<Integer, UserInfo> usersInfo;
/**
* Activity context
*/
private Context mContext;
/**
* Conversation messages
*/
private ArrayList<ConversationMessage> mList;
/** /**
* Public class constructor * Public class constructor
* *
@ -56,177 +66,137 @@ public class ConversationMessageAdapter extends ArrayAdapter<ConversationMessage
*/ */
public ConversationMessageAdapter(Context context, ArrayList<ConversationMessage> list, public ConversationMessageAdapter(Context context, ArrayList<ConversationMessage> list,
int userID, ArrayMap<Integer, UserInfo> usersInfo){ int userID, ArrayMap<Integer, UserInfo> usersInfo){
super(context, 0, list); super();
//Set user ID //Set values
this.userID = userID; this.userID = userID;
//Set user information list
this.usersInfo = usersInfo; this.usersInfo = usersInfo;
this.mContext = context;
this.mList = list;
} }
@Override
public int getItemCount() {
return mList.size();
}
public ConversationMessage getAt(int pos){
return mList.get(pos);
}
@Override
public int getItemViewType(int position) {
return mList.get(position).getUser_id() == userID ? VIEW_TYPE_MESSAGE_SENT
: VIEW_TYPE_MESSAGE_RECEIVED;
}
@NonNull @NonNull
@Override @Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) {
View view;
//Inflate view if required if(type == VIEW_TYPE_MESSAGE_SENT){
if(convertView == null) view = LayoutInflater.from(mContext).inflate(R.layout.conversation_message_item_sent,
convertView = LayoutInflater.from(getContext()). viewGroup, false);
inflate(R.layout.fragment_conversation_message_item, parent, false); return new SentMessageHolder(view);
//Get the content of the message
ConversationMessage message = getItem(position);
assert message != null;
//Get the previous message
ConversationMessage previousMessage = null;
if(position > 0){
previousMessage = getItem(position-1);
} }
/* else if(type == VIEW_TYPE_MESSAGE_RECEIVED){
Get the view of the messages view = LayoutInflater.from(mContext).inflate(R.layout.conversation_message_item_received,
viewGroup, false);
Update the general layout of the message return new ReceivedMessageHolder(view);
*/
//Get the views
LinearLayout containerView = convertView
.findViewById(R.id.fragment_conversation_message_item_container);
TextView contentView = convertView.
findViewById(R.id.fragment_conversation_message_item_content);
WebImageView messageImageView = convertView.
findViewById(R.id.fragment_conversation_message_item_messageimage);
WebUserAccountImage accountImageView;
TextView userNameView = convertView.
findViewById(R.id.fragment_conversation_message_item_username);
//Adapt the layout depending of user of the message
if(message.getUser_id() == userID){
//Message appears on the right
((LinearLayout)convertView).setGravity(Gravity.END);
//Message appears in blue
containerView.setBackground(getContext().
getDrawable(R.drawable.fragment_conversation_message_currentuser_bg));
//User account image appears on the right
accountImageView = convertView.
findViewById(R.id.fragment_conversation_message_item_right_account_image);
accountImageView.setVisibility(View.VISIBLE);
//Hide left image
convertView
.findViewById(R.id.fragment_conversation_message_item_left_account_image)
.setVisibility(View.GONE);
//Align text on the right
contentView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
}
else {
//Message appears on the right
((LinearLayout)convertView).setGravity(Gravity.START);
//Message appears in blue
containerView.setBackground(getContext().
getDrawable(R.drawable.fragment_conversation_message_otheruser_bg));
//User account image appears on the left
accountImageView = convertView.
findViewById(R.id.fragment_conversation_message_item_left_account_image);
accountImageView.setVisibility(View.VISIBLE);
//Hide right image
convertView
.findViewById(R.id.fragment_conversation_message_item_right_account_image)
.setVisibility(View.GONE);
//Align text on the left
contentView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
} }
/*
Check for user information
*/
UserInfo user = null;
if(usersInfo.containsKey(message.getUser_id())){
user = usersInfo.get(message.getUser_id());
}
/*
Update message content
*/
//Set the text of the message
contentView.setText(message.getContent());
//Change the color of the text
if(message.getUser_id() == userID){
contentView.setTextColor(UiUtils.getColor(getContext(),
R.color.conversation_user_messages_textColor));
}
else {
contentView.setTextColor(UiUtils.getColor(getContext(),
R.color.conversation_otheruser_messages_textColor));
}
/*
Update message image
*/
if(message.hasImage()){
//Load the image
messageImageView.loadURL(message.getImage_path());
//Make the image visible
messageImageView.setVisibility(View.VISIBLE);
}
else {
messageImageView.setVisibility(View.GONE);
}
/*
Update user name
*/
if(userNameView != null){
//Hide user name by default
userNameView.setVisibility(View.GONE);
if(user != null){
if(userID != user.getId()) {
//Set the name of the user
userNameView.setText(user.getFullName());
userNameView.setVisibility(View.VISIBLE);
}
}
if(previousMessage != null){
if (message.getUser_id() == previousMessage.getUser_id()){
userNameView.setVisibility(View.GONE);
}
}
}
/*
Update account image
*/
//Check if we can load a specific image
if(user != null) {
accountImageView.setUser(user);
}
else else
accountImageView.removeUser(); throw new RuntimeException("Could not determine view type!");
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()){
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageHolder) viewHolder).bind(position);
break;
return convertView; case VIEW_TYPE_MESSAGE_RECEIVED:
((ReceivedMessageHolder) viewHolder).bind(position);
break;
}
}
/**
* Base messages holder
*/
private class BaseMessageHolder extends RecyclerView.ViewHolder {
private TextView mMessage;
BaseMessageHolder(@NonNull View itemView) {
super(itemView);
mMessage = itemView.findViewById(R.id.message_body);
}
/**
* Bind view for a conversation message
*
* @param pos The message to bind
*/
@CallSuper
void bind(int pos){
mMessage.setText(getAt(pos).getContent());
}
}
/**
* Sent messages holder
*/
private class SentMessageHolder extends BaseMessageHolder {
SentMessageHolder(@NonNull View itemView) {
super(itemView);
}
}
/**
* Received messages holder
*/
private class ReceivedMessageHolder extends BaseMessageHolder {
WebUserAccountImage mUserAccountImage;
TextView mUserName;
ReceivedMessageHolder(@NonNull View itemView) {
super(itemView);
mUserAccountImage = itemView.findViewById(R.id.account_image);
mUserName = itemView.findViewById(R.id.user_name);
}
void setUserInfoVisibility(boolean visible){
mUserAccountImage.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mUserName.setVisibility(visible ? View.VISIBLE : View.GONE);
}
void bind(int pos) {
super.bind(pos);
//Apply user information
mUserAccountImage.removeUser();
mUserName.setText("");
if(usersInfo.containsKey(getAt(pos).getUser_id())){
UserInfo info = usersInfo.get(getAt(pos).getUser_id());
mUserAccountImage.setUser(info);
mUserName.setText(info.getDisplayFullName());
}
if(pos < 2)
setUserInfoVisibility(true);
else
if(getAt(pos).getUser_id() == getAt(pos-1).getUser_id())
setUserInfoVisibility(false);
}
} }
} }

View File

@ -9,6 +9,8 @@ import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -31,7 +33,6 @@ import org.communiquons.android.comunic.client.data.models.ConversationsInfo;
import org.communiquons.android.comunic.client.data.models.UserInfo; import org.communiquons.android.comunic.client.data.models.UserInfo;
import org.communiquons.android.comunic.client.data.runnables.ConversationRefreshRunnable; import org.communiquons.android.comunic.client.data.runnables.ConversationRefreshRunnable;
import org.communiquons.android.comunic.client.data.utils.AccountUtils; import org.communiquons.android.comunic.client.data.utils.AccountUtils;
import org.communiquons.android.comunic.client.ui.activities.MainActivity;
import org.communiquons.android.comunic.client.ui.adapters.ConversationMessageAdapter; import org.communiquons.android.comunic.client.ui.adapters.ConversationMessageAdapter;
import org.communiquons.android.comunic.client.ui.listeners.OnScrollChangeDetectListener; import org.communiquons.android.comunic.client.ui.listeners.OnScrollChangeDetectListener;
import org.communiquons.android.comunic.client.ui.utils.BitmapUtils; import org.communiquons.android.comunic.client.ui.utils.BitmapUtils;
@ -114,7 +115,7 @@ public class ConversationFragment extends Fragment
/** /**
* Conversation message listView * Conversation message listView
*/ */
private ScrollListView convMessListView; private RecyclerView convMessRecyclerView;
/** /**
* Conversation messages helper * Conversation messages helper
@ -224,7 +225,7 @@ public class ConversationFragment extends Fragment
display_not_msg_notice(false); display_not_msg_notice(false);
//Conversation messages listView //Conversation messages listView
convMessListView = view.findViewById(R.id.fragment_conversation_messageslist); convMessRecyclerView = view.findViewById(R.id.fragment_conversation_messageslist);
//Need user ID //Need user ID
int userID = new AccountUtils(getActivity()).get_current_user_id(); int userID = new AccountUtils(getActivity()).get_current_user_id();
@ -234,7 +235,8 @@ public class ConversationFragment extends Fragment
messagesList, userID, users); messagesList, userID, users);
//Apply adapter //Apply adapter
convMessListView.setAdapter(convMessAdapter); convMessRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
convMessRecyclerView.setAdapter(convMessAdapter);
//Get new messages input fields //Get new messages input fields
new_message_content = view.findViewById(R.id.fragment_conversation_newmessage_content); new_message_content = view.findViewById(R.id.fragment_conversation_newmessage_content);
@ -285,7 +287,7 @@ public class ConversationFragment extends Fragment
//Set a listener to detect when the user reaches the top of the conversation //Set a listener to detect when the user reaches the top of the conversation
convMessListView.setOnScrollChangeDetectListener(this); //convMessRecyclerView.setOnScrollChangeDetectListener(this);
} }
@Override @Override
@ -407,9 +409,9 @@ public class ConversationFragment extends Fragment
} }
/** /**
* This method is called when we get informations about users * This method is called when we get information about users
* *
* @param info Informations about the user * @param info Information about the user
*/ */
public void onGotUserInfo(@Nullable ArrayMap<Integer, UserInfo> info ){ public void onGotUserInfo(@Nullable ArrayMap<Integer, UserInfo> info ){

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- View background color -->
<solid
android:color="@color/conversation_user_messages_background" >
</solid>
<!-- The radius makes the corners rounded -->
<corners
android:radius="20dp">
</corners>
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- View background color -->
<solid
android:color="@color/conversation_otheruser_messages_background" >
</solid>
<!-- The radius makes the corners rounded -->
<corners
android:radius="20dp">
</corners>
</shape>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape
android:shape="rectangle" >
<solid android:color="#3949ab" >
</solid>
<corners android:radius="5dp" >
</corners>
</shape>
</item>
<item>
<shape
android:shape="rectangle" >
<solid android:color="@color/conversation_user_messages_background">
</solid>
<corners android:radius="5dp" >
</corners>
</shape>
</item>
</selector>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape
android:shape="rectangle" >
<solid android:color="#C0C0C0" >
</solid>
<corners android:radius="5dp" >
</corners>
</shape>
</item>
<item>
<shape
android:shape="rectangle" >
<solid android:color="@color/conversation_otheruser_messages_background">
</solid>
<corners android:radius="5dp" >
</corners>
</shape>
</item>
</selector>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp">
<org.communiquons.android.comunic.client.ui.views.WebUserAccountImage
android:id="@+id/account_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/default_account_image"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:id="@+id/user_name"
tools:text="John Doe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
app:layout_constraintLeft_toRightOf="@+id/account_image"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="4dp" />
<TextView
android:id="@+id/message_body"
tools:text="Hello man, how are you?"
android:background="@drawable/conversation_message_otheruser_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="240dp"
android:padding="8dp"
android:textColor="@color/conversation_otheruser_messages_textColor"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/user_name"
app:layout_constraintLeft_toRightOf="@+id/account_image"
android:layout_marginStart="8dp" />
<!---<TextView
android:id="@+id/text_message_time"
tools:text="5min"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
app:layout_constraintLeft_toRightOf="@+id/message_body"
android:layout_marginLeft="4dp"
app:layout_constraintBottom_toBottomOf="@+id/message_body" />-->
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp">
<TextView
android:id="@+id/message_body"
tools:text="Hello, hello!"
android:background="@drawable/conversation_message_currentuser_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="240dp"
android:padding="8dp"
android:textColor="#ffffff"
android:layout_marginEnd="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--<TextView
android:id="@+id/text_message_time"
android:text="11:40"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
android:layout_marginRight="4dp"
app:layout_constraintBottom_toBottomOf="@+id/message_body"
app:layout_constraintRight_toLeftOf="@+id/message_body" />-->
</android.support.constraint.ConstraintLayout>

View File

@ -27,7 +27,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<!-- Messages --> <!-- Messages -->
<org.communiquons.android.comunic.client.ui.views.ScrollListView <android.support.v7.widget.RecyclerView
android:id="@+id/fragment_conversation_messageslist" android:id="@+id/fragment_conversation_messageslist"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingEnd="5dp"
android:paddingStart="5dp"
android:paddingTop="5dp">
<TextView
android:id="@+id/fragment_conversation_message_item_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="User name" />
<LinearLayout
android:id="@+id/fragment_conversation_message_item_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp"
android:background="@drawable/fragment_conversation_message_otheruser_bg">
<org.communiquons.android.comunic.client.ui.views.WebUserAccountImage
android:id="@+id/fragment_conversation_message_item_left_account_image"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginEnd="5dp"
android:layout_gravity="center"
android:contentDescription="@string/user_image_description"
android:src="@drawable/default_account_image"/>
<TextView
android:id="@+id/fragment_conversation_message_item_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:padding="5dp"
android:textColor="@color/conversation_otheruser_messages_textColor"
tools:text="A message"/>
<org.communiquons.android.comunic.client.ui.views.EnlargeableWebImageView
android:id="@+id/fragment_conversation_message_item_messageimage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:contentDescription="@string/fragment_conversation_message_image"
android:scaleType="fitCenter"
tools:background="@android:color/black"
tools:layout_height="40dp"
tools:layout_width="40dp"/>
<org.communiquons.android.comunic.client.ui.views.WebUserAccountImage
android:id="@+id/fragment_conversation_message_item_right_account_image"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginStart="5dp"
android:layout_gravity="center"
android:contentDescription="@string/user_image_description"
android:src="@drawable/default_account_image"/>
</LinearLayout>
</LinearLayout>