From 77119dc1719af955e162248e5747bd9ef8921b4c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 22 Oct 2019 20:43:24 -0400 Subject: added ink audio scrubbing --- src/client/documents/Documents.ts | 4 +--- src/client/views/InkingCanvas.tsx | 11 +++++++---- src/client/views/InkingControl.tsx | 1 + src/client/views/InkingStroke.tsx | 18 ++++++++++++------ src/client/views/nodes/AudioBox.tsx | 21 +++++++++++++-------- src/client/views/nodes/VideoBox.tsx | 2 -- src/new_fields/InkField.ts | 4 +++- .../authentication/models/current_user_utils.ts | 1 + 8 files changed, 38 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 316efe44c..5ae4ca82a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -334,9 +334,7 @@ export namespace Docs { let dataDoc = MakeDataDelegate(proto, protoProps, data); let viewDoc = Doc.MakeDelegate(dataDoc, delegId); - AudioBox.ActiveRecordings.map(d => { - DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "link to audio: " + d.title); - }); + AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "link to audio: " + d.title)); return Doc.assign(viewDoc, delegateProps); } diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 920ebaedd..0037b95d0 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -78,7 +78,7 @@ export class InkingCanvas extends React.Component { this.previousState = new Map(this.inkData); - if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { // start the new line, saves a uuid to represent the field of the stroke this._currentStrokeId = Utils.GenerateGuid(); const data = this.inkData; @@ -87,7 +87,8 @@ export class InkingCanvas extends React.Component { color: InkingControl.Instance.selectedColor, width: InkingControl.Instance.selectedWidth, tool: InkingControl.Instance.selectedTool, - displayTimecode: NumCast(this.props.Document.currentTimecode, -1) + displayTimecode: NumCast(this.props.Document.currentTimecode, -1), + creationTime: new Date().getTime() }); this.inkData = data; } @@ -120,7 +121,7 @@ export class InkingCanvas extends React.Component { onPointerMove = (e: PointerEvent): void => { e.stopPropagation(); e.preventDefault(); - if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { let data = this.inkData; // add points to new line as it is being drawn let strokeData = data.get(this._currentStrokeId); if (strokeData) { @@ -161,6 +162,7 @@ export class InkingCanvas extends React.Component { color={strokeData.color} width={strokeData.width} tool={strokeData.tool} + creationTime={strokeData.creationTime} deleteCallback={this.removeLine} />); } return paths; @@ -181,7 +183,8 @@ export class InkingCanvas extends React.Component { render() { let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None && !this.props.Document.isBackground ? "canSelect" : "noSelect"; - let cursor = svgCanvasStyle === "canSelect" ? (InkingControl.Instance.selectedTool === InkTool.Eraser ? "pointer" : "default") : undefined; + let cursor = svgCanvasStyle === "canSelect" ? (InkingControl.Instance.selectedTool === InkTool.Eraser || + InkingControl.Instance.selectedTool === InkTool.Scrubber ? "pointer" : "default") : undefined; return (
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 105adc03d..75faa9641 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -126,6 +126,7 @@ export class InkingControl { Scripting.addGlobal(function activatePen(pen: any, width: any, color: any) { InkingControl.Instance.switchTool(pen ? InkTool.Pen : InkTool.None); InkingControl.Instance.switchWidth(width); InkingControl.Instance.updateSelectedColor(color); }); Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any) { InkingControl.Instance.switchTool(pen ? InkTool.Highlighter : InkTool.None); InkingControl.Instance.switchWidth(width); InkingControl.Instance.updateSelectedColor(color); }); Scripting.addGlobal(function activateEraser(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Eraser : InkTool.None); }); +Scripting.addGlobal(function activateScrubber(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Scrubber : InkTool.None); }); Scripting.addGlobal(function deactivateInk() { return InkingControl.Instance.switchTool(InkTool.None); }); Scripting.addGlobal(function setInkWidth(width: any) { return InkingControl.Instance.switchWidth(width); }); Scripting.addGlobal(function setInkColor(color: any) { return InkingControl.Instance.updateSelectedColor(color); }); \ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index b8d428d31..7bbf71482 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,9 +1,10 @@ import { observer } from "mobx-react"; -import { observable, trace } from "mobx"; +import { observable, trace, runInAction } from "mobx"; import { InkingControl } from "./InkingControl"; import React = require("react"); import { InkTool } from "../../new_fields/InkField"; import "./InkingStroke.scss"; +import { AudioBox } from "./nodes/AudioBox"; interface StrokeProps { @@ -15,6 +16,7 @@ interface StrokeProps { color: string; width: string; tool: InkTool; + creationTime: number; deleteCallback: (index: string) => void; } @@ -31,6 +33,11 @@ export class InkingStroke extends React.Component { e.stopPropagation(); e.preventDefault(); } + if (InkingControl.Instance.selectedTool === InkTool.Scrubber && e.buttons === 1) { + runInAction(() => AudioBox.ScrubTime = this.props.creationTime); + e.stopPropagation(); + e.preventDefault(); + } } parseData = (line: Array<{ x: number, y: number }>): string => { @@ -55,10 +62,9 @@ export class InkingStroke extends React.Component { let pathlength = this.props.count; // bcz: this is needed to force reactions to the line's data changes let marker = this.props.tool === InkTool.Highlighter ? "-marker" : ""; - let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser ? "all" : "none"; - return ( - - ); + let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser || + InkingControl.Instance.selectedTool === InkTool.Scrubber ? "all" : "none"; + return (); } } \ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 55b472726..62ec683da 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -38,11 +38,13 @@ export class AudioBox extends DocExtendableComponent this.playFrom(Doc.AreProtosEqual(la1, this.dataDoc) ? la2 : la1), 250); + let doc = Doc.AreProtosEqual(la1, this.dataDoc) ? la2 : la1; + let seek = DateCast(la1.creationTime); + setTimeout(() => this.playFrom(seek.date.getTime()), 250); } }); scrollLinkId && (this.layoutDoc.scrollLinkID = undefined); @@ -61,8 +65,9 @@ export class AudioBox extends DocExtendableComponent SelectionManager.SelectedDocuments(), selected => { let sel = selected.length ? selected[0].props.Document : undefined; - this.Document.playOnSelect && sel && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFrom(sel); + this.Document.playOnSelect && sel && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFrom(DateCast(sel.creationTime).date.getTime()); }); + this._scrubbingDisposer = reaction(() => AudioBox.ScrubTime, time => this.Document.playOnSelect && this.playFrom(time)); } updateHighlights = () => { @@ -86,14 +91,13 @@ export class AudioBox extends DocExtendableComponent { + playFrom = (seek: number) => { const extensionDoc = this.extensionDoc; let start = extensionDoc && DateCast(extensionDoc.recordingStart); - let seek = sel && DateCast(sel.creationDate); - if (this._ele && start && seek) { - if (sel) { - let delta = (seek.date.getTime() - start.date.getTime()) / 1000; - if (start && seek && delta > 0 && delta < this._ele.duration) { + if (this._ele && start) { + if (seek) { + let delta = (seek - start.date.getTime()) / 1000; + if (start && delta > 0 && delta < this._ele.duration) { this._ele.currentTime = delta; this._ele.play(); this._lastUpdate = delta; @@ -110,6 +114,7 @@ export class AudioBox extends DocExtendableComponent { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 48a699e58..53baea4ae 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -301,7 +301,6 @@ export class VideoBox extends DocAnnotatableComponent { @@ -314,7 +313,6 @@ export class VideoBox extends DocAnnotatableComponent { document.removeEventListener("pointermove", this.onResetMove, true); document.removeEventListener("pointerup", this.onResetUp, true); - InkingControl.Instance.switchTool(InkTool.None); this._isResetClick < 10 && (this.Document.currentTimecode = 0); } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index e381d0218..d94834e91 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -8,7 +8,8 @@ export enum InkTool { None, Pen, Highlighter, - Eraser + Eraser, + Scrubber } export interface StrokeData { @@ -17,6 +18,7 @@ export interface StrokeData { width: string; tool: InkTool; displayTimecode: number; + creationTime: number; } export type InkData = Map; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 477b36ea4..95ebe3cb6 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -58,6 +58,7 @@ export class CurrentUserUtils { { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', unchecked: `!sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, + { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', unchecked: `!sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', unchecked: `!sameDocs(this.activePen.pen, this) && this.activePen.pen !== undefined`, backgroundColor: "white", activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ -- cgit v1.2.3-70-g09d2