From 1dbb02a80d2e1a2d2a3539048ddc0840743a55e4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 8 Aug 2019 17:51:06 +0200 Subject: [PATCH] Read receipts: create custom view to use it wherever we want easily --- .../riotx/core/ui/views/ReadReceiptsView.kt | 77 +++++++++++++++++++ .../timeline/factory/NoticeItemFactory.kt | 13 +--- .../detail/timeline/item/AbsMessageItem.kt | 38 +-------- .../room/detail/timeline/item/NoticeItem.kt | 3 + .../res/layout/item_timeline_event_base.xml | 59 +------------- .../item_timeline_event_base_noinfo.xml | 9 +++ .../main/res/layout/view_read_receipts.xml | 57 ++++++++++++-- vector/src/main/res/values/styles_riot.xml | 1 + 8 files changed, 153 insertions(+), 104 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/core/ui/views/ReadReceiptsView.kt diff --git a/vector/src/main/java/im/vector/riotx/core/ui/views/ReadReceiptsView.kt b/vector/src/main/java/im/vector/riotx/core/ui/views/ReadReceiptsView.kt new file mode 100644 index 0000000000..12d5861477 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/core/ui/views/ReadReceiptsView.kt @@ -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 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, 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 + } + + } + +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt index 52771ad6e9..b1cb540786 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt index 1462e842d9..51d2ce92fa 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -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 : BaseEventItem() { @EpoxyAttribute @@ -125,28 +124,7 @@ abstract class AbsMessageItem : BaseEventItem() { 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 : BaseEventItem() { val avatarImageView by bind(R.id.messageAvatarImageView) val memberNameView by bind(R.id.messageMemberNameView) val timeView by bind(R.id.messageTimeView) - val readReceiptsView by bind(R.id.readReceiptsView) - val receiptAvatar1 by bind(R.id.message_avatar_receipt_1) - val receiptAvatar2 by bind(R.id.message_avatar_receipt_2) - val receiptAvatar3 by bind(R.id.message_avatar_receipt_3) - val receiptAvatar4 by bind(R.id.message_avatar_receipt_4) - val receiptAvatar5 by bind(R.id.message_avatar_receipt_5) - val receiptMoreView by bind(R.id.message_more_than_expected) - val receiptAvatars: List by lazy { - listOf(receiptAvatar1, receiptAvatar2, receiptAvatar3, receiptAvatar4, receiptAvatar5) - } - + val readReceiptsView by bind(R.id.readReceiptsView) var reactionWrapper: ViewGroup? = null var reactionFlowHelper: Flow? = null } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt index 2879073f18..b18a665d6b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/NoticeItem.kt @@ -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() { 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() { class Holder : BaseHolder(STUB_ID) { val avatarImageView by bind(R.id.itemNoticeAvatarView) val noticeTextView by bind(R.id.itemNoticeTextView) + val readReceiptsView by bind(R.id.readReceiptsView) } companion object { diff --git a/vector/src/main/res/layout/item_timeline_event_base.xml b/vector/src/main/res/layout/item_timeline_event_base.xml index a8b81606e1..2f0be78f38 100644 --- a/vector/src/main/res/layout/item_timeline_event_base.xml +++ b/vector/src/main/res/layout/item_timeline_event_base.xml @@ -123,65 +123,14 @@ - - - - - - - - - - - - - - - + app:layout_constraintEnd_toEndOf="parent" /> \ No newline at end of file diff --git a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml index 004428eccf..7726839902 100644 --- a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml +++ b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml @@ -52,5 +52,14 @@ android:layout="@layout/item_timeline_event_merged_header_stub" tools:ignore="MissingConstraints" /> + + \ No newline at end of file diff --git a/vector/src/main/res/layout/view_read_receipts.xml b/vector/src/main/res/layout/view_read_receipts.xml index 4f65a82a60..e3cbc6ba06 100644 --- a/vector/src/main/res/layout/view_read_receipts.xml +++ b/vector/src/main/res/layout/view_read_receipts.xml @@ -1,11 +1,58 @@ - + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:parentTag="android.widget.LinearLayout"> + + - + + + + + + + + + diff --git a/vector/src/main/res/values/styles_riot.xml b/vector/src/main/res/values/styles_riot.xml index eaf0530b96..80f5148a6e 100644 --- a/vector/src/main/res/values/styles_riot.xml +++ b/vector/src/main/res/values/styles_riot.xml @@ -297,6 +297,7 @@