forked from GitHub-Mirror/riotX-android
Read receipts: create custom view to use it wherever we want easily
This commit is contained in:
parent
825463d9cd
commit
1dbb02a80d
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.riotx.core.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.ButterKnife
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import kotlinx.android.synthetic.main.view_read_receipts.view.*
|
||||
|
||||
private const val MAX_RECEIPT_DISPLAYED = 5
|
||||
|
||||
class ReadReceiptsView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val receiptAvatars: List<ImageView> by lazy {
|
||||
listOf(receiptAvatar1, receiptAvatar2, receiptAvatar3, receiptAvatar4, receiptAvatar5)
|
||||
}
|
||||
|
||||
init {
|
||||
setupView()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_read_receipts, this)
|
||||
ButterKnife.bind(this)
|
||||
}
|
||||
|
||||
fun render(readReceipts: List<ReadReceiptData>, avatarRenderer: AvatarRenderer) {
|
||||
if (readReceipts.isNotEmpty()) {
|
||||
isVisible = true
|
||||
for (index in 0 until MAX_RECEIPT_DISPLAYED) {
|
||||
val receiptData = readReceipts.getOrNull(index)
|
||||
if (receiptData == null) {
|
||||
receiptAvatars[index].isVisible = false
|
||||
} else {
|
||||
receiptAvatars[index].isVisible = true
|
||||
avatarRenderer.render(receiptData.avatarUrl, receiptData.userId, receiptData.displayName, receiptAvatars[index])
|
||||
}
|
||||
}
|
||||
if (readReceipts.size > MAX_RECEIPT_DISPLAYED) {
|
||||
receiptMore.isVisible = true
|
||||
receiptMore.text = context.getString(
|
||||
R.string.x_plus, readReceipts.size - MAX_RECEIPT_DISPLAYED
|
||||
)
|
||||
} else {
|
||||
receiptMore.isVisible = false
|
||||
}
|
||||
} else {
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -25,23 +25,18 @@ import im.vector.riotx.features.home.room.detail.timeline.helper.senderName
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_
|
||||
import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter,
|
||||
private val avatarRenderer: AvatarRenderer) {
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val informationDataFactory: MessageInformationDataFactory) {
|
||||
|
||||
fun create(event: TimelineEvent,
|
||||
highlight: Boolean,
|
||||
callback: TimelineEventController.Callback?): NoticeItem? {
|
||||
val formattedText = eventFormatter.format(event) ?: return null
|
||||
val informationData = MessageInformationData(
|
||||
eventId = event.root.eventId ?: "?",
|
||||
senderId = event.root.senderId ?: "",
|
||||
sendState = event.root.sendState,
|
||||
avatarUrl = event.senderAvatar(),
|
||||
memberName = event.senderName(),
|
||||
showInformation = false
|
||||
)
|
||||
val informationData = informationDataFactory.create(event, null)
|
||||
|
||||
return NoticeItem_()
|
||||
.avatarRenderer(avatarRenderer)
|
||||
|
@ -33,6 +33,7 @@ import com.airbnb.epoxy.EpoxyAttribute
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.ui.views.ReadReceiptsView
|
||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||
import im.vector.riotx.core.utils.DimensionUtils.dpToPx
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
@ -40,8 +41,6 @@ import im.vector.riotx.features.home.room.detail.timeline.TimelineEventControlle
|
||||
import im.vector.riotx.features.reactions.widget.ReactionButton
|
||||
import im.vector.riotx.features.ui.getMessageTextColor
|
||||
|
||||
private const val MAX_RECEIPT_DISPLAYED = 5
|
||||
|
||||
abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
@ -125,28 +124,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
holder.memberNameView.setOnLongClickListener(null)
|
||||
}
|
||||
|
||||
if (informationData.readReceipts.isNotEmpty()) {
|
||||
holder.readReceiptsView.isVisible = true
|
||||
for (index in 0 until MAX_RECEIPT_DISPLAYED) {
|
||||
val receiptData = informationData.readReceipts.getOrNull(index)
|
||||
if (receiptData == null) {
|
||||
holder.receiptAvatars[index].isVisible = false
|
||||
} else {
|
||||
holder.receiptAvatars[index].isVisible = true
|
||||
avatarRenderer.render(receiptData.avatarUrl, receiptData.userId, receiptData.displayName, holder.receiptAvatars[index])
|
||||
}
|
||||
}
|
||||
if (informationData.readReceipts.size > MAX_RECEIPT_DISPLAYED) {
|
||||
holder.receiptMoreView.isVisible = true
|
||||
holder.receiptMoreView.text = holder.view.context.getString(
|
||||
R.string.x_plus, informationData.readReceipts.size - MAX_RECEIPT_DISPLAYED
|
||||
)
|
||||
} else {
|
||||
holder.receiptMoreView.isVisible = false
|
||||
}
|
||||
} else {
|
||||
holder.readReceiptsView.isVisible = false
|
||||
}
|
||||
holder.readReceiptsView.render(informationData.readReceipts, avatarRenderer)
|
||||
|
||||
if (!shouldShowReactionAtBottom() || informationData.orderedReactionList.isNullOrEmpty()) {
|
||||
holder.reactionWrapper?.isVisible = false
|
||||
@ -198,17 +176,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
||||
val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
||||
val timeView by bind<TextView>(R.id.messageTimeView)
|
||||
val readReceiptsView by bind<ViewGroup>(R.id.readReceiptsView)
|
||||
val receiptAvatar1 by bind<ImageView>(R.id.message_avatar_receipt_1)
|
||||
val receiptAvatar2 by bind<ImageView>(R.id.message_avatar_receipt_2)
|
||||
val receiptAvatar3 by bind<ImageView>(R.id.message_avatar_receipt_3)
|
||||
val receiptAvatar4 by bind<ImageView>(R.id.message_avatar_receipt_4)
|
||||
val receiptAvatar5 by bind<ImageView>(R.id.message_avatar_receipt_5)
|
||||
val receiptMoreView by bind<TextView>(R.id.message_more_than_expected)
|
||||
val receiptAvatars: List<ImageView> by lazy {
|
||||
listOf(receiptAvatar1, receiptAvatar2, receiptAvatar3, receiptAvatar4, receiptAvatar5)
|
||||
}
|
||||
|
||||
val readReceiptsView by bind<ReadReceiptsView>(R.id.readReceiptsView)
|
||||
var reactionWrapper: ViewGroup? = null
|
||||
var reactionFlowHelper: Flow? = null
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.ui.views.ReadReceiptsView
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||
|
||||
@ -55,6 +56,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
||||
holder.avatarImageView
|
||||
)
|
||||
holder.view.setOnLongClickListener(longClickListener)
|
||||
holder.readReceiptsView.render(informationData.readReceipts, avatarRenderer)
|
||||
}
|
||||
|
||||
override fun getViewType() = STUB_ID
|
||||
@ -62,6 +64,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
||||
class Holder : BaseHolder(STUB_ID) {
|
||||
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
|
||||
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
|
||||
val readReceiptsView by bind<ReadReceiptsView>(R.id.readReceiptsView)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -123,65 +123,14 @@
|
||||
</ViewStub>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
<im.vector.riotx.core.ui.views.ReadReceiptsView
|
||||
android:id="@+id/readReceiptsView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message_more_than_expected"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
tools:text="999+" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/message_avatar_receipt_5"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/message_avatar_receipt_4"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/message_avatar_receipt_3"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/message_avatar_receipt_2"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/message_avatar_receipt_1"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
</LinearLayout>
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -52,5 +52,14 @@
|
||||
android:layout="@layout/item_timeline_event_merged_header_stub"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<im.vector.riotx.core.ui.views.ReadReceiptsView
|
||||
android:id="@+id/readReceiptsView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,11 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/readReceiptsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/receiptMore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
tools:text="999+" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar5"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
</RelativeLayout>
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar4"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar3"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar2"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar1"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
</merge>
|
||||
|
@ -297,6 +297,7 @@
|
||||
|
||||
<style name="TimelineContentStubNoInfoLayoutParams" parent="TimelineContentStubBaseParams">
|
||||
<item name="layout_constraintTop_toTopOf">parent</item>
|
||||
<item name="layout_constraintBottom_toTopOf">@id/readReceiptsView</item>
|
||||
</style>
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user