diff --git a/web/src/api/statestore/main.ts b/web/src/api/statestore/main.ts index e81ff2a8..31fe6572 100644 --- a/web/src/api/statestore/main.ts +++ b/web/src/api/statestore/main.ts @@ -39,7 +39,7 @@ import { } from "../types" import { InvitedRoomStore } from "./invitedroom.ts" import { RoomStateStore } from "./room.ts" -import { DirectChatSpace, RoomListFilter, SpaceEdgeStore, SpaceOrphansSpace, UnreadsSpace } from "./space.ts" +import { DirectChatSpace, RoomListFilter, Space, SpaceEdgeStore, SpaceOrphansSpace, UnreadsSpace } from "./space.ts" export interface RoomListEntry { room_id: RoomID @@ -128,6 +128,22 @@ export class StateStore { return null } + findMatchingSpace(room: RoomListEntry): Space | null { + if (this.spaceOrphans.include(room)) { + return this.spaceOrphans + } + for (const spaceID of this.topLevelSpaces.current) { + const space = this.spaceEdges.get(spaceID) + if (space?.include(room)) { + return space + } + } + if (this.directChatsSpace.include(room)) { + return this.directChatsSpace + } + return null + } + get roomListFilterFunc(): ((entry: RoomListEntry) => boolean) | null { if (!this.currentRoomListFilter && !this.currentRoomListQuery) { return null diff --git a/web/src/ui/MainScreen.tsx b/web/src/ui/MainScreen.tsx index 3bb15e63..e3220a64 100644 --- a/web/src/ui/MainScreen.tsx +++ b/web/src/ui/MainScreen.tsx @@ -96,12 +96,17 @@ class ContextFields implements MainScreenContextFields { } } - setActiveRoom = (roomID: RoomID | null, previewMeta?: Partial, pushState = true) => { + setActiveRoom = ( + roomID: RoomID | null, + previewMeta?: Partial, + toSpace?: RoomListFilter, + pushState = true, + ) => { console.log("Switching to room", roomID) if (roomID) { const room = this.client.store.rooms.get(roomID) if (room) { - this.#setActiveRoom(room, pushState) + this.#setActiveRoom(room, toSpace, pushState) } else { this.#setPreviewRoom(roomID, pushState, previewMeta) } @@ -151,10 +156,21 @@ class ContextFields implements MainScreenContextFields { return room.preferences.room_window_title.replace("$room", name!) } - #setActiveRoom(room: RoomStateStore, pushState: boolean) { + #setActiveRoom(room: RoomStateStore, space: RoomListFilter | undefined | null, pushState: boolean) { window.activeRoom = room this.directSetActiveRoom(room) this.directSetRightPanel(null) + if (!space && this.client.store.currentRoomListFilter) { + const roomListEntry = this.client.store.roomListEntries.get(room.roomID) + if (roomListEntry && !this.client.store.currentRoomListFilter.include(roomListEntry)) { + space = this.client.store.findMatchingSpace(roomListEntry) + } + } + if (space && space !== this.client.store.currentRoomListFilter) { + console.log("Switching to space", space?.id) + this.directSetSpace(space) + this.client.store.currentRoomListFilter = space + } this.rightPanelStack = [] this.client.store.activeRoomID = room.roomID this.client.store.activeRoomIsPreview = false @@ -168,7 +184,7 @@ class ContextFields implements MainScreenContextFields { .querySelector(`div.room-entry[data-room-id="${CSS.escape(room.roomID)}"]`) ?.scrollIntoView({ block: "nearest" }) if (pushState) { - history.pushState({ room_id: room.roomID, space_id: history.state?.space_id }, "") + history.pushState({ room_id: room.roomID, space_id: space?.id ?? history.state?.space_id }, "") } let roomNameForTitle = room.meta.current.name if (roomNameForTitle && roomNameForTitle.length > 48) { @@ -217,7 +233,7 @@ class ContextFields implements MainScreenContextFields { const SYNC_ERROR_HIDE_DELAY = 30 * 1000 -const handleURLHash = (client: Client) => { +const handleURLHash = (client: Client, context: MainScreenContextFields) => { if (!location.hash.startsWith("#/uri/")) { if (location.search) { const currentETag = ( @@ -268,7 +284,7 @@ const handleURLHash = (client: Client) => { // TODO loading indicator or something for this? client.rpc.resolveAlias(uri.identifier).then( res => { - window.mainScreenContext.setActiveRoom(res.room_id, { + context.setActiveRoom(res.room_id, { alias: uri.identifier, via: res.servers.slice(0, 3), }) @@ -321,13 +337,13 @@ const MainScreen = () => { context.setActiveRoom(roomID, { alias: ensureString(evt.state?.source_alias) || undefined, via: ensureStringArray(evt.state?.source_via), - }, false) + }, undefined, false) } context.setRightPanel(evt.state?.right_panel ?? null, false) } window.addEventListener("popstate", listener) const initHandle = () => { - const state = handleURLHash(client) + const state = handleURLHash(client, context) listener({ state } as PopStateEvent) } let cancel = () => {} diff --git a/web/src/ui/MainScreenContext.ts b/web/src/ui/MainScreenContext.ts index 28aa97d1..de714253 100644 --- a/web/src/ui/MainScreenContext.ts +++ b/web/src/ui/MainScreenContext.ts @@ -13,14 +13,14 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { createContext } from "react" +import React, { createContext } from "react" import { RoomListFilter } from "@/api/statestore" import type { RoomID } from "@/api/types" import type { RightPanelProps } from "./rightpanel/RightPanel.tsx" import type { RoomPreviewProps } from "./roomview/RoomPreview.tsx" export interface MainScreenContextFields { - setActiveRoom: (roomID: RoomID | null, previewMeta?: Partial) => void + setActiveRoom: (roomID: RoomID | null, previewMeta?: Partial, toSpace?: RoomListFilter) => void setSpace: (space: RoomListFilter | null, pushState?: boolean) => void clickRoom: (evt: React.MouseEvent) => void clearActiveRoom: () => void diff --git a/web/src/ui/roomlist/RoomList.tsx b/web/src/ui/roomlist/RoomList.tsx index 39d4cb54..c83be1da 100644 --- a/web/src/ui/roomlist/RoomList.tsx +++ b/web/src/ui/roomlist/RoomList.tsx @@ -77,8 +77,7 @@ const RoomList = ({ activeRoomID, space }: RoomListProps) => { for (let i = client.store.roomList.current.length - 1; i >= 0; i--) { const entry = client.store.roomList.current[i] if (entry[wantedField] > 0 && space.include(entry)) { - mainScreen.setActiveRoom(entry.room_id) - mainScreen.setSpace(space) + mainScreen.setActiveRoom(entry.room_id, undefined, space) evt.stopPropagation() break }