From 9b928b5a5dac48d2c13ed4d09bebea0c96e6aa80 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 20:12:32 -0600 Subject: [PATCH] Handle remaining cases for room updates in new room list For https://github.com/vector-im/riot-web/issues/13635 This adds support for: * Tag changes * DM changes * Marking our own rooms as read * Our own membership changes The remaining branch we didn't need was the alternate 'new room' branch, so it was removed. This is not optimized - optimization is deferred. --- src/stores/room-list/RoomListStore2.ts | 52 +++++++++++++------ .../list-ordering/ImportanceAlgorithm.ts | 7 +++ src/stores/room-list/models.ts | 3 +- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/stores/room-list/RoomListStore2.ts b/src/stores/room-list/RoomListStore2.ts index af9970d3cc..e71a8185bf 100644 --- a/src/stores/room-list/RoomListStore2.ts +++ b/src/stores/room-list/RoomListStore2.ts @@ -145,13 +145,19 @@ export class RoomListStore2 extends AsyncStore { // First see if the receipt event is for our own user. If it was, trigger // a room update (we probably read the room on a different device). if (readReceiptChangeIsFor(payload.event, this.matrixClient)) { - // TODO: Update room now that it's been read - console.log(payload); + console.log(`[RoomListDebug] Got own read receipt in ${payload.event.roomId}`); + const room = this.matrixClient.getRoom(payload.event.roomId); + if (!room) { + console.warn(`Own read receipt was in unknown room ${payload.event.roomId}`); + return; + } + await this.handleRoomUpdate(room, RoomUpdateCause.ReadReceipt); return; } } else if (payload.action === 'MatrixActions.Room.tags') { - // TODO: Update room from tags - console.log(payload); + const roomPayload = (payload); // TODO: Type out the dispatcher types + console.log(`[RoomListDebug] Got tag change in ${roomPayload.room.roomId}`); + await this.handleRoomUpdate(roomPayload.room, RoomUpdateCause.PossibleTagChange); } else if (payload.action === 'MatrixActions.Room.timeline') { const eventPayload = (payload); // TODO: Type out the dispatcher types @@ -189,23 +195,39 @@ export class RoomListStore2 extends AsyncStore { // cause inaccuracies with the list ordering. We may have to decrypt the last N messages of every room :( await this.handleRoomUpdate(room, RoomUpdateCause.Timeline); } else if (payload.action === 'MatrixActions.accountData' && payload.event_type === 'm.direct') { - // TODO: Update DMs - console.log(payload); + const eventPayload = (payload); // TODO: Type out the dispatcher types + console.log(`[RoomListDebug] Received updated DM map`); + const dmMap = eventPayload.event.getContent(); + for (const userId of Object.keys(dmMap)) { + const roomIds = dmMap[userId]; + for (const roomId of roomIds) { + const room = this.matrixClient.getRoom(roomId); + if (!room) { + console.warn(`${roomId} was found in DMs but the room is not in the store`); + continue; + } + + // We expect this RoomUpdateCause to no-op if there's no change, and we don't expect + // the user to have hundreds of rooms to update in one event. As such, we just hammer + // away at updates until the problem is solved. If we were expecting more than a couple + // of rooms to be updated at once, we would consider batching the rooms up. + await this.handleRoomUpdate(room, RoomUpdateCause.PossibleTagChange); + } + } } else if (payload.action === 'MatrixActions.Room.myMembership') { - // TODO: Improve new room check const membershipPayload = (payload); // TODO: Type out the dispatcher types - if (!membershipPayload.oldMembership && membershipPayload.membership === "join") { + if (membershipPayload.oldMembership !== "join" && membershipPayload.membership === "join") { console.log(`[RoomListDebug] Handling new room ${membershipPayload.room.roomId}`); await this.algorithm.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom); + return; } - // TODO: Update room from membership change - console.log(payload); - } else if (payload.action === 'MatrixActions.Room') { - // TODO: Improve new room check - // const roomPayload = (payload); // TODO: Type out the dispatcher types - // console.log(`[RoomListDebug] Handling new room ${roomPayload.room.roomId}`); - // await this.algorithm.handleRoomUpdate(roomPayload.room, RoomUpdateCause.NewRoom); + // If it's not a join, it's transitioning into a different list (possibly historical) + if (membershipPayload.oldMembership !== membershipPayload.membership) { + console.log(`[RoomListDebug] Handling membership change in ${membershipPayload.room.roomId}`); + await this.algorithm.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.PossibleTagChange); + return; + } } else if (payload.action === 'view_room') { // TODO: Update sticky room console.log(payload); diff --git a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts index 6c4498dad3..fe13e1972b 100644 --- a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts +++ b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts @@ -189,6 +189,13 @@ export class ImportanceAlgorithm extends Algorithm { } public async handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise { + if (cause === RoomUpdateCause.PossibleTagChange) { + // TODO: Be smarter and splice rather than regen the planet. + // TODO: No-op if no change. + await this.setKnownRooms(this.rooms); + return; + } + if (cause === RoomUpdateCause.NewRoom) { // TODO: Be smarter and insert rather than regen the planet. await this.setKnownRooms([room, ...this.rooms]); diff --git a/src/stores/room-list/models.ts b/src/stores/room-list/models.ts index 9a27569db4..43320809d9 100644 --- a/src/stores/room-list/models.ts +++ b/src/stores/room-list/models.ts @@ -38,6 +38,7 @@ export type TagID = string | DefaultTagID; export enum RoomUpdateCause { Timeline = "TIMELINE", - RoomRead = "ROOM_READ", // TODO: Use this. + PossibleTagChange = "POSSIBLE_TAG_CHANGE", + ReadReceipt = "READ_RECEIPT", NewRoom = "NEW_ROOM", }