mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-02-22 04:30:33 +09:00
84 lines
2.0 KiB
JavaScript
84 lines
2.0 KiB
JavaScript
import { Controller } from "@hotwired/stimulus"
|
|
import { cable } from "@hotwired/turbo-rails"
|
|
import { delay, nextFrame } from "helpers/timing_helpers"
|
|
|
|
const REFRESH_INTERVAL = 50 * 1000 // 50 seconds
|
|
|
|
// We delay transmitting visibility changes to ignore brief periods of invisibility,
|
|
// like switching to another tab and back
|
|
const VISIBILITY_CHANGE_DELAY = 5000 // 5 seconds
|
|
|
|
export default class extends Controller {
|
|
async connect() {
|
|
this.channel = await cable.subscribeTo({ channel: "PresenceChannel", room_id: Current.room.id }, {
|
|
connected: this.#websocketConnected,
|
|
disconnected: this.#websocketDisconnected
|
|
})
|
|
|
|
this.wasVisible = true
|
|
|
|
await nextFrame()
|
|
this.dispatch("present", { detail: { roomId: Current.room.id } })
|
|
}
|
|
|
|
disconnect() {
|
|
this.#stopRefreshTimer()
|
|
this.channel?.unsubscribe()
|
|
}
|
|
|
|
visibilityChanged = () => {
|
|
if (this.#isVisible) {
|
|
this.#visible()
|
|
} else {
|
|
this.#hidden()
|
|
}
|
|
}
|
|
|
|
#websocketConnected = () => {
|
|
this.connected = true
|
|
this.#startRefreshTimer()
|
|
}
|
|
|
|
#websocketDisconnected = () => {
|
|
this.connected = false
|
|
this.#stopRefreshTimer()
|
|
}
|
|
|
|
#visible = async () => {
|
|
await delay(VISIBILITY_CHANGE_DELAY)
|
|
|
|
if (this.connected && this.#isVisible && !this.wasVisible) {
|
|
this.channel.send({ action: "present" })
|
|
this.#startRefreshTimer()
|
|
this.wasVisible = true
|
|
}
|
|
}
|
|
|
|
#hidden = async () => {
|
|
await delay(VISIBILITY_CHANGE_DELAY)
|
|
|
|
if (this.connected && this.wasVisible && !this.#isVisible) {
|
|
this.#stopRefreshTimer()
|
|
this.channel.send({ action: "absent" })
|
|
this.wasVisible = false
|
|
}
|
|
}
|
|
|
|
#startRefreshTimer = () => {
|
|
this.refreshTimer ??= setInterval(this.#refresh, REFRESH_INTERVAL)
|
|
}
|
|
|
|
#stopRefreshTimer = () => {
|
|
clearInterval(this.refreshTimer)
|
|
this.refreshTimer = null
|
|
}
|
|
|
|
#refresh = () => {
|
|
this.channel.send({ action: "refresh" })
|
|
}
|
|
|
|
get #isVisible() {
|
|
return document.visibilityState === "visible"
|
|
}
|
|
}
|