diff options
Diffstat (limited to 'src/client/views/nodes/AudioBox.tsx')
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 267 |
1 files changed, 105 insertions, 162 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index e66003f88..6e6558030 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -23,7 +23,6 @@ import { Colors } from "../global/globalEnums"; import "./AudioBox.scss"; import { FieldView, FieldViewProps } from "./FieldView"; import { LinkDocPreview } from "./LinkDocPreview"; -import e = require("connect-flash"); declare class MediaRecorder { constructor(e: any); // whatever MediaRecorder has @@ -44,6 +43,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp public static Enabled = false; static playheadWidth = 40; // width of playhead static heightPercent = 75; // height of timeline in percent of height of audioBox. + @observable static _scrubTime = 0; _dropDisposer?: DragManager.DragDropDisposer; _disposers: { [name: string]: IReactionDisposer } = {}; @@ -57,7 +57,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp _stream: MediaStream | undefined; _play: any = null; - @observable static _scrubTime = 0; @observable _paused: boolean = false; @computed get recordingStart() { return DateCast(this.dataDoc[this.fieldKey + "-recordingStart"])?.date.getTime(); } @computed get rawDuration() { return NumCast(this.dataDoc[`${this.fieldKey}-duration`]); } @@ -116,33 +115,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp this.path && this.setAnchorTime(NumCast(this.layoutDoc.clipStart)); this.path && this.timecodeChanged(); - - this._disposers.triggerAudio = reaction( - () => !LinkDocPreview.LinkInfo && this.props.renderDepth !== -1 - ? NumCast(this.Document._triggerAudio, null) - : undefined, - (start) => - start !== undefined && setTimeout(() => { - this.playFrom(start); - setTimeout(() => { - this.Document._currentTimecode = start; - this.Document._triggerAudio = undefined; - }, 10); - }), // wait for mainCont and try again to play - { fireImmediately: true } - ); - - this._disposers.audioStop = reaction( - () => this.props.renderDepth !== -1 && !LinkDocPreview.LinkInfo - ? Cast(this.Document._audioStop, "number", null) - : undefined, - (audioStop) => - audioStop !== undefined && setTimeout(() => { - this.Pause(); - setTimeout(() => (this.Document._audioStop = undefined), 10); - }), // wait for mainCont and try again to play - { fireImmediately: true } - ); } // for updating the timecode @@ -305,12 +277,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp onFile = (e: any) => { const newDoc = CurrentUserUtils.GetNewTextDoc( "", - NumCast(this.props.Document.x), - NumCast(this.props.Document.y) + - NumCast(this.props.Document._height) + + NumCast(this.rootDoc.x), + NumCast(this.rootDoc.y) + + NumCast(this.layoutDoc._height) + 10, - NumCast(this.props.Document._width), - 2 * NumCast(this.props.Document._height) + NumCast(this.layoutDoc._width), + 2 * NumCast(this.layoutDoc._height) ); Doc.GetProto(newDoc).recordingSource = this.dataDoc; Doc.GetProto(newDoc).recordingStart = ComputedField.MakeFunction( @@ -332,8 +304,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp // returns the path of the audio file @computed get path() { - const field = Cast(this.props.Document[this.fieldKey], AudioField); - const path = field instanceof AudioField ? field.url.href : ""; + const path = Cast(this.props.Document[this.fieldKey], AudioField, null)?.url.href || ""; return path === nullAudio ? "" : path; } @@ -473,133 +444,105 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp })); } - render() { - return ( - <div - ref={r => { - if (r && this.timeline) { - this._dropDisposer?.(); - this._dropDisposer = DragManager.MakeDropTarget(r, - (e, de) => { - const [xp, yp] = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); - de.complete.docDragData && this.timeline!.internalDocDrop(e, de, de.complete.docDragData, xp); - } - , this.layoutDoc, undefined); - } - }} - className="audiobox-container" - onContextMenu={this.specificContextMenu} - onClick={ - !this.path && !this._recorder ? this.recordAudioAnnotation : undefined - } - style={{ - pointerEvents: - this.props.layerProvider?.(this.layoutDoc) === false - ? "none" - : undefined, - }} - > - {!this.path ? ( - <div className="audiobox-buttons"> - <div className="audiobox-dictation" onClick={this.onFile}> - <FontAwesomeIcon - style={{ width: "30px" }} - icon="file-alt" - size={this.props.PanelHeight() < 36 ? "1x" : "2x"} - /> - </div> - {this.mediaState === media_state.Recording || this.mediaState === media_state.Playing ? ( - <div className="recording" onClick={(e) => e.stopPropagation()}> - <div className="recording-buttons" onClick={this.recordClick}> - <FontAwesomeIcon - icon="stop" - size={this.props.PanelHeight() < 36 ? "1x" : "2x"} - /> - </div> - <div - className="recording-buttons" - onClick={this._paused ? this.recordPlay : this.recordPause} - > - <FontAwesomeIcon - icon={this._paused ? "play" : "pause"} - size={this.props.PanelHeight() < 36 ? "1x" : "2x"} - /> - </div> - <div className="time"> - {formatTime( - Math.round(NumCast(this.layoutDoc._currentTimecode)) - )} - </div> - </div> - ) : ( - <div - className={`audiobox-record${this.props.isContentActive() ? "-interactive" : ""}`} - style={{ backgroundColor: Colors.DARK_GRAY }} - > - <FontAwesomeIcon icon="microphone" /> - RECORD - </div> - )} + @computed get recordingControls() { + return <div className="audiobox-buttons"> + <div className="audiobox-dictation" onClick={this.onFile}> + <FontAwesomeIcon + style={{ width: "30px" }} + icon="file-alt" + size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /> + </div> + {[media_state.Recording, media_state.Playing].includes(this.mediaState) ? + <div className="recording" onClick={(e) => e.stopPropagation()}> + <div className="recording-buttons" onClick={this.recordClick}> + <FontAwesomeIcon + icon="stop" + size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /> </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}%` }} - > - <div - className="audiobox-buttons" - title={this.mediaState === media_state.Paused ? "play" : "pause"} - onClick={this.mediaState === media_state.Paused ? this.Play : this.Pause} - > - {" "} - <FontAwesomeIcon - icon={this.mediaState === media_state.Paused ? "play" : "pause"} - size={"1x"} - /> - </div> - <div - className="audiobox-buttons" - title={this.timeline?.IsTrimming !== TrimScope.None ? "finish" : "trim"} - onPointerDown={this.onClipPointerDown} - > - <FontAwesomeIcon - icon={this.timeline?.IsTrimming !== TrimScope.None ? "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.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))} - </div> - <div className="audioBox-total-time"> - {this.timeline && formatTime(Math.round(NumCast(this.timeline?.clipDuration)))} - </div> - </div> - </div> - )} + <div className="recording-buttons" + onClick={this._paused ? this.recordPlay : this.recordPause} + > + <FontAwesomeIcon + icon={this._paused ? "play" : "pause"} + size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /> + </div> + <div className="time"> + {formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode)))} + </div> + </div> + : + <div className={`audiobox-record${this.props.isContentActive() ? "-interactive" : ""}`}> + <FontAwesomeIcon icon="microphone" /> + RECORD + </div>} + </div>; + } + + @computed get playbackControls() { + return <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}%` }} + > + <div className="audiobox-buttons" + title={this.mediaState === media_state.Paused ? "play" : "pause"} + onClick={this.mediaState === media_state.Paused ? this.Play : this.Pause} + > + {" "} + <FontAwesomeIcon + icon={this.mediaState === media_state.Paused ? "play" : "pause"} + size={"1x"} /> + </div> + <div className="audiobox-buttons" + title={this.timeline?.IsTrimming !== TrimScope.None ? "finish" : "trim"} + onPointerDown={this.onClipPointerDown} + > + <FontAwesomeIcon + icon={this.timeline?.IsTrimming !== TrimScope.None ? "check" : "cut"} + size={"1x"} /> + </div> + <div className="audiobox-timeline" + style={{ + left: AudioBox.playheadWidth, + width: `calc(100% - ${AudioBox.playheadWidth}px)`, + }} + > + {this.renderTimeline} + </div> + {this.audio} + <div className="audioBox-current-time"> + {this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))} + </div> + <div className="audioBox-total-time"> + {this.timeline && formatTime(Math.round(NumCast(this.timeline?.clipDuration)))} + </div> </div> - ); + </div>; + } + + setupTimelineDrop = (r: HTMLDivElement | null) => { + if (r && this.timeline) { + this._dropDisposer?.(); + this._dropDisposer = DragManager.MakeDropTarget(r, + (e, de) => { + const [xp, yp] = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + de.complete.docDragData && this.timeline!.internalDocDrop(e, de, de.complete.docDragData, xp); + }, + this.layoutDoc, undefined); + } + } + + render() { + return <div + ref={this.setupTimelineDrop} + className="audiobox-container" + onContextMenu={this.specificContextMenu} + onClick={!this.path && !this._recorder ? this.recordAudioAnnotation : undefined} + style={{ pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined }} + > + {!this.path ? this.recordingControls : this.playbackControls} + </div>; } }
\ No newline at end of file |