aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/ScreenshotBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/ScreenshotBox.tsx')
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx238
1 files changed, 125 insertions, 113 deletions
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index dbb567d3a..76a24d831 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,32 +1,31 @@
-import React = require("react");
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import React = require('react');
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
// import { Canvas } from '@react-three/fiber';
-import { computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
+import { computed, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
// import { BufferAttribute, Camera, Vector2, Vector3 } from 'three';
-import { DateField } from "../../../fields/DateField";
-import { Doc, HeightSym, WidthSym } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { ComputedField } from "../../../fields/ScriptField";
-import { Cast, NumCast } from "../../../fields/Types";
-import { AudioField, VideoField } from "../../../fields/URLField";
-import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, OmitKeys, returnFalse, returnOne } from "../../../Utils";
-import { DocUtils } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { Networking } from "../../Network";
-import { CaptureManager } from "../../util/CaptureManager";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
-import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline";
-import { ContextMenu } from "../ContextMenu";
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
+import { DateField } from '../../../fields/DateField';
+import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { ComputedField } from '../../../fields/ScriptField';
+import { Cast, NumCast } from '../../../fields/Types';
+import { AudioField, VideoField } from '../../../fields/URLField';
+import { TraceMobx } from '../../../fields/util';
+import { emptyFunction, OmitKeys, returnFalse, returnOne } from '../../../Utils';
+import { DocUtils } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { Networking } from '../../Network';
+import { CaptureManager } from '../../util/CaptureManager';
+import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
+import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline';
+import { ContextMenu } from '../ContextMenu';
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
import { FieldView, FieldViewProps } from './FieldView';
-import { FormattedTextBox } from "./formattedText/FormattedTextBox";
-import "./ScreenshotBox.scss";
-import { VideoBox } from "./VideoBox";
+import { FormattedTextBox } from './formattedText/FormattedTextBox';
+import './ScreenshotBox.scss';
+import { VideoBox } from './VideoBox';
declare class MediaRecorder {
- constructor(e: any, options?: any); // whatever MediaRecorder has
+ constructor(e: any, options?: any); // whatever MediaRecorder has
}
// interface VideoTileProps {
@@ -107,12 +106,16 @@ declare class MediaRecorder {
@observer
export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); }
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(ScreenshotBox, fieldKey);
+ }
private _audioRec: any;
private _videoRec: any;
@observable private _videoRef: HTMLVideoElement | null = null;
@observable _screenCapture = false;
- @computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
+ @computed get recordingStart() {
+ return Cast(this.dataDoc[this.props.fieldKey + '-recordingStart'], DateField)?.date.getTime();
+ }
constructor(props: any) {
super(props);
@@ -126,11 +129,9 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
}
}
getAnchor = () => {
- const startTime = Cast(this.layoutDoc._currentTimecode, "number", null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
- return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "_timecodeToShow", "_timecodeToHide",
- startTime, startTime === undefined ? undefined : startTime + 3)
- || this.rootDoc;
- }
+ const startTime = Cast(this.layoutDoc._currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
+ return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow', '_timecodeToHide', startTime, startTime === undefined ? undefined : startTime + 3) || this.rootDoc;
+ };
videoLoad = () => {
const aspect = this._videoRef!.videoWidth / this._videoRef!.videoHeight;
@@ -141,7 +142,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
Doc.SetNativeHeight(this.dataDoc, (nativeWidth || 1200) / aspect);
this.layoutDoc._height = (this.layoutDoc[WidthSym]() || 0) / aspect;
}
- }
+ };
componentDidMount() {
this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = 0;
@@ -159,33 +160,37 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
}
componentWillUnmount() {
const ind = DocUtils.ActiveRecordings.indexOf(this);
- ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
+ ind !== -1 && DocUtils.ActiveRecordings.splice(ind, 1);
}
specificContextMenu = (e: React.MouseEvent): void => {
- const subitems = [{ description: "Screen Capture", event: this.toggleRecording, icon: "expand-arrows-alt" as any }];
- ContextMenu.Instance.addItem({ description: "Options...", subitems, icon: "video" });
- }
+ const subitems = [{ description: 'Screen Capture', event: this.toggleRecording, icon: 'expand-arrows-alt' as any }];
+ ContextMenu.Instance.addItem({ description: 'Options...', subitems, icon: 'video' });
+ };
@computed get content() {
- if (this.rootDoc.videoWall) return (null);
- return <video className={"videoBox-content"} key="video"
- ref={r => {
- this._videoRef = r;
- setTimeout(() => {
- if (this.rootDoc.mediaState === "pendingRecording" && this._videoRef) {
- this.toggleRecording();
- }
- }, 100);
- }}
- autoPlay={this._screenCapture}
- style={{ width: this._screenCapture ? "100%" : undefined, height: this._screenCapture ? "100%" : undefined }}
- onCanPlay={this.videoLoad}
- controls={true}
- onClick={e => e.preventDefault()}>
- <source type="video/mp4" />
- Not supported.
- </video>;
+ if (this.rootDoc.videoWall) return null;
+ return (
+ <video
+ className={'videoBox-content'}
+ key="video"
+ ref={r => {
+ this._videoRef = r;
+ setTimeout(() => {
+ if (this.rootDoc.mediaState === 'pendingRecording' && this._videoRef) {
+ this.toggleRecording();
+ }
+ }, 100);
+ }}
+ autoPlay={this._screenCapture}
+ style={{ width: this._screenCapture ? '100%' : undefined, height: this._screenCapture ? '100%' : undefined }}
+ onCanPlay={this.videoLoad}
+ controls={true}
+ onClick={e => e.preventDefault()}>
+ <source type="video/mp4" />
+ Not supported.
+ </video>
+ );
}
// _numScreens = 5;
@@ -209,7 +214,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
// {screens}
// </ Canvas>;
// }
- return (null);
+ return null;
}
toggleRecording = async () => {
if (!this._screenCapture) {
@@ -219,31 +224,33 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
this._audioRec.onstop = async (e: any) => {
const [{ result }] = await Networking.UploadFilesToServer(aud_chunks);
if (!(result instanceof Error)) {
- this.dataDoc[this.props.fieldKey + "-audio"] = new AudioField(result.accessPaths.agnostic.client);
+ this.dataDoc[this.props.fieldKey + '-audio'] = new AudioField(result.accessPaths.agnostic.client);
}
};
this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
this._videoRec = new MediaRecorder(this._videoRef!.srcObject);
const vid_chunks: any = [];
- this._videoRec.onstart = () => this.dataDoc[this.props.fieldKey + "-recordingStart"] = new DateField(new Date());
+ this._videoRec.onstart = () => (this.dataDoc[this.props.fieldKey + '-recordingStart'] = new DateField(new Date()));
this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data);
this._videoRec.onstop = async (e: any) => {
+ console.log('screenshotbox: upload');
const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
const [{ result }] = await Networking.UploadFilesToServer(file);
- this.dataDoc[this.fieldKey + "-duration"] = (new Date().getTime() - this.recordingStart!) / 1000;
- if (!(result instanceof Error)) { // convert this screenshotBox into normal videoBox
+ this.dataDoc[this.fieldKey + '-duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
+ if (!(result instanceof Error)) {
+ // convert this screenshotBox into normal videoBox
this.dataDoc.type = DocumentType.VID;
this.layoutDoc.layout = VideoBox.LayoutString(this.fieldKey);
this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = undefined;
this.layoutDoc._fitWidth = undefined;
this.dataDoc[this.props.fieldKey] = new VideoField(result.accessPaths.agnostic.client);
- } else alert("video conversion failed");
+ } else alert('video conversion failed');
};
this._audioRec.start();
this._videoRec.start();
runInAction(() => {
this._screenCapture = true;
- this.dataDoc.mediaState = "recording";
+ this.dataDoc.mediaState = 'recording';
});
DocUtils.ActiveRecordings.push(this);
} else {
@@ -251,81 +258,86 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
this._videoRec?.stop();
runInAction(() => {
this._screenCapture = false;
- this.dataDoc.mediaState = "paused";
+ this.dataDoc.mediaState = 'paused';
});
const ind = DocUtils.ActiveRecordings.indexOf(this);
- ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
+ ind !== -1 && DocUtils.ActiveRecordings.splice(ind, 1);
CaptureManager.Instance.open(this.rootDoc);
}
- }
+ };
setupDictation = () => {
- if (this.dataDoc[this.fieldKey + "-dictation"]) return;
- const dictationText = CurrentUserUtils.GetNewTextDoc("dictation",
- NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10,
- NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
+ if (this.dataDoc[this.fieldKey + '-dictation']) return;
+ const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
dictationText._autoHeight = false;
const dictationTextProto = Doc.GetProto(dictationText);
dictationTextProto.recordingSource = this.dataDoc;
dictationTextProto.recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.props.fieldKey}-recordingStart"]`);
- dictationTextProto.mediaState = ComputedField.MakeFunction("self.recordingSource.mediaState");
- this.dataDoc[this.fieldKey + "-dictation"] = dictationText;
- }
+ dictationTextProto.mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState');
+ this.dataDoc[this.fieldKey + '-dictation'] = dictationText;
+ };
contentFunc = () => [this.threed, this.content];
- videoPanelHeight = () => NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], this.layoutDoc[WidthSym]()) * this.props.PanelWidth();
+ videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth();
formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
render() {
TraceMobx();
- return <div className="videoBox" onContextMenu={this.specificContextMenu} style={{ width: "100%", height: "100%" }} >
- <div className="videoBox-viewer" >
- <div style={{ position: "relative", height: this.videoPanelHeight() }}>
- <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
- PanelHeight={this.videoPanelHeight}
- PanelWidth={this.props.PanelWidth}
- focus={this.props.focus}
- isSelected={this.props.isSelected}
- isAnnotationOverlay={true}
- select={emptyFunction}
- isContentActive={returnFalse}
- scaling={returnOne}
- whenChildContentsActiveChanged={emptyFunction}
- removeDocument={returnFalse}
- moveDocument={returnFalse}
- addDocument={returnFalse}
- CollectionView={undefined}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
- renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
- {this.contentFunc}
- </CollectionFreeFormView></div>
- <div style={{ position: "relative", height: this.formattedPanelHeight() }}>
- {!(this.dataDoc[this.fieldKey + "-dictation"] instanceof Doc) ? (null) :
- <FormattedTextBox {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
- Document={this.dataDoc[this.fieldKey + "-dictation"]}
- fieldKey={"text"}
- PanelHeight={this.formattedPanelHeight}
+ return (
+ <div className="videoBox" onContextMenu={this.specificContextMenu} style={{ width: '100%', height: '100%' }}>
+ <div className="videoBox-viewer">
+ <div style={{ position: 'relative', height: this.videoPanelHeight() }}>
+ <CollectionFreeFormView
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+ PanelHeight={this.videoPanelHeight}
+ PanelWidth={this.props.PanelWidth}
+ focus={this.props.focus}
+ isSelected={this.props.isSelected}
isAnnotationOverlay={true}
select={emptyFunction}
- isContentActive={emptyFunction}
- scaling={returnOne}
- xPadding={25}
- yPadding={10}
+ isContentActive={returnFalse}
+ NativeDimScaling={returnOne}
whenChildContentsActiveChanged={emptyFunction}
removeDocument={returnFalse}
moveDocument={returnFalse}
addDocument={returnFalse}
CollectionView={undefined}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
- </FormattedTextBox>}
+ {this.contentFunc}
+ </CollectionFreeFormView>
+ </div>
+ <div style={{ position: 'relative', height: this.formattedPanelHeight() }}>
+ {!(this.dataDoc[this.fieldKey + '-dictation'] instanceof Doc) ? null : (
+ <FormattedTextBox
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit}
+ Document={this.dataDoc[this.fieldKey + '-dictation']}
+ fieldKey={'text'}
+ PanelHeight={this.formattedPanelHeight}
+ isAnnotationOverlay={true}
+ select={emptyFunction}
+ isContentActive={emptyFunction}
+ NativeDimScaling={returnOne}
+ xPadding={25}
+ yPadding={10}
+ whenChildContentsActiveChanged={emptyFunction}
+ removeDocument={returnFalse}
+ moveDocument={returnFalse}
+ addDocument={returnFalse}
+ CollectionView={undefined}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}></FormattedTextBox>
+ )}
+ </div>
</div>
+ {!this.props.isSelected() ? null : (
+ <div className="screenshotBox-uiButtons">
+ <div className="screenshotBox-recorder" key="snap" onPointerDown={this.toggleRecording}>
+ <FontAwesomeIcon icon="file" size="lg" />
+ </div>
+ </div>
+ )}
</div>
- {!this.props.isSelected() ? (null) : <div className="screenshotBox-uiButtons">
- <div className="screenshotBox-recorder" key="snap" onPointerDown={this.toggleRecording} >
- <FontAwesomeIcon icon="file" size="lg" />
- </div>
- </div>}
- </div >;
+ );
}
-} \ No newline at end of file
+}