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 rotation of full-size image (#647)
- Fix joining rooms from directory via federation isn't working. (#808) - Fix joining rooms from directory via federation isn't working. (#808)
- Leaving a room creates a stuck "leaving room" loading screen. (#1041) - Leaving a room creates a stuck "leaving room" loading screen. (#1041)
- Fix some invitation handling issues (#1013)
Translations 🗣: Translations 🗣:
- -

View File

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

View File

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

View File

@ -32,7 +32,8 @@ internal object EventMapper {
val uds = if (event.unsignedData == null) null val uds = if (event.unsignedData == null) null
else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(event.unsignedData) else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(event.unsignedData)
val eventEntity = EventEntity() 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.roomId = event.roomId ?: roomId
eventEntity.content = ContentMapper.map(event.content) eventEntity.content = ContentMapper.map(event.content)
val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent

View File

@ -77,7 +77,8 @@ internal class RoomSummaryMapper @Inject constructor(
isEncrypted = roomSummaryEntity.isEncrypted, isEncrypted = roomSummaryEntity.isEncrypted,
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList(), typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList(),
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex, 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 im.vector.matrix.android.internal.di.MoshiProvider
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Index 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 roomId: String = "",
@Index var type: String = "", @Index var type: String = "",
var content: String? = null, var content: String? = null,

View File

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

View File

@ -23,6 +23,13 @@ import io.realm.RealmList
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.kotlin.where 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> { internal fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<EventEntity> {
return realm.where<EventEntity>() return realm.where<EventEntity>()
.equalTo(EventEntityFields.EVENT_ID, eventId) .equalTo(EventEntityFields.EVENT_ID, eventId)

View File

@ -81,7 +81,8 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummary: RoomSyncSummary? = null, roomSummary: RoomSyncSummary? = null,
unreadNotifications: RoomSyncUnreadNotifications? = null, unreadNotifications: RoomSyncUnreadNotifications? = null,
updateMembers: Boolean = false, updateMembers: Boolean = false,
ephemeralResult: RoomSyncHandler.EphemeralResult? = null) { ephemeralResult: RoomSyncHandler.EphemeralResult? = null,
inviterId: String? = null) {
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
if (roomSummary != null) { if (roomSummary != null) {
if (roomSummary.heroes.isNotEmpty()) { if (roomSummary.heroes.isNotEmpty()) {
@ -134,6 +135,12 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummaryEntity.typingUserIds.clear() roomSummaryEntity.typingUserIds.clear()
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty()) 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) { if (updateMembers) {
val otherRoomMembers = RoomMemberHelper(realm, roomId) val otherRoomMembers = RoomMemberHelper(realm, roomId)
.queryRoomMembersEvent() .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.mapper.toEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity 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.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.getOrCreate
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
@ -73,9 +74,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
if (roomMemberEvent.eventId == null || roomMemberEvent.stateKey == null) { if (roomMemberEvent.eventId == null || roomMemberEvent.stateKey == null) {
continue continue
} }
val eventEntity = roomMemberEvent.toEntity(roomId, SendState.SYNCED).let { val eventEntity = roomMemberEvent.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
realm.copyToRealmOrUpdate(it)
}
CurrentStateEventEntity.getOrCreate(realm, roomId, roomMemberEvent.stateKey, roomMemberEvent.type).apply { CurrentStateEventEntity.getOrCreate(realm, roomId, roomMemberEvent.stateKey, roomMemberEvent.type).apply {
eventId = roomMemberEvent.eventId eventId = roomMemberEvent.eventId
root = eventEntity 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.RoomEntity
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.copyToRealmOrIgnore
import im.vector.matrix.android.internal.database.query.create 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.find
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents 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 val stateEvents = receivedChunk.stateEvents
for (stateEvent in stateEvents) { for (stateEvent in stateEvents) {
val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED).let { val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
realm.copyToRealmOrUpdate(it)
}
currentChunk.addStateEvent(roomId, stateEventEntity, direction) currentChunk.addStateEvent(roomId, stateEventEntity, direction)
if (stateEvent.type == EventType.STATE_ROOM_MEMBER && stateEvent.stateKey != null) { if (stateEvent.type == EventType.STATE_ROOM_MEMBER && stateEvent.stateKey != null) {
roomMemberContentsByUser[stateEvent.stateKey] = stateEvent.content.toModel<RoomMemberContent>() roomMemberContentsByUser[stateEvent.stateKey] = stateEvent.content.toModel<RoomMemberContent>()
@ -213,9 +212,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
continue continue
} }
eventIds.add(event.eventId) eventIds.add(event.eventId)
val eventEntity = event.toEntity(roomId, SendState.SYNCED).let { val eventEntity = event.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
realm.copyToRealmOrUpdate(it)
}
if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null) { if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null) {
val contentToUse = if (direction == PaginationDirection.BACKWARDS) { val contentToUse = if (direction == PaginationDirection.BACKWARDS) {
event.prevContent 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.ChunkEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity 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.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.find
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
import im.vector.matrix.android.internal.database.query.getOrCreate import im.vector.matrix.android.internal.database.query.getOrCreate
@ -93,7 +94,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
} }
is HandlingStrategy.INVITED -> is HandlingStrategy.INVITED ->
handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_invited_rooms, 0.1f) { 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 -> { is HandlingStrategy.LEFT -> {
@ -134,9 +135,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
if (event.eventId == null || event.stateKey == null) { if (event.eventId == null || event.stateKey == null) {
continue continue
} }
val eventEntity = event.toEntity(roomId, SendState.SYNCED).let { val eventEntity = event.toEntity(roomId, SendState.SYNCED).copyToRealmOrIgnore(realm)
realm.copyToRealmOrUpdate(it)
}
CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply { CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply {
eventId = event.eventId eventId = event.eventId
root = eventEntity root = eventEntity
@ -177,19 +176,27 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
private fun handleInvitedRoom(realm: Realm, private fun handleInvitedRoom(realm: Realm,
roomId: String, roomId: String,
roomSync: InvitedRoomSync, roomSync: InvitedRoomSync): RoomEntity {
syncLocalTimestampMillis: Long): RoomEntity {
Timber.v("Handle invited sync for room $roomId") Timber.v("Handle invited sync for room $roomId")
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
roomEntity.membership = Membership.INVITE roomEntity.membership = Membership.INVITE
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) { if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
val chunkEntity = handleTimelineEvents(realm, roomId, roomEntity, roomSync.inviteState.events, syncLocalTimestampMillis = syncLocalTimestampMillis) roomSync.inviteState.events.forEach {
roomEntity.addOrUpdate(chunkEntity) 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 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 return roomEntity
} }
@ -197,7 +204,6 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
roomId: String, roomId: String,
roomSync: RoomSync): RoomEntity { roomSync: RoomSync): RoomEntity {
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
roomEntity.membership = Membership.LEAVE roomEntity.membership = Membership.LEAVE
roomEntity.chunks.deleteAllFromRealm() roomEntity.chunks.deleteAllFromRealm()
roomSummaryUpdater.update(realm, roomId, Membership.LEAVE, roomSync.summary, roomSync.unreadNotifications) 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) eventIds.add(event.eventId)
val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it } val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it }
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).let { val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm)
realm.copyToRealmOrUpdate(it)
}
if (event.isStateEvent() && event.stateKey != null) { if (event.isStateEvent() && event.stateKey != null) {
CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply { CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply {
eventId = event.eventId eventId = event.eventId

View File

@ -950,8 +950,8 @@ 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.latestPreviewableEvent?.root?.senderId?.let { senderId -> summary.inviterId?.let { inviterId ->
session.getUser(senderId) session.getUser(inviterId)
}?.also { }?.also {
setState { copy(asyncInviter = Success(it)) } setState { copy(asyncInviter = Success(it)) }
} }

View File

@ -101,7 +101,18 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
.observeOn(Schedulers.computation()) .observeOn(Schedulers.computation())
.map { buildRoomSummaries(it) } .map { buildRoomSummaries(it) }
.execute { async -> .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) else -> groupRooms.add(room)
} }
} }
return RoomSummaries().apply { return RoomSummaries().apply {
put(RoomCategory.INVITE, invites) put(RoomCategory.INVITE, invites)
put(RoomCategory.FAVOURITE, favourites) put(RoomCategory.FAVOURITE, favourites)

View File

@ -60,9 +60,9 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
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.latestPreviewableEvent?.root?.senderId roomSummary.inviterId
} else { } else {
roomSummary.latestPreviewableEvent?.root?.senderId?.let { roomSummary.inviterId?.let {
stringProvider.getString(R.string.invited_by, it) 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? { fun resolveEvent(event: Event/*, roomState: RoomState?, bingRule: PushRule?*/, session: Session): NotifiableEvent? {
val roomID = event.roomId ?: return null val roomID = event.roomId ?: return null
val eventId = event.eventId ?: 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 val timelineEvent = session.getRoom(roomID)?.getTimeLineEvent(eventId) ?: return null
when (event.getClearType()) { when (event.getClearType()) {
EventType.MESSAGE -> { EventType.MESSAGE -> {
return resolveMessageEvent(timelineEvent, session) return resolveMessageEvent(timelineEvent, session)
} }
EventType.ENCRYPTED -> { EventType.ENCRYPTED -> {
val messageEvent = resolveMessageEvent(timelineEvent, session) val messageEvent = resolveMessageEvent(timelineEvent, session)
messageEvent?.lockScreenVisibility = NotificationCompat.VISIBILITY_PRIVATE messageEvent?.lockScreenVisibility = NotificationCompat.VISIBILITY_PRIVATE
return messageEvent return messageEvent
} }
EventType.STATE_ROOM_MEMBER -> { else -> {
return resolveStateRoomEvent(event, session)
}
else -> {
// If the event can be displayed, display it as is // If the event can be displayed, display it as is
Timber.w("NotifiableEventResolver Received an unsupported event matching a bing rule") Timber.w("NotifiableEventResolver Received an unsupported event matching a bing rule")
// TODO Better event text display // TODO Better event text display

View File

@ -130,9 +130,9 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
fun onEventRedacted(eventId: String) { fun onEventRedacted(eventId: String) {
synchronized(eventList) { synchronized(eventList) {
eventList.filter { it.eventId == eventId }.map { notifiableEvent -> eventList.find { it.eventId == eventId }?.apply {
notifiableEvent.isRedacted = true isRedacted = true
notifiableEvent.hasBeenDisplayed = false hasBeenDisplayed = false
} }
} }
} }
@ -182,7 +182,6 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
e is InviteNotifiableEvent && e.roomId == roomId e is InviteNotifiableEvent && e.roomId == roomId
} }
} }
notificationUtils.cancelNotificationMessage(roomId, ROOM_INVITATION_NOTIFICATION_ID) 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) val joinIntent = Intent(context, NotificationBroadcastReceiver::class.java)
joinIntent.action = JOIN_ACTION joinIntent.action = JOIN_ACTION
joinIntent.data = Uri.parse("foobar://$roomId&$matrixId") 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, val joinIntentPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(), joinIntent,
PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT)
addAction( addAction(