Add hasFailedSending in RoomSummary and a small warning icon on room list

This commit is contained in:
ganfra 2020-07-22 15:21:48 +02:00
parent d7558902f7
commit aa5ae45a0c
10 changed files with 51 additions and 11 deletions

View file

@ -53,7 +53,8 @@ data class RoomSummary constructor(
val typingUsers: List<SenderInfo>,
val inviterId: String? = null,
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null,
val hasFailedSending: Boolean = false
) {
val isVersioned: Boolean

View file

@ -62,7 +62,8 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
encryptionEventTs = roomSummaryEntity.encryptionEventTs,
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
inviterId = roomSummaryEntity.inviterId
inviterId = roomSummaryEntity.inviterId,
hasFailedSending = roomSummaryEntity.hasFailedSending
)
}
}

View file

@ -51,7 +51,8 @@ internal open class RoomSummaryEntity(
var isEncrypted: Boolean = false,
var encryptionEventTs: Long? = 0,
var roomEncryptionTrustLevelStr: String? = null,
var inviterId: String? = null
var inviterId: String? = null,
var hasFailedSending: Boolean = false
) : RealmObject() {
private var membershipStr: String = Membership.NONE.name

View file

@ -93,9 +93,12 @@ internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(realm: Re
roomId: String,
sendStates: List<SendState>)
: RealmResults<TimelineEventEntity> {
val sendStatesStr = sendStates.map { it.name }.toTypedArray()
return realm.where<TimelineEventEntity>()
.equalTo(TimelineEventEntityFields.ROOM_ID, roomId)
.`in`(TimelineEventEntityFields.ROOT.SEND_STATE_STR, sendStatesStr)
return whereRoomId(realm, roomId)
.filterSendStates(sendStates)
.findAll()
}
internal fun RealmQuery<TimelineEventEntity>.filterSendStates(sendStates: List<SendState>): RealmQuery<TimelineEventEntity> {
val sendStatesStr = sendStates.map { it.name }.toTypedArray()
return `in`(TimelineEventEntityFields.ROOT.SEND_STATE_STR, sendStatesStr)
}

View file

@ -82,7 +82,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
realm.insert(eventInsertEntity)
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return@writeAsync
roomEntity.sendingTimelineEvents.add(0, timelineEventEntity)
roomSummaryUpdater.update(realm, roomId)
roomSummaryUpdater.updateSendingInformation(realm, roomId)
}
}
@ -96,6 +96,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
} else {
sendingEventEntity.sendState = sendState
}
roomSummaryUpdater.update(realm, sendingEventEntity.roomId)
}
}
}
@ -115,6 +116,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
monarchy.awaitTransaction { realm ->
TimelineEventEntity.where(realm, roomId = roomId, eventId = localEcho.root.eventId ?: "").findFirst()?.deleteFromRealm()
EventEntity.where(realm, eventId = localEcho.root.eventId ?: "").findFirst()?.deleteFromRealm()
roomSummaryUpdater.updateSendingInformation(realm, roomId)
}
}
@ -125,6 +127,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
.forEach {
it.root?.sendState = SendState.UNSENT
}
roomSummaryUpdater.updateSendingInformation(realm, roomId)
}
}
@ -134,6 +137,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
timelineEvents.forEach {
it.root?.sendState = sendState
}
roomSummaryUpdater.updateSendingInformation(realm, roomId)
}
}

View file

