aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/RecordingBox
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/RecordingBox')
-rw-r--r--src/client/views/nodes/RecordingBox/ProgressBar.tsx205
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx93
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx43
-rw-r--r--src/client/views/nodes/RecordingBox/index.ts4
4 files changed, 175 insertions, 170 deletions
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.tsx b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
index 1bb2b7c84..62798bc2f 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.tsx
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
@@ -1,31 +1,33 @@
+/* eslint-disable react/no-array-index-key */
+/* eslint-disable react/require-default-props */
import * as React from 'react';
-import { useEffect, useState, useCallback, useRef } from "react"
-import "./ProgressBar.scss"
+import { useEffect, useState, useRef } from 'react';
+import './ProgressBar.scss';
import { MediaSegment } from './RecordingView';
interface ProgressBarProps {
- videos: MediaSegment[],
- setVideos: React.Dispatch<React.SetStateAction<MediaSegment[]>>,
- orderVideos: boolean,
- progress: number,
- recording: boolean,
- doUndo: boolean,
- setCanUndo?: React.Dispatch<React.SetStateAction<boolean>>,
+ videos: MediaSegment[];
+ setVideos: React.Dispatch<React.SetStateAction<MediaSegment[]>>;
+ orderVideos: boolean;
+ progress: number;
+ recording: boolean;
+ doUndo: boolean;
+ setCanUndo?: React.Dispatch<React.SetStateAction<boolean>>;
}
interface SegmentBox {
- endTime: number,
- startTime: number,
- order: number,
+ endTime: number;
+ startTime: number;
+ order: number;
}
interface CurrentHover {
- index: number,
- minX: number,
- maxX: number
+ index: number;
+ minX: number;
+ maxX: number;
}
export function ProgressBar(props: ProgressBarProps) {
- const progressBarRef = useRef<HTMLDivElement | null>(null)
+ const progressBarRef = useRef<HTMLDivElement | null>(null);
// the actual list of JSX elements rendered as segments
const [segments, setSegments] = useState<JSX.Element[]>([]);
@@ -47,8 +49,6 @@ export function ProgressBar(props: ProgressBarProps) {
// update the canUndo props based on undo stack
useEffect(() => props.setCanUndo?.(undoStack.length > 0), [undoStack.length]);
- // useEffect for undo - brings back the most recently deleted segment
- useEffect(() => handleUndo(), [props.doUndo])
const handleUndo = () => {
// get the last element from the undo if it exists
if (undoStack.length === 0) return;
@@ -59,27 +59,36 @@ export function ProgressBar(props: ProgressBarProps) {
// update the removed time and place element back into ordered
setTotalRemovedTime(prevRemoved => prevRemoved - (last.endTime - last.startTime));
setOrdered(prevOrdered => [...prevOrdered, last]);
- }
+ };
+ // useEffect for undo - brings back the most recently deleted segment
+ useEffect(() => handleUndo(), [props.doUndo]);
// useEffect for recording changes - changes style to disabled and adds the "expanding-segment"
useEffect(() => {
// get segments segment's html using it's id -> make them appeared disabled (or enabled)
- segments.forEach((seg) => document.getElementById(seg.props.id)?.classList.toggle('segment-disabled', props.recording));
+ segments.forEach(seg => document.getElementById(seg.props.id)?.classList.toggle('segment-disabled', props.recording));
progressBarRef.current?.classList.toggle('progressbar-disabled', props.recording);
if (props.recording)
- setSegments(prevSegments => [...prevSegments, <div key='segment-expanding' id='segment-expanding' className='segment segment-expanding blink' style={{ width: 'fit-content' }}>{props.videos.length + 1}</div>]);
- }, [props.recording])
-
+ setSegments(prevSegments => [
+ ...prevSegments,
+ <div key="segment-expanding" id="segment-expanding" className="segment segment-expanding blink" style={{ width: 'fit-content' }}>
+ {props.videos.length + 1}
+ </div>,
+ ]);
+ }, [props.recording]);
// useEffect that updates the segmentsJSX, which is rendered
// only updated when ordered is updated or if the user is dragging around a segment
useEffect(() => {
const totalTime = props.progress * 1000 - totalRemovedTime;
- const segmentsJSX = ordered.map((seg, i) =>
- <div key={`segment-${i}`} id={`segment-${i}`} className={dragged === i ? 'segment-hide' : 'segment'} style={{ width: `${((seg.endTime - seg.startTime) / totalTime) * 100}%` }}>{seg.order + 1}</div>);
+ const segmentsJSX = ordered.map((seg, i) => (
+ <div key={`segment-${i}`} id={`segment-${i}`} className={dragged === i ? 'segment-hide' : 'segment'} style={{ width: `${((seg.endTime - seg.startTime) / totalTime) * 100}%` }}>
+ {seg.order + 1}
+ </div>
+ ));
- setSegments(segmentsJSX)
+ setSegments(segmentsJSX);
}, [dragged, ordered]);
// useEffect for dragged - update the cursor to be grabbing while grabbing
@@ -89,14 +98,14 @@ export function ProgressBar(props: ProgressBarProps) {
// to imporve performance, only want to update the CSS width, not re-render the whole JSXList
useEffect(() => {
- if (!props.recording) return
+ if (!props.recording) return;
const totalTime = props.progress * 1000 - totalRemovedTime;
let remainingTime = totalTime;
segments.forEach((seg, i) => {
// for the last segment, we need to set that directly
if (i === segments.length - 1) return;
// update remaining time
- remainingTime -= (ordered[i].endTime - ordered[i].startTime);
+ remainingTime -= ordered[i].endTime - ordered[i].startTime;
// update the width for this segment
const htmlId = seg.props.id;
@@ -106,8 +115,7 @@ export function ProgressBar(props: ProgressBarProps) {
// update the width of the expanding segment using the remaining time
const segExapandHtml = document.getElementById('segment-expanding');
- if (segExapandHtml)
- segExapandHtml.style.width = ordered.length === 0 ? '100%' : `${(remainingTime / totalTime) * 100}%`;
+ if (segExapandHtml) segExapandHtml.style.width = ordered.length === 0 ? '100%' : `${(remainingTime / totalTime) * 100}%`;
}, [props.progress]);
// useEffect for props.videos - update the ordered array when a new video is added
@@ -120,9 +128,7 @@ export function ProgressBar(props: ProgressBarProps) {
// in this case, a new video is added -> push it onto ordered
if (order >= ordered.length) {
const { endTime, startTime } = props.videos.lastElement();
- setOrdered(prevOrdered => {
- return [...prevOrdered, { endTime, startTime, order }];
- });
+ setOrdered(prevOrdered => [...prevOrdered, { endTime, startTime, order }]);
}
// in this case, a video is removed
@@ -132,7 +138,7 @@ export function ProgressBar(props: ProgressBarProps) {
}, [props.videos]);
// useEffect for props.orderVideos - matched the order array with the videos array before the export
- useEffect(() => props.setVideos(vids => ordered.map((seg) => vids[seg.order])), [props.orderVideos]);
+ useEffect(() => props.setVideos(vids => ordered.map(seg => vids[seg.order])), [props.orderVideos]);
// useEffect for removed - handles logic for removing a segment
useEffect(() => {
@@ -151,36 +157,68 @@ export function ProgressBar(props: ProgressBarProps) {
// returns the new currentHover based on the new index
const updateCurrentHover = (segId: number): CurrentHover | null => {
// get the segId of the segment that will become the new bounding area
- const rect = progressBarRef.current?.children[segId].getBoundingClientRect()
- if (rect == null) return null
+ const rect = progressBarRef.current?.children[segId].getBoundingClientRect();
+ if (rect == null) return null;
return {
index: segId,
minX: rect.x,
maxX: rect.x + rect.width,
- }
- }
+ };
+ };
+
+ const swapSegments = (oldIndex: number, newIndex: number) => {
+ if (newIndex == null) return;
+ setOrdered(prevOrdered => {
+ const temp = { ...prevOrdered[oldIndex] };
+ prevOrdered[oldIndex] = prevOrdered[newIndex];
+ prevOrdered[newIndex] = temp;
+ return prevOrdered;
+ });
+ // update visually where the segment is hovering over
+ setDragged(newIndex);
+ };
+
+ // functions for the floating segment that tracks the cursor while grabbing it
+ const initDetachSegment = (dot: HTMLDivElement, rect: DOMRect) => {
+ dot.classList.add('segment-selected');
+ dot.style.transitionDuration = '0s';
+ dot.style.position = 'absolute';
+ dot.style.zIndex = '999';
+ dot.style.width = `${rect.width}px`;
+ dot.style.height = `${rect.height}px`;
+ dot.style.left = `${rect.x}px`;
+ dot.style.top = `${rect.y}px`;
+ dot.draggable = false;
+ document.body.append(dot);
+ };
+ const followCursor = (event: PointerEvent, dot: HTMLDivElement): void => {
+ // event.stopPropagation()
+ const { width, height } = dot.getBoundingClientRect();
+ dot.style.left = `${event.clientX - width / 2}px`;
+ dot.style.top = `${event.clientY - height / 2}px`;
+ };
// pointerdown event for the progress bar
- const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
- // don't move the videobox element
- e.stopPropagation();
+ const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
+ // don't move the videobox element
+ e.stopPropagation();
// if recording, do nothing
- if (props.recording) return;
+ if (props.recording) return;
// get the segment the user clicked on to be dragged
- const clickedSegment = e.target as HTMLDivElement & EventTarget
+ const clickedSegment = e.target as HTMLDivElement & EventTarget;
// get the profess bar ro add event listeners
// don't do anything if null
- const progressBar = progressBarRef.current
- if (progressBar == null || clickedSegment.id === progressBar.id) return
+ const progressBar = progressBarRef.current;
+ if (progressBar == null || clickedSegment.id === progressBar.id) return;
// if holding shift key, let's remove that segment
if (e.shiftKey) {
const segId = parseInt(clickedSegment.id.split('-')[1]);
setRemoved(segId);
- return
+ return;
}
// if holding ctrl key and click, let's undo that segment #hiddenfeature lol
@@ -192,26 +230,26 @@ export function ProgressBar(props: ProgressBarProps) {
// if we're here, the user is dragging a segment around
// let the progress bar capture all the pointer events until the user releases (pointerUp)
const ptrId = e.pointerId;
- progressBar.setPointerCapture(ptrId)
+ progressBar.setPointerCapture(ptrId);
- const rect = clickedSegment.getBoundingClientRect()
- // id for segment is like 'segment-1' or 'segment-10',
+ const rect = clickedSegment.getBoundingClientRect();
+ // id for segment is like 'segment-1' or 'segment-10',
// so this works to get the id
- const segId = parseInt(clickedSegment.id.split('-')[1])
+ const segId = parseInt(clickedSegment.id.split('-')[1]);
// set the selected segment to be the one dragged
- setDragged(segId)
+ setDragged(segId);
- // this is the logic for storing the lower X bound and upper X bound to know
+ // this is the logic for storing the lower X bound and upper X bound to know
// whether a swap is needed between two segments
let currentHover: CurrentHover = {
index: segId,
minX: rect.x,
maxX: rect.x + rect.width,
- }
+ };
// create the floating segment that tracks the cursor
- const detchedSegment = document.createElement("div")
- initDeatchSegment(detchedSegment, rect);
+ const detchedSegment = document.createElement('div');
+ initDetachSegment(detchedSegment, rect);
const updateSegmentOrder = (event: PointerEvent): void => {
event.stopPropagation();
@@ -219,6 +257,7 @@ export function ProgressBar(props: ProgressBarProps) {
// this fixes a bug where pointerup doesn't fire while cursor is upped while being dragged
if (!progressBar.hasPointerCapture(ptrId)) {
+ // eslint-disable-next-line no-use-before-define
placeSegmentandCleanup();
return;
}
@@ -228,24 +267,23 @@ export function ProgressBar(props: ProgressBarProps) {
const curX = event.clientX;
// handle the left bound
if (curX < currentHover.minX && currentHover.index > 0) {
- swapSegments(currentHover.index, currentHover.index - 1)
- currentHover = updateCurrentHover(currentHover.index - 1) ?? currentHover
+ swapSegments(currentHover.index, currentHover.index - 1);
+ currentHover = updateCurrentHover(currentHover.index - 1) ?? currentHover;
}
// handle the right bound
else if (curX > currentHover.maxX && currentHover.index < segments.length - 1) {
- swapSegments(currentHover.index, currentHover.index + 1)
- currentHover = updateCurrentHover(currentHover.index + 1) ?? currentHover
+ swapSegments(currentHover.index, currentHover.index + 1);
+ currentHover = updateCurrentHover(currentHover.index + 1) ?? currentHover;
}
- }
+ };
// handles when the user is done dragging the segment (pointerUp)
const placeSegmentandCleanup = (event?: PointerEvent): void => {
event?.stopPropagation();
event?.preventDefault();
// if they put the segment outside of the bounds, remove it
- if (event && (event.clientX < 0 || event.clientX > document.body.clientWidth || event.clientY < 0 || event.clientY > document.body.clientHeight))
- setRemoved(currentHover.index);
-
+ if (event && (event.clientX < 0 || event.clientX > document.body.clientWidth || event.clientY < 0 || event.clientY > document.body.clientHeight)) setRemoved(currentHover.index);
+
// remove the update event listener for pointermove
progressBar.removeEventListener('pointermove', updateSegmentOrder);
// remove the floating segment from the DOM
@@ -253,49 +291,16 @@ export function ProgressBar(props: ProgressBarProps) {
// dragged is -1 is equiv to nothing being dragged, so the normal state
// so this will place the segment in it's location and update the segment bar
setDragged(-1);
- }
+ };
// event listeners that allow the user to drag and release the floating segment
progressBar.addEventListener('pointermove', updateSegmentOrder);
progressBar.addEventListener('pointerup', placeSegmentandCleanup, { once: true });
- }
-
- const swapSegments = (oldIndex: number, newIndex: number) => {
- if (newIndex == null) return;
- setOrdered(prevOrdered => {
- const temp = { ...prevOrdered[oldIndex] }
- prevOrdered[oldIndex] = prevOrdered[newIndex]
- prevOrdered[newIndex] = temp
- return prevOrdered
- });
- // update visually where the segment is hovering over
- setDragged(newIndex);
- }
-
- // functions for the floating segment that tracks the cursor while grabbing it
- const initDeatchSegment = (dot: HTMLDivElement, rect: DOMRect) => {
- dot.classList.add("segment-selected");
- dot.style.transitionDuration = '0s';
- dot.style.position = 'absolute';
- dot.style.zIndex = '999';
- dot.style.width = `${rect.width}px`;
- dot.style.height = `${rect.height}px`;
- dot.style.left = `${rect.x}px`;
- dot.style.top = `${rect.y}px`;
- dot.draggable = false;
- document.body.append(dot);
- }
- const followCursor = (event: PointerEvent, dot: HTMLDivElement): void => {
- // event.stopPropagation()
- const { width, height } = dot.getBoundingClientRect();
- dot.style.left = `${event.clientX - width / 2}px`;
- dot.style.top = `${event.clientY - height / 2}px`;
- }
-
+ };
return (
<div className="progressbar" id="progressbar" onPointerDown={onPointerDown} ref={progressBarRef}>
{segments}
</div>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 1f976f926..07381c7d0 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast } from '../../../../fields/Doc';
+import { DocData } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
import { BoolCast, DocCast } from '../../../../fields/Types';
@@ -10,18 +11,18 @@ import { VideoField } from '../../../../fields/URLField';
import { Upload } from '../../../../server/SharedMediaTypes';
import { DocumentType } from '../../../documents/DocumentTypes';
import { Docs } from '../../../documents/Documents';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager, dropActionType } from '../../../util/DragManager';
+import { DragManager } from '../../../util/DragManager';
+import { dropActionType } from '../../../util/DropActionTypes';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { Presentation } from '../../../util/TrackMovements';
import { undoBatch } from '../../../util/UndoManager';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
-import { media_state } from '../AudioBox';
+import { mediaState } from '../AudioBox';
+import { DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { VideoBox } from '../VideoBox';
import { RecordingView } from './RecordingView';
-import { DocData } from '../../../../fields/DocSymbols';
@observer
export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -43,20 +44,15 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@observable result: Upload.AccessPathInfo | undefined = undefined;
- @observable videoDuration: number | undefined = undefined;
-
- @action
- setVideoDuration = (duration: number) => (this.videoDuration = duration);
@action
setResult = (info: Upload.AccessPathInfo, presentation?: Presentation) => {
this.result = info;
this.dataDoc.type = DocumentType.VID;
- this.dataDoc[this.fieldKey + '_duration'] = this.videoDuration;
- this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey);
+ this.dataDoc[this.fieldKey + '_recorded'] = this.dataDoc.layout; // save the recording layout to allow re-recording later
+ this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey); // then convert the recording box to a video
this.dataDoc[this._props.fieldKey] = new VideoField(this.result.accessPaths.client);
- this.dataDoc[this.fieldKey + '_recorded'] = true;
// stringify the presentation and store it
if (presentation?.movements) {
const presCopy = { ...presentation };
@@ -68,17 +64,17 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static WorkspaceStopRecording() {
const remDoc = RecordingBox.screengrabber?.Document;
if (remDoc) {
- //if recordingbox is true; when we press the stop button. changed vals temporarily to see if changes happening
+ // if recordingbox is true; when we press the stop button. changed vals temporarily to see if changes happening
RecordingBox.screengrabber?.Pause?.();
setTimeout(() => {
RecordingBox.screengrabber?.Finish?.();
- remDoc.overlayX = 70; //was 100
+ remDoc.overlayX = 70; // was 100
remDoc.overlayY = 590;
RecordingBox.screengrabber = undefined;
}, 100);
- //could break if recording takes too long to turn into videobox. If so, either increase time on setTimeout below or find diff place to do this
+ // could break if recording takes too long to turn into videobox. If so, either increase time on setTimeout below or find diff place to do this
setTimeout(() => Doc.RemFromMyOverlay(remDoc), 1000);
- Doc.UserDoc().workspaceRecordingState = media_state.Paused;
+ Doc.UserDoc().workspaceRecordingState = mediaState.Paused;
Doc.AddDocToList(Doc.UserDoc(), 'workspaceRecordings', remDoc);
}
}
@@ -102,15 +98,15 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
_width: 205,
_height: 115,
});
- screengrabber.overlayX = 70; //was -400
- screengrabber.overlayY = 590; //was 0
+ screengrabber.overlayX = 70; // was -400
+ screengrabber.overlayY = 590; // was 0
screengrabber[DocData][Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
- Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay
- DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
+ Doc.AddToMyOverlay(screengrabber); // just adds doc to overlay
+ DocumentView.addViewRenderedCb(screengrabber, docView => {
RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
RecordingBox.screengrabber.Record?.();
});
- Doc.UserDoc().workspaceRecordingState = media_state.Recording;
+ Doc.UserDoc().workspaceRecordingState = mediaState.Recording;
}
/**
@@ -123,7 +119,7 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
value.overlayX = 70;
value.overlayY = window.innerHeight - 180;
Doc.AddToMyOverlay(value);
- DocumentManager.Instance.AddViewRenderedCb(value, docView => {
+ DocumentView.addViewRenderedCb(value, docView => {
Doc.UserDoc().currentRecording = docView.Document;
docView.select(false);
RecordingBox.resumeWorkspaceReplaying(value);
@@ -136,7 +132,7 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
*/
@undoBatch
public static addRecToWorkspace(value: RecordingBox) {
- let ffView = Array.from(DocumentManager.Instance.DocumentViews).find(view => view.ComponentView instanceof CollectionFreeFormView);
+ const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView);
(ffView?.ComponentView as CollectionFreeFormView)._props.addDocument?.(value.Document);
Doc.RemoveDocFromList(Doc.UserDoc(), 'workspaceRecordings', value.Document);
Doc.RemFromMyOverlay(value.Document);
@@ -146,20 +142,15 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
public static resumeWorkspaceReplaying(doc: Doc) {
- const docView = DocumentManager.Instance.getDocumentView(doc);
- if (docView?.ComponentView instanceof VideoBox) {
- docView.ComponentView.Play();
- }
- Doc.UserDoc().workspaceReplayingState = media_state.Playing;
+ const docView = DocumentView.getDocumentView(doc);
+ docView?.ComponentView?.Play?.();
+ Doc.UserDoc().workspaceReplayingState = mediaState.Playing;
}
public static pauseWorkspaceReplaying(doc: Doc) {
- const docView = DocumentManager.Instance.getDocumentView(doc);
- const videoBox = docView?.ComponentView as VideoBox;
- if (videoBox) {
- videoBox.Pause();
- }
- Doc.UserDoc().workspaceReplayingState = media_state.Paused;
+ const docView = DocumentView.getDocumentView(doc);
+ docView?.ComponentView?.Pause?.();
+ Doc.UserDoc().workspaceReplayingState = mediaState.Paused;
}
public static stopWorkspaceReplaying(value: Doc) {
@@ -191,66 +182,78 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
render() {
return (
<div className="recordingBox" style={{ width: '100%' }} ref={this._ref}>
- {!this.result && (
- <RecordingView
- forceTrackScreen={BoolCast(this.layoutDoc[this.fieldKey + '_trackScreen'])}
- getControls={this.getControls}
- setResult={this.setResult}
- setDuration={this.setVideoDuration}
- id={DocCast(this.Document.proto)?.[Id] || ''}
- />
- )}
+ {!this.result && <RecordingView forceTrackScreen={BoolCast(this.layoutDoc[this.fieldKey + '_trackScreen'])} getControls={this.getControls} setResult={this.setResult} id={DocCast(this.Document.proto)?.[Id] || ''} />}
</div>
);
}
+ // eslint-disable-next-line no-use-before-define
static screengrabber: RecordingBox | undefined;
}
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function stopWorkspaceRecording() {
RecordingBox.WorkspaceStopRecording();
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function stopWorkspaceReplaying(value: Doc) {
RecordingBox.stopWorkspaceReplaying(value);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function removeWorkspaceReplaying(value: Doc) {
RecordingBox.removeWorkspaceReplaying(value);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function getCurrentRecording() {
return Doc.UserDoc().currentRecording;
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function getWorkspaceRecordings() {
return new List<any>(['Record Workspace', `Record Webcam`, ...DocListCast(Doc.UserDoc().workspaceRecordings)]);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function isWorkspaceRecording() {
- return Doc.UserDoc().workspaceRecordingState === media_state.Recording;
+ return Doc.UserDoc().workspaceRecordingState === mediaState.Recording;
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function isWorkspaceReplaying() {
return Doc.UserDoc().workspaceReplayingState;
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function replayWorkspace(value: Doc | string, _readOnly_: boolean) {
if (_readOnly_) return DocCast(Doc.UserDoc().currentRecording) ?? 'Record Workspace';
if (typeof value === 'string') RecordingBox.WorkspaceStartRecording(value);
else RecordingBox.replayWorkspace(value);
+ return undefined;
});
-ScriptingGlobals.add(function pauseWorkspaceReplaying(value: Doc, _readOnly_: boolean) {
+// eslint-disable-next-line prefer-arrow-callback
+ScriptingGlobals.add(function pauseWorkspaceReplaying(value: Doc) {
RecordingBox.pauseWorkspaceReplaying(value);
});
-ScriptingGlobals.add(function resumeWorkspaceReplaying(value: Doc, _readOnly_: boolean) {
+// eslint-disable-next-line prefer-arrow-callback
+ScriptingGlobals.add(function resumeWorkspaceReplaying(value: Doc) {
RecordingBox.resumeWorkspaceReplaying(value);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function startRecordingDrag(value: { doc: Doc | string; e: React.PointerEvent }) {
if (DocCast(value.doc)) {
DragManager.StartDocumentDrag([value.e.target as HTMLElement], new DragManager.DocumentDragData([DocCast(value.doc)], dropActionType.embed), value.e.clientX, value.e.clientY);
value.e.preventDefault();
return true;
}
+ return undefined;
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function renderDropdown() {
if (!Doc.UserDoc().workspaceRecordings || DocListCast(Doc.UserDoc().workspaceRecordings).length === 0) {
return true;
}
return false;
});
+
+Docs.Prototypes.TemplateMap.set(DocumentType.WEBCAM, {
+ layout: { view: RecordingBox, dataField: 'data' },
+ options: { acl: '', systemIcon: 'BsFillCameraVideoFill' },
+});
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index f7ed82643..b8451fe60 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -1,10 +1,13 @@
+/* eslint-disable jsx-a11y/label-has-associated-control */
+/* eslint-disable react/button-has-type */
+/* eslint-disable jsx-a11y/control-has-associated-label */
import * as React from 'react';
import { useEffect, useRef, useState } from 'react';
import { IconContext } from 'react-icons';
import { FaCheckCircle } from 'react-icons/fa';
import { MdBackspace } from 'react-icons/md';
import { Upload } from '../../../../server/SharedMediaTypes';
-import { returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
+import { returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils';
import { Networking } from '../../../Network';
import { Presentation, TrackMovements } from '../../../util/TrackMovements';
import { ProgressBar } from './ProgressBar';
@@ -19,19 +22,18 @@ export interface MediaSegment {
interface IRecordingViewProps {
setResult: (info: Upload.AccessPathInfo, presentation?: Presentation) => void;
- setDuration: (seconds: number) => void;
id: string;
getControls: (record: () => void, pause: () => void, finish: () => void) => void;
forceTrackScreen: boolean;
}
const MAXTIME = 100000;
+const iconVals = { color: '#cc1c08', className: 'video-edit-buttons' };
export function RecordingView(props: IRecordingViewProps) {
const [recording, setRecording] = useState(false);
const recordingTimerRef = useRef<number>(0);
const [recordingTimer, setRecordingTimer] = useState(0); // unit is 0.01 second
- const [playing, setPlaying] = useState(false);
const [progress, setProgress] = useState(0);
// acts as a "refresh state" to tell progressBar when to undo
@@ -62,7 +64,7 @@ export function RecordingView(props: IRecordingViewProps) {
useEffect(() => {
if (finished) {
// make the total presentation that'll match the concatted video
- let concatPres = (trackScreen || props.forceTrackScreen) && TrackMovements.Instance.concatPresentations(videos.map(v => v.presentation as Presentation));
+ const concatPres = (trackScreen || props.forceTrackScreen) && TrackMovements.Instance.concatPresentations(videos.map(v => v.presentation as Presentation));
// this async function uses the server to create the concatted video and then sets the result to it's accessPaths
(async () => {
@@ -100,16 +102,16 @@ export function RecordingView(props: IRecordingViewProps) {
return () => clearInterval(interval);
}, [recording]);
+ const setVideoProgressHelper = (curProgrss: number) => {
+ const newProgress = (curProgrss / MAXTIME) * 100;
+ setProgress(newProgress);
+ };
+
useEffect(() => {
setVideoProgressHelper(recordingTimer);
recordingTimerRef.current = recordingTimer;
}, [recordingTimer]);
- const setVideoProgressHelper = (progress: number) => {
- const newProgress = (progress / MAXTIME) * 100;
- setProgress(newProgress);
- };
-
const startShowingStream = async (mediaConstraints = DEFAULT_MEDIA_CONSTRAINTS) => {
const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
@@ -131,7 +133,7 @@ export function RecordingView(props: IRecordingViewProps) {
if (event.data.size > 0) videoChunks.push(event.data);
};
- videoRecorder.current.onstart = (event: any) => {
+ videoRecorder.current.onstart = () => {
setRecording(true);
// start the recording api when the video recorder starts
(trackScreen || props.forceTrackScreen) && TrackMovements.Instance.start();
@@ -149,7 +151,7 @@ export function RecordingView(props: IRecordingViewProps) {
// depending on if a presenation exists, add it to the video
const presentation = TrackMovements.Instance.yieldPresentation();
- setVideos(videos => [...videos, presentation != null && (trackScreen || props.forceTrackScreen) ? { ...nextVideo, presentation } : nextVideo]);
+ setVideos(theVideos => [...theVideos, presentation != null && (trackScreen || props.forceTrackScreen) ? { ...nextVideo, presentation } : nextVideo]);
}
// reset the temporary chunks
@@ -186,7 +188,7 @@ export function RecordingView(props: IRecordingViewProps) {
e,
returnTrue,
returnFalse,
- e => {
+ () => {
// start recording if not already recording
if (!videoRecorder.current || videoRecorder.current.state === 'inactive') record();
@@ -202,14 +204,8 @@ export function RecordingView(props: IRecordingViewProps) {
setDoUndo(prev => !prev);
};
- const handleOnTimeUpdate = () => {
- playing && setVideoProgressHelper(videoElementRef.current!.currentTime);
- };
-
const millisecondToMinuteSecond = (milliseconds: number) => {
- const toTwoDigit = (digit: number) => {
- return String(digit).length == 1 ? '0' + digit : digit;
- };
+ const toTwoDigit = (digit: number) => (String(digit).length === 1 ? '0' + digit : digit);
const minutes = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((milliseconds % (1000 * 60)) / 1000);
return toTwoDigit(minutes) + ' : ' + toTwoDigit(seconds);
@@ -219,10 +215,11 @@ export function RecordingView(props: IRecordingViewProps) {
props.getControls(record, pause, finish);
}, []);
+ const iconUndoVals = React.useMemo(() => ({ color: 'grey', className: 'video-edit-buttons', style: { display: canUndo ? 'inherit' : 'none' } }), []);
return (
<div className="recording-container">
<div className="video-wrapper">
- <video id={`video-${props.id}`} autoPlay muted onTimeUpdate={() => handleOnTimeUpdate()} ref={videoElementRef} />
+ <video id={`video-${props.id}`} autoPlay muted ref={videoElementRef} />
<div className="recording-sign">
<span className="dot" />
<p className="timer">{millisecondToMinuteSecond(recordingTimer * 10)}</p>
@@ -246,10 +243,10 @@ export function RecordingView(props: IRecordingViewProps) {
{!recording &&
(videos.length > 0 ? (
<div className="options-wrapper video-edit-wrapper">
- <IconContext.Provider value={{ color: 'grey', className: 'video-edit-buttons', style: { display: canUndo ? 'inherit' : 'none' } }}>
+ <IconContext.Provider value={iconUndoVals}>
<MdBackspace onPointerDown={undoPrevious} />
</IconContext.Provider>
- <IconContext.Provider value={{ color: '#cc1c08', className: 'video-edit-buttons' }}>
+ <IconContext.Provider value={iconVals}>
<FaCheckCircle
onPointerDown={e => {
e.stopPropagation();
@@ -268,7 +265,7 @@ export function RecordingView(props: IRecordingViewProps) {
setTrackScreen(e.target.checked);
}}
/>
- <span className="checkmark"></span>
+ <span className="checkmark" />
Track Screen
</label>
</div>
diff --git a/src/client/views/nodes/RecordingBox/index.ts b/src/client/views/nodes/RecordingBox/index.ts
index ff21eaed6..e4f9b5e55 100644
--- a/src/client/views/nodes/RecordingBox/index.ts
+++ b/src/client/views/nodes/RecordingBox/index.ts
@@ -1,2 +1,2 @@
-export * from './RecordingView'
-export * from './RecordingBox' \ No newline at end of file
+export * from './RecordingView';
+export * from './RecordingBox';