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