mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
web/composer: send typing notifications
This commit is contained in:
parent
c16a2c2c80
commit
3c596a200f
4 changed files with 27 additions and 5 deletions
2
go.mod
2
go.mod
|
@ -13,7 +13,7 @@ require (
|
||||||
golang.org/x/crypto v0.27.0
|
golang.org/x/crypto v0.27.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
maunium.net/go/mauflag v1.0.0
|
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 (
|
require (
|
||||||
|
|
4
go.sum
4
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=
|
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 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
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.20241014212413-e2c698098862 h1:L+UmRjYbb7Y1R/iOpVCFksH9oGI59o8qI07S3hy+hq4=
|
||||||
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/go.mod h1:yIs8uVcl3ZiTuDzAYmk/B4/z9dQqegF0rcOWV4ncgko=
|
||||||
|
|
|
@ -131,6 +131,10 @@ export default abstract class RPCClient {
|
||||||
return this.request("mark_read", { room_id, event_id, receipt_type })
|
return this.request("mark_read", { room_id, event_id, receipt_type })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTyping(room_id: RoomID, timeout: number): Promise<boolean> {
|
||||||
|
return this.request("set_typing", { room_id, timeout })
|
||||||
|
}
|
||||||
|
|
||||||
ensureGroupSessionShared(room_id: RoomID): Promise<boolean> {
|
ensureGroupSessionShared(room_id: RoomID): Promise<boolean> {
|
||||||
return this.request("ensure_group_session_shared", { room_id })
|
return this.request("ensure_group_session_shared", { room_id })
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ const MessageComposer = ({ room, replyTo, setTextRows, closeReply }: MessageComp
|
||||||
const client = use(ClientContext)!
|
const client = use(ClientContext)!
|
||||||
const [text, setText] = useState("")
|
const [text, setText] = useState("")
|
||||||
const textRows = useRef(1)
|
const textRows = useRef(1)
|
||||||
|
const typingSentAt = useRef(0)
|
||||||
const fullSetText = useCallback((text: string, setDraft: boolean) => {
|
const fullSetText = useCallback((text: string, setDraft: boolean) => {
|
||||||
setText(text)
|
setText(text)
|
||||||
textRows.current = text === "" ? 1 : text.split("\n").length
|
textRows.current = text === "" ? 1 : text.split("\n").length
|
||||||
|
@ -74,12 +75,29 @@ const MessageComposer = ({ room, replyTo, setTextRows, closeReply }: MessageComp
|
||||||
}, [sendMessage])
|
}, [sendMessage])
|
||||||
const onChange = useCallback((evt: React.ChangeEvent<HTMLTextAreaElement>) => {
|
const onChange = useCallback((evt: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
fullSetText(evt.target.value, true)
|
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 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
|
// To try to avoid the input bar flashing, use useLayoutEffect instead of useEffect
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
fullSetText(draftStore.get(room.roomID), false)
|
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 <div className="message-composer">
|
return <div className="message-composer">
|
||||||
{replyTo && <ReplyBody room={room} event={replyTo} onClose={closeReply}/>}
|
{replyTo && <ReplyBody room={room} event={replyTo} onClose={closeReply}/>}
|
||||||
<div className="input-area">
|
<div className="input-area">
|
||||||
|
|
Loading…
Add table
Reference in a new issue