From d0025200b23f57ec25d3452d425de8725a032c6a Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 22 Jan 2021 21:14:37 -0500 Subject: fixed selection bounds for video box annotations, especially when in full screen view. --- src/client/views/nodes/DocumentView.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6217f473f..e3da48749 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -410,7 +410,7 @@ export class DocumentViewInternal extends DocComponent func().result === true ? this.props.select(false) : "", "on click"); } else func(); }; if (this.onDoubleClickHandler) { @@ -935,7 +935,9 @@ export class DocumentView extends React.Component { PanelWidth = () => this.panelWidth; PanelHeight = () => this.panelHeight; ContentScale = () => this.nativeScaling; - screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling); + screenToLocalTransform = () => { + return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling); + } componentDidMount() { !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this); -- cgit v1.2.3-70-g09d2 From 5a7e3df397e06fffee6a05e57f109714be184034 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 25 Jan 2021 14:01:36 -0500 Subject: fixed linking to video to create an anchor if the timecode is not zero. --- src/client/util/LinkManager.ts | 3 +- src/client/views/nodes/AudioBox.tsx | 8 ++-- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 70 +++++++++++++++++---------------- 4 files changed, 43 insertions(+), 40 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index accf53676..bf927c5b8 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -54,7 +54,8 @@ export class LinkManager { }, true); relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] { - return DocListCast(anchor[Doc.LayoutFieldKey(anchor) + "-annotations"]).reduce((list, anno) => + const lfield = Doc.LayoutFieldKey(anchor); + return DocListCast(anchor[lfield + "-annotations"]).concat(DocListCast(anchor[lfield + "-annotations-timeline"])).reduce((list, anno) => [...list, ...LinkManager.Instance.relatedLinker(anno)], LinkManager.Instance.directLinker(anchor).slice()); }, true); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index e854d40be..8614200de 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -108,16 +108,16 @@ export class AudioBox extends ViewBoxAnnotatableComponent { + return this.createMarker(this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined)); + } + componentWillUnmount() { Object.values(this._disposers).forEach(disposer => disposer?.()); const ind = DocUtils.ActiveRecordings.indexOf(this); ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1)); } - getAnchor = () => { - return this.createMarker(this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined)); - } - @action componentDidMount() { this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link. diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e3da48749..6620614f8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -541,7 +541,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.props.LayoutTemplateString) return; + if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return; if (this.props.Document === CurrentUserUtils.ActiveDashboard) { alert((e.target as any)?.closest?.("*.lm_content") ? "You can't perform this move most likely because you don't have permission to modify the destination." : diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index c5e61eedd..6ca4a589a 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -28,7 +28,6 @@ import { LinkDocPreview } from "./LinkDocPreview"; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; import { StyleProp } from "../StyleProvider"; import { computedFn } from "mobx-utils"; -import { DocumentManager } from "../../util/DocumentManager"; import { Dictionary } from "typescript-collections"; import { MarqueeAnnotator } from "../MarqueeAnnotator"; import { Id } from "../../../fields/FieldSymbols"; @@ -78,14 +77,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent) { super(props); @@ -98,6 +97,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent { + return this.createMarker(Cast(this.layoutDoc._currentTimecode, "number", null)); + } + + choosePath(url: string) { + return url.indexOf(window.location.origin) === -1 ? Utils.CorsProxy(url) : url; + } + videoLoad = () => { const aspect = this.player!.videoWidth / this.player!.videoHeight; Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth); @@ -154,13 +161,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.props.isSelected(), selected => { if (!selected) { @@ -239,29 +241,19 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.Document._videoStart, - (videoStart) => { - if (videoStart !== undefined) { - if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) { - const delay = this.player ? 0 : 250; // wait for mainCont and try again to play - setTimeout(() => this.player && this.Play(), delay); - setTimeout(() => this.Document._videoStart = undefined, 10 + delay); - } - } - }, + () => !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc && this.props.renderDepth !== -1 ? Cast(this.Document._videoStart, "number", null) : undefined, + videoStart => videoStart !== undefined && setTimeout(() => { + this.player && this.Play(); + setTimeout(() => this.Document._videoStart = undefined, 10); + }, this.player ? 0 : 250), // wait for mainCont and try again to play { fireImmediately: true } ); this._disposers.videoStop = reaction( - () => this.Document._videoStop, - (videoStop) => { - if (videoStop !== undefined) { - if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) { - const delay = this.player ? 0 : 250; // wait for mainCont and try again to play - setTimeout(() => this.player && this.Pause(), delay); - setTimeout(() => { this.Document._videoStop = undefined; }, 10 + delay); - } - } - }, + () => this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc ? Cast(this.Document._videoStop, "number", null) : undefined, + videoStop => videoStop !== undefined && setTimeout(() => { + this.player && this.Pause(); + setTimeout(() => this.Document._videoStop = undefined, 10); + }, this.player ? 0 : 250), // wait for mainCont and try again to play { fireImmediately: true } ); if (this.youtubeVideoId) { @@ -334,7 +326,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent([marker]); } + return marker; } // play back the video from time @@ -628,6 +620,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent { + const startTime = NumCast(doc.displayTimecode); + const endTime = NumCast(doc.undisplayTimecode, null); + if (startTime !== undefined) { + this.layoutDoc.playOnSelect && (endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime)); + } + } // renders the markers as a document renderInner = computedFn(function (this: VideoBox, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number, annotationKey: string) { const marker = observable({ view: undefined as any }); @@ -635,6 +634,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent marker.view = r)} Document={mark} DataDoc={undefined} + focus={() => this.playLink(mark)} PanelWidth={() => width} PanelHeight={() => height} renderDepth={this.props.renderDepth + 1} @@ -703,7 +703,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent; })} {this.selectionContainer} -
{ e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc._currentTimecode) / this.videoDuration * 100}%`, pointerEvents: "none" }} /> +
{ e.stopPropagation(); e.preventDefault(); }} + style={{ left: `${NumCast(this.layoutDoc._currentTimecode) / this.videoDuration * 100}%`, pointerEvents: "none" }} + />
; } @@ -773,7 +775,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.props.scaling?.() || 1; panelWidth = () => this.props.PanelWidth() * this.heightPercent / 100; - panelHeight = () => this.props.PanelHeight() * this.heightPercent / 100; + panelHeight = () => this.layoutDoc._fitWidth ? this.panelWidth() / Doc.NativeAspect(this.rootDoc) : this.props.PanelHeight() * this.heightPercent / 100; screenToLocalTransform = () => { const offset = (this.props.PanelWidth() - this.panelWidth()) / 2 / this.scaling(); return this.props.ScreenToLocalTransform().translate(-offset, 0).scale(100 / this.heightPercent); -- cgit v1.2.3-70-g09d2 From eba56b17b3e1f6c1cbabaafdeb4ee16421fd5a32 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 25 Jan 2021 15:56:44 -0500 Subject: changed how to start/stop video when clicking/double-clicking on markers --- src/client/views/nodes/AudioBox.tsx | 7 ++-- src/client/views/nodes/DocumentView.tsx | 10 ++++- src/client/views/nodes/VideoBox.tsx | 73 +++++++++++++++++++++------------ 3 files changed, 57 insertions(+), 33 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8614200de..a481317c3 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -196,7 +196,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - if (this.layoutDoc.playOnClick) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime); + if (this.layoutDoc.autoPlay) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime); this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds); return true; } @@ -262,7 +262,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" }); funcs.push({ description: (this.layoutDoc.hideMarkers ? "Don't hide" : "Hide") + " range markers", event: () => this.layoutDoc.hideMarkers = !this.layoutDoc.hideMarkers, icon: "expand-arrows-alt" }); - funcs.push({ description: (this.layoutDoc.playOnClick ? "Don't play" : "Play") + " markers onClick", event: () => this.layoutDoc.playOnClick = !this.layoutDoc.playOnClick, icon: "expand-arrows-alt" }); funcs.push({ description: (this.layoutDoc.autoPlay ? "Don't auto play" : "Auto play") + " markers onClick", event: () => this.layoutDoc.autoPlay = !this.layoutDoc.autoPlay, icon: "expand-arrows-alt" }); ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @@ -408,7 +407,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent screen_delta / width * this.audioDuration; + const toTimeline = (screen_delta: number, width: number) => Math.max(0, Math.min(this.audioDuration, screen_delta / width * this.audioDuration)); setupMoveUpEvents(this, e, (e) => { const rect = (e.target as any).getBoundingClientRect(); @@ -514,7 +513,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.props.isSelected(out) || this._isChildActive} whenActiveChanged={action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive))} onClick={script} - onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript} + onDoubleClick={this.layoutDoc.autoPlay ? undefined : doublescript} ignoreAutoHeight={false} bringToFront={emptyFunction} scriptContext={this} /> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6620614f8..7b1b1bf0c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -382,9 +382,11 @@ export class DocumentViewInternal extends DocComponent func().result?.select === true ? this.props.select(false) : "", "on double click"); } else if (!Doc.IsSystem(this.props.Document)) { if (this.props.Document.type !== DocumentType.LABEL) { UndoManager.RunInBatch(() => { @@ -398,19 +400,23 @@ export class DocumentViewInternal extends DocComponent this.onClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, documentView: this.props.DocumentView, + clientX: clientX, + clientY: clientY, shiftKey }, console.log); const clickFunc = () => { if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) && !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc) && !this.onClickHandler.script.originalScript.includes("selectMainMenu")) { - UndoManager.RunInBatch(() => func().result === true ? this.props.select(false) : "", "on click"); + UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on click"); } else func(); }; if (this.onDoubleClickHandler) { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 6ca4a589a..fe76af55e 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -91,10 +91,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent { @@ -320,8 +320,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.layoutDoc.playOnClick = !this.layoutDoc.playOnClick, icon: "expand-arrows-alt" }); - subitems.push({ description: (this.layoutDoc.playOnClick ? "Don't auto play" : "Auto play") + " markers onClick", event: () => this.layoutDoc.autoPlay = !this.layoutDoc.autoPlay, icon: "expand-arrows-alt" }); + subitems.push({ description: (this.layoutDoc.autoPlay ? "Don't auto play" : "Auto play") + " markers onClick", event: () => this.layoutDoc.autoPlay = !this.layoutDoc.autoPlay, icon: "expand-arrows-alt" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" }); } } @@ -515,20 +514,18 @@ export class VideoBox extends ViewBoxAnnotatableComponent { const rect = this._timeline?.getBoundingClientRect();// (e.target as any).getBoundingClientRect(); if (rect && e.target !== this._audioRef.current && this.active()) { - const wasPaused = !this._playing; - this.player!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.videoDuration; - wasPaused && this.Pause(); + const wasPlaying = this._playing; + if (this._playing) this.Pause(); - const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.videoDuration; - this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x); + this._markerStart = this._markerEnd = this.toTimeline(e.clientX - rect.x, rect.width); VideoBox.SelectingRegion = this; setupMoveUpEvents(this, e, action(e => { - this._markerEnd = toTimeline(e.clientX - rect.x); + this._markerEnd = this.toTimeline(e.clientX - rect.x, rect.width); return false; }), action((e, movement) => { - this._markerEnd = toTimeline(e.clientX - rect.x); + this._markerEnd = this.toTimeline(e.clientX - rect.x, rect.width); if (this._markerEnd < this._markerStart) { const tmp = this._markerStart; this._markerStart = this._markerEnd; @@ -537,9 +534,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent 15) && this.createMarker(this._markerStart, this._markerEnd); VideoBox.SelectingRegion = undefined; }), - e => { + (e, doubleTap) => { this.props.select(false); e.shiftKey && this.createMarker(this.player!.currentTime); + !wasPlaying && (this.player!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.videoDuration); + !wasPlaying && doubleTap && this.Play(); } , this.props.isSelected(true) || this._isChildActive); } @@ -563,36 +562,56 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - this.playFrom(seekTimeInSeconds, endTime); - return true; // select + playOnClick = (anchorDoc: Doc, clientX: number, seekTimeInSeconds: number, endTime: number = this.videoDuration) => { + if (this.layoutDoc.autoPlay) { + if (this._playing) this.Pause(); + else this.playFrom(seekTimeInSeconds, endTime); + } else { + if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) && endTime > NumCast(this.layoutDoc._currentTimecode)) { + if (!this.layoutDoc.autoPlay && this._playing) { + this.Pause(); + } else { + this.Play(); + } + } else { + this.playFrom(seekTimeInSeconds, endTime); + } + } + return { select: true }; } - // play back the video from time @action - clickMarker = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.videoDuration) => { - if (this.layoutDoc.playOnClick) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime); - this.player && (this.player.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds); - return true; // select + clickMarker = (anchorDoc: Doc, clientX: number, seekTimeInSeconds: number, endTime: number = this.videoDuration) => { + if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) { + if (this._playing) this.Pause(); + else if (this.layoutDoc.autoPlay) this.Play(); + else if (!this.layoutDoc.autoPlay) { + const rect = this._timeline?.getBoundingClientRect(); + rect && this.Seek(this.toTimeline(clientX - rect.x, rect.width)); + } + } else { + if (this.layoutDoc.autoPlay) this.playFrom(seekTimeInSeconds, endTime); + else this.Seek(seekTimeInSeconds); + } + return { select: true }; } + toTimeline = (screen_delta: number, width: number) => Math.max(0, Math.min(this.videoDuration, screen_delta / width * this.videoDuration)); // starting the drag event for marker resizing onPointerDown = (e: React.PointerEvent, m: any, left: boolean): void => { this._currMarker = m; this._left = left; this._timeline?.setPointerCapture(e.pointerId); - const toTimeline = (screen_delta: number, width: number) => screen_delta / width * this.videoDuration; setupMoveUpEvents(this, e, (e: PointerEvent) => { const rect = (e.target as any).getBoundingClientRect(); - this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x, rect.width)); + this.changeMarker(this._currMarker, this.toTimeline(e.clientX - rect.x, rect.width)); return false; }, (e: PointerEvent) => { const rect = (e.target as any).getBoundingClientRect(); - this.player!.currentTime = this.layoutDoc._currentTimecode = toTimeline(e.clientX - rect.x, rect.width); + this.player!.currentTime = this.layoutDoc._currentTimecode = this.toTimeline(e.clientX - rect.x, rect.width); this._timeline?.releasePointerCapture(e.pointerId); }, emptyFunction); @@ -647,7 +666,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.props.isSelected(out) || this._isChildActive} whenActiveChanged={action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive))} onClick={script} - onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript} + onDoubleClick={doublescript} ignoreAutoHeight={false} bringToFront={emptyFunction} scriptContext={this} /> -- cgit v1.2.3-70-g09d2