import { CollectionFreeFormView } from "../../views/collections/collectionFreeForm"; import React, { useState } from "react"; export function RecordingApi() { type Movement = { time: number, panX: number, panY: number, } type Presentation = { movements: Array meta: Object, startDate: Date | null, } const NULL_PRESENTATION = { movements: [], meta: {}, startDate: null, } const [currentPresentation, setCurrentPresenation] = useState(NULL_PRESENTATION) const [isRecording, setIsRecording] = useState(false) const [absoluteStart, setAbsoluteStart] = useState(-1) const initAndStart = (view: CollectionFreeFormView, meta?: Object): Error | undefined => { // check if already init a presentation if (currentPresentation.startDate !== null) { console.error('[recordingApi.ts] start() failed: current presentation data exists. please call clear() first.') return new Error('[recordingApi.ts] start()') } // (1a) get start date for presenation const startDate = new Date() // (1b) set start timestamp to absolute timestamp setAbsoluteStart(startDate.getTime()) // TODO: (2) assign meta content // (3) assign init values to currentPresenation setCurrentPresenation({ ...currentPresentation, startDate }) // (4) set isRecording true to allow trackMovements setIsRecording(true) } const clear = (): Error | undefined => { // TODO: maybe archive the data? if (isRecording) { console.error('[recordingApi.ts] clear() failed: currently recording presentation. call pause() or finish() first') return new Error('[recordingApi.ts] clear()') } // clear presenation data setCurrentPresenation(NULL_PRESENTATION) // clear isRecording setIsRecording(false) // clear absoluteStart setAbsoluteStart(-1) } const pause = (): Error | undefined => { if (currentPresentation.startDate === null) { console.error('[recordingApi.ts] pause() failed: no presentation started. try calling init() first') return new Error('[recordingApi.ts] pause(): no presenation') } // don't allow track movments setIsRecording(false) // set relativeStart to the pausedTimestamp const timestamp = new Date().getTime() setAbsoluteStart(timestamp) } const resume = () => { if (currentPresentation.startDate === null) { console.error('[recordingApi.ts] resume() failed: no presentation started. try calling init() first') return new Error('[recordingApi.ts] resume()') } const timestamp = new Date().getTime() const startTimestamp = currentPresentation.startDate?.getTime() if (!startTimestamp) { console.error('[recordingApi.ts] resume() failed: no presentation data. try calling init() first') return new Error('[recordingApi.ts] pause()') } setAbsoluteStart(prevTime => { // const relativeUnpause = timestamp - absoluteStart // const timePaused = relativeUnpause - prevTime // return timePaused + absoluteStart const absoluteTimePaused = timestamp - prevTime return absoluteTimePaused }) } const finish = (): Error | Presentation => { if (currentPresentation.movements === null) { console.error('[recordingApi.ts] finish() failed: no presentation data. try calling init() first') return new Error('[recordingApi.ts] finish()') } // make copy and clear this class's data const returnCopy = { ...currentPresentation } clear() // return the copy return returnCopy } const trackMovements = (panX: number, panY: number): Error | undefined => { // ensure we are recording if (!isRecording) { console.error('[recordingApi.ts] pause() failed: recording is paused()') return new Error('[recordingApi.ts] pause()') } // get the relative time const timestamp = new Date().getTime() const relativeTime = timestamp - absoluteStart // make new movement struct const movement: Movement = { time: relativeTime, panX, panY } // add that movement struct to the current presentation data setCurrentPresenation(prevPres => { const movements = [...prevPres.movements, movement] return {...prevPres, movements} }) } // TOOD: need to pause all intervals if possible lol // TODO: extract this into different class with pause and resume recording const followMovements = (presentation: Presentation, docView: CollectionFreeFormView): void => { const document = docView.Document const { movements } = presentation movements.forEach(movement => { const { panX, panY, time } = movement // set the pan to what was stored setTimeout(() => { document._panX = panX; document._panY = panY; }, time) }) } }