Home | History | Annotate | Download | only in chat
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.example.android.wearable.wear.messaging.chat;
     17 
     18 import android.content.Context;
     19 import android.graphics.Bitmap;
     20 import android.support.percent.PercentRelativeLayout;
     21 import android.support.v4.content.ContextCompat;
     22 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
     23 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
     24 import android.support.v7.util.SortedList;
     25 import android.support.v7.widget.RecyclerView;
     26 import android.support.v7.widget.util.SortedListAdapterCallback;
     27 import android.support.wearable.view.WearableRecyclerView;
     28 import android.view.LayoutInflater;
     29 import android.view.View;
     30 import android.view.ViewGroup;
     31 import android.widget.ImageView;
     32 import android.widget.TextView;
     33 import com.bumptech.glide.Glide;
     34 import com.bumptech.glide.request.animation.GlideAnimation;
     35 import com.bumptech.glide.request.target.SimpleTarget;
     36 import com.example.android.wearable.wear.messaging.R;
     37 import com.example.android.wearable.wear.messaging.model.Chat;
     38 import com.example.android.wearable.wear.messaging.model.Message;
     39 import com.example.android.wearable.wear.messaging.model.Profile;
     40 import java.util.Calendar;
     41 import java.util.Collection;
     42 import java.util.Locale;
     43 
     44 /**
     45  * Adapter for chat view. Uses a SortedList of Messages by sent time. Determines if the senderId is
     46  * the current user and chooses the corresponding senderId layout.
     47  *
     48  * <p>The adapter will tint the background of a message so that there is an alternating visual
     49  * difference to make reading messages easier by providing better visual clues
     50  */
     51 class ChatAdapter extends WearableRecyclerView.Adapter<ChatAdapter.MessageViewHolder> {
     52 
     53     private final Context mContext;
     54     private final Chat mChat;
     55     private final Profile mUser;
     56     private final SortedList<Message> mMessages;
     57 
     58     private final int mBlue30;
     59     private final int mBlue15;
     60 
     61     ChatAdapter(Context context, Chat chat, Profile user) {
     62         this.mContext = context;
     63         this.mChat = chat;
     64         this.mUser = user;
     65 
     66         mBlue15 = ContextCompat.getColor(mContext, R.color.blue_15);
     67         mBlue30 = ContextCompat.getColor(mContext, R.color.blue_30);
     68 
     69         mMessages =
     70                 new SortedList<>(
     71                         Message.class,
     72                         new SortedListAdapterCallback<Message>(this) {
     73                             @Override
     74                             public int compare(Message m1, Message m2) {
     75                                 return (int) (m1.getSentTime() - m2.getSentTime());
     76                             }
     77 
     78                             @Override
     79                             public boolean areContentsTheSame(Message oldItem, Message newItem) {
     80                                 return oldItem.equals(newItem);
     81                             }
     82 
     83                             @Override
     84                             public boolean areItemsTheSame(Message item1, Message item2) {
     85                                 return item1.getId().equals(item2.getId());
     86                             }
     87                         });
     88     }
     89 
     90     @Override
     91     public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     92         return new MessageViewHolder(
     93                 LayoutInflater.from(mContext).inflate(R.layout.chat_message, parent, false));
     94     }
     95 
     96     @Override
     97     public void onBindViewHolder(final MessageViewHolder holder, int position) {
     98         Message message = mMessages.get(position);
     99         Profile sender = mChat.getParticipants().get(mMessages.get(position).getSenderId());
    100         if (sender == null) {
    101             sender = mUser;
    102         }
    103 
    104         Glide.with(mContext)
    105                 .load(sender.getProfileImageSource())
    106                 .asBitmap()
    107                 .placeholder(R.drawable.ic_face_white_24dp)
    108                 .into(
    109                         new SimpleTarget<Bitmap>(100, 100) {
    110                             @Override
    111                             public void onResourceReady(
    112                                     Bitmap resource,
    113                                     GlideAnimation<? super Bitmap> glideAnimation) {
    114                                 RoundedBitmapDrawable circularBitmapDrawable =
    115                                         RoundedBitmapDrawableFactory.create(
    116                                                 mContext.getResources(), resource);
    117                                 circularBitmapDrawable.setCircular(true);
    118                                 holder.profileImage.setImageDrawable(circularBitmapDrawable);
    119                             }
    120                         });
    121 
    122         // Convert to just the first name of the sender or short hand it if the sender is you.
    123         String name;
    124         if (isUser(sender.getId())) {
    125             name = "You";
    126         } else {
    127             name = sender.getName().split("\\s")[0];
    128         }
    129         holder.textName.setText(name);
    130 
    131         // Odd messages have a darker background.
    132         if (position % 2 == 0) {
    133             holder.parentLayout.setBackgroundColor(mBlue15);
    134         } else {
    135             holder.parentLayout.setBackgroundColor(mBlue30);
    136         }
    137 
    138         holder.textContent.setText(message.getText());
    139         holder.textTime.setText(millisToDateTime(message.getSentTime()));
    140     }
    141 
    142     @Override
    143     public int getItemCount() {
    144         return mMessages.size();
    145     }
    146 
    147     public void addMessage(Message message) {
    148         mMessages.add(message);
    149     }
    150 
    151     public void addMessages(Collection<Message> messages) {
    152         // There is a bug with {@link SortedList#addAll} that will add new items to the end
    153         // of the list allowing duplications in the view which is unexpected behavior
    154         // https://code.google.com/p/android/issues/detail?id=201618
    155         // so we will mimic the add all operation (add individually but execute in one batch)
    156         mMessages.beginBatchedUpdates();
    157         for (Message message : messages) {
    158             mMessages.add(message);
    159         }
    160         mMessages.endBatchedUpdates();
    161     }
    162 
    163     /**
    164      * Converts time since epoch to Month Date Time.
    165      *
    166      * @param time since epoch
    167      * @return String formatted in Month Date HH:MM
    168      */
    169     private String millisToDateTime(long time) {
    170         Calendar cal = Calendar.getInstance();
    171         cal.setTimeInMillis(time);
    172         String month = cal.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US);
    173         int date = cal.get(Calendar.DAY_OF_MONTH);
    174         int hour = cal.get(Calendar.HOUR_OF_DAY);
    175         int minute = cal.get(Calendar.MINUTE);
    176 
    177         return month + " " + date + " " + hour + ":" + String.format(Locale.US, "%02d", minute);
    178     }
    179 
    180     private boolean isUser(String id) {
    181         return id.equals(mUser.getId());
    182     }
    183 
    184     /** View holder to encapsulate the details of a chat message. */
    185     class MessageViewHolder extends RecyclerView.ViewHolder {
    186 
    187         final ViewGroup parentLayout;
    188         final TextView textContent;
    189         final TextView textName;
    190         final ImageView profileImage;
    191         final TextView textTime;
    192 
    193         public MessageViewHolder(View itemView) {
    194             super(itemView);
    195 
    196             parentLayout = (PercentRelativeLayout) itemView.findViewById(R.id.layout_container);
    197             textContent = (TextView) itemView.findViewById(R.id.text_content);
    198             textName = (TextView) itemView.findViewById(R.id.text_name);
    199             textTime = (TextView) itemView.findViewById(R.id.text_time);
    200             profileImage = (ImageView) itemView.findViewById(R.id.profile_img);
    201         }
    202     }
    203 }
    204