@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.room.model.RoomAliasesContent
import im.vector.matrix.android.api.session.room.model.RoomCanonicalAliasContent
import im.vector.matrix.android.api.session.room.model.RoomNameContent
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.crypto.crosssigning.SessionToCryptoRoomMembersUpdate
import im.vector.matrix.android.internal.database.mapper.ContentMapper
@ -34,6 +35,7 @@ import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityFields
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.findAllInRoomWithSendStates
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.getOrNull
import im.vector.matrix.android.internal.database.query.isEventRead
@ -145,6 +147,7 @@ internal class RoomSummaryUpdater @Inject constructor(
} else if (roomSummaryEntity.membership != Membership.INVITE) {
roomSummaryEntity.inviterId = null
}
roomSummaryEntity.updateHasFailedSending()
if (latestPreviewableEvent?.root?.type == EventType.ENCRYPTED && latestPreviewableEvent.root?.decryptionResultJson == null) {
Timber.v("Should decrypt ${latestPreviewableEvent.eventId}")
@ -167,6 +170,17 @@ internal class RoomSummaryUpdater @Inject constructor(
}
}
private fun RoomSummaryEntity.updateHasFailedSending() {
hasFailedSending = TimelineEventEntity.findAllInRoomWithSendStates(realm, roomId, SendState.HAS_FAILED_STATES).isNotEmpty()
}
fun updateSendingInformation(realm: Realm, roomId: String) {
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
roomSummaryEntity.updateHasFailedSending()
roomSummaryEntity.latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true,
filterTypes = PREVIEWABLE_TYPES, filterContentRelation = true)
}
fun updateShieldTrust(realm: Realm,
roomId: String,
trust: RoomEncryptionTrustLevel?) {

View file

@ -30,6 +30,7 @@ import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.MatrixPatterns
import im.vector.matrix.android.api.NoOpMatrixCallback
import im.vector.matrix.android.api.extensions.orFalse
import im.vector.matrix.android.api.query.QueryStringValue
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.MXCryptoError
@ -415,11 +416,11 @@ class RoomDetailViewModel @AssistedInject constructor(
R.id.clear_message_queue ->
// For now always disable when not in developer mode, worker cancellation is not working properly
timeline.pendingEventCount() > 0 && vectorPreferences.developerMode()
R.id.resend_all -> timeline.failedToDeliverEventCount() > 0
R.id.clear_all -> timeline.failedToDeliverEventCount() > 0
R.id.resend_all -> state.asyncRoomSummary()?.hasFailedSending == true
R.id.clear_all -> state.asyncRoomSummary()?.hasFailedSending == true
R.id.open_matrix_apps -> true
R.id.voice_call,
R.id.video_call -> room.canStartCall() && webRtcPeerConnectionManager.currentCall == null
R.id.video_call -> state.asyncRoomSummary()?.canStartCall == true && webRtcPeerConnectionManager.currentCall == null
R.id.hangup_call -> webRtcPeerConnectionManager.currentCall != null
else -> false
}

View file

@ -52,6 +52,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
@EpoxyAttribute var hasUnreadMessage: Boolean = false
@EpoxyAttribute var hasDraft: Boolean = false
@EpoxyAttribute var showHighlighted: Boolean = false
@EpoxyAttribute var hasFailedSending: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemLongClickListener: View.OnLongClickListener? = null
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: View.OnClickListener? = null
@EpoxyAttribute var showSelected: Boolean = false
@ -72,6 +73,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.roomAvatarDecorationImageView.isVisible = encryptionTrustLevel != null
holder.roomAvatarDecorationImageView.setImageResource(encryptionTrustLevel.toImageRes())
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
renderSelection(holder, showSelected)
holder.typingView.setTextOrHide(typingMessage)
holder.lastEventView.isInvisible = holder.typingView.isVisible
@ -106,6 +108,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
val avatarCheckedImageView by bind<ImageView>(R.id.roomAvatarCheckedImageView)
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
val roomAvatarDecorationImageView by bind<ImageView>(R.id.roomAvatarDecorationImageView)
val roomAvatarFailSendingImageView by bind<ImageView>(R.id.roomAvatarFailSendingImageView)
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
}
}

View file

@ -109,6 +109,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
.lastFormattedEvent(latestFormattedEvent)
.showHighlighted(showHighlighted)
.showSelected(showSelected)
.hasFailedSending(roomSummary.hasFailedSending)
.unreadNotificationCount(unreadCount)
.hasUnreadMessage(roomSummary.hasUnreadMessages)
.hasDraft(roomSummary.userDrafts.isNotEmpty())

View file

@ -47,6 +47,17 @@
</FrameLayout>
<ImageView
android:id="@+id/roomAvatarFailSendingImageView"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintCircle="@id/roomAvatarContainer"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="30dp"
tools:ignore="MissingConstraints"
android:src="@drawable/ic_warning_small"
/>
<ImageView
android:id="@+id/roomAvatarDecorationImageView"
android:layout_width="24dp"