From 3c596a200f9af3b572238cd4f4f1b0649bbba4f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Oct 2024 00:40:06 +0300 Subject: [PATCH] web/composer: send typing notifications --- go.mod | 2 +- go.sum | 4 ++-- web/src/api/rpc.ts | 4 ++++ web/src/ui/MessageComposer.tsx | 22 ++++++++++++++++++++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index e870a9f..36657b8 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( golang.org/x/crypto v0.27.0 gopkg.in/yaml.v3 v3.0.1 maunium.net/go/mauflag v1.0.0 - maunium.net/go/mautrix v0.21.1-0.20241014142315-efc532bfb2ce + maunium.net/go/mautrix v0.21.1-0.20241014212413-e2c698098862 ) require ( diff --git a/go.sum b/go.sum index b555844..6fb9c39 100644 --- a/go.sum +++ b/go.sum @@ -66,5 +66,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.21.1-0.20241014142315-efc532bfb2ce h1:7fgaFJvpsy11S8KcZhbcwhg4kPzFid9aRNgqJjNpOHE= -maunium.net/go/mautrix v0.21.1-0.20241014142315-efc532bfb2ce/go.mod h1:yIs8uVcl3ZiTuDzAYmk/B4/z9dQqegF0rcOWV4ncgko= +maunium.net/go/mautrix v0.21.1-0.20241014212413-e2c698098862 h1:L+UmRjYbb7Y1R/iOpVCFksH9oGI59o8qI07S3hy+hq4= +maunium.net/go/mautrix v0.21.1-0.20241014212413-e2c698098862/go.mod h1:yIs8uVcl3ZiTuDzAYmk/B4/z9dQqegF0rcOWV4ncgko= diff --git a/web/src/api/rpc.ts b/web/src/api/rpc.ts index 6349421..1e323b5 100644 --- a/web/src/api/rpc.ts +++ b/web/src/api/rpc.ts @@ -131,6 +131,10 @@ export default abstract class RPCClient { return this.request("mark_read", { room_id, event_id, receipt_type }) } + setTyping(room_id: RoomID, timeout: number): Promise { + return this.request("set_typing", { room_id, timeout }) + } + ensureGroupSessionShared(room_id: RoomID): Promise { return this.request("ensure_group_session_shared", { room_id }) } diff --git a/web/src/ui/MessageComposer.tsx b/web/src/ui/MessageComposer.tsx index e237d8a..d531ab6 100644 --- a/web/src/ui/MessageComposer.tsx +++ b/web/src/ui/MessageComposer.tsx @@ -37,6 +37,7 @@ const MessageComposer = ({ room, replyTo, setTextRows, closeReply }: MessageComp const client = use(ClientContext)! const [text, setText] = useState("") const textRows = useRef(1) + const typingSentAt = useRef(0) const fullSetText = useCallback((text: string, setDraft: boolean) => { setText(text) textRows.current = text === "" ? 1 : text.split("\n").length @@ -74,12 +75,29 @@ const MessageComposer = ({ room, replyTo, setTextRows, closeReply }: MessageComp }, [sendMessage]) const onChange = useCallback((evt: React.ChangeEvent) => { fullSetText(evt.target.value, true) - }, [fullSetText]) + const now = Date.now() + if (evt.target.value !== "" && typingSentAt.current + 5_000 < now) { + typingSentAt.current = now + client.rpc.setTyping(room.roomID, 10_000) + .catch(err => console.error("Failed to send typing notification:", err)) + } else if (evt.target.value == "" && typingSentAt.current > 0) { + typingSentAt.current = 0 + client.rpc.setTyping(room.roomID, 0) + .catch(err => console.error("Failed to send stop typing notification:", err)) + } + }, [client, room.roomID, fullSetText]) // To ensure the cursor jumps to the end, do this in an effect rather than as the initial value of useState // To try to avoid the input bar flashing, use useLayoutEffect instead of useEffect useLayoutEffect(() => { fullSetText(draftStore.get(room.roomID), false) - }, [room.roomID, fullSetText]) + return () => { + if (typingSentAt.current > 0) { + typingSentAt.current = 0 + client.rpc.setTyping(room.roomID, 0) + .catch(err => console.error("Failed to send stop typing notification due to room switch:", err)) + } + } + }, [client, room.roomID, fullSetText]) return
{replyTo && }