aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-03-21 14:33:04 -0400
committerbobzel <zzzman@gmail.com>2021-03-21 14:33:04 -0400
commit77180785d160f465375eba3a51067fb3ae77adaf (patch)
tree4cdcfc888495cf170ea0524289645c250fc83f06
parent217594bb340afa6e98449624e7c7b2175e77bff4 (diff)
added auto-linking to video screen grabs.
-rw-r--r--src/client/documents/Documents.ts5
-rw-r--r--src/client/views/nodes/AudioBox.tsx5
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx24
3 files changed, 27 insertions, 7 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 3ed1aa76e..16b303f7d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -59,6 +59,7 @@ import { DocumentType } from "./DocumentTypes";
import { EquationBox } from "../views/nodes/EquationBox";
import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
import { CurrentUserUtils } from "../util/CurrentUserUtils";
+import { FieldViewProps } from "../views/nodes/FieldView";
const path = require('path');
const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
@@ -1043,12 +1044,12 @@ export namespace DocUtils {
options?.afterFocus?.(false);
}
- export let ActiveRecordings: AudioBox[] = [];
+ export let ActiveRecordings: { props: FieldViewProps, getAnchor: () => Doc }[] = [];
export function MakeLinkToActiveAudio(doc: Doc) {
let lastLink: Doc | undefined;
DocUtils.ActiveRecordings.map(audio => {
- lastLink = DocUtils.MakeLink({ doc: doc }, { doc: audio.getAnchor() || audio.props.Document }, "audio link", "audio timeline");
+ lastLink = DocUtils.MakeLink({ doc: doc }, { doc: audio.getAnchor() || audio.props.Document }, "recording link", "recording timeline");
});
return lastLink;
}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index c0b5476fa..629d0c79b 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -88,7 +88,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
}
getAnchor = () => {
- return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "_timecodeToShow" /* audioStart */, "_timecodeToHide" /* audioEnd */, this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined)) || this.rootDoc;
+ return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey,
+ "_timecodeToShow" /* audioStart */, "_timecodeToHide" /* audioEnd */, this._ele?.currentTime ||
+ Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined))
+ || this.rootDoc;
}
componentWillUnmount() {
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 087a1be7a..9ad93d4dd 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -10,11 +10,11 @@ import { listSpec, makeInterface } from "../../../fields/Schema";
import { Cast, NumCast } from "../../../fields/Types";
import { VideoField } from "../../../fields/URLField";
import { emptyFunction, returnFalse, returnOne, returnZero, Utils, OmitKeys } from "../../../Utils";
-import { Docs } from "../../documents/Documents";
+import { Docs, DocUtils } from "../../documents/Documents";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
-import { ViewBoxBaseComponent } from "../DocComponent";
+import { ViewBoxBaseComponent, ViewBoxAnnotatableComponent } from "../DocComponent";
import { FieldView, FieldViewProps } from './FieldView';
import "./ScreenshotBox.scss";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -22,6 +22,8 @@ import { Networking } from "../../Network";
import { DocumentType } from "../../documents/DocumentTypes";
import { VideoBox } from "./VideoBox";
import { Id } from "../../../fields/FieldSymbols";
+import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline";
+import { DateField } from "../../../fields/DateField";
const path = require('path');
declare class MediaRecorder {
constructor(e: any, options?: any); // whatever MediaRecorder has
@@ -32,15 +34,23 @@ type ScreenshotDocument = makeInterface<[typeof documentSchema]>;
const ScreenshotDocument = makeInterface(documentSchema);
@observer
-export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
+export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
private _reactionDisposer?: IReactionDisposer;
private _videoRef: HTMLVideoElement | null = null;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); }
+ @computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
public get player(): HTMLVideoElement | null {
return this._videoRef;
}
+ getAnchor = () => {
+ return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "_timecodeToShow" /* audioStart */, "_timecodeToHide" /* audioEnd */,
+ Cast(this.layoutDoc._currentTimecode, "number", null) ||
+ (this._recorder ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined))
+ || this.rootDoc;
+ }
+
videoLoad = () => {
const aspect = this.player!.videoWidth / this.player!.videoHeight;
const nativeWidth = Doc.NativeWidth(this.layoutDoc);
@@ -96,7 +106,9 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
}
componentWillUnmount() {
- this._reactionDisposer && this._reactionDisposer();
+ this._reactionDisposer?.();
+ const ind = DocUtils.ActiveRecordings.indexOf(this);
+ ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
}
@action
@@ -154,6 +166,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
const stream = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
this._videoRef!.srcObject = stream;
this._recorder = new MediaRecorder(stream);
+ this.dataDoc[this.props.fieldKey + "-recordingStart"] = new DateField(new Date());
this._chunks = [];
this._recorder.ondataavailable = (e: any) => this._chunks.push(e.data);
this._recorder.onstop = async (e: any) => {
@@ -169,8 +182,11 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
} else alert("video conversion failed");
};
this._recorder.start();
+ DocUtils.ActiveRecordings.push(this);
} else {
this._recorder.stop();
+ const ind = DocUtils.ActiveRecordings.indexOf(this);
+ ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
}
});