Fix bugs in dm tab
authorAjay Bura <ajbura@gmail.com>
Wed, 4 May 2022 08:52:16 +0000 (14:22 +0530)
committerAjay Bura <ajbura@gmail.com>
Wed, 4 May 2022 08:52:16 +0000 (14:22 +0530)
src/app/organisms/invite-list/InviteList.jsx
src/app/organisms/navigation/Directs.jsx
src/app/organisms/navigation/Drawer.jsx
src/client/action/room.js
src/client/state/RoomList.js

index e9a5adef8870d8d56a21ceddf8b5f00ed98bea2e..231928fee27ee9ebf7a83852b40c84c9603c53e9 100644 (file)
@@ -56,9 +56,10 @@ function InviteList({ isOpen, onRequestClose }) {
   function renderRoomTile(roomId) {
     const mx = initMatrix.matrixClient;
     const myRoom = mx.getRoom(roomId);
+    if (!myRoom) return null;
     const roomName = myRoom.name;
     let roomAlias = myRoom.getCanonicalAlias();
-    if (roomAlias === null) roomAlias = myRoom.roomId;
+    if (!roomAlias) roomAlias = myRoom.roomId;
     const inviterName = myRoom.getMember(mx.getUserId())?.events?.member?.getSender?.() ?? '';
     return (
       <RoomTile
@@ -97,12 +98,13 @@ function InviteList({ isOpen, onRequestClose }) {
         {
           Array.from(initMatrix.roomList.inviteDirects).map((roomId) => {
             const myRoom = initMatrix.matrixClient.getRoom(roomId);
+            if (myRoom === null) return null;
             const roomName = myRoom.name;
             return (
               <RoomTile
                 key={myRoom.roomId}
                 name={roomName}
-                id={myRoom.getDMInviter()}
+                id={myRoom.getDMInviter() || roomId}
                 options={
                   procInvite.has(myRoom.roomId)
                     ? (<Spinner size="small" />)
index c2a9798b58ef99943904abe31b0c0c245b035347..e65c8afcf39bc5b89d615ab59982bae3b46c6ca6 100644 (file)
@@ -1,4 +1,5 @@
 import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
 
 import initMatrix from '../../../client/initMatrix';
 import cons from '../../../client/state/cons';
@@ -9,12 +10,12 @@ import { roomIdByActivity } from '../../../util/sort';
 import RoomsCategory from './RoomsCategory';
 
 const drawerPostie = new Postie();
-function Directs() {
+function Directs({ size }) {
   const mx = initMatrix.matrixClient;
   const { roomList, notifications } = initMatrix;
   const [directIds, setDirectIds] = useState([]);
 
-  useEffect(() => setDirectIds([...roomList.directs].sort(roomIdByActivity)), []);
+  useEffect(() => setDirectIds([...roomList.directs].sort(roomIdByActivity)), [size]);
 
   useEffect(() => {
     const handleTimeline = (event, room, toStartOfTimeline, removed, data) => {
@@ -63,5 +64,8 @@ function Directs() {
 
   return <RoomsCategory name="People" hideHeader roomIds={directIds} drawerPostie={drawerPostie} />;
 }
+Directs.propTypes = {
+  size: PropTypes.number.isRequired,
+};
 
 export default Directs;
index 8e3e4ea6d0edbffa117bce9b3192770cb467c311..5e6badc783263b029d209f4d80f9ca849481d491 100644 (file)
@@ -42,12 +42,15 @@ function Drawer() {
   const [spaceId] = useSelectedSpace();
   const [, forceUpdate] = useForceUpdate();
   const scrollRef = useRef(null);
+  const { roomList } = initMatrix;
 
   useEffect(() => {
-    const { roomList } = initMatrix;
-    roomList.on(cons.events.roomList.ROOMLIST_UPDATED, forceUpdate);
+    const handleUpdate = () => {
+      forceUpdate();
+    };
+    roomList.on(cons.events.roomList.ROOMLIST_UPDATED, handleUpdate);
     return () => {
-      roomList.removeListener(cons.events.roomList.ROOMLIST_UPDATED, forceUpdate);
+      roomList.removeListener(cons.events.roomList.ROOMLIST_UPDATED, handleUpdate);
     };
   }, []);
 
@@ -68,7 +71,7 @@ function Drawer() {
               {
                 selectedTab !== cons.tabs.DIRECTS
                   ? <Home spaceId={spaceId} />
-                  : <Directs />
+                  : <Directs size={roomList.directs.size} />
               }
             </div>
           </ScrollView>
index 5bc9bf170f8c3e703753b2b93b8b2eb4774e0a16..bb96f99cd9a7b9ce2e1ed5db0c600b586c386b6c 100644 (file)
@@ -113,17 +113,20 @@ async function join(roomIdOrAlias, isDM, via) {
  * @param {string} roomId
  * @param {boolean} isDM
  */
-function leave(roomId) {
+async function leave(roomId) {
   const mx = initMatrix.matrixClient;
   const isDM = initMatrix.roomList.directs.has(roomId);
-  mx.leave(roomId)
-    .then(() => {
-      appDispatcher.dispatch({
-        type: cons.actions.room.LEAVE,
-        roomId,
-        isDM,
-      });
-    }).catch();
+  try {
+    await mx.leave(roomId);
+    await mx.forget(roomId);
+    appDispatcher.dispatch({
+      type: cons.actions.room.LEAVE,
+      roomId,
+      isDM,
+    });
+  } catch {
+    console.error('Unable to leave room.');
+  }
 }
 
 async function create(options, isDM = false) {
index 8b7cdc197c82e23d07cc3eabfe9bf8da8217f07e..6ea4dad4b25994cec5029ed5a54ae900657f37ba 100644 (file)
@@ -6,6 +6,21 @@ function isMEventSpaceChild(mEvent) {
   return mEvent.getType() === 'm.space.child' && Object.keys(mEvent.getContent()).length > 0;
 }
 
+/**
+ * @param {() => boolean} callback if return true wait will over else callback will be called again.
+ * @param {number} timeout timeout to callback
+ * @param {number} maxTry maximum callback try > 0. -1 means no limit
+ */
+async function waitFor(callback, timeout = 400, maxTry = -1) {
+  if (maxTry === 0) return false;
+  const isOver = async () => new Promise((resolve) => {
+    setTimeout(() => resolve(callback()), timeout);
+  });
+
+  if (await isOver()) return true;
+  return waitFor(callback, timeout, maxTry - 1);
+}
+
 class RoomList extends EventEmitter {
   constructor(matrixClient) {
     super();
@@ -228,6 +243,7 @@ class RoomList extends EventEmitter {
   }
 
   _isDMInvite(room) {
+    if (this.mDirects.has(room.roomId)) return true;
     const me = room.getMember(this.matrixClient.getUserId());
     const myEventContent = me.events.member.getContent();
     return myEventContent.membership === 'invite' && myEventContent.is_direct;
@@ -243,22 +259,11 @@ class RoomList extends EventEmitter {
       latestMDirects.forEach((directId) => {
         const myRoom = this.matrixClient.getRoom(directId);
         if (this.mDirects.has(directId)) return;
-
-        // Update mDirects
         this.mDirects.add(directId);
 
         if (myRoom === null) return;
-
-        if (this._isDMInvite(myRoom)) return;
-
-        if (myRoom.getMyMembership === 'join' && !this.directs.has(directId)) {
+        if (myRoom.getMyMembership() === 'join') {
           this.directs.add(directId);
-        }
-
-        // Newly added room.
-        // at this time my membership can be invite | join
-        if (myRoom.getMyMembership() === 'join' && this.rooms.has(directId)) {
-          // found a DM which accidentally gets added to this.rooms
           this.rooms.delete(directId);
           this.emit(cons.events.roomList.ROOMLIST_UPDATED);
         }
@@ -298,23 +303,17 @@ class RoomList extends EventEmitter {
       }
     });
 
-    this.matrixClient.on('Room.myMembership', (room, membership, prevMembership) => {
+    this.matrixClient.on('Room.myMembership', async (room, membership, prevMembership) => {
       // room => prevMembership = null | invite | join | leave | kick | ban | unban
       // room => membership = invite | join | leave | kick | ban | unban
       const { roomId } = room;
+      const isRoomReady = () => this.matrixClient.getRoom(roomId) !== null;
+      if (['join', 'invite'].includes(membership) && isRoomReady() === false) {
+        if (await waitFor(isRoomReady, 200, 100) === false) return;
+      }
 
       if (membership === 'unban') return;
 
-      // When user_reject/sender_undo room invite
-      if (prevMembership === 'invite') {
-        if (this.inviteDirects.has(roomId)) this.inviteDirects.delete(roomId);
-        else if (this.inviteSpaces.has(roomId)) this.inviteSpaces.delete(roomId);
-        else this.inviteRooms.delete(roomId);
-
-        this.emit(cons.events.roomList.INVITELIST_UPDATED, roomId);
-      }
-
-      // When user get invited
       if (membership === 'invite') {
         if (this._isDMInvite(room)) this.inviteDirects.add(roomId);
         else if (room.isSpaceRoom()) this.inviteSpaces.add(roomId);
@@ -324,88 +323,53 @@ class RoomList extends EventEmitter {
         return;
       }
 
-      // When user join room (first time) or start DM.
-      if ((prevMembership === null || prevMembership === 'invite') && membership === 'join') {
-        // when user create room/DM OR accept room/dm invite from this client.
-        // we will update this.rooms/this.directs with user action
-        if (this.directs.has(roomId) || this.spaces.has(roomId) || this.rooms.has(roomId)) return;
+      if (prevMembership === 'invite') {
+        if (this.inviteDirects.has(roomId)) this.inviteDirects.delete(roomId);
+        else if (this.inviteSpaces.has(roomId)) this.inviteSpaces.delete(roomId);
+        else this.inviteRooms.delete(roomId);
 
-        if (this.processingRooms.has(roomId)) {
-          const procRoomInfo = this.processingRooms.get(roomId);
+        this.emit(cons.events.roomList.INVITELIST_UPDATED, roomId);
+      }
 
-          if (procRoomInfo.isDM) this.directs.add(roomId);
-          else if (room.isSpaceRoom()) this.addToSpaces(roomId);
-          else this.rooms.add(roomId);
+      if (['leave', 'kick', 'ban'].includes(membership)) {
+        if (this.directs.has(roomId)) this.directs.delete(roomId);
+        else if (this.spaces.has(roomId)) this.deleteFromSpaces(roomId);
+        else this.rooms.delete(roomId);
+        this.emit(cons.events.roomList.ROOM_LEAVED, roomId);
+        this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+        return;
+      }
 
-          if (procRoomInfo.task === 'CREATE') this.emit(cons.events.roomList.ROOM_CREATED, roomId);
-          this.emit(cons.events.roomList.ROOM_JOINED, roomId);
-          this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+      // when user create room/DM OR accept room/dm invite from this client.
+      // we will update this.rooms/this.directs with user action
+      if (membership === 'join' && this.processingRooms.has(roomId)) {
+        const procRoomInfo = this.processingRooms.get(roomId);
 
-          this.processingRooms.delete(roomId);
-          return;
-        }
-        if (room.isSpaceRoom()) {
-          this.addToSpaces(roomId);
+        if (procRoomInfo.isDM) this.directs.add(roomId);
+        else if (room.isSpaceRoom()) this.addToSpaces(roomId);
+        else this.rooms.add(roomId);
 
-          this.emit(cons.events.roomList.ROOM_JOINED, roomId);
-          this.emit(cons.events.roomList.ROOMLIST_UPDATED);
-          return;
-        }
+        if (procRoomInfo.task === 'CREATE') this.emit(cons.events.roomList.ROOM_CREATED, roomId);
+        this.emit(cons.events.roomList.ROOM_JOINED, roomId);
+        this.emit(cons.events.roomList.ROOMLIST_UPDATED);
 
-        // below code intented to work when user create room/DM
-        // OR accept room/dm invite from other client.
-        // and we have to update our client. (it's ok to have 10sec delay)
-
-        // create a buffer of 10sec and HOPE client.accoundData get updated
-        // then accoundData event listener will update this.mDirects.
-        // and we will be able to know if it's a DM.
-        // ----------
-        // less likely situation:
-        // if we don't get accountData with 10sec then:
-        // we will temporary add it to this.rooms.
-        // and in future when accountData get updated
-        // accountData listener will automatically goona REMOVE it from this.rooms
-        // and will ADD it to this.directs
-        // and emit the cons.events.roomList.ROOMLIST_UPDATED to update the UI.
-
-        setTimeout(() => {
-          if (this.directs.has(roomId) || this.spaces.has(roomId) || this.rooms.has(roomId)) return;
-          if (this.mDirects.has(roomId)) this.directs.add(roomId);
-          else this.rooms.add(roomId);
-
-          this.emit(cons.events.roomList.ROOM_JOINED, roomId);
-          this.emit(cons.events.roomList.ROOMLIST_UPDATED);
-        }, 10000);
+        this.processingRooms.delete(roomId);
         return;
       }
 
-      // when room is a DM add/remove it from DM's and return.
-      if (this.directs.has(roomId)) {
-        if (membership === 'leave' || membership === 'kick' || membership === 'ban') {
-          this.directs.delete(roomId);
-          this.emit(cons.events.roomList.ROOM_LEAVED, roomId);
-        }
-      }
-      if (this.mDirects.has(roomId)) {
-        if (membership === 'join') {
-          this.directs.add(roomId);
-          this.emit(cons.events.roomList.ROOM_JOINED, roomId);
-        }
+      if (this.mDirects.has(roomId) && membership === 'join') {
+        this.directs.add(roomId);
+        this.emit(cons.events.roomList.ROOM_JOINED, roomId);
         this.emit(cons.events.roomList.ROOMLIST_UPDATED);
         return;
       }
-      // when room is not a DM add/remove it from rooms.
-      if (membership === 'leave' || membership === 'kick' || membership === 'ban') {
-        if (room.isSpaceRoom()) this.deleteFromSpaces(roomId);
-        else this.rooms.delete(roomId);
-        this.emit(cons.events.roomList.ROOM_LEAVED, roomId);
-      }
+
       if (membership === 'join') {
         if (room.isSpaceRoom()) this.addToSpaces(roomId);
         else this.rooms.add(roomId);
         this.emit(cons.events.roomList.ROOM_JOINED, roomId);
+        this.emit(cons.events.roomList.ROOMLIST_UPDATED);
       }
-      this.emit(cons.events.roomList.ROOMLIST_UPDATED);
     });
   }
 }