aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-09-22 13:33:34 -0400
committerbobzel <zzzman@gmail.com>2021-09-22 13:33:34 -0400
commitad921f6ee14735be136784e90c824632086aa43a (patch)
tree566b6abdbef7a667d36bacbfe2765f6ccc2a4235 /src
parenta8d8c9a115d1de3946a4f3d971c953f4b1222551 (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.tsx4
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx49
-rw-r--r--src/client/views/nodes/AudioBox.tsx153
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>
);
}