diff --git a/CHANGES.md b/CHANGES.md index cd6db863c5..a5f2a24e12 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features: - Improvements: - - + - Add unread indent on room list (#485) Other changes: - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt index aae72dd41f..e4bf1bd32b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt @@ -29,10 +29,11 @@ data class RoomSummary( val topic: String = "", val avatarUrl: String = "", val isDirect: Boolean = false, - val latestEvent: TimelineEvent? = null, + val latestPreviewableEvent: TimelineEvent? = null, val otherMemberIds: List = emptyList(), val notificationCount: Int = 0, val highlightCount: Int = 0, + val hasUnreadMessages: Boolean = false, val tags: List = emptyList(), val membership: Membership = Membership.NONE, val versioningState: VersioningState = VersioningState.NONE diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt index 38d3e69589..625f81de86 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ObjectSigner.kt @@ -20,7 +20,7 @@ import im.vector.matrix.android.api.auth.data.Credentials import javax.inject.Inject internal class ObjectSigner @Inject constructor(private val credentials: Credentials, - private val olmDevice: MXOlmDevice) { + private val olmDevice: MXOlmDevice) { /** * Sign Object diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt index 840a66c543..f929859d76 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt @@ -27,14 +27,14 @@ import java.util.* import javax.inject.Inject internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val olmDevice: MXOlmDevice, - private val cryptoStore: IMXCryptoStore, - private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) { + private val cryptoStore: IMXCryptoStore, + private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) { /** * Try to make sure we have established olm sessions for the given users. * @param users a list of user ids. */ - suspend fun handle(users: List) : MXUsersDevicesMap { + suspend fun handle(users: List): MXUsersDevicesMap { Timber.v("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users") val devicesByUser = HashMap>() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt index 7fc39312e1..d5c41769ef 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt @@ -23,8 +23,8 @@ import timber.log.Timber import javax.inject.Inject internal class SetDeviceVerificationAction @Inject constructor(private val cryptoStore: IMXCryptoStore, - private val credentials: Credentials, - private val keysBackup: KeysBackup) { + private val credentials: Credentials, + private val keysBackup: KeysBackup) { fun handle(verificationStatus: Int, deviceId: String, userId: String) { val device = cryptoStore.getUserDevice(deviceId, userId) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt index eb8df7b9f8..11c43649e9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt @@ -28,14 +28,14 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal class MXMegolmDecryptionFactory @Inject constructor(private val credentials: Credentials, - private val olmDevice: MXOlmDevice, - private val deviceListManager: DeviceListManager, - private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager, - private val messageEncrypter: MessageEncrypter, - private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction, - private val cryptoStore: IMXCryptoStore, - private val sendToDeviceTask: SendToDeviceTask, - private val coroutineDispatchers: MatrixCoroutineDispatchers) { + private val olmDevice: MXOlmDevice, + private val deviceListManager: DeviceListManager, + private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager, + private val messageEncrypter: MessageEncrypter, + private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction, + private val cryptoStore: IMXCryptoStore, + private val sendToDeviceTask: SendToDeviceTask, + private val coroutineDispatchers: MatrixCoroutineDispatchers) { fun create(): MXMegolmDecryption { return MXMegolmDecryption( diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt index 3ec51226af..8cb738807f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt @@ -26,8 +26,8 @@ import java.util.UUID import javax.inject.Inject internal class RoomSummaryMapper @Inject constructor( - val cryptoService: CryptoService, - val timelineEventMapper: TimelineEventMapper + private val cryptoService: CryptoService, + private val timelineEventMapper: TimelineEventMapper ) { fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary { @@ -35,7 +35,7 @@ internal class RoomSummaryMapper @Inject constructor( RoomTag(it.tagName, it.tagOrder) } - val latestEvent = roomSummaryEntity.latestEvent?.let { + val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let { timelineEventMapper.map(it) } if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) { @@ -43,26 +43,28 @@ internal class RoomSummaryMapper @Inject constructor( //for now decrypt sync try { val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString()) - latestEvent.root.mxDecryptionResult = OlmDecryptionResult( - payload = result.clearEvent, - senderKey = result.senderCurve25519Key, - keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, - forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain - ) + latestEvent.root.mxDecryptionResult = OlmDecryptionResult( + payload = result.clearEvent, + senderKey = result.senderCurve25519Key, + keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, + forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain + ) } catch (e: MXCryptoError) { } } + return RoomSummary( roomId = roomSummaryEntity.roomId, displayName = roomSummaryEntity.displayName ?: "", topic = roomSummaryEntity.topic ?: "", avatarUrl = roomSummaryEntity.avatarUrl ?: "", isDirect = roomSummaryEntity.isDirect, - latestEvent = latestEvent, + latestPreviewableEvent = latestEvent, otherMemberIds = roomSummaryEntity.otherMemberIds.toList(), highlightCount = roomSummaryEntity.highlightCount, notificationCount = roomSummaryEntity.notificationCount, + hasUnreadMessages = roomSummaryEntity.hasUnreadMessages, tags = tags, membership = roomSummaryEntity.membership, versioningState = roomSummaryEntity.versioningState diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt index 6fe81f4cdd..95308d367e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt @@ -26,7 +26,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var displayName: String? = "", var avatarUrl: String? = "", var topic: String? = "", - var latestEvent: TimelineEventEntity? = null, + var latestPreviewableEvent: TimelineEventEntity? = null, var heroes: RealmList = RealmList(), var joinedMembersCount: Int? = 0, var invitedMembersCount: Int? = 0, @@ -35,6 +35,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var otherMemberIds: RealmList = RealmList(), var notificationCount: Int = 0, var highlightCount: Int = 0, + var hasUnreadMessages: Boolean = false, var tags: RealmList = RealmList() ) : RealmObject() { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt new file mode 100644 index 0000000000..82ab72db26 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt @@ -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 +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt index 306b8a91e6..5c344a0b11 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt @@ -24,7 +24,7 @@ import timber.log.Timber import javax.inject.Inject @MatrixScope -internal class UserAgentHolder @Inject constructor(val context: Context) { +internal class UserAgentHolder @Inject constructor(private val context: Context) { var userAgent: String = "" private set diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt index dda8b9322f..a8814771cf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt @@ -16,6 +16,7 @@ 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.session.events.model.EventType 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.RoomSummaryEntity 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.prev 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, 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 private val PREVIEWABLE_TYPES = listOf( @@ -63,8 +66,7 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C membership: Membership? = null, roomSummary: RoomSyncSummary? = null, unreadNotifications: RoomSyncUnreadNotifications? = null) { - val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) if (roomSummary != null) { if (roomSummary.heroes.isNotEmpty()) { @@ -85,9 +87,13 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C 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() + 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) .queryRoomMembersEvent() .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.avatarUrl = roomAvatarResolver.resolve(roomId) roomSummaryEntity.topic = lastTopicEvent?.content.toModel()?.topic - roomSummaryEntity.latestEvent = latestEvent + roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent roomSummaryEntity.otherMemberIds.clear() roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) - } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt index 505b958911..11dfee5f81 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt @@ -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.internal.database.RealmLiveData 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.query.find -import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom +import im.vector.matrix.android.internal.database.query.isEventRead import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.task.TaskExecutor 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 { - var isEventRead = false - 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 + return isEventRead(monarchy, credentials.userId, roomId, eventId) } override fun getEventReadReceiptsLive(eventId: String): LiveData> { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt index 41c9cca507..4fa365bb66 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt @@ -101,6 +101,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI ?: return@writeAsync roomSummary.notificationCount = 0 roomSummary.highlightCount = 0 + roomSummary.hasUnreadMessages = false } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt index e4f48d35a4..efd099e9f9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultGetContextOfEventTask.kt @@ -32,8 +32,8 @@ internal interface GetContextOfEventTask : Task() { +class KeysBackupSettingsRecyclerViewController @Inject constructor(private val stringProvider: StringProvider, + private val session: Session) : TypedEpoxyController() { var listener: Listener? = null diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt index 83e6361252..fa10850590 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt @@ -54,7 +54,7 @@ import kotlin.collections.HashMap */ @Singleton -class KeyRequestHandler @Inject constructor(val context: Context) +class KeyRequestHandler @Inject constructor(private val context: Context) : RoomKeysRequestListener, SasVerificationService.SasVerificationListener { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt index e138eb9ea4..98bd8d34ed 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -29,7 +29,7 @@ import javax.inject.Singleton * Listens to the VerificationManager and add a new notification when an incoming request is detected. */ @Singleton -class IncomingVerificationRequestHandler @Inject constructor(val context: Context) : SasVerificationService.SasVerificationListener { +class IncomingVerificationRequestHandler @Inject constructor(private val context: Context) : SasVerificationService.SasVerificationListener { private var session: Session? = null diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 1cd8cc4a41..8ec133c642 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -658,7 +658,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro private fun observeSummaryState() { asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> if (summary.membership == Membership.INVITE) { - summary.latestEvent?.root?.senderId?.let { senderId -> + summary.latestPreviewableEvent?.root?.senderId?.let { senderId -> session.getUser(senderId) }?.also { setState { copy(asyncInviter = Success(it)) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/ChronologicalRoomComparator.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/ChronologicalRoomComparator.kt index c4a1633bed..d25198f56a 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/ChronologicalRoomComparator.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/ChronologicalRoomComparator.kt @@ -25,14 +25,14 @@ class ChronologicalRoomComparator @Inject constructor() : Comparator() { @EpoxyAttribute lateinit var title: CharSequence @EpoxyAttribute var expanded: Boolean = false - @EpoxyAttribute var unreadCount: Int = 0 + @EpoxyAttribute var unreadNotificationCount: Int = 0 @EpoxyAttribute var showHighlighted: Boolean = false @EpoxyAttribute var listener: (() -> Unit)? = null @@ -42,7 +42,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel() { val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also { 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.text = title holder.rootView.setOnClickListener { listener?.invoke() } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt index 03bedbc7b5..42e3a3db85 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt @@ -101,7 +101,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri id(titleRes) title(stringProvider.getString(titleRes).toUpperCase()) expanded(isExpanded) - unreadCount(unreadCount) + unreadNotificationCount(unreadCount) showHighlighted(showHighlighted) listener { mutateExpandedState() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt index 72f5b973fb..2ee1f30645 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItem.kt @@ -16,9 +16,11 @@ package im.vector.riotx.features.home.room.list +import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotx.R @@ -36,7 +38,8 @@ abstract class RoomSummaryItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var lastFormattedEvent: CharSequence @EpoxyAttribute lateinit var lastEventTime: CharSequence @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 listener: (() -> Unit)? = null @@ -47,13 +50,15 @@ abstract class RoomSummaryItem : VectorEpoxyModel() { holder.titleView.text = roomName holder.lastEventTimeView.text = lastEventTime 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) } class Holder : VectorEpoxyHolder() { val titleView by bind(R.id.roomNameView) val unreadCounterBadgeView by bind(R.id.roomUnreadCounterBadgeView) + val unreadIndentIndicator by bind(R.id.roomUnreadIndicator) val lastEventView by bind(R.id.roomLastEventView) val lastEventTimeView by bind(R.id.roomLastEventTimeView) val avatarImageView by bind(R.id.roomAvatarImageView) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt index 38f15974f3..015e54b368 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryItemFactory.kt @@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.riotx.R +import im.vector.riotx.core.date.VectorDateFormatter import im.vector.riotx.core.epoxy.VectorEpoxyModel import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.core.resources.ColorProvider @@ -29,7 +30,6 @@ import im.vector.riotx.core.resources.DateProvider import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter -import im.vector.riotx.core.date.VectorDateFormatter import im.vector.riotx.features.home.room.detail.timeline.helper.senderName import me.gujun.android.span.span import javax.inject.Inject @@ -59,9 +59,9 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte rejectingErrorRoomsIds: Set, listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> { val secondLine = if (roomSummary.isDirect) { - roomSummary.latestEvent?.root?.senderId + roomSummary.latestPreviewableEvent?.root?.senderId } else { - roomSummary.latestEvent?.root?.senderId?.let { + roomSummary.latestPreviewableEvent?.root?.senderId?.let { stringProvider.getString(R.string.invited_by, it) } } @@ -88,13 +88,13 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte var latestFormattedEvent: CharSequence = "" var latestEventTime: CharSequence = "" - val latestEvent = roomSummary.latestEvent + val latestEvent = roomSummary.latestPreviewableEvent if (latestEvent != null) { val date = latestEvent.root.localDateTime() val currentDate = DateProvider.currentLocalDateTime() val isSameDay = date.toLocalDate() == currentDate.toLocalDate() latestFormattedEvent = if (latestEvent.root.isEncrypted() - && latestEvent.root.mxDecryptionResult == null) { + && latestEvent.root.mxDecryptionResult == null) { stringProvider.getString(R.string.encrypted_message) } else if (latestEvent.root.getClearType() == EventType.MESSAGE) { val senderName = latestEvent.senderName() ?: latestEvent.root.senderId @@ -131,7 +131,8 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte .roomName(roomSummary.displayName) .avatarUrl(roomSummary.avatarUrl) .showHighlighted(showHighlighted) - .unreadCount(unreadCount) + .unreadNotificationCount(unreadCount) + .hasUnreadMessage(roomSummary.hasUnreadMessages) .listener { listener?.onRoomSelected(roomSummary) } } diff --git a/vector/src/main/java/im/vector/riotx/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/riotx/features/html/EventHtmlRenderer.kt index 476a70e7a4..fcd2c011ee 100644 --- a/vector/src/main/java/im/vector/riotx/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/riotx/features/html/EventHtmlRenderer.kt @@ -40,7 +40,7 @@ import javax.inject.Singleton @Singleton class EventHtmlRenderer @Inject constructor(context: Context, - val avatarRenderer: AvatarRenderer, + avatarRenderer: AvatarRenderer, sessionHolder: ActiveSessionHolder) { private val markwon = Markwon.builder(context) .usePlugin(MatrixPlugin.create(GlideApp.with(context), context, avatarRenderer, sessionHolder)) diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/BitmapLoader.kt b/vector/src/main/java/im/vector/riotx/features/notifications/BitmapLoader.kt index c3a74bd9c3..fbef196c53 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/BitmapLoader.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/BitmapLoader.kt @@ -26,7 +26,7 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class BitmapLoader @Inject constructor(val context: Context) { +class BitmapLoader @Inject constructor(private val context: Context) { /** * Avatar Url -> Bitmap diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/IconLoader.kt b/vector/src/main/java/im/vector/riotx/features/notifications/IconLoader.kt index 0c4477f41f..dccae42279 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/IconLoader.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/IconLoader.kt @@ -28,7 +28,7 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class IconLoader @Inject constructor(val context: Context) { +class IconLoader @Inject constructor(private val context: Context) { /** * Avatar Url -> IconCompat diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsController.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsController.kt index 47a7722e9d..9502370219 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsController.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsController.kt @@ -33,7 +33,7 @@ import javax.inject.Inject class PublicRoomsController @Inject constructor(private val stringProvider: StringProvider, private val avatarRenderer: AvatarRenderer, - private val errorFormatter: ErrorFormatter) : TypedEpoxyController() { + private val errorFormatter: ErrorFormatter) : TypedEpoxyController() { var callback: Callback? = null diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomController.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomController.kt index ad58c0ce26..7559606315 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomController.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomController.kt @@ -31,7 +31,7 @@ import im.vector.riotx.features.form.formSwitchItem import javax.inject.Inject class CreateRoomController @Inject constructor(private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter + private val errorFormatter: ErrorFormatter ) : TypedEpoxyController() { var listener: Listener? = null diff --git a/vector/src/main/res/layout/item_room.xml b/vector/src/main/res/layout/item_room.xml index b110e20082..7eb2083ecb 100644 --- a/vector/src/main/res/layout/item_room.xml +++ b/vector/src/main/res/layout/item_room.xml @@ -10,12 +10,22 @@ android:focusable="true" android:foreground="?attr/selectableItemBackground"> + +