diff options
author | bobzel <zzzman@gmail.com> | 2021-09-22 13:33:34 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2021-09-22 13:33:34 -0400 |
commit | ad921f6ee14735be136784e90c824632086aa43a (patch) | |
tree | 566b6abdbef7a667d36bacbfe2765f6ccc2a4235 /src | |
parent | a8d8c9a115d1de3946a4f3d971c953f4b1222551 (diff) |
fixed dragging anchor on audio timeline to position correctly. fixed being able to drop anywhere on audio box. fixed undoing drag anchor and drag handles of audio anchors.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 4 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackedTimeline.tsx | 49 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 153 |
3 files changed, 112 insertions, 94 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d785d5419..29fcee822 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -426,8 +426,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection && !docView.props.Document.isGroup && !docView.props.Document.hideOpenButton); const canDelete = SelectionManager.Views().some(docView => { const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit; - return (!docView.rootDoc._stayInCollection || docView.rootDoc.isInkMask) && - (collectionAcl === AclAdmin || collectionAcl === AclEdit || GetEffectiveAcl(docView.rootDoc) === AclAdmin); + //return (!docView.rootDoc._stayInCollection || docView.rootDoc.isInkMask) && + return (collectionAcl === AclAdmin || collectionAcl === AclEdit || GetEffectiveAcl(docView.rootDoc) === AclAdmin); }); const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( <Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top"> diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 9577256c9..970947b12 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -30,7 +30,7 @@ import { LinkManager } from "../../util/LinkManager"; import { Scripting } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; -import { undoBatch } from "../../util/UndoManager"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; import { AudioWaveform } from "../AudioWaveform"; import { CollectionSubView } from "../collections/CollectionSubView"; import { LightboxView } from "../LightboxView"; @@ -354,12 +354,13 @@ export class CollectionStackedTimeline extends CollectionSubView< // determine x coordinate of drop and assign it to the documents being dragged --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view - const x = docDragData.offset[0]; + const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + const x = localPt[0] - docDragData.offset[0]; const timelineContentWidth = this.props.PanelWidth(); for (let i = 0; i < docDragData.droppedDocuments.length; i++) { - const d = docDragData.droppedDocuments[i]; - d._timecodeToShow = x / timelineContentWidth * this.props.trimDuration + NumCast(d._timecodeToShow); - d._timecodeToHide = x / timelineContentWidth * this.props.trimDuration + NumCast(d._timecodeToHide); + const d = Doc.GetProto(docDragData.droppedDocuments[i]); + d._timecodeToHide = x / timelineContentWidth * this.props.trimDuration + NumCast(d._timecodeToHide) - NumCast(d._timecodeToShow); + d._timecodeToShow = x / timelineContentWidth * this.props.trimDuration; } return true; @@ -774,13 +775,19 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> } return false; }; + var undo: UndoManager.Batch | undefined; + setupMoveUpEvents( this, e, - (e) => changeAnchor(anchor, left, newTime(e)), + (e) => { + if (!undo) undo = UndoManager.StartBatch("drag anchor"); + return changeAnchor(anchor, left, newTime(e)) + }, (e) => { this.props.setTime(newTime(e)); this.props._timeline?.releasePointerCapture(e.pointerId); + undo?.end(); }, emptyFunction ); @@ -862,21 +869,21 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> {inner.view} {!inner.anchor.view || !SelectionManager.IsSelected(inner.anchor.view) ? null : ( - <> - <div - key="left" - className="collectionStackedTimeline-left-resizer" - onPointerDown={(e) => this.onAnchorDown(e, this.props.mark, true)} - /> - <div - key="right" - className="collectionStackedTimeline-resizer" - onPointerDown={(e) => - this.onAnchorDown(e, this.props.mark, false) - } - /> - </> - )} + <> + <div + key="left" + className="collectionStackedTimeline-left-resizer" + onPointerDown={(e) => this.onAnchorDown(e, this.props.mark, true)} + /> + <div + key="right" + className="collectionStackedTimeline-resizer" + onPointerDown={(e) => + this.onAnchorDown(e, this.props.mark, false) + } + /> + </> + )} </> ); } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 830c73278..9281cac9a 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -6,7 +6,7 @@ import { IReactionDisposer, observable, reaction, - runInAction, + runInAction } from "mobx"; import { observer } from "mobx-react"; import { DateField } from "../../../fields/DateField"; @@ -20,19 +20,19 @@ import { emptyFunction, formatTime } from "../../../Utils"; import { DocUtils } from "../../documents/Documents"; import { Networking } from "../../Network"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; +import { DragManager } from "../../util/DragManager"; import { SnappingManager } from "../../util/SnappingManager"; import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { ViewBoxAnnotatableComponent, - ViewBoxAnnotatableProps, + ViewBoxAnnotatableProps } from "../DocComponent"; +import { Colors } from "../global/globalEnums"; import "./AudioBox.scss"; import { FieldView, FieldViewProps } from "./FieldView"; import { LinkDocPreview } from "./LinkDocPreview"; -import { faLessThan } from "@fortawesome/free-solid-svg-icons"; -import { Colors } from "../global/globalEnums"; import e = require("connect-flash"); declare class MediaRecorder { @@ -167,11 +167,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent< } componentWillUnmount() { + this.dropDisposer?.(); Object.values(this._disposers).forEach((disposer) => disposer?.()); const ind = DocUtils.ActiveRecordings.indexOf(this); ind !== -1 && DocUtils.ActiveRecordings.splice(ind, 1); } + private dropDisposer?: DragManager.DragDropDisposer; @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. @@ -337,8 +339,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent< (this.layoutDoc.dontAutoPlayFollowedLinks ? "" : "Don't") + " play when link is selected", event: () => - (this.layoutDoc.dontAutoPlayFollowedLinks = - !this.layoutDoc.dontAutoPlayFollowedLinks), + (this.layoutDoc.dontAutoPlayFollowedLinks = + !this.layoutDoc.dontAutoPlayFollowedLinks), icon: "expand-arrows-alt", }); funcs.push({ @@ -591,6 +593,17 @@ export class AudioBox extends ViewBoxAnnotatableComponent< : ""; return ( <div + ref={r => { + if (r && this._stackedTimeline.current) { + this.dropDisposer?.(); + this.dropDisposer = DragManager.MakeDropTarget(r, + (e, de) => { + const [xp, yp] = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + de.complete.docDragData && this._stackedTimeline.current!.internalDocDrop(e, de, de.complete.docDragData, xp); + } + , this.layoutDoc, undefined); + } + }} className="audiobox-container" onContextMenu={this.specificContextMenu} onClick={ @@ -607,9 +620,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< <div className="audiobox-buttons"> <div className="audiobox-dictation" onClick={this.onFile}> <FontAwesomeIcon - style={{ - width: "30px" - }} + style={{ width: "30px" }} icon="file-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /> @@ -638,77 +649,77 @@ export class AudioBox extends ViewBoxAnnotatableComponent< </div> </div> ) : ( - <div - className={`audiobox-record${interactive}`} - style={{ backgroundColor: Colors.DARK_GRAY }} - > - <FontAwesomeIcon icon="microphone" /> + <div + className={`audiobox-record${interactive}`} + style={{ backgroundColor: Colors.DARK_GRAY }} + > + <FontAwesomeIcon icon="microphone" /> RECORD - </div> - )} + </div> + )} </div> ) : ( - <div - className="audiobox-controls" - style={{ - pointerEvents: - this._isAnyChildContentActive || this.props.isContentActive() - ? "all" - : "none", - }} - > - <div className="audiobox-dictation" /> <div - className="audiobox-player" - style={{ height: `${AudioBox.heightPercent}%` }} + className="audiobox-controls" + style={{ + pointerEvents: + this._isAnyChildContentActive || this.props.isContentActive() + ? "all" + : "none", + }} > + <div className="audiobox-dictation" /> <div - className="audiobox-buttons" - title={this.mediaState === "paused" ? "play" : "pause"} - onClick={this.mediaState === "paused" ? this.Play : this.Pause} - > - {" "} - <FontAwesomeIcon - icon={this.mediaState === "paused" ? "play" : "pause"} - size={"1x"} - /> - </div> - <div - className="audiobox-buttons" - title={this._trimming ? "finish" : "trim"} - onClick={this._trimming ? this.finishTrim : this.startTrim} + className="audiobox-player" + style={{ height: `${AudioBox.heightPercent}%` }} > - <FontAwesomeIcon - icon={this._trimming ? "check" : "cut"} - size={"1x"} - /> - </div> - <div - className="audiobox-timeline" - style={{ - top: 0, - height: `100%`, - left: AudioBox.playheadWidth, - width: `calc(100% - ${AudioBox.playheadWidth}px)`, - background: "white", - }} - > - {this.renderTimeline} - </div> - {this.audio} - <div className="audioBox-current-time"> - {this._trimming ? - formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode))) - : formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this._trimStart)))} - </div> - <div className="audioBox-total-time"> - {this._trimming || !this._trimEnd ? - formatTime(Math.round(NumCast(this.duration))) - : formatTime(Math.round(NumCast(this.trimDuration)))} + <div + className="audiobox-buttons" + title={this.mediaState === "paused" ? "play" : "pause"} + onClick={this.mediaState === "paused" ? this.Play : this.Pause} + > + {" "} + <FontAwesomeIcon + icon={this.mediaState === "paused" ? "play" : "pause"} + size={"1x"} + /> + </div> + <div + className="audiobox-buttons" + title={this._trimming ? "finish" : "trim"} + onClick={this._trimming ? this.finishTrim : this.startTrim} + > + <FontAwesomeIcon + icon={this._trimming ? "check" : "cut"} + size={"1x"} + /> + </div> + <div + className="audiobox-timeline" + style={{ + top: 0, + height: `100%`, + left: AudioBox.playheadWidth, + width: `calc(100% - ${AudioBox.playheadWidth}px)`, + background: "white", + }} + > + {this.renderTimeline} + </div> + {this.audio} + <div className="audioBox-current-time"> + {this._trimming ? + formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode))) + : formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this._trimStart)))} + </div> + <div className="audioBox-total-time"> + {this._trimming || !this._trimEnd ? + formatTime(Math.round(NumCast(this.duration))) + : formatTime(Math.round(NumCast(this.trimDuration)))} + </div> </div> </div> - </div> - )} + )} </div> ); } |