1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.example.android.bubbles.ui.chat 17 18 import android.content.Context 19 import android.content.res.ColorStateList 20 import android.view.Gravity 21 import android.view.LayoutInflater 22 import android.view.ViewGroup 23 import android.widget.FrameLayout 24 import android.widget.TextView 25 import androidx.core.content.ContextCompat 26 import androidx.core.view.ViewCompat 27 import androidx.recyclerview.widget.DiffUtil 28 import androidx.recyclerview.widget.ListAdapter 29 import androidx.recyclerview.widget.RecyclerView 30 import com.example.android.bubbles.R 31 import com.example.android.bubbles.data.Message 32 33 class MessageAdapter( 34 context: Context, 35 private val onPhotoClicked: (photo: Int) -> Unit 36 ) : ListAdapter<Message, MessageViewHolder>(DIFF_CALLBACK) { 37 38 private val tint = object { 39 val incoming: ColorStateList = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.incoming)) 40 val outgoing: ColorStateList = ColorStateList.valueOf( 41 ContextCompat.getColor(context, R.color.outgoing) 42 ) 43 } 44 45 private val padding = object { 46 val vertical: Int = context.resources.getDimensionPixelSize(R.dimen.message_padding_vertical) 47 48 val horizontalShort: Int = context.resources.getDimensionPixelSize( 49 R.dimen.message_padding_horizontal_short 50 ) 51 52 val horizontalLong: Int = context.resources.getDimensionPixelSize( 53 R.dimen.message_padding_horizontal_long 54 ) 55 } 56 57 58 init { 59 setHasStableIds(true) 60 } 61 getItemIdnull62 override fun getItemId(position: Int): Long { 63 return getItem(position).id 64 } 65 onCreateViewHoldernull66 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder { 67 val holder = MessageViewHolder(parent) 68 holder.message.setOnClickListener { 69 val photo: Int? = it.getTag(R.id.tag_photo) as Int? 70 if (photo != null) { 71 onPhotoClicked(photo) 72 } 73 } 74 return holder 75 } 76 onBindViewHoldernull77 override fun onBindViewHolder(holder: MessageViewHolder, position: Int) { 78 val message = getItem(position) 79 val lp = holder.message.layoutParams as FrameLayout.LayoutParams 80 if (message.isIncoming) { 81 holder.message.run { 82 setBackgroundResource(R.drawable.message_incoming) 83 ViewCompat.setBackgroundTintList(this, tint.incoming) 84 setPadding( 85 padding.horizontalLong, padding.vertical, 86 padding.horizontalShort, padding.vertical 87 ) 88 layoutParams = lp.apply { 89 gravity = Gravity.START 90 } 91 if (message.photo != null) { 92 holder.message.setTag(R.id.tag_photo, message.photo) 93 setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, message.photo) 94 } else { 95 holder.message.setTag(R.id.tag_photo, null) 96 setCompoundDrawables(null, null, null, null) 97 } 98 } 99 } else { 100 holder.message.run { 101 setBackgroundResource(R.drawable.message_outgoing) 102 ViewCompat.setBackgroundTintList(this, tint.outgoing) 103 setPadding( 104 padding.horizontalShort, padding.vertical, 105 padding.horizontalLong, padding.vertical 106 ) 107 layoutParams = lp.apply { 108 gravity = Gravity.END 109 } 110 } 111 } 112 holder.message.text = message.text 113 } 114 } 115 116 private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Message>() { 117 areItemsTheSamenull118 override fun areItemsTheSame(oldItem: Message, newItem: Message): Boolean { 119 return oldItem.id == newItem.id 120 } 121 areContentsTheSamenull122 override fun areContentsTheSame(oldItem: Message, newItem: Message): Boolean { 123 return oldItem == newItem 124 } 125 126 } 127 128 class MessageViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder( 129 LayoutInflater.from(parent.context).inflate(R.layout.message_item, parent, false) 130 ) { 131 val message: TextView = itemView.findViewById(R.id.message) 132 } 133