Merge pull request #1049 from vector-im/feature/fix_invites

Feature/fix invites
This commit is contained in:
Benoit Marty 2020-02-25 11:39:35 +01:00 committed by GitHub
commit 68400cce03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 76 additions and 49 deletions

View File

@ -19,6 +19,7 @@ Bugfix 🐛:
- Fix rotation of full-size image (#647)
- Fix joining rooms from directory via federation isn't working. (#808)
- Leaving a room creates a stuck "leaving room" loading screen. (#1041)
- Fix some invitation handling issues (#1013)
Translations 🗣:
-

View File

@ -20,7 +20,7 @@ import java.util.UUID
object LocalEcho {
private const val PREFIX = "local."
private const val PREFIX = "\$local."
fun isLocalEchoId(eventId: String) = eventId.startsWith(PREFIX)

View File

@ -45,7 +45,8 @@ data class RoomSummary constructor(
val versioningState: VersioningState = VersioningState.NONE,
val readMarkerId: String? = null,
val userDrafts: List<UserDraft> = emptyList(),
var isEncrypted: Boolean,
val isEncrypted: Boolean,
val inviterId: String? = null,
val typingRoomMemberIds: List<String> = emptyList(),
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
// TODO Plug it

View File

@ -32,7 +32,8 @@ internal object EventMapper {
val uds = if (event.unsignedData == null) null
else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(event.unsignedData)
val eventEntity = EventEntity()
eventEntity.eventId = event.eventId ?: ""
// TODO change this as we shouldn't use event everywhere
eventEntity.eventId = event.eventId ?: "$$roomId-${System.currentTimeMillis()}-${event.hashCode()}"
eventEntity.roomId = event.roomId ?: roomId
eventEntity.content = ContentMapper.map(event.content)
val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent

View File

@ -77,7 +77,8 @@ internal class RoomSummaryMapper @Inject constructor(
isEncrypted = roomSummaryEntity.isEncrypted,
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList(),
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
inviterId = roomSummaryEntity.inviterId
)
}
}

View File

@ -22,9 +22,8 @@ import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResu
import im.vector.matrix.android.internal.di.MoshiProvider
import io.realm.RealmObject
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
internal open class EventEntity(@PrimaryKey var eventId: String = "",
internal open class EventEntity(@Index var eventId: String = "",
@Index var roomId: String = "",
@Index var type: String = "",
var content: String? = null,

View File

@ -49,7 +49,8 @@ internal open class RoomSummaryEntity(
var flatAliases: String = "",
var isEncrypted: Boolean = false,
var typingUserIds: RealmList<String> = RealmList(),
var roomEncryptionTrustLevelStr: String? = null
var roomEncryptionTrustLevelStr: String? = null,
var inviterId: String? = null
) : RealmObject() {
private var membershipStr: String = Membership.NONE.name

View File

@ -23,6 +23,13 @@ import io.realm.RealmList
import io.realm.RealmQuery
import io.realm.kotlin.where
internal fun EventEntity.copyToRealmOrIgnore(realm: Realm): EventEntity {
return realm.where<EventEntity>()
.equalTo(EventEntityFields.EVENT_ID, eventId)
.equalTo(EventEntityFields.ROOM_ID, roomId)
.findFirst() ?: realm.copyToRealm(this)
}
internal fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<EventEntity> {
return realm.where<EventEntity>()
.equalTo(EventEntityFields.EVENT_ID, eventId)

View File

@ -81,7 +81,8 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummary: RoomSyncSummary? = null,
unreadNotifications: RoomSyncUnreadNotifications? = null,
updateMembers: Boolean = false,
ephemeralResult: RoomSyncHandler.EphemeralResult? = null) {
ephemeralResult: RoomSyncHandler.EphemeralResult? = null,
inviterId: String? = null) {
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
if (roomSummary != null) {
if (roomSummary.heroes.isNotEmpty()) {
@ -134,6 +135,12 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummaryEntity.typingUserIds.clear()
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty())
if (roomSummaryEntity.membership == Membership.INVITE && inviterId != null) {
roomSummaryEntity.inviterId = inviterId
} else if (roomSummaryEntity.membership != Membership.INVITE) {
roomSummaryEntity.inviterId = null
}
if (updateMembers) {
val otherRoomMembers = RoomMemberHelper(realm, roomId)
.queryRoomMembersEvent()

View File

@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.query.copyToRealmOrIgnore
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.network.executeRequest
@ -73,9 +74,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
if (roomMemberEvent.eventId == null || roomMemberEvent.stateKey == null) {
continue
}
val eventEntity = roomMemberEvent.toEntity(roomId, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
val eventEntity = roomMemberEvent.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
CurrentStateEventEntity.getOrCreate(realm, roomId, roomMemberEvent.stateKey, roomMemberEvent.type).apply {
eventId = roomMemberEvent.eventId
root = eventEntity

View File

@ -31,6 +31,7 @@ import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
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.copyToRealmOrIgnore
import im.vector.matrix.android.internal.database.query.create
import im.vector.matrix.android.internal.database.query.find
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
@ -199,9 +200,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
val stateEvents = receivedChunk.stateEvents
for (stateEvent in stateEvents) {
val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
currentChunk.addStateEvent(roomId, stateEventEntity, direction)
if (stateEvent.type == EventType.STATE_ROOM_MEMBER && stateEvent.stateKey != null) {
roomMemberContentsByUser[stateEvent.stateKey] = stateEvent.content.toModel<RoomMemberContent>()
@ -213,9 +212,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
continue
}
eventIds.add(event.eventId)
val eventEntity = event.toEntity(roomId, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
val eventEntity = event.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null) {
val contentToUse = if (direction == PaginationDirection.BACKWARDS) {
event.prevContent

View File

@ -32,6 +32,7 @@ import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.query.copyToRealmOrIgnore
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.getOrCreate
@ -93,7 +94,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
}
is HandlingStrategy.INVITED ->
handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_invited_rooms, 0.1f) {
handleInvitedRoom(realm, it.key, it.value, syncLocalTimeStampMillis)
handleInvitedRoom(realm, it.key, it.value)
}
is HandlingStrategy.LEFT -> {
@ -134,9 +135,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
if (event.eventId == null || event.stateKey == null) {
continue
}
val eventEntity = event.toEntity(roomId, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
val eventEntity = event.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply {
eventId = event.eventId
root = eventEntity
@ -177,19 +176,27 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
private fun handleInvitedRoom(realm: Realm,
roomId: String,
roomSync: InvitedRoomSync,
syncLocalTimestampMillis: Long): RoomEntity {
roomSync: InvitedRoomSync): RoomEntity {
Timber.v("Handle invited sync for room $roomId")
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
roomEntity.membership = Membership.INVITE
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
val chunkEntity = handleTimelineEvents(realm, roomId, roomEntity, roomSync.inviteState.events, syncLocalTimestampMillis = syncLocalTimestampMillis)
roomEntity.addOrUpdate(chunkEntity)
roomSync.inviteState.events.forEach {
if (it.stateKey == null) {
return@forEach
}
val eventEntity = it.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
CurrentStateEventEntity.getOrCreate(realm, roomId, it.stateKey, it.type).apply {
eventId = eventEntity.eventId
root = eventEntity
}
roomMemberEventHandler.handle(realm, roomId, it)
}
}
val hasRoomMember = roomSync.inviteState?.events?.firstOrNull {
val inviterEvent = roomSync.inviteState?.events?.lastOrNull {
it.type == EventType.STATE_ROOM_MEMBER
} != null
roomSummaryUpdater.update(realm, roomId, Membership.INVITE, updateMembers = hasRoomMember)
}
roomSummaryUpdater.update(realm, roomId, Membership.INVITE, updateMembers = true, inviterId = inviterEvent?.senderId)
return roomEntity
}
@ -197,7 +204,6 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
roomId: String,
roomSync: RoomSync): RoomEntity {
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
roomEntity.membership = Membership.LEAVE
roomEntity.chunks.deleteAllFromRealm()
roomSummaryUpdater.update(realm, roomId, Membership.LEAVE, roomSync.summary, roomSync.unreadNotifications)
@ -229,9 +235,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
}
eventIds.add(event.eventId)
val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it }
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).let {
realm.copyToRealmOrUpdate(it)
}
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm)
if (event.isStateEvent() && event.stateKey != null) {
CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply {
eventId = event.eventId

View File

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

View File

@ -101,7 +101,18 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
.observeOn(Schedulers.computation())
.map { buildRoomSummaries(it) }
.execute { async ->
copy(asyncFilteredRooms = async)
val invitedRooms = async()?.get(RoomCategory.INVITE)?.map { it.roomId }.orEmpty()
val remainingJoining = joiningRoomsIds.intersect(invitedRooms)
val remainingJoinErrors = joiningErrorRoomsIds.intersect(invitedRooms)
val remainingRejecting = rejectingRoomsIds.intersect(invitedRooms)
val remainingRejectErrors = rejectingErrorRoomsIds.intersect(invitedRooms)
copy(
asyncFilteredRooms = async,
joiningRoomsIds = remainingJoining,
joiningErrorRoomsIds = remainingJoinErrors,
rejectingRoomsIds = remainingRejecting,
rejectingErrorRoomsIds = remainingRejectErrors
)
}
}
@ -229,7 +240,6 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
else -> groupRooms.add(room)
}
}
return RoomSummaries().apply {
put(RoomCategory.INVITE, invites)
put(RoomCategory.FAVOURITE, favourites)

View File

@ -60,9 +60,9 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
rejectingErrorRoomsIds: Set<String>,
listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
val secondLine = if (roomSummary.isDirect) {
roomSummary.latestPreviewableEvent?.root?.senderId
roomSummary.inviterId
} else {
roomSummary.latestPreviewableEvent?.root?.senderId?.let {
roomSummary.inviterId?.let {
stringProvider.getString(R.string.invited_by, it)
}
}

View File

@ -51,20 +51,20 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
fun resolveEvent(event: Event/*, roomState: RoomState?, bingRule: PushRule?*/, session: Session): NotifiableEvent? {
val roomID = event.roomId ?: return null
val eventId = event.eventId ?: return null
if (event.getClearType() == EventType.STATE_ROOM_MEMBER) {
return resolveStateRoomEvent(event, session)
}
val timelineEvent = session.getRoom(roomID)?.getTimeLineEvent(eventId) ?: return null
when (event.getClearType()) {
EventType.MESSAGE -> {
EventType.MESSAGE -> {
return resolveMessageEvent(timelineEvent, session)
}
EventType.ENCRYPTED -> {
EventType.ENCRYPTED -> {
val messageEvent = resolveMessageEvent(timelineEvent, session)
messageEvent?.lockScreenVisibility = NotificationCompat.VISIBILITY_PRIVATE
return messageEvent
}
EventType.STATE_ROOM_MEMBER -> {
return resolveStateRoomEvent(event, session)
}
else -> {
else -> {
// If the event can be displayed, display it as is
Timber.w("NotifiableEventResolver Received an unsupported event matching a bing rule")
// TODO Better event text display

View File

@ -130,9 +130,9 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
fun onEventRedacted(eventId: String) {
synchronized(eventList) {
eventList.filter { it.eventId == eventId }.map { notifiableEvent ->
notifiableEvent.isRedacted = true
notifiableEvent.hasBeenDisplayed = false
eventList.find { it.eventId == eventId }?.apply {
isRedacted = true
hasBeenDisplayed = false
}
}
}
@ -182,7 +182,6 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
e is InviteNotifiableEvent && e.roomId == roomId
}
}
notificationUtils.cancelNotificationMessage(roomId, ROOM_INVITATION_NOTIFICATION_ID)
}

View File

@ -515,7 +515,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
val joinIntent = Intent(context, NotificationBroadcastReceiver::class.java)
joinIntent.action = JOIN_ACTION
joinIntent.data = Uri.parse("foobar://$roomId&$matrixId")
rejectIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
joinIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
val joinIntentPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(), joinIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
addAction(