aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/VideoBox.tsx
diff options
context:
space:
mode:
authormehekj <mehek.jethani@gmail.com>2022-03-12 16:40:40 -0500
committermehekj <mehek.jethani@gmail.com>2022-03-12 16:40:40 -0500
commite474d02cf51c5e20e42baa6b7d9c4aeb4ab51967 (patch)
tree255af51acbfb6acb7b6ec1707fc611963de033c9 /src/client/views/nodes/VideoBox.tsx
parent017016a8de25709b11febb0252b57824339e9151 (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.tsx172
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 >);
}