diff --git a/src/matrix/Session.js b/src/matrix/Session.js index 11bca80b..99ed5035 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -284,20 +284,28 @@ export class Session { } } const pendingEventsByRoomId = await this._getPendingEventsByRoom(txn); - // load rooms - const rooms = await txn.roomSummary.getAll(); - await Promise.all(rooms.map(async summary => { - const room = this.createRoom(summary.roomId, pendingEventsByRoomId.get(summary.roomId)); - await log.wrap("room", log => room.load(summary, txn, log)); - this._rooms.add(room.id, room); - })); // load invites const invites = await txn.invites.getAll(); - await Promise.all(invites.map(async inviteData => { + const inviteLoadPromise = Promise.all(invites.map(async inviteData => { const invite = this.createInvite(inviteData.roomId); log.wrap("invite", log => invite.load(inviteData, log)); this._invites.add(invite.id, invite); })); + // load rooms + const rooms = await txn.roomSummary.getAll(); + const roomLoadPromise = Promise.all(rooms.map(async summary => { + const room = this.createRoom(summary.roomId, pendingEventsByRoomId.get(summary.roomId)); + await log.wrap("room", log => room.load(summary, txn, log)); + this._rooms.add(room.id, room); + })); + // load invites and rooms in parallel + await Promise.all([inviteLoadPromise, roomLoadPromise]); + for (const [roomId, invite] of this.invites) { + const room = this.rooms.get(roomId); + if (room) { + room.setInvite(invite); + } + } } dispose() { diff --git a/src/matrix/Sync.js b/src/matrix/Sync.js index c8454dd6..8c8e3423 100644 --- a/src/matrix/Sync.js +++ b/src/matrix/Sync.js @@ -300,6 +300,10 @@ export class Sync { if (is.isNewInvite) { this._session.addInviteAfterSync(is.invite); } + // if we haven't archived or forgotten the (left) room yet, + // notify there is an invite now, so we can update the UI + if (is.room) { + is.room.setInvite(is.invite); } } } @@ -352,7 +356,7 @@ export class Sync { // if there is an existing invite, add a process state for it // so its writeSync and afterSync will run and remove the invite if (invite) { - inviteStates.push(new InviteSyncProcessState(invite, false, membership, null)); + inviteStates.push(new InviteSyncProcessState(invite, false, null, membership, null)); } roomStates.push(new RoomSyncProcessState( room, isNewRoom, invite, roomResponse, membership)); @@ -373,7 +377,9 @@ export class Sync { invite = this._session.createInvite(roomId); isNewInvite = true; } - inviteStates.push(new InviteSyncProcessState(invite, isNewInvite, "invite", roomResponse)); + const room = this._session.rooms.get(roomId); + // TODO let the room know there is an invite now, so + inviteStates.push(new InviteSyncProcessState(invite, isNewInvite, room, "invite", roomResponse)); } } return inviteStates; @@ -417,9 +423,10 @@ class RoomSyncProcessState { } class InviteSyncProcessState { - constructor(invite, isNewInvite, membership, roomResponse) { + constructor(invite, isNewInvite, room, membership, roomResponse) { this.invite = invite; this.isNewInvite = isNewInvite; + this.room = room; this.membership = membership; this.roomResponse = roomResponse; this.changes = null; diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index f75b1148..8564f860 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -54,6 +54,7 @@ export class Room extends EventEmitter { this._getSyncToken = getSyncToken; this._platform = platform; this._observedEvents = null; + this._invite = null; } async _eventIdsToEntries(eventIds, txn) { @@ -344,6 +345,10 @@ export class Room extends EventEmitter { } let emitChange = false; if (summaryChanges) { + // if we joined the room, we can't have an invite anymore + if (summaryChanges.membership === "join" && this._summary.data.membership !== "join") { + this._invite = null; + } this._summary.applyChanges(summaryChanges); if (!this._summary.data.needsHeroes) { this._heroes = null; @@ -427,6 +432,14 @@ export class Room extends EventEmitter { } } + /** @internal */ + setInvite(invite) { + // called when an invite comes in for this room + // (e.g. when we're in membership leave and haven't been archived or forgotten yet) + this._invite = invite; + this._emitUpdate(); + } + /** @public */ sendEvent(eventType, content, attachments, log = null) { this._platform.logger.wrapOrRun(log, "send", log => { @@ -589,6 +602,17 @@ export class Room extends EventEmitter { return this._summary.data.membership; } + /** + * The invite for this room, if any. + * This will only be set if you've left a room, and + * don't archive or forget it, and then receive an invite + * for it again + * @return {Invite?} + */ + get invite() { + return this._invite; + } + enableSessionBackup(sessionBackup) { this._roomEncryption?.enableSessionBackup(sessionBackup); // TODO: do we really want to do this every time you open the app?