import { CollectionFreeFormView } from "../../views/collections/collectionFreeForm"; import React, { useState } from "react"; import { IReactionDisposer, observe, reaction, observable } from "mobx"; import { SelectionManager } from "../../util/SelectionManager"; export class RecordingApi { @observable static _instance: LinkManager; constructor() { } type Movement = { time: number, panX: number, panY: number, } export 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) export const initAndStart = (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) } export 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) // set isRecording false setIsRecording(false) // default absoluteStart setAbsoluteStart(-1) } export 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()') } // don't allow track movments setIsRecording(false) // set relativeStart to the pausedTimestamp const timestamp = new Date().getTime() setAbsoluteStart(timestamp) } export 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 }) } export 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 return currentPresentation } export 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 export 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) }) } // export let pres: Map = new Map() // export function AddRecordingFFView(ffView: CollectionFreeFormView): void { // pres.set(ffView, // reaction(() => ({ x: ffView.panX, y: ffView.panY }), // (pt) => RecordingApi.trackMovements(ffView, pt.x, pt.y))) // ) // } // export function RemoveRecordingFFView(ffView: CollectionFreeFormView): void { // const disposer = pres.get(ffView); // disposer?.(); // pres.delete(ffView) // } }