diff options
| author | mehekj <mehek.jethani@gmail.com> | 2022-03-12 16:40:40 -0500 |
|---|---|---|
| committer | mehekj <mehek.jethani@gmail.com> | 2022-03-12 16:40:40 -0500 |
| commit | e474d02cf51c5e20e42baa6b7d9c4aeb4ab51967 (patch) | |
| tree | 255af51acbfb6acb7b6ec1707fc611963de033c9 /src/client/views/nodes/VideoBox.tsx | |
| parent | 017016a8de25709b11febb0252b57824339e9151 (diff) | |
video ui in progress, basic functions show up
Diffstat (limited to 'src/client/views/nodes/VideoBox.tsx')
| -rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 172 |
1 files changed, 131 insertions, 41 deletions
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index d56363348..bd9423d74 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -59,6 +59,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp private _disposers: { [name: string]: IReactionDisposer } = {}; private _youtubePlayer: YT.Player | undefined = undefined; private _videoRef: HTMLVideoElement | null = null; + private _contentRef: HTMLDivElement | null = null; private _youtubeIframeId: number = -1; private _youtubeContentCreated = false; private _audioPlayer: HTMLAudioElement | null = null; @@ -77,6 +78,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @observable _fullScreen = false; @observable _playing = false; @observable _finished: boolean = false; + @observable _volume: number = 1; + @observable _muted: boolean = false; @computed get links() { return DocListCast(this.dataDoc.links); } @computed get heightPercent() { return NumCast(this.layoutDoc._timelineHeightPercent, 100); } @@ -168,8 +171,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } @action public FullScreen = () => { - this._fullScreen = true; - this.player && this.player.requestFullscreen(); + if (document.fullscreenElement == this._contentRef) { + this._fullScreen = false; + this.player && this._contentRef && document.exitFullscreen(); + } + else { + this._fullScreen = true; + this.player && this._contentRef && this._contentRef.requestFullscreen(); + } try { this._youtubePlayer && this.props.addDocTab(this.rootDoc, "add"); } catch (e) { @@ -269,13 +278,21 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp if (vref) { this._videoRef!.ontimeupdate = this.updateTimecode; // @ts-ignore - vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); + // vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); this._disposers.reactionDisposer?.(); this._disposers.reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0), time => !this._playing && (vref.currentTime = time), { fireImmediately: true }); } } + @action + setContentRef = (cref: HTMLDivElement | null) => { + this._contentRef = cref; + if (cref) { + cref.onfullscreenchange = action((e) => this._fullScreen = (document.fullscreenElement == cref)); + } + } + specificContextMenu = (e: React.MouseEvent): void => { const field = Cast(this.dataDoc[this.props.fieldKey], VideoField); if (field) { @@ -292,10 +309,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp subitems.push({ description: (this.layoutDoc.dontAutoFollowLinks ? "" : "Don't") + " follow links when encountered", event: () => this.layoutDoc.dontAutoFollowLinks = !this.layoutDoc.dontAutoFollowLinks, icon: "expand-arrows-alt" }); subitems.push({ description: (this.layoutDoc.dontAutoPlayFollowedLinks ? "" : "Don't") + " play when link is selected", event: () => this.layoutDoc.dontAutoPlayFollowedLinks = !this.layoutDoc.dontAutoPlayFollowedLinks, icon: "expand-arrows-alt" }); subitems.push({ description: (this.layoutDoc.autoPlayAnchors ? "Don't auto play" : "Auto play") + " anchors onClick", event: () => this.layoutDoc.autoPlayAnchors = !this.layoutDoc.autoPlayAnchors, icon: "expand-arrows-alt" }); - subitems.push({ description: "Toggle Native Controls", event: action(() => VideoBox._nativeControls = !VideoBox._nativeControls), icon: "expand-arrows-alt" }); - subitems.push({ description: "Start Trim All", event: () => this.startTrim(TrimScope.All), icon: "expand-arrows-alt" }); - subitems.push({ description: "Start Trim Clip", event: () => this.startTrim(TrimScope.Clip), icon: "expand-arrows-alt" }); - subitems.push({ description: "Stop Trim", event: () => this.finishTrim(), icon: "expand-arrows-alt" }); + // subitems.push({ description: "Toggle Native Controls", event: action(() => VideoBox._nativeControls = !VideoBox._nativeControls), icon: "expand-arrows-alt" }); + // subitems.push({ description: "Start Trim All", event: () => this.startTrim(TrimScope.All), icon: "expand-arrows-alt" }); + // subitems.push({ description: "Start Trim Clip", event: () => this.startTrim(TrimScope.Clip), icon: "expand-arrows-alt" }); + // subitems.push({ description: "Stop Trim", event: () => this.finishTrim(), icon: "expand-arrows-alt" }); subitems.push({ description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" }); } @@ -309,7 +326,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp const classname = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive; return !field ? <div key="loading">Loading</div> : <div className="videoBox-contentContainer" key="container" style={{ mixBlendMode: "multiply" }}> - <div className={classname}> + <div className={classname} ref={this.setContentRef}> + {this.uIButtons} <video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef} onCanPlay={this.videoLoad} controls={VideoBox._nativeControls} @@ -489,6 +507,25 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp })); } + @action + setVolume = (volume: number) => { + if (this.player) { + this._volume = volume; + this.player.volume = volume; + } + } + + @action + toggleMute = (e: React.PointerEvent) => { + e.stopPropagation(); + console.log("click"); + if (this.player) { + console.log("audio exists"); + this._muted = !this._muted; + this.player.muted = this._muted; + } + } + playLink = (doc: Doc) => { const startTime = Math.max(0, (this._stackedTimeline.current?.anchorStart(doc) || 0)); const endTime = this.timeline?.anchorEnd(doc); @@ -534,41 +571,95 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @computed get uIButtons() { const curTime = (this.layoutDoc._currentTimecode || 0) - (this.timeline?.clipStart || 0); - const nonNativeControls = [ - <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} key="play" placement="bottom"> - <div className="videoBox-play" onPointerDown={this.onPlayDown} > - <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" /> - </div> - </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} key="time" placement="bottom"> - <div className="videoBox-time" onPointerDown={this.onResetDown} > - <span>{formatTime(curTime)}</span> - <span style={{ fontSize: 8 }}>{" " + Math.floor((curTime - Math.trunc(curTime)) * 100).toString().padStart(2, "0")}</span> - </div> - </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} key="full" placement="bottom"> - <div className="videoBox-full" onPointerDown={this.FullScreen}> - <FontAwesomeIcon icon="expand" size="lg" /> - </div> - </Tooltip>]; - return <div className="videoBox-ui"> - {[...(VideoBox._nativeControls ? [] : nonNativeControls), - <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} key="snap" placement="bottom"> - <div className="videoBox-snapshot" onPointerDown={this.onSnapshotDown} > - <FontAwesomeIcon icon="camera" size="lg" /> + // const nonNativeControls = [ + // <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} key="play" placement="bottom"> + // <div className="videoBox-play" onPointerDown={this.onPlayDown} > + // <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" /> + // </div> + // </Tooltip>, + // <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} key="time" placement="bottom"> + // <div className="videoBox-time" onPointerDown={this.onResetDown} > + // <span>{formatTime(curTime)}</span> + // <span style={{ fontSize: 8 }}>{" " + Math.floor((curTime - Math.trunc(curTime)) * 100).toString().padStart(2, "0")}</span> + // </div> + // </Tooltip>, + // <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} key="full" placement="bottom"> + // <div className="videoBox-full" onPointerDown={this.FullScreen}> + // <FontAwesomeIcon icon="expand" size="lg" /> + // </div> + // </Tooltip>]; + // return <div className="videoBox-ui"> + // {[...(VideoBox._nativeControls ? [] : nonNativeControls), + // <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} key="snap" placement="bottom"> + // <div className="videoBox-snapshot" onPointerDown={this.onSnapshotDown} > + // <FontAwesomeIcon icon="camera" size="lg" /> + // </div> + // </Tooltip>, + // <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} key="timeline" placement="bottom"> + // <div className="videoBox-timelineButton" onPointerDown={this.onTimelineHdlDown}> + // <FontAwesomeIcon icon="eye" size="lg" /> + // </div> + // </Tooltip>, + // <Tooltip title={<div className="dash-tooltip">{this.timeline?.IsTrimming !== TrimScope.None ? "finish trimming" : "start trim"}</div>} key="trim" placement="bottom"> + // <div className="videoBox-timelineButton" onPointerDown={this.onClipPointerDown}> + // <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? "check" : "cut"} size="lg" /> + // </div> + // </Tooltip>,]} + // </div>; + return <div className="videoBox-ui" style={{ top: `calc(100% - 10px)` }}> + <div className="videobox-button" + title={this._playing ? "play" : "pause"} + onPointerDown={this.onPlayDown}> + <FontAwesomeIcon icon={this._playing ? "pause" : "play"} /> + </div> + + {this.timeline && <div className="timecode-controls"> + <div className="timecode-current"> + {formatTime(curTime)} </div> - </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} key="timeline" placement="bottom"> - <div className="videoBox-timelineButton" onPointerDown={this.onTimelineHdlDown}> - <FontAwesomeIcon icon="eye" size="lg" /> + + <div className="timeline-slider"> + <input type="range" step="0.1" min={this.timeline.clipStart} max={this.timeline.clipEnd} value={curTime} + className="toolbar-slider time-progress" + onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }} + onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.setPlayheadTime(Number(e.target.value)) }} + /> </div> - </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{this.timeline?.IsTrimming !== TrimScope.None ? "finish trimming" : "start trim"}</div>} key="trim" placement="bottom"> - <div className="videoBox-timelineButton" onPointerDown={this.onClipPointerDown}> - <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? "check" : "cut"} size="lg" /> + + <div className="timecode-end"> + {formatTime(this.timeline.clipDuration)} </div> - </Tooltip>,]} - </div>; + </div>} + + <div className="videobox-button" + title={"full screen"} + onPointerDown={this.onFullDown}> + <FontAwesomeIcon icon="expand" /> + </div> + + {!this._fullScreen && <div className="videobox-button" + title={"show timeline"} + onPointerDown={this.onTimelineHdlDown}> + <FontAwesomeIcon icon="eye" /> + </div>} + + {!this._fullScreen && <div className="videobox-button" + title={this.timeline?.IsTrimming !== TrimScope.None ? "finish trimming" : "start trim"} + onPointerDown={this.onClipPointerDown}> + <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? "check" : "cut"} /> + </div>} + + <div className="videobox-button" + title={this._muted ? "unmute" : "mute"} + onPointerDown={this.toggleMute}> + <FontAwesomeIcon icon={this._muted || this._volume == 0 ? "volume-mute" : "volume-up"} /> + </div> + <input type="range" step="0.1" min="0" max="1" value={this._muted ? 0 : this._volume} + className="toolbar-slider volume" + onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }} + onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.setVolume(Number(e.target.value)) }} + /> + </div> } @computed get renderTimeline() { return <div className="videoBox-stackPanel" style={{ transition: this.transition, height: `${100 - this.heightPercent}%` }}> @@ -653,7 +744,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp mainCont={this._mainCont.current} />} {this.renderTimeline} - {this.uIButtons} </div> </div >); } |
