change(tracker): add confirmation state for recording, borders around screen etc

This commit is contained in:
sylenien 2022-11-08 14:58:18 +01:00 committed by Delirium
parent 249e731569
commit 3ee4da6190
3 changed files with 105 additions and 1 deletions

View file

@ -150,6 +150,7 @@ export default class AssistManager {
const now = +new Date()
this.store.update({ assistStart: now })
// @ts-ignore
import('socket.io-client').then(({ default: io }) => {
if (this.cleaned) { return }
if (this.socket) { this.socket.close() } // TODO: single socket connection
@ -395,6 +396,8 @@ export default class AssistManager {
// @ts-ignore
const urlObject = new URL(window.env.API_EDP || window.location.origin)
// @ts-ignore TODO: set module in ts settings
return import('peerjs').then(({ default: Peer }) => {
if (this.cleaned) {return Promise.reject("Already cleaned")}
const peerOpts: Peer.PeerJSOption = {

View file

@ -12,6 +12,7 @@ import AnnotationCanvas from './AnnotationCanvas.js'
import ConfirmWindow from './ConfirmWindow/ConfirmWindow.js'
import { callConfirmDefault, } from './ConfirmWindow/defaults.js'
import type { Options as ConfirmOptions, } from './ConfirmWindow/defaults.js'
import ScreenRecordingState, { RecordingState, } from './ScreenRecordingState'
// TODO: fully specified strict check with no-any (everywhere)
@ -21,6 +22,7 @@ export interface Options {
onAgentConnect: StartEndCallback;
onCallStart: StartEndCallback;
onRemoteControlStart: StartEndCallback;
onRecordingRequest?: (agentInfo: Record<string, any>) => any;
session_calling_peer_key: string;
session_control_peer_key: string;
callConfirm: ConfirmOptions;
@ -144,6 +146,7 @@ export default class Assist {
private onStart() {
const app = this.app
const sessionId = app.getSessionID()
if (!sessionId) {
return app.debug.error('No session ID')
}
@ -199,6 +202,14 @@ export default class Assist {
},
)
const onAcceptRecording = () => {
socket.emit('recording_accepted')
}
const onDenyRecording = () => {
socket.emit('recording_denied')
}
const recordingState = new ScreenRecordingState(onAcceptRecording, onDenyRecording)
setTimeout(() => recordingState.requestRecording(), 5000)
// TODO: check incoming args
socket.on('request_control', this.remoteControl.requestControl)
socket.on('release_control', this.remoteControl.releaseControl)
@ -231,7 +242,7 @@ export default class Assist {
ids.forEach(id =>{
const agentInfo = this.agents[id]?.agentInfo
this.agents[id] = {
agentInfo,
...this.agents[id],
onDisconnect: this.options.onAgentConnect?.(agentInfo),
}
})
@ -269,6 +280,12 @@ export default class Assist {
socket.on('videofeed', (id, feedState) => {
callUI?.toggleVideoStream(feedState)
})
socket.on('request_recording', (id, agentData) => {
if (recordingState.status === RecordingState.Off) {
console.log('requested screen recording', this.agents[id].agentInfo, agentData)
this.options.onRecordingRequest?.(agentData)
}
})
const callingAgents: Map<string, string> = new Map() // !! uses socket.io ID
// TODO: merge peerId & socket.io id (simplest way - send peerId with the name)

View file

@ -0,0 +1,84 @@
export enum RecordingState {
Off,
Requested,
Recording,
}
const defaultStyles = '2px dashed red; position: fixed;'
const leftTop = 'left: 0; top: 0'
const bottomRight = 'right: 0; bottom: 0'
const borderEmulationStyles = {
left: `${leftTop}; height: 100vh; width: 0; border-left: ${defaultStyles}`,
top: `${leftTop}; height: 0; width: 100vw; border-top: ${defaultStyles}`,
right: `${bottomRight}; height: 100vh; width: 0; border-right: ${defaultStyles}`,
bottom: `${bottomRight}; height: 0; width: 100vw; border-bottom: ${defaultStyles}`,
}
export default class ScreenRecordingState {
public status = RecordingState.Off
constructor(
private readonly onAccept: () => void,
private readonly onDeny: () => void,
) {}
public requestRecording = () => {
// mount recording window
if (this.status !== RecordingState.Off) return
this.status = RecordingState.Requested
// todo: change timeout to deny after testing
setTimeout(() => {
console.log('starting recording')
this.acceptRecording()
}, 5000)
}
private readonly acceptRecording = () => {
const borders = {
left: window.document.createElement('div'),
top: window.document.createElement('div'),
right: window.document.createElement('div'),
bottom: window.document.createElement('div'),
}
const stopButton = window.document.createElement('div')
stopButton.onclick = this.denyRecording
const buttonStyle = 'position: fixed; bottom: 0; left: calc(50vw - 10px); padding: 4px; background: blue; border-radius: 6px; text-align: center;'
buttonStyle.split(';').forEach(styleEntry => {
console.log(styleEntry)
const styleKeyVal = styleEntry.split(':')
stopButton.style[styleKeyVal[0]] = styleKeyVal[1]
})
stopButton.textContent = 'Stop Recording'
stopButton.id = 'or-recording-border'
Object.entries(borderEmulationStyles).forEach(([key, style,]) => {
const styleEntries = style.split(';')
styleEntries.forEach(styleEntry => {
console.log(styleEntry)
const styleKeyVal = styleEntry.split(':')
borders[key].style[styleKeyVal[0]] = styleKeyVal[1]
})
borders[key].style = style
borders[key].id = 'or-recording-border'
window.document.appendChild(borders[key])
})
window.document.appendChild(stopButton)
this.onAccept()
this.status = RecordingState.Recording
}
private readonly denyRecording = () => {
this.onDeny()
this.status = RecordingState.Off
const borders = window.document.querySelectorAll('#or-recording-border')
if (borders.length > 0) {
borders.forEach(border => border.parentElement?.removeChild(border))
}
}
}