Add unread indent on room list

This commit is contained in:
Benoit Marty 2019-09-19 12:42:01 +02:00 committed by Benoit Marty
parent ffa8b7e73a
commit b4a13f9504
16 changed files with 107 additions and 52 deletions

View File

@ -5,7 +5,7 @@ Features:
- -
Improvements: Improvements:
- - Add unread indent on room list (#485)
Other changes: Other changes:
- -

View File

@ -29,10 +29,11 @@ data class RoomSummary(
val topic: String = "", val topic: String = "",
val avatarUrl: String = "", val avatarUrl: String = "",
val isDirect: Boolean = false, val isDirect: Boolean = false,
val latestEvent: TimelineEvent? = null, val latestPreviewableEvent: TimelineEvent? = null,
val otherMemberIds: List<String> = emptyList(), val otherMemberIds: List<String> = emptyList(),
val notificationCount: Int = 0, val notificationCount: Int = 0,
val highlightCount: Int = 0, val highlightCount: Int = 0,
val hasUnreadMessages: Boolean = false,
val tags: List<RoomTag> = emptyList(), val tags: List<RoomTag> = emptyList(),
val membership: Membership = Membership.NONE, val membership: Membership = Membership.NONE,
val versioningState: VersioningState = VersioningState.NONE val versioningState: VersioningState = VersioningState.NONE

View File

@ -35,7 +35,7 @@ internal class RoomSummaryMapper @Inject constructor(
RoomTag(it.tagName, it.tagOrder) RoomTag(it.tagName, it.tagOrder)
} }
val latestEvent = roomSummaryEntity.latestEvent?.let { val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
timelineEventMapper.map(it) timelineEventMapper.map(it)
} }
if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) { if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) {
@ -43,26 +43,28 @@ internal class RoomSummaryMapper @Inject constructor(
//for now decrypt sync //for now decrypt sync
try { try {
val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString()) val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString())
latestEvent.root.mxDecryptionResult = OlmDecryptionResult( latestEvent.root.mxDecryptionResult = OlmDecryptionResult(
payload = result.clearEvent, payload = result.clearEvent,
senderKey = result.senderCurve25519Key, senderKey = result.senderCurve25519Key,
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
) )
} catch (e: MXCryptoError) { } catch (e: MXCryptoError) {
} }
} }
return RoomSummary( return RoomSummary(
roomId = roomSummaryEntity.roomId, roomId = roomSummaryEntity.roomId,
displayName = roomSummaryEntity.displayName ?: "", displayName = roomSummaryEntity.displayName ?: "",
topic = roomSummaryEntity.topic ?: "", topic = roomSummaryEntity.topic ?: "",
avatarUrl = roomSummaryEntity.avatarUrl ?: "", avatarUrl = roomSummaryEntity.avatarUrl ?: "",
isDirect = roomSummaryEntity.isDirect, isDirect = roomSummaryEntity.isDirect,
latestEvent = latestEvent, latestPreviewableEvent = latestEvent,
otherMemberIds = roomSummaryEntity.otherMemberIds.toList(), otherMemberIds = roomSummaryEntity.otherMemberIds.toList(),
highlightCount = roomSummaryEntity.highlightCount, highlightCount = roomSummaryEntity.highlightCount,
notificationCount = roomSummaryEntity.notificationCount, notificationCount = roomSummaryEntity.notificationCount,
hasUnreadMessages = roomSummaryEntity.hasUnreadMessages,
tags = tags, tags = tags,
membership = roomSummaryEntity.membership, membership = roomSummaryEntity.membership,
versioningState = roomSummaryEntity.versioningState versioningState = roomSummaryEntity.versioningState

View File

@ -26,7 +26,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
var displayName: String? = "", var displayName: String? = "",
var avatarUrl: String? = "", var avatarUrl: String? = "",
var topic: String? = "", var topic: String? = "",
var latestEvent: TimelineEventEntity? = null, var latestPreviewableEvent: TimelineEventEntity? = null,
var heroes: RealmList<String> = RealmList(), var heroes: RealmList<String> = RealmList(),
var joinedMembersCount: Int? = 0, var joinedMembersCount: Int? = 0,
var invitedMembersCount: Int? = 0, var invitedMembersCount: Int? = 0,
@ -35,6 +35,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
var otherMemberIds: RealmList<String> = RealmList(), var otherMemberIds: RealmList<String> = RealmList(),
var notificationCount: Int = 0, var notificationCount: Int = 0,
var highlightCount: Int = 0, var highlightCount: Int = 0,
var hasUnreadMessages: Boolean = false,
var tags: RealmList<RoomTagEntity> = RealmList() var tags: RealmList<RoomTagEntity> = RealmList()
) : RealmObject() { ) : RealmObject() {

View File

@ -0,0 +1,42 @@
/*
* 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.matrix.android.internal.database.query
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
internal fun isEventRead(monarchy: Monarchy,
userId: String?,
roomId: String?,
eventId: String?): Boolean {
if (userId.isNullOrBlank() || roomId.isNullOrBlank() || eventId.isNullOrBlank()) {
return false
}
var isEventRead = false
monarchy.doWithRealm { realm ->
val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() ?: return@doWithRealm
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) ?: return@doWithRealm
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex ?: Int.MIN_VALUE
val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex ?: Int.MAX_VALUE
isEventRead = eventToCheckIndex <= readReceiptIndex
}
return isEventRead
}

View File

@ -16,6 +16,7 @@
package im.vector.matrix.android.internal.session.room package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.events.model.toModel
@ -26,6 +27,7 @@ import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntityFields import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.isEventRead
import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.latestEvent
import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.prev
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
@ -39,7 +41,8 @@ import javax.inject.Inject
internal class RoomSummaryUpdater @Inject constructor(private val credentials: Credentials, internal class RoomSummaryUpdater @Inject constructor(private val credentials: Credentials,
private val roomDisplayNameResolver: RoomDisplayNameResolver, private val roomDisplayNameResolver: RoomDisplayNameResolver,
private val roomAvatarResolver: RoomAvatarResolver) { private val roomAvatarResolver: RoomAvatarResolver,
private val monarchy: Monarchy) {
// TODO: maybe allow user of SDK to give that list // TODO: maybe allow user of SDK to give that list
private val PREVIEWABLE_TYPES = listOf( private val PREVIEWABLE_TYPES = listOf(
@ -63,8 +66,7 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
membership: Membership? = null, membership: Membership? = null,
roomSummary: RoomSyncSummary? = null, roomSummary: RoomSyncSummary? = null,
unreadNotifications: RoomSyncUnreadNotifications? = null) { unreadNotifications: RoomSyncUnreadNotifications? = null) {
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
?: realm.createObject(roomId)
if (roomSummary != null) { if (roomSummary != null) {
if (roomSummary.heroes.isNotEmpty()) { if (roomSummary.heroes.isNotEmpty()) {
@ -85,9 +87,13 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
roomSummaryEntity.membership = membership roomSummaryEntity.membership = membership
} }
val latestEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES) val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES)
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain() val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
//avoid this call if we are sure there are unread events
|| !isEventRead(monarchy, credentials.userId, roomId, latestPreviewableEvent?.eventId)
val otherRoomMembers = RoomMembers(realm, roomId) val otherRoomMembers = RoomMembers(realm, roomId)
.queryRoomMembersEvent() .queryRoomMembersEvent()
.notEqualTo(EventEntityFields.STATE_KEY, credentials.userId) .notEqualTo(EventEntityFields.STATE_KEY, credentials.userId)
@ -98,9 +104,8 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString() roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId) roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
roomSummaryEntity.latestEvent = latestEvent roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
roomSummaryEntity.otherMemberIds.clear() roomSummaryEntity.otherMemberIds.clear()
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
} }
} }

View File

@ -27,11 +27,8 @@ import im.vector.matrix.android.api.session.room.model.ReadReceipt
import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.internal.database.RealmLiveData import im.vector.matrix.android.internal.database.RealmLiveData
import im.vector.matrix.android.internal.database.mapper.ReadReceiptsSummaryMapper import im.vector.matrix.android.internal.database.mapper.ReadReceiptsSummaryMapper
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity
import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.isEventRead
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
@ -78,19 +75,7 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private
override fun isEventRead(eventId: String): Boolean { override fun isEventRead(eventId: String): Boolean {
var isEventRead = false return isEventRead(monarchy, credentials.userId, roomId, eventId)
monarchy.doWithRealm {
val readReceipt = ReadReceiptEntity.where(it, roomId, credentials.userId).findFirst()
?: return@doWithRealm
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
?: return@doWithRealm
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex
?: Int.MIN_VALUE
val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex
?: Int.MAX_VALUE
isEventRead = eventToCheckIndex <= readReceiptIndex
}
return isEventRead
} }
override fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> { override fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> {

View File

@ -101,6 +101,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
?: return@writeAsync ?: return@writeAsync
roomSummary.notificationCount = 0 roomSummary.notificationCount = 0
roomSummary.highlightCount = 0 roomSummary.highlightCount = 0
roomSummary.hasUnreadMessages = false
} }
} }
} }

View File

@ -113,12 +113,12 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
private fun handleJoinedRoom(realm: Realm, private fun handleJoinedRoom(realm: Realm,
roomId: String, roomId: String,
roomSync: RoomSync, roomSync: RoomSync,
isInitalSync: Boolean): RoomEntity { isInitialSync: Boolean): RoomEntity {
Timber.v("Handle join sync for room $roomId") Timber.v("Handle join sync for room $roomId")
if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) { if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) {
handleEphemeral(realm, roomId, roomSync.ephemeral, isInitalSync) handleEphemeral(realm, roomId, roomSync.ephemeral, isInitialSync)
} }
if (roomSync.accountData != null && roomSync.accountData.events.isNullOrEmpty().not()) { if (roomSync.accountData != null && roomSync.accountData.events.isNullOrEmpty().not()) {

View File

@ -658,7 +658,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
private fun observeSummaryState() { private fun observeSummaryState() {
asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary ->
if (summary.membership == Membership.INVITE) { if (summary.membership == Membership.INVITE) {
summary.latestEvent?.root?.senderId?.let { senderId -> summary.latestPreviewableEvent?.root?.senderId?.let { senderId ->
session.getUser(senderId) session.getUser(senderId)
}?.also { }?.also {
setState { copy(asyncInviter = Success(it)) } setState { copy(asyncInviter = Success(it)) }

View File

@ -25,14 +25,14 @@ class ChronologicalRoomComparator @Inject constructor() : Comparator<RoomSummary
var rightTimestamp = 0L var rightTimestamp = 0L
var leftTimestamp = 0L var leftTimestamp = 0L
if (null != leftRoomSummary) { if (null != leftRoomSummary) {
leftTimestamp = leftRoomSummary.latestEvent?.root?.originServerTs ?: 0 leftTimestamp = leftRoomSummary.latestPreviewableEvent?.root?.originServerTs ?: 0
} }
if (null != rightRoomSummary) { if (null != rightRoomSummary) {
rightTimestamp = rightRoomSummary.latestEvent?.root?.originServerTs ?: 0 rightTimestamp = rightRoomSummary.latestPreviewableEvent?.root?.originServerTs ?: 0
} }
return if (rightRoomSummary?.latestEvent?.root == null) { return if (rightRoomSummary?.latestPreviewableEvent?.root == null) {
-1 -1
} else if (leftRoomSummary?.latestEvent?.root == null) { } else if (leftRoomSummary?.latestPreviewableEvent?.root == null) {
1 1
} else { } else {
val deltaTimestamp = rightTimestamp - leftTimestamp val deltaTimestamp = rightTimestamp - leftTimestamp

View File

@ -32,7 +32,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
@EpoxyAttribute lateinit var title: CharSequence @EpoxyAttribute lateinit var title: CharSequence
@EpoxyAttribute var expanded: Boolean = false @EpoxyAttribute var expanded: Boolean = false
@EpoxyAttribute var unreadCount: Int = 0 @EpoxyAttribute var unreadNotificationCount: Int = 0
@EpoxyAttribute var showHighlighted: Boolean = false @EpoxyAttribute var showHighlighted: Boolean = false
@EpoxyAttribute var listener: (() -> Unit)? = null @EpoxyAttribute var listener: (() -> Unit)? = null
@ -42,7 +42,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also { val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also {
DrawableCompat.setTint(it, tintColor) DrawableCompat.setTint(it, tintColor)
} }
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted)) holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
holder.titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null) holder.titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null)
holder.titleView.text = title holder.titleView.text = title
holder.rootView.setOnClickListener { listener?.invoke() } holder.rootView.setOnClickListener { listener?.invoke() }

View File

@ -101,7 +101,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
id(titleRes) id(titleRes)
title(stringProvider.getString(titleRes).toUpperCase()) title(stringProvider.getString(titleRes).toUpperCase())
expanded(isExpanded) expanded(isExpanded)
unreadCount(unreadCount) unreadNotificationCount(unreadCount)
showHighlighted(showHighlighted) showHighlighted(showHighlighted)
listener { listener {
mutateExpandedState() mutateExpandedState()

View File

@ -16,9 +16,11 @@
package im.vector.riotx.features.home.room.list package im.vector.riotx.features.home.room.list
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R import im.vector.riotx.R
@ -36,7 +38,8 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
@EpoxyAttribute lateinit var lastFormattedEvent: CharSequence @EpoxyAttribute lateinit var lastFormattedEvent: CharSequence
@EpoxyAttribute lateinit var lastEventTime: CharSequence @EpoxyAttribute lateinit var lastEventTime: CharSequence
@EpoxyAttribute var avatarUrl: String? = null @EpoxyAttribute var avatarUrl: String? = null
@EpoxyAttribute var unreadCount: Int = 0 @EpoxyAttribute var unreadNotificationCount: Int = 0
@EpoxyAttribute var hasUnreadMessage: Boolean = false
@EpoxyAttribute var showHighlighted: Boolean = false @EpoxyAttribute var showHighlighted: Boolean = false
@EpoxyAttribute var listener: (() -> Unit)? = null @EpoxyAttribute var listener: (() -> Unit)? = null
@ -47,13 +50,15 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
holder.titleView.text = roomName holder.titleView.text = roomName
holder.lastEventTimeView.text = lastEventTime holder.lastEventTimeView.text = lastEventTime
holder.lastEventView.text = lastFormattedEvent holder.lastEventView.text = lastFormattedEvent
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted)) holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView) avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
} }
class Holder : VectorEpoxyHolder() { class Holder : VectorEpoxyHolder() {
val titleView by bind<TextView>(R.id.roomNameView) val titleView by bind<TextView>(R.id.roomNameView)
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView) val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
val unreadIndentIndicator by bind<View>(R.id.roomUnreadIndicator)
val lastEventView by bind<TextView>(R.id.roomLastEventView) val lastEventView by bind<TextView>(R.id.roomLastEventView)
val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView) val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView)
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView) val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)

View File

@ -16,6 +16,7 @@
package im.vector.riotx.features.home.room.list package im.vector.riotx.features.home.room.list
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.Membership
@ -38,7 +39,8 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
private val dateFormatter: VectorDateFormatter, private val dateFormatter: VectorDateFormatter,
private val colorProvider: ColorProvider, private val colorProvider: ColorProvider,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val avatarRenderer: AvatarRenderer) { private val avatarRenderer: AvatarRenderer,
private val session: Session) {
fun create(roomSummary: RoomSummary, fun create(roomSummary: RoomSummary,
joiningRoomsIds: Set<String>, joiningRoomsIds: Set<String>,
@ -59,9 +61,9 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
rejectingErrorRoomsIds: Set<String>, rejectingErrorRoomsIds: Set<String>,
listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> { listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
val secondLine = if (roomSummary.isDirect) { val secondLine = if (roomSummary.isDirect) {
roomSummary.latestEvent?.root?.senderId roomSummary.latestPreviewableEvent?.root?.senderId
} else { } else {
roomSummary.latestEvent?.root?.senderId?.let { roomSummary.latestPreviewableEvent?.root?.senderId?.let {
stringProvider.getString(R.string.invited_by, it) stringProvider.getString(R.string.invited_by, it)
} }
} }
@ -88,7 +90,7 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
var latestFormattedEvent: CharSequence = "" var latestFormattedEvent: CharSequence = ""
var latestEventTime: CharSequence = "" var latestEventTime: CharSequence = ""
val latestEvent = roomSummary.latestEvent val latestEvent = roomSummary.latestPreviewableEvent
if (latestEvent != null) { if (latestEvent != null) {
val date = latestEvent.root.localDateTime() val date = latestEvent.root.localDateTime()
val currentDate = DateProvider.currentLocalDateTime() val currentDate = DateProvider.currentLocalDateTime()
@ -131,7 +133,8 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
.roomName(roomSummary.displayName) .roomName(roomSummary.displayName)
.avatarUrl(roomSummary.avatarUrl) .avatarUrl(roomSummary.avatarUrl)
.showHighlighted(showHighlighted) .showHighlighted(showHighlighted)
.unreadCount(unreadCount) .unreadNotificationCount(unreadCount)
.hasUnreadMessage(roomSummary.hasUnreadMessages)
.listener { listener?.onRoomSelected(roomSummary) } .listener { listener?.onRoomSelected(roomSummary) }
} }

View File

@ -10,12 +10,22 @@
android:focusable="true" android:focusable="true"
android:foreground="?attr/selectableItemBackground"> android:foreground="?attr/selectableItemBackground">
<View
android:id="@+id/roomUnreadIndicator"
android:layout_width="4dp"
android:layout_height="0dp"
android:background="?attr/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"
tools:visibility="visible"/>
<ImageView <ImageView
android:id="@+id/roomAvatarImageView" android:id="@+id/roomAvatarImageView"
android:layout_width="56dp" android:layout_width="56dp"
android:layout_height="56dp" android:layout_height="56dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"