From 171e5a1716e4a2f981e647ae26f8ddd0e2332693 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 22 Oct 2019 19:15:29 -0400 Subject: playback highlights from audio --- src/client/documents/Documents.ts | 2 +- src/client/views/MainView.tsx | 2 +- src/client/views/nodes/AudioBox.scss | 12 ++++++-- src/client/views/nodes/AudioBox.tsx | 58 ++++++++++++++++++++++++++---------- 4 files changed, 54 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index fd2009dd6..316efe44c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -336,7 +336,7 @@ export namespace Docs { 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/MainView.tsx b/src/client/views/MainView.tsx index c14739aa2..78b8ac0b7 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -449,7 +449,7 @@ export class MainView extends React.Component { public static expandFlyout = action(() => { MainView.Instance._flyoutTranslate = true; MainView.Instance.flyoutWidth = 250; - }) + }); @computed get expandButton() { return !this._flyoutTranslate ? (
) : (null); diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 5c43c3c00..9bda5b2a7 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -1,14 +1,21 @@ .audiobox-container, .audiobox-container-interactive { width: 100%; height: 100%; + min-height: 32px; position: inherit; - display:inline-block; + display:flex; pointer-events: all; + .audiobox-handle { + width:20px; + height:100%; + display:inline-block; + background: gray; + } .audiobox-control, .audiobox-control-interactive { top:0; max-height: 32px; - position: absolute; width: 100%; + display:inline-block; pointer-events: none; } .audiobox-control-interactive { @@ -23,6 +30,5 @@ } .audiobox-record-interactive { pointer-events: all; - } } \ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 85607c6b8..55b472726 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -38,8 +38,9 @@ export class AudioBox extends DocExtendableComponent(); + _ele: HTMLAudioElement | null = null; _recorder: any; + _lastUpdate = 0; @observable private _audioState = 0; public static ActiveRecordings: Doc[] = []; @@ -64,21 +65,44 @@ export class AudioBox extends DocExtendableComponent { + const extensionDoc = this.extensionDoc; + const htmlEle = this._ele; + const start = extensionDoc && DateCast(extensionDoc.recordingStart); + if (htmlEle && !htmlEle.paused && start) { + setTimeout(this.updateHighlights, 30); + DocListCast(this.dataDoc.links).map(l => { + let la1 = l.anchor1 as Doc; + if (Doc.AreProtosEqual(la1, this.dataDoc)) { + la1 = l.anchor2 as Doc; + } + let date = DateCast(la1.creationDate); + let offset = (date!.date.getTime() - start.date.getTime()) / 1000; + if (offset > this._lastUpdate && offset < htmlEle.currentTime) { + Doc.linkFollowHighlight(la1); + } + }); + this._lastUpdate = htmlEle.currentTime; + } + } + playFrom = (sel: Doc) => { const extensionDoc = this.extensionDoc; let start = extensionDoc && DateCast(extensionDoc.recordingStart); - let seek = sel && DateCast(sel.creationDate) - if (this._ref.current && start && seek) { + 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._ref.current.duration) { - this._ref.current.currentTime = delta; - this._ref.current.play(); + if (start && seek && delta > 0 && delta < this._ele.duration) { + this._ele.currentTime = delta; + this._ele.play(); + this._lastUpdate = delta; + setTimeout(this.updateHighlights, 0); } else { - this._ref.current.pause(); + this._ele.pause(); } } else { - this._ref.current.pause(); + this._ele.pause(); } } } @@ -132,19 +156,22 @@ export class AudioBox extends DocExtendableComponent { if (e.button === 0 && !e.ctrlKey) { - if (this._recorder) { - this.stopRecording(); - } else { - this.recordAudioAnnotation(); - } + this._recorder ? this.stopRecording() : this.recordAudioAnnotation(); e.stopPropagation(); } } + playClick = (e: any) => setTimeout(this.updateHighlights, 30); + + setRef = (e: HTMLAudioElement | null) => { + e && e.addEventListener("play", this.playClick as any); + this._ele = e; + } + @computed get path() { let field = Cast(this.props.Document[this.props.fieldKey], AudioField); let path = (field instanceof AudioField) ? field.url.href : ""; @@ -153,7 +180,7 @@ export class AudioBox extends DocExtendableComponent + return ; @@ -163,6 +190,7 @@ export class AudioBox extends DocExtendableComponent +
{!this.path ?