summaryrefslogtreecommitdiff
path: root/animism-align/frontend/app/views/viewer/player/components.media
diff options
context:
space:
mode:
Diffstat (limited to 'animism-align/frontend/app/views/viewer/player/components.media')
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/index.js2
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/media.css51
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js82
3 files changed, 123 insertions, 12 deletions
diff --git a/animism-align/frontend/app/views/viewer/player/components.media/index.js b/animism-align/frontend/app/views/viewer/player/components.media/index.js
index 37f6f64..04b7f03 100644
--- a/animism-align/frontend/app/views/viewer/player/components.media/index.js
+++ b/animism-align/frontend/app/views/viewer/player/components.media/index.js
@@ -13,6 +13,7 @@ import {
} from './media.gallery'
import Carousel from './media.carousel'
+import VideoScrubber from './video.scrubber'
import {
Grid
@@ -24,4 +25,5 @@ export {
Gallery,
Carousel,
Grid,
+ VideoScrubber,
} \ No newline at end of file
diff --git a/animism-align/frontend/app/views/viewer/player/components.media/media.css b/animism-align/frontend/app/views/viewer/player/components.media/media.css
index 32d35d0..653a53b 100644
--- a/animism-align/frontend/app/views/viewer/player/components.media/media.css
+++ b/animism-align/frontend/app/views/viewer/player/components.media/media.css
@@ -302,29 +302,56 @@
.video-scrubber {
position: absolute;
- bottom: 5rem;
- left: 50%;
- width: 300px;
- height: 16px;
- margin-left: -150px;
+ bottom: 4rem;
+ left: 1rem;
+ width: calc(100% - 2rem);
+ height: 3rem;
+ background: white;
+ border-radius: 1.5rem;
+ display: flex;
+ align-items: center;
+}
+.video-scrubber .start-controls {
+ width: 3rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.video-scrubber .scrub-bar-container {
+ flex: 1;
+ height: 3rem;
+ display: flex;
+ align-items: center;
+ position: relative;
cursor: pointer;
}
.video-scrubber .scrub-bar {
- position: absolute;
- top: 7px;
- left: 0;
+ position: relative;
width: 100%;
height: 2px;
- background: white;
+ margin-top: 1px;
+ background: black;
}
.video-scrubber .scrub-dot {
position: absolute;
- top: 0;
+ top: 50%;
left: 0;
width: 16px;
height: 16px;
+ margin-top: -7px;
margin-left: -8px;
border-radius: 50%;
- background: white;
- cursor: pointer;
+ background: black;
+ pointer-events: none;
+}
+.video-scrubber .end-controls {
+ width: 7rem;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ color: black;
}
+.video-scrubber .playerTime {
+ display: flex;
+ align-items: center;
+} \ No newline at end of file
diff --git a/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js b/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js
new file mode 100644
index 0000000..7bbbc07
--- /dev/null
+++ b/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js
@@ -0,0 +1,82 @@
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+
+import actions from 'app/actions'
+import { clamp, timestamp } from 'app/utils'
+import { PlayButton, VolumeControl } from 'app/views/viewer/nav/viewer.icons'
+
+class VideoScrubber extends Component {
+ constructor(props) {
+ super(props)
+ this.scrubberRef = React.createRef()
+ this.handleScrubDotMouseDown = this.handleScrubDotMouseDown.bind(this)
+ this.handleScrubDotMouseMove = this.handleScrubDotMouseMove.bind(this)
+ this.handleScrubDotMouseUp = this.handleScrubDotMouseUp.bind(this)
+ }
+ componentDidMount() {
+ window.addEventListener('mousemove', this.handleScrubDotMouseMove)
+ window.addEventListener('mouseup', this.handleScrubDotMouseUp)
+ }
+ componentWillUnmount() {
+ window.removeEventListener('mousemove', this.handleScrubDotMouseMove)
+ window.removeEventListener('mouseup', this.handleScrubDotMouseUp)
+ }
+ scrub(x, scrubbing) {
+ const { timing, start_ts, onScrub } = this.props
+ const bounds = this.scrubberRef.current.getBoundingClientRect()
+ const percent = clamp((x - bounds.left) / bounds.width, 0, 1)
+ const seconds = percent * timing.duration
+ actions.audio.seek(start_ts + seconds)
+ onScrub({
+ seek: seconds,
+ percent, seconds, scrubbing
+ })
+ }
+ handleScrubDotMouseDown(e) {
+ e.stopPropagation()
+ this.scrub(e.pageX, true)
+ }
+ handleScrubDotMouseMove(e) {
+ e.stopPropagation()
+ if (!this.props.timing.scrubbing) return
+ this.scrub(e.pageX, true)
+ }
+ handleScrubDotMouseUp(e) {
+ e.stopPropagation()
+ this.props.onScrub({ scrubbing: false })
+ }
+ render() {
+ const { playing, volume, timing } = this.props
+ return (
+ <div className='video-scrubber'>
+ <div className='start-controls'>
+ <PlayButton playing={playing} />
+ </div>
+ <div
+ className='scrub-bar-container'
+ onMouseDown={this.handleScrubDotMouseDown}
+ ref={this.scrubberRef}
+ >
+ <div className='scrub-bar' />
+ <div
+ className='scrub-dot'
+ style={{ left: (100 * timing.percent) + "%" }}
+ />
+ </div>
+ <div className='end-controls'>
+ <div className='playerTime'>
+ {timestamp(clamp(timing.seconds, 0, timing.duration))}
+ </div>
+ <VolumeControl volume={volume} />
+ </div>
+ </div>
+ )
+ }
+}
+
+const mapStateToProps = state => ({
+ playing: state.audio.playing,
+ volume: state.audio.volume,
+})
+
+export default connect(mapStateToProps)(VideoScrubber)