Send own typing status

This commit is contained in:
Cadence Ember 2020-11-09 01:11:28 +13:00
parent c87b6dcaa7
commit f4b13dbde4
Signed by: cadence
GPG key ID: BC1C2C61CF521B17
4 changed files with 69 additions and 2 deletions

View file

@ -5,24 +5,85 @@ const {chat} = require("./chat.js")
const input = q("#c-chat-textarea") const input = q("#c-chat-textarea")
class TypingManager {
constructor() {
this.time = 20000 // how long to appear to type for
this.margin = 5000 // how long before the end of the timeout to send the request again
/** The room that we're typing in. We can semantically only type in one room at a time. */
this.typingRoom = null
this.timeout = null
}
request(id, typing) {
const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/rooms/${id}/typing/${lsm.get("mx_user_id")}`)
url.searchParams.set("access_token", lsm.get("access_token"))
const body = {typing}
if (typing) body.timeout = this.time
fetch(url.toString(), {
method: "PUT",
body: JSON.stringify(body)
})
}
schedule(id) {
this.request(id, true)
this.timeout = setTimeout(() => {
this.schedule(id)
}, this.time - this.margin)
}
update(id) {
if (id) { // typing somewhere
if (this.typingRoom === id) return // already typing, don't do anything
// state
this.typingRoom = id
// mark and schedule
this.schedule(id)
// add self to typing list now instead of waiting a round trip
const typing = store.rooms.get(id).value().timeline.typing
typing.edit(list => list.concat(lsm.get("mx_user_id")))
} else { // stopped typing
if (this.typingRoom) {
clearTimeout(this.timeout)
this.request(this.typingRoom, false)
}
this.typingRoom = null
}
}
}
const typingManager = new TypingManager()
store.activeRoom.subscribe("changeSelf", () => { store.activeRoom.subscribe("changeSelf", () => {
// stop typing. you semantically can't type in a room you're not in.
typingManager.update(null)
// focus input box
if (store.activeRoom.exists()) { if (store.activeRoom.exists()) {
input.focus() input.focus()
} }
}) })
input.addEventListener("keydown", event => { input.addEventListener("keydown", event => {
if (!store.activeRoom.exists()) return
// send message?
if (event.key === "Enter" && !event.shiftKey && !event.ctrlKey) { if (event.key === "Enter" && !event.shiftKey && !event.ctrlKey) {
event.preventDefault() event.preventDefault()
const body = input.value const body = input.value
send(input.value) send(input.value)
input.value = "" input.value = ""
fixHeight() fixHeight()
return
} }
}) })
input.addEventListener("input", () => { input.addEventListener("input", () => {
fixHeight() fixHeight()
// set typing
if (input.value) {
typingManager.update(store.activeRoom.value().id)
} else {
typingManager.update(null)
}
}) })
function fixHeight() { function fixHeight() {

View file

@ -30,7 +30,7 @@ class SubscribeValue extends Subscribable {
edit(f) { edit(f) {
if (this.exists()) { if (this.exists()) {
f(this.data) this.data = f(this.data)
this.set(this.data) this.set(this.data)
} else { } else {
throw new Error("Tried to edit a SubscribeValue that had no value") throw new Error("Tried to edit a SubscribeValue that had no value")

View file

@ -1,5 +1,6 @@
const {ElemJS, ejs, q} = require("./basic") const {ElemJS, ejs, q} = require("./basic")
const {store} = require("./store/store") const {store} = require("./store/store")
const lsm = require("./lsm")
/** /**
* Maximum number of typing users to display all names for. * Maximum number of typing users to display all names for.
@ -26,6 +27,7 @@ class Typing extends ElemJS {
changeRoom() { changeRoom() {
if (this.typingUnsubscribe) { if (this.typingUnsubscribe) {
this.typingUnsubscribe() this.typingUnsubscribe()
this.typingUnsubscribe = null
} }
if (!store.activeRoom.exists()) return if (!store.activeRoom.exists()) return
const room = store.activeRoom.value() const room = store.activeRoom.value()
@ -36,8 +38,11 @@ class Typing extends ElemJS {
render() { render() {
if (!store.activeRoom.exists()) return if (!store.activeRoom.exists()) return
const room = store.activeRoom.value() const room = store.activeRoom.value()
const users = room.timeline.typing.value() let users = [...room.timeline.typing.value()]
// don't show own typing status
users = users.filter(u => u !== lsm.get("mx_user_id"))
if (users.length === 0) { if (users.length === 0) {
// nobody is typing
this.removeClass("c-typing--typing") this.removeClass("c-typing--typing")
} else { } else {
let message = "" let message = ""

View file

@ -92,6 +92,7 @@
background-color: c.$darkest background-color: c.$darkest
padding: 8px padding: 8px
border: 1px solid c.$divider border: 1px solid c.$divider
white-space: pre-wrap
code code
background-color: c.$darker background-color: c.$darker