diff options
author | bobzel <zzzman@gmail.com> | 2021-03-21 14:33:04 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2021-03-21 14:33:04 -0400 |
commit | 77180785d160f465375eba3a51067fb3ae77adaf (patch) | |
tree | 4cdcfc888495cf170ea0524289645c250fc83f06 /src | |
parent | 217594bb340afa6e98449624e7c7b2175e77bff4 (diff) |
added auto-linking to video screen grabs.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 5 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 5 | ||||
-rw-r--r-- | src/client/views/nodes/ScreenshotBox.tsx | 24 |
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)); } }); |