aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/recording/recordingApi.tsx151
-rw-r--r--src/client/util/RecordingApi.ts257
-rw-r--r--src/client/views/Main.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx37
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx14
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.scss18
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx41
-rw-r--r--src/client/views/nodes/VideoBox.tsx23
8 files changed, 336 insertions, 207 deletions
diff --git a/src/client/apis/recording/recordingApi.tsx b/src/client/apis/recording/recordingApi.tsx
deleted file mode 100644
index 55714f03b..000000000
--- a/src/client/apis/recording/recordingApi.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-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<Movement>
- meta: Object,
- startDate: Date | null,
- }
-
- const NULL_PRESENTATION = {
- movements: [],
- meta: {},
- startDate: null,
- }
-
- const [currentPresentation, setCurrentPresenation] = useState<Presentation>(NULL_PRESENTATION)
- const [isRecording, setIsRecording] = useState(false)
- const [absoluteStart, setAbsoluteStart] = useState<number>(-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)
- })
- }
-
-} \ No newline at end of file
diff --git a/src/client/util/RecordingApi.ts b/src/client/util/RecordingApi.ts
new file mode 100644
index 000000000..fec579486
--- /dev/null
+++ b/src/client/util/RecordingApi.ts
@@ -0,0 +1,257 @@
+import { CollectionFreeFormView } from "../views/collections/collectionFreeForm";
+import { IReactionDisposer, observable, reaction } from "mobx";
+import { NumCast } from "../../fields/Types";
+import { Doc } from "../../fields/Doc";
+import { VideoBox } from "../views/nodes/VideoBox";
+
+type Movement = {
+ time: number,
+ panX: number,
+ panY: number,
+}
+
+type Presentation = {
+ movements: Array<Movement> | null
+ meta: Object,
+}
+
+export class RecordingApi {
+
+ private static NULL_PRESENTATION: Presentation = {
+ movements: null,
+ meta: {},
+ }
+
+ // instance variables
+ private currentPresentation: Presentation;
+ private isRecording: boolean;
+ private absoluteStart: number;
+
+
+ // create static instance and getter for global use
+ @observable static _instance: RecordingApi;
+ public static get Instance(): RecordingApi { return RecordingApi._instance }
+ public constructor() {
+ // init the global instance
+ RecordingApi._instance = this;
+
+ // init the instance variables
+ this.currentPresentation = RecordingApi.NULL_PRESENTATION
+ this.isRecording = false;
+ this.absoluteStart = -1;
+
+ // used for tracking movements in the view frame
+ this.disposeFunc = null;
+ this.recordingFFView = null;
+
+ // for now, set playFFView
+ this.playFFView = null;
+ this.timers = null;
+ }
+
+ // little helper :)
+ private get isInitPresenation(): boolean {
+ return this.currentPresentation.movements === null
+ }
+
+ public start = (meta?: Object): Error | undefined => {
+ // check if already init a presentation
+ if (!this.isInitPresenation) {
+ console.error('[recordingApi.ts] start() failed: current presentation data exists. please call clear() first.')
+ return new Error('[recordingApi.ts] start()')
+ }
+
+ // update the presentation mode
+ Doc.UserDoc().presentationMode = 'recording'
+
+ // (1a) get start date for presenation
+ const startDate = new Date()
+ // (1b) set start timestamp to absolute timestamp
+ this.absoluteStart = startDate.getTime()
+
+ // (2) assign meta content if it exists
+ this.currentPresentation.meta = meta || {}
+ // (3) assign start date to currentPresenation
+ this.currentPresentation.movements = []
+ // (4) set isRecording true to allow trackMovements
+ this.isRecording = true
+ }
+
+ public clear = (): Error | Presentation => {
+ // TODO: maybe archive the data?
+ if (this.isRecording) {
+ console.error('[recordingApi.ts] clear() failed: currently recording presentation. call pause() first')
+ return new Error('[recordingApi.ts] clear()')
+ }
+
+ // update the presentation mode
+ Doc.UserDoc().presentationMode = 'none'
+
+ const presCopy = { ...this.currentPresentation }
+
+ // clear presenation data
+ this.currentPresentation = RecordingApi.NULL_PRESENTATION
+ // clear isRecording
+ this.isRecording = false
+ // clear absoluteStart
+ this.absoluteStart = -1
+ // clear the disposeFunc
+ this.removeRecordingFFView()
+
+ return presCopy;
+ }
+
+ public pause = (): Error | undefined => {
+ if (this.isInitPresenation) {
+ console.error('[recordingApi.ts] pause() failed: no presentation started. try calling init() first')
+ return new Error('[recordingApi.ts] pause(): no presentation')
+ }
+ // don't allow track movments
+ this.isRecording = false
+
+ // set adjust absoluteStart to add the time difference
+ const timestamp = new Date().getTime()
+ this.absoluteStart = timestamp - this.absoluteStart
+ }
+
+ public resume = () => {
+ this.isRecording = true
+ // set absoluteStart to the pausedTimestamp
+ this.absoluteStart = new Date().getTime() - this.absoluteStart
+ }
+
+ private trackMovements = (panX: number, panY: number): Error | undefined => {
+ // ensure we are recording
+ if (!this.isRecording) {
+ return new Error('[recordingApi.ts] trackMovements()')
+ }
+ // check to see if the presetation is init
+ if (this.isInitPresenation) {
+ return new Error('[recordingApi.ts] trackMovements(): no presentation')
+ }
+
+ // get the time
+ const time = new Date().getTime() - this.absoluteStart
+ // make new movement object
+ console.log(time)
+ const movement: Movement = { time, panX, panY }
+
+ // add that movement to the current presentation data's movement array
+ this.currentPresentation.movements && this.currentPresentation.movements.push(movement)
+ }
+
+ // instance variable for the FFView
+ private disposeFunc: IReactionDisposer | null;
+ private recordingFFView: CollectionFreeFormView | null;
+
+ // set the FFView that will be used in a reaction to track the movements
+ public setRecordingFFView = (view: CollectionFreeFormView): void => {
+ // set the view to the current view
+ if (view === this.recordingFFView || view === null) return;
+
+ //this.recordingFFView = view;
+ // set the reaction to track the movements
+ this.disposeFunc = reaction(
+ () => ({ x: NumCast(view.Document.panX, -1), y: NumCast(view.Document.panY, -1) }),
+ (res) => (res.x !== -1 && res.y !== -1) && this.trackMovements(res.x, res.y)
+ )
+
+ // for now, set the most recent recordingFFView to the playFFView
+ this.recordingFFView = view;
+ }
+
+ // call on dispose function to stop tracking movements
+ public removeRecordingFFView = (): void => {
+ this.disposeFunc?.();
+ this.disposeFunc = null;
+ }
+
+ // TODO: extract this into different class with pause and resume recording
+ // TODO: store the FFview with the movements
+ private playFFView: CollectionFreeFormView | null;
+ private timers: NodeJS.Timeout[] | null;
+
+ public setPlayFFView = (view: CollectionFreeFormView): void => {
+ this.playFFView = view
+ }
+
+ public pauseMovements = (): undefined | Error => {
+ if (this.playFFView === null) {
+ return new Error('[recordingApi.ts] pauseMovements() failed: no view')
+ }
+
+ if (!this._isPlaying) {
+ //return new Error('[recordingApi.ts] pauseMovements() failed: not playing')
+ return
+ }
+ this._isPlaying = false
+ // TODO: set userdoc presentMode to browsing
+ this.timers?.map(timer => clearTimeout(timer))
+
+ // this.videoBox = null;
+ }
+
+ private videoBox: VideoBox | null = null;
+
+ // by calling pause on the VideoBox, the pauseMovements will be called
+ public pauseVideoAndMovements = (): boolean => {
+ this.videoBox?.Pause()
+ return this.videoBox === null
+ }
+
+ private _isPlaying = false;
+
+ public playMovements = (presentation: Presentation, timeViewed: number = 0, videoBox?: VideoBox): undefined | Error => {
+ if (presentation.movements === null || this.playFFView === null) {
+ return new Error('[recordingApi.ts] followMovements() failed: no presentation data or no view')
+ }
+
+ if (this._isPlaying) {
+ //return new Error('[recordingApi.ts] playMovements() failed: already playing')
+ return
+ }
+ this._isPlaying = true;
+ Doc.UserDoc().presentationMode = 'watching';
+
+ // TODO: consider this bug at the end of the clip on seek
+ // console.log(timeViewed)
+ this.videoBox = videoBox || null;
+
+ const document = this.playFFView.Document
+ const { movements } = presentation
+ this.timers = movements.reduce((arr: NodeJS.Timeout[], movement) => {
+ const { panX, panY, time } = movement
+
+ const timeDiff = time - timeViewed*1000
+ if (timeDiff < 0) return arr;
+
+ // set the pan to what was stored
+ arr.push(setTimeout(() => {
+ document._panX = panX;
+ document._panY = panY;
+ if (movement === movements[movements.length - 1]) {
+ this._isPlaying = false;
+ Doc.UserDoc().presentationMode = 'none';
+ }
+ }, timeDiff))
+ return arr;
+ }, [])
+
+ }
+
+ // Unfinished code for tracing multiple free form views
+ // export let pres: Map<CollectionFreeFormView, IReactionDisposer> = 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)
+ // }
+}
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 8560ccb29..517fe097c 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -8,6 +8,7 @@ import { AssignAllExtensions } from "../../extensions/General/Extensions";
import { Docs } from "../documents/Documents";
import { CurrentUserUtils } from "../util/CurrentUserUtils";
import { LinkManager } from "../util/LinkManager";
+import { RecordingApi } from "../util/RecordingApi";
import { CollectionView } from "./collections/CollectionView";
import { MainView } from "./MainView";
@@ -36,5 +37,6 @@ AssignAllExtensions();
const expires = "expires=" + d.toUTCString();
document.cookie = `loadtime=${loading};${expires};path=/`;
new LinkManager();
+ new RecordingApi;
ReactDOM.render(<MainView />, document.getElementById('root'));
})(); \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index edc872a40..aa2e0c417 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -54,6 +54,7 @@ import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
import e = require("connect-flash");
+import { RecordingApi } from "../../../util/RecordingApi";
export const panZoomSchema = createSchema({
_panX: "number",
@@ -121,8 +122,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _keyframeEditing = false;
@observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged.
- @observable storedMovements: object[] = []; // stores the movement if in recoding mode
-
@computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
@computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
@computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); }
@@ -964,36 +963,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
}
-
- followMovements = (): void => {
- // need the first for subtraction
- let first = null;
-
- this.storedMovements.forEach(movement => {
- if (first === null) first = movement.time;
-
- // set the pan to what was stored
- setTimeout(() => {
- this.Document._panX = movement.panX;
- this.Document._panY = movement.panY;
- }, movement.time - first)
- })
-
- // for now, clear the movements
- this.storedMovements = []
- }
-
@action
setPan(panX: number, panY: number, panTime: number = 0, clamp: boolean = false) {
- // if not presenting, just retrace the movements
+ // set the current respective FFview to the tab being panned.
+ Doc.UserDoc()?.presentationMode === 'recording' && RecordingApi.Instance.setRecordingFFView(this);
+ // TODO: make this based off the specific recording FFView
+ Doc.UserDoc()?.presentationMode === 'none' && RecordingApi.Instance.setPlayFFView(this);
if (Doc.UserDoc()?.presentationMode === 'watching') {
- this.followMovements()
- return;
- }
-
- if (Doc.UserDoc()?.presentationMode === 'recording') {
- // store as many movments as possible
- this.storedMovements.push({time: new Date().getTime(), panX, panY})
+ RecordingApi.Instance.pauseVideoAndMovements();
+ Doc.UserDoc().presentationMode = 'none';
+ // RecordingApi.Instance.pauseMovements()
}
if (!this.isAnnotationOverlay && clamp) {
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index a49cbbea5..d00f05759 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -1,7 +1,7 @@
import { action, observable } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
-import { AudioField, VideoField } from "../../../../fields/URLField";
+import { VideoField } from "../../../../fields/URLField";
import { Upload } from "../../../../server/SharedMediaTypes";
import { ViewBoxBaseComponent } from "../../DocComponent";
import { FieldView } from "../FieldView";
@@ -9,6 +9,8 @@ import { VideoBox } from "../VideoBox";
import { RecordingView } from './RecordingView';
import { DocumentType } from "../../../documents/DocumentTypes";
+import { RecordingApi } from "../../../util/RecordingApi";
+
@observer
export class RecordingBox extends ViewBoxBaseComponent() {
@@ -31,18 +33,20 @@ export class RecordingBox extends ViewBoxBaseComponent() {
@action
setResult = (info: Upload.FileInformation) => {
- console.log("Setting result to " + info)
+ // console.log("Setting result to " + info)
this.result = info
- console.log(this.result.accessPaths.agnostic.client)
+ // console.log(this.result.accessPaths.agnostic.client)
this.dataDoc.type = DocumentType.VID;
- console.log(this.videoDuration)
+ // console.log(this.videoDuration)
this.dataDoc[this.fieldKey + "-duration"] = this.videoDuration;
// this.layoutDoc.layout = VideoBox.LayoutString(this.fieldKey);
this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey);
// this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = undefined;
// this.layoutDoc._fitWidth = undefined;
- this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.agnostic.client);
+ this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.agnostic.client);
+ // stringify the presenation and store it
+ this.dataDoc[this.fieldKey + "-presentation"] = JSON.stringify(RecordingApi.Instance.clear());
}
render() {
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.scss b/src/client/views/nodes/RecordingBox/RecordingView.scss
index 0c153c9c8..c55af5952 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.scss
+++ b/src/client/views/nodes/RecordingBox/RecordingView.scss
@@ -1,9 +1,11 @@
video {
- flex: 100%;
+ // flex: 100%;
width: 100%;
// min-height: 400px;
- height: auto;
- display: block;
+ //height: auto;
+ height: 100%;
+ //display: block;
+ object-fit: cover;
background-color: black;
}
@@ -14,18 +16,20 @@ button {
.recording-container {
height: 100%;
width: 100%;
- display: flex;
+ // display: flex;
pointer-events: all;
+ background-color: grey;
}
.video-wrapper {
- max-width: 600px;
- max-width: 700px;
+ // max-width: 600px;
+ // max-width: 700px;
position: relative;
display: flex;
justify-content: center;
- overflow: hidden;
+ // overflow: hidden;
border-radius: 10px;
+ margin: 0;
}
.video-wrapper:hover .controls {
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index e5f6deca2..0a8294dcf 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -8,6 +8,8 @@ import { IconContext } from "react-icons";
import { Networking } from '../../../Network';
import { Upload } from '../../../../server/SharedMediaTypes';
+import { RecordingApi } from '../../../util/RecordingApi';
+
enum RecordingStatus {
Recording,
@@ -43,18 +45,23 @@ export function RecordingView(props: IRecordingViewProps) {
const audioRecorder = useRef<MediaRecorder | null>(null);
const videoElementRef = useRef<HTMLVideoElement | null>(null);
- const [finished, setFinished] = useState<Boolean>(false)
+ const [finished, setFinished] = useState<Boolean>(false)
const DEFAULT_MEDIA_CONSTRAINTS = {
- video: true,
- audio: true,
- // audio: {
- // echoCancellation: true,
- // noiseSuppression: true,
- // sampleRate: 44100
- // }
+ // video: true,
+ // audio: true
+ video: {
+ width: 1280,
+ height: 720,
+ },
+ // audio: true,
+ audio: {
+ echoCancellation: true,
+ noiseSuppression: true,
+ sampleRate: 44100
+ }
}
useEffect(() => {
@@ -150,7 +157,9 @@ export function RecordingView(props: IRecordingViewProps) {
// }
videoRecorder.current.onstart = (event: any) => {
- setRecording(true);
+ setRecording(true);
+ // RecordingApi.Instance.clear();
+ RecordingApi.Instance.start();
}
videoRecorder.current.onstop = () => {
@@ -163,7 +172,8 @@ export function RecordingView(props: IRecordingViewProps) {
// reset the temporary chunks
videoChunks = []
setRecording(false);
- setFinished(true);
+ setFinished(true);
+ RecordingApi.Instance.pause();
}
// recording paused
@@ -173,12 +183,14 @@ export function RecordingView(props: IRecordingViewProps) {
// reset the temporary chunks
videoChunks = []
- setRecording(false);
+ setRecording(false);
+ RecordingApi.Instance.pause();
}
videoRecorder.current.onresume = async (event: any) => {
await startShowingStream();
- setRecording(true);
+ setRecording(true);
+ RecordingApi.Instance.resume();
}
videoRecorder.current.start(200)
@@ -244,7 +256,7 @@ export function RecordingView(props: IRecordingViewProps) {
return toTwoDigit(minutes) + " : " + toTwoDigit(seconds);
}
- return (
+ return (
<div className="recording-container">
<div className="video-wrapper">
<video id="video"
@@ -293,8 +305,7 @@ export function RecordingView(props: IRecordingViewProps) {
<i className="bx bxs-volume-mute"></i>
)}
</button> */}
- </div>
-
+ </div>
</div>
</div>)
} \ No newline at end of file
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index b424225e7..8aecc2483 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -28,6 +28,7 @@ import { AnchorMenu } from "../pdf/AnchorMenu";
import { StyleProp } from "../StyleProvider";
import { FieldView, FieldViewProps } from './FieldView';
import "./VideoBox.scss";
+import { RecordingApi } from "../../util/RecordingApi";
const path = require('path');
@@ -117,6 +118,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
return field?.url.href ?? vfield?.url.href ?? "";
}
+ // returns the presentation data if it exists, null otherwise
+ @computed get presentation() {
+ const data = this.dataDoc[this.fieldKey + '-presentation'];
+ return data ? JSON.parse(data) : null;
+ }
+
@computed private get timeline() { return this._stackedTimeline; }
private get transition() { return this._clicking ? "left 0.5s, width 0.5s, height 0.5s" : ""; } // css transition for hiding/showing timeline
@@ -147,6 +154,17 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// plays video
@action public Play = (update: boolean = true) => {
+ if (Doc.UserDoc().presentationMode === 'watching' && !this._playing) {
+ console.log('VideoBox : Play : presentation mode', this._playing);
+ return;
+ }
+
+ // if presentation isn't null, call followmovements on the recording api
+ if (this.presentation) {
+ const err = RecordingApi.Instance.playMovements(this.presentation, this.player?.currentTime || 0, this);
+ err && console.log(err)
+ }
+
this._playing = true;
const eleTime = this.player?.currentTime || 0;
if (this.timeline) {
@@ -184,6 +202,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// pauses video
@action public Pause = (update: boolean = true) => {
+ if (this.presentation) {
+ const err = RecordingApi.Instance.pauseMovements();
+ err && console.log(err);
+ }
+
this._playing = false;
this.removeCurrentlyPlaying();
try {