diff --git a/src/app/hooks/useSpaceShortcut.js b/src/app/hooks/useSpaceShortcut.js index 8dca2ba..a1710c6 100644 --- a/src/app/hooks/useSpaceShortcut.js +++ b/src/app/hooks/useSpaceShortcut.js @@ -5,16 +5,19 @@ import initMatrix from '../../client/initMatrix'; import cons from '../../client/state/cons'; export function useSpaceShortcut() { - const { roomList } = initMatrix; - const [spaceShortcut, setSpaceShortcut] = useState([...roomList.spaceShortcut]); + const { accountData } = initMatrix; + const [spaceShortcut, setSpaceShortcut] = useState([...accountData.spaceShortcut]); useEffect(() => { const onSpaceShortcutUpdated = () => { - setSpaceShortcut([...roomList.spaceShortcut]); + setSpaceShortcut([...accountData.spaceShortcut]); }; - roomList.on(cons.events.roomList.SPACE_SHORTCUT_UPDATED, onSpaceShortcutUpdated); + accountData.on(cons.events.accountData.SPACE_SHORTCUT_UPDATED, onSpaceShortcutUpdated); return () => { - roomList.removeListener(cons.events.roomList.SPACE_SHORTCUT_UPDATED, onSpaceShortcutUpdated); + accountData.removeListener( + cons.events.accountData.SPACE_SHORTCUT_UPDATED, + onSpaceShortcutUpdated, + ); }; }, []); diff --git a/src/app/molecules/space-options/SpaceOptions.jsx b/src/app/molecules/space-options/SpaceOptions.jsx index cb69e18..223ff57 100644 --- a/src/app/molecules/space-options/SpaceOptions.jsx +++ b/src/app/molecules/space-options/SpaceOptions.jsx @@ -5,10 +5,13 @@ import { twemojify } from '../../../util/twemojify'; import initMatrix from '../../../client/initMatrix'; import { openSpaceSettings, openSpaceManage, openInviteUser } from '../../../client/action/navigation'; -import { leave, createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/room'; +import { leave } from '../../../client/action/room'; +import { createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/accountData'; import { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu'; +import CategoryIC from '../../../../public/res/ic/outlined/category.svg'; +import CategoryFilledIC from '../../../../public/res/ic/filled/category.svg'; import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg'; import SettingsIC from '../../../../public/res/ic/outlined/settings.svg'; import HashSearchIC from '../../../../public/res/ic/outlined/hash-search.svg'; @@ -20,7 +23,7 @@ function SpaceOptions({ roomId, afterOptionSelect }) { const mx = initMatrix.matrixClient; const room = mx.getRoom(roomId); const canInvite = room?.canInvite(mx.getUserId()); - const isPinned = initMatrix.roomList.spaceShortcut.has(roomId); + const isPinned = initMatrix.accountData.spaceShortcut.has(roomId); const handleInviteClick = () => { openInviteUser(roomId); @@ -31,7 +34,10 @@ function SpaceOptions({ roomId, afterOptionSelect }) { else createSpaceShortcut(roomId); afterOptionSelect(); }; - + const handleCategorizeClick = () => { + alert('categorize'); + afterOptionSelect(); + }; const handleSettingsClick = () => { openSpaceSettings(roomId); afterOptionSelect(); @@ -51,6 +57,12 @@ function SpaceOptions({ roomId, afterOptionSelect }) { return (
{twemojify(`Options for ${initMatrix.matrixClient.getRoom(roomId)?.name}`)} + + Categorize subspaces + { - if (roomList.spaceShortcut.has(roomId)) return; + if (accountData.spaceShortcut.has(roomId)) return; if (!notifications.hasNoti(roomId)) return; if (noti === null) noti = { total: 0, highlight: 0 }; const childNoti = notifications.getNoti(roomId); diff --git a/src/app/organisms/space-settings/SpaceSettings.jsx b/src/app/organisms/space-settings/SpaceSettings.jsx index 697bbc1..76f68a6 100644 --- a/src/app/organisms/space-settings/SpaceSettings.jsx +++ b/src/app/organisms/space-settings/SpaceSettings.jsx @@ -7,7 +7,8 @@ import { twemojify } from '../../../util/twemojify'; import initMatrix from '../../../client/initMatrix'; import cons from '../../../client/state/cons'; import navigation from '../../../client/state/navigation'; -import { leave, createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/room'; +import { leave } from '../../../client/action/room'; +import { createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/accountData'; import Text from '../../atoms/text/Text'; import IconButton from '../../atoms/button/IconButton'; @@ -51,7 +52,7 @@ const tabItems = [{ }]; function GeneralSettings({ roomId }) { - const isPinned = initMatrix.roomList.spaceShortcut.has(roomId); + const isPinned = initMatrix.accountData.spaceShortcut.has(roomId); const [, forceUpdate] = useForceUpdate(); return ( diff --git a/src/client/action/accountData.js b/src/client/action/accountData.js new file mode 100644 index 0000000..00ddf23 --- /dev/null +++ b/src/client/action/accountData.js @@ -0,0 +1,16 @@ +import appDispatcher from '../dispatcher'; +import cons from '../state/cons'; + +export function createSpaceShortcut(roomId) { + appDispatcher.dispatch({ + type: cons.actions.accountData.CREATE_SPACE_SHORTCUT, + roomId, + }); +} + +export function deleteSpaceShortcut(roomId) { + appDispatcher.dispatch({ + type: cons.actions.accountData.DELETE_SPACE_SHORTCUT, + roomId, + }); +} diff --git a/src/client/action/room.js b/src/client/action/room.js index 1092751..5bc9bf1 100644 --- a/src/client/action/room.js +++ b/src/client/action/room.js @@ -298,24 +298,9 @@ async function setPowerLevel(roomId, userId, powerLevel) { return result; } -function createSpaceShortcut(roomId) { - appDispatcher.dispatch({ - type: cons.actions.room.CREATE_SPACE_SHORTCUT, - roomId, - }); -} - -function deleteSpaceShortcut(roomId) { - appDispatcher.dispatch({ - type: cons.actions.room.DELETE_SPACE_SHORTCUT, - roomId, - }); -} - export { join, leave, createDM, createRoom, invite, kick, ban, unban, setPowerLevel, - createSpaceShortcut, deleteSpaceShortcut, }; diff --git a/src/client/initMatrix.js b/src/client/initMatrix.js index ce5bf64..bcf5c28 100644 --- a/src/client/initMatrix.js +++ b/src/client/initMatrix.js @@ -4,6 +4,7 @@ import * as sdk from 'matrix-js-sdk'; import { secret } from './state/auth'; import RoomList from './state/RoomList'; +import AccountData from './state/AccountData'; import RoomsInput from './state/RoomsInput'; import Notifications from './state/Notifications'; import { initHotkeys } from './event/hotkeys'; @@ -62,6 +63,7 @@ class InitMatrix extends EventEmitter { global.initMatrix = this; if (prevState === null) { this.roomList = new RoomList(this.matrixClient); + this.accountData = new AccountData(this.roomList); this.roomsInput = new RoomsInput(this.matrixClient); this.notifications = new Notifications(this.roomList); initHotkeys(); diff --git a/src/client/state/AccountData.js b/src/client/state/AccountData.js new file mode 100644 index 0000000..f75d861 --- /dev/null +++ b/src/client/state/AccountData.js @@ -0,0 +1,79 @@ +import EventEmitter from 'events'; +import appDispatcher from '../dispatcher'; +import cons from './cons'; + +class AccountData extends EventEmitter { + constructor(roomList) { + super(); + + this.matrixClient = roomList.matrixClient; + this.roomList = roomList; + this.spaces = roomList.spaces; + + this.spaceShortcut = new Set(); + this._populateSpaceShortcut(); + this._listenEvents(); + + appDispatcher.register(this.roomActions.bind(this)); + } + + _populateSpaceShortcut() { + this.spaceShortcut.clear(); + const spacesContent = this.matrixClient.getAccountData(cons.IN_CINNY_SPACES)?.getContent(); + + if (!spacesContent) return; + if (spacesContent?.shortcut === undefined) return; + + spacesContent.shortcut.forEach((shortcut) => { + if (this.spaces.has(shortcut)) this.spaceShortcut.add(shortcut); + }); + if (spacesContent.shortcut.length !== this.spaceShortcut.size) { + // update shortcut list from account data if shortcut space doesn't exist. + // TODO: we can wait for sync to complete or else we may end up removing valid space id + this._updateSpaceShortcutData([...this.spaceShortcut]); + } + } + + _updateSpaceShortcutData(shortcutList) { + const spaceContent = this.matrixClient.getAccountData(cons.IN_CINNY_SPACES)?.getContent() || {}; + spaceContent.shortcut = shortcutList; + this.matrixClient.setAccountData(cons.IN_CINNY_SPACES, spaceContent); + } + + roomActions(action) { + const actions = { + [cons.actions.accountData.CREATE_SPACE_SHORTCUT]: () => { + if (this.spaceShortcut.has(action.roomId)) return; + this.spaceShortcut.add(action.roomId); + this._updateSpaceShortcutData([...this.spaceShortcut]); + this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED, action.roomId); + }, + [cons.actions.accountData.DELETE_SPACE_SHORTCUT]: () => { + if (!this.spaceShortcut.has(action.roomId)) return; + this.spaceShortcut.delete(action.roomId); + this._updateSpaceShortcutData([...this.spaceShortcut]); + this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED, action.roomId); + }, + }; + actions[action.type]?.(); + } + + _listenEvents() { + this.matrixClient.on('accountData', (event) => { + if (event.getType() !== cons.IN_CINNY_SPACES) return; + this._populateSpaceShortcut(); + this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED); + }); + + this.roomList.on(cons.events.roomList.ROOM_LEAVED, (roomId) => { + if (this.spaceShortcut.has(roomId)) { + // if deleted space has shortcut remove it. + this.spaceShortcut.delete(roomId); + this._updateSpaceShortcutData([...this.spaceShortcut]); + this.emit(cons.events.accountData.SPACE_SHORTCUT_UPDATED, roomId); + } + }); + } +} + +export default AccountData; diff --git a/src/client/state/RoomList.js b/src/client/state/RoomList.js index 27401e1..263c454 100644 --- a/src/client/state/RoomList.js +++ b/src/client/state/RoomList.js @@ -16,8 +16,6 @@ class RoomList extends EventEmitter { // No matter if you have joined those children rooms or not. this.roomIdToParents = new Map(); - this.spaceShortcut = new Set(); - this.inviteDirects = new Set(); this.inviteSpaces = new Set(); this.inviteRooms = new Set(); @@ -29,18 +27,11 @@ class RoomList extends EventEmitter { this.processingRooms = new Map(); this._populateRooms(); - this._populateSpaceShortcut(); this._listenEvents(); appDispatcher.register(this.roomActions.bind(this)); } - _updateSpaceShortcutData(shortcutList) { - const spaceContent = this.matrixClient.getAccountData(cons['in.cinny.spaces'])?.getContent() || {}; - spaceContent.shortcut = shortcutList; - this.matrixClient.setAccountData(cons['in.cinny.spaces'], spaceContent); - } - isOrphan(roomId) { return !this.roomIdToParents.has(roomId); } @@ -103,12 +94,6 @@ class RoomList extends EventEmitter { spaceChildren?.forEach((childRoomId) => { this.removeFromRoomIdToParents(childRoomId, roomId); }); - - if (this.spaceShortcut.has(roomId)) { - // if delete space has shortcut remove it. - this.spaceShortcut.delete(roomId); - this._updateSpaceShortcutData([...this.spaceShortcut]); - } } roomActions(action) { @@ -151,18 +136,6 @@ class RoomList extends EventEmitter { }); } }, - [cons.actions.room.CREATE_SPACE_SHORTCUT]: () => { - if (this.spaceShortcut.has(action.roomId)) return; - this.spaceShortcut.add(action.roomId); - this._updateSpaceShortcutData([...this.spaceShortcut]); - this.emit(cons.events.roomList.SPACE_SHORTCUT_UPDATED, action.roomId); - }, - [cons.actions.room.DELETE_SPACE_SHORTCUT]: () => { - if (!this.spaceShortcut.has(action.roomId)) return; - this.spaceShortcut.delete(action.roomId); - this._updateSpaceShortcutData([...this.spaceShortcut]); - this.emit(cons.events.roomList.SPACE_SHORTCUT_UPDATED, action.roomId); - }, }; actions[action.type]?.(); } @@ -182,21 +155,6 @@ class RoomList extends EventEmitter { return mDirectsId; } - _populateSpaceShortcut() { - this.spaceShortcut.clear(); - const spacesContent = this.matrixClient.getAccountData(cons['in.cinny.spaces'])?.getContent(); - - if (spacesContent && Array.isArray(spacesContent?.shortcut)) { - spacesContent.shortcut.forEach((shortcut) => { - if (this.spaces.has(shortcut)) this.spaceShortcut.add(shortcut); - }); - if (spacesContent.shortcut.length !== this.spaceShortcut.size) { - // update shortcut list from account data if shortcut space doesn't exist. - this._updateSpaceShortcutData([...this.spaceShortcut]); - } - } - } - _populateRooms() { this.directs.clear(); this.roomIdToParents.clear(); @@ -238,12 +196,6 @@ class RoomList extends EventEmitter { _listenEvents() { // Update roomList when m.direct changes this.matrixClient.on('accountData', (event) => { - if (event.getType() === cons['in.cinny.spaces']) { - this._populateSpaceShortcut(); - this.emit(cons.events.roomList.SPACE_SHORTCUT_UPDATED); - return; - } - if (event.getType() !== 'm.direct') return; const latestMDirects = this.getMDirects(); diff --git a/src/client/state/cons.js b/src/client/state/cons.js index e9413cb..d277ea1 100644 --- a/src/client/state/cons.js +++ b/src/client/state/cons.js @@ -7,7 +7,7 @@ const cons = { BASE_URL: 'cinny_hs_base_url', }, DEVICE_DISPLAY_NAME: 'Cinny Web', - 'in.cinny.spaces': 'in.cinny.spaces', + IN_CINNY_SPACES: 'in.cinny.spaces', tabs: { HOME: 'home', DIRECTS: 'dm', @@ -51,6 +51,8 @@ const cons = { JOIN: 'JOIN', LEAVE: 'LEAVE', CREATE: 'CREATE', + }, + accountData: { CREATE_SPACE_SHORTCUT: 'CREATE_SPACE_SHORTCUT', DELETE_SPACE_SHORTCUT: 'DELETE_SPACE_SHORTCUT', }, @@ -91,9 +93,11 @@ const cons = { ROOM_JOINED: 'ROOM_JOINED', ROOM_LEAVED: 'ROOM_LEAVED', ROOM_CREATED: 'ROOM_CREATED', - SPACE_SHORTCUT_UPDATED: 'SPACE_SHORTCUT_UPDATED', ROOM_PROFILE_UPDATED: 'ROOM_PROFILE_UPDATED', }, + accountData: { + SPACE_SHORTCUT_UPDATED: 'SPACE_SHORTCUT_UPDATED', + }, notifications: { NOTI_CHANGED: 'NOTI_CHANGED', FULL_READ: 'FULL_READ',