blob: fce4a8193eac6ba4bfff1ceaa541b80d5cd4d672 [file] [log] [blame]
/*
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.wearable.wear.messaging.chatlist;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.example.android.wearable.wear.messaging.R;
import com.example.android.wearable.wear.messaging.model.Chat;
import com.example.android.wearable.wear.messaging.model.Message;
import com.example.android.wearable.wear.messaging.model.Profile;
import java.util.Collection;
/**
* Adapter for list of chats.
*
* <p>If chat is empty, displays icon to start a new chat. Otherwise, activity displays the title of
* chat as first element followed by the rest of the conversation.
*
* <p>The RecyclerView holds the title so it can scroll off the screen as a user scrolls down the
* page.
*/
public class ChatListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "ChatListAdapter";
private static final int TYPE_ADD = 0;
private static final int TYPE_CONTENT = 1;
private static final int INDEX_OFFSET = 1;
private final Context mContext;
private final ChatAdapterListener mListener;
private final SortedList<Chat> mChats;
public ChatListAdapter(Context context, ChatAdapterListener listener) {
this.mContext = context;
this.mListener = listener;
mChats =
new SortedList<>(
Chat.class,
new SortedList.Callback<Chat>() {
// Descending list based on chat's last message time.
@Override
public int compare(Chat chat1, Chat chat2) {
Long diff =
(chat2.getLastMessage().getSentTime()
- chat1.getLastMessage().getSentTime());
return diff.intValue();
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position + INDEX_OFFSET, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position + INDEX_OFFSET, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(
fromPosition + INDEX_OFFSET, toPosition + INDEX_OFFSET);
}
@Override
public void onChanged(int position, int count) {
Log.d(
TAG,
String.format("Item changed %d", position + INDEX_OFFSET));
// Since position 0 is the title
notifyItemRangeChanged(position + INDEX_OFFSET, count);
}
@Override
public boolean areContentsTheSame(Chat oldItem, Chat newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(Chat item1, Chat item2) {
return item1.getId().equals(item2.getId());
}
});
}
/**
* Listens for actions that occur in the adapter; i.e., either the user wants a new chat started
* or they are opening an existing chat.
*/
public interface ChatAdapterListener {
void newChatSelected();
void openChat(Chat chat);
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_ADD;
}
return TYPE_CONTENT;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ADD) {
return new AddChatViewHolder(
LayoutInflater.from(parent.getContext())
.inflate(R.layout.action_new_chat, parent, false));
} else {
return new ChatItemViewHolder(
LayoutInflater.from(parent.getContext())
.inflate(R.layout.chat_list_item, parent, false));
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof AddChatViewHolder) {
((AddChatViewHolder) holder)
.row.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "New chat has been selected");
mListener.newChatSelected();
}
});
} else if (holder instanceof ChatItemViewHolder) {
final ChatItemViewHolder chatItemViewHolder = (ChatItemViewHolder) holder;
//need to account for having the add button before the list of mChats
final Chat chat = mChats.get(position - INDEX_OFFSET);
chatItemViewHolder.row.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.openChat(chat);
}
});
chatItemViewHolder.alias.setText(chat.getAlias());
Message lastMessage = chat.getLastMessage();
if (lastMessage != null) {
Profile lastMessageSender;
if (chat.getParticipants().size() == 1) {
lastMessageSender = chat.getParticipants().values().iterator().next();
} else {
lastMessageSender = chat.getParticipants().get(lastMessage.getSenderId());
}
if (lastMessageSender == null) {
chatItemViewHolder.aliasImage.setImageResource(R.drawable.ic_face_white_24dp);
// Blank out any text that may be left after updating the view holder contents.
chatItemViewHolder.lastMessage.setText("");
} else {
String lastMessageText = lastMessage.getText();
String messageString = lastMessageSender.getName() + ": " + lastMessageText;
chatItemViewHolder.lastMessage.setText(messageString);
Glide.with(mContext)
.load(lastMessageSender.getProfileImageSource())
.asBitmap()
.placeholder(R.drawable.ic_face_white_24dp)
.into(
new SimpleTarget<Bitmap>(100, 100) {
@Override
public void onResourceReady(
Bitmap resource,
GlideAnimation<? super Bitmap> glideAnimation) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(
mContext.getResources(), resource);
circularBitmapDrawable.setCircular(true);
chatItemViewHolder.aliasImage.setImageDrawable(
circularBitmapDrawable);
}
});
}
}
// Show group icon if more than 1 participant
int numParticipants = chat.getParticipants().size();
if (numParticipants > 1) {
chatItemViewHolder.aliasImage.setImageResource(R.drawable.ic_group_white_48dp);
}
}
}
@Override
public int getItemCount() {
return mChats.size() + INDEX_OFFSET;
}
public void setChats(final Collection<Chat> chats) {
// There is a bug with {@link SortedList#addAll} that will add new items to the end
// of the list allowing duplications in the view which is unexpected behavior
// https://code.google.com/p/android/issues/detail?id=201618
// so we will mimic the add all operation (add individually but execute in one batch)
mChats.beginBatchedUpdates();
for (Chat chat : chats) {
mChats.add(chat);
}
mChats.endBatchedUpdates();
}
private class AddChatViewHolder extends RecyclerView.ViewHolder {
private final ViewGroup row;
AddChatViewHolder(View itemView) {
super(itemView);
row = (ViewGroup) itemView.findViewById(R.id.percent_layout);
}
}
private class ChatItemViewHolder extends RecyclerView.ViewHolder {
private ViewGroup row;
private final TextView alias;
private final ImageView aliasImage;
private final TextView lastMessage;
ChatItemViewHolder(View itemView) {
super(itemView);
row = (ViewGroup) itemView.findViewById(R.id.layout_chat_list_item);
alias = (TextView) itemView.findViewById(R.id.text_alias);
aliasImage = (ImageView) itemView.findViewById(R.id.profile);
lastMessage = (TextView) itemView.findViewById(R.id.text_last_message);
}
}
}