diff --git a/web/src/App.tsx b/web/src/App.tsx index 85b33b0..8de3b8e 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { useEffect, useLayoutEffect, useMemo } from "react" +import { useEffect, useMemo } from "react" import { ScaleLoader } from "react-spinners" import Client from "./api/client.ts" import RPCClient from "./api/rpc.ts" @@ -36,10 +36,10 @@ function App() { const client = useMemo(() => new Client(makeRPCClient()), []) const connState = useEventAsState(client.rpc.connect) const clientState = useEventAsState(client.state) - useLayoutEffect(() => { + useEffect(() => { window.client = client + client.start() }, [client]) - useEffect(() => client.start(), [client]) const afterConnectError = Boolean(connState?.error && connState.reconnecting && clientState?.is_verified) useEffect(() => { diff --git a/web/src/api/statestore/room.ts b/web/src/api/statestore/room.ts index 98acbb0..23fc555 100644 --- a/web/src/api/statestore/room.ts +++ b/web/src/api/statestore/room.ts @@ -92,6 +92,7 @@ export class RoomStateStore { readonly meta: NonNullCachedEventDispatcher timeline: TimelineRowTuple[] = [] timelineCache: (MemDBEvent | null)[] = [] + editTargets: EventRowID[] = [] state: Map> = new Map() stateLoaded = false typing: UserID[] = [] @@ -134,16 +135,25 @@ export class RoomStateStore { } #updateTimelineCache() { + const ownMessages: EventRowID[] = [] this.timelineCache = this.timeline.map(rt => { const evt = this.eventsByRowID.get(rt.event_rowid) if (!evt) { return null } evt.timeline_rowid = rt.timeline_rowid + if ( + evt.sender === this.parent.userID + && evt.type === "m.room.message" + && evt.relation_type !== "m.replace" + ) { + ownMessages.push(evt.rowid) + } return evt }).concat(this.pendingEvents .map(rowID => this.eventsByRowID.get(rowID)) .filter(evt => !!evt)) + this.editTargets = ownMessages } notifyTimelineSubscribers() { diff --git a/web/src/ui/MainScreen.tsx b/web/src/ui/MainScreen.tsx index 2cfb2fc..ca2c381 100644 --- a/web/src/ui/MainScreen.tsx +++ b/web/src/ui/MainScreen.tsx @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { JSX, use, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react" +import { JSX, use, useEffect, useMemo, useReducer, useRef, useState } from "react" import { SyncLoader } from "react-spinners" import Client from "@/api/client.ts" import { RoomStateStore } from "@/api/statestore" @@ -280,10 +280,8 @@ const MainScreen = () => { () => new ContextFields(directSetRightPanel, directSetActiveRoom, client), [client], ) - useLayoutEffect(() => { - window.mainScreenContext = context - }, [context]) useEffect(() => { + window.mainScreenContext = context const listener = (evt: PopStateEvent) => { skipNextTransitionRef.current = evt.hasUAVisualTransition const roomID = evt.state?.room_id ?? null diff --git a/web/src/ui/composer/MessageComposer.tsx b/web/src/ui/composer/MessageComposer.tsx index e11be36..f9437b3 100644 --- a/web/src/ui/composer/MessageComposer.tsx +++ b/web/src/ui/composer/MessageComposer.tsx @@ -310,18 +310,18 @@ const MessageComposer = () => { } } else if (fullKey === "ArrowUp" && inp.selectionStart === 0 && inp.selectionEnd === 0) { const currentlyEditing = editing - ? roomCtx.ownMessages.indexOf(editing.rowid) - : roomCtx.ownMessages.length - const prevEventToEditID = roomCtx.ownMessages[currentlyEditing - 1] + ? room.editTargets.indexOf(editing.rowid) + : room.editTargets.length + const prevEventToEditID = room.editTargets[currentlyEditing - 1] const prevEventToEdit = prevEventToEditID ? room.eventsByRowID.get(prevEventToEditID) : undefined if (prevEventToEdit) { roomCtx.setEditing(prevEventToEdit) evt.preventDefault() } } else if (editing && fullKey === "ArrowDown" && inp.selectionStart === state.text.length) { - const currentlyEditingIdx = roomCtx.ownMessages.indexOf(editing.rowid) + const currentlyEditingIdx = room.editTargets.indexOf(editing.rowid) const nextEventToEdit = currentlyEditingIdx - ? room.eventsByRowID.get(roomCtx.ownMessages[currentlyEditingIdx + 1]) : undefined + ? room.eventsByRowID.get(room.editTargets[currentlyEditingIdx + 1]) : undefined roomCtx.setEditing(nextEventToEdit ?? null) // This timeout is very hacky and probably doesn't work in every case setTimeout(() => inp.setSelectionRange(0, 0), 0) diff --git a/web/src/ui/roomview/roomcontext.ts b/web/src/ui/roomview/roomcontext.ts index 3b80e3b..d38ff54 100644 --- a/web/src/ui/roomview/roomcontext.ts +++ b/web/src/ui/roomview/roomcontext.ts @@ -15,7 +15,7 @@ // along with this program. If not, see . import { RefObject, createContext, createRef, use } from "react" import { RoomStateStore } from "@/api/statestore" -import { EventID, EventRowID, MemDBEvent } from "@/api/types" +import { EventID, MemDBEvent } from "@/api/types" import { NonNullCachedEventDispatcher } from "@/util/eventdispatcher.ts" import { escapeMarkdown } from "@/util/markdown.ts" @@ -29,7 +29,6 @@ export class RoomContextData { public setEditing: (evt: MemDBEvent | null) => void = noop("setEditing") public insertText: (text: string) => void = noop("insertText") public readonly isEditing = new NonNullCachedEventDispatcher(false) - public ownMessages: EventRowID[] = [] public scrolledToBottom = true constructor(public store: RoomStateStore) {} diff --git a/web/src/ui/timeline/TimelineView.tsx b/web/src/ui/timeline/TimelineView.tsx index 9bb8903..8499f38 100644 --- a/web/src/ui/timeline/TimelineView.tsx +++ b/web/src/ui/timeline/TimelineView.tsx @@ -67,12 +67,6 @@ const TimelineView = () => { timelineViewRef.current.scrollTop += timelineViewRef.current.scrollHeight - oldScrollHeight.current } prevOldestTimelineRow.current = timeline[0]?.timeline_rowid ?? 0 - roomCtx.ownMessages = timeline - .filter(evt => evt !== null - && evt.sender === client.userID - && evt.type === "m.room.message" - && evt.relation_type !== "m.replace") - .map(evt => evt!.rowid) }, [client.userID, roomCtx, timeline]) useEffect(() => { const newestEvent = timeline[timeline.length - 1]