import React, { Component } from 'react' import { connect } from 'react-redux' import actions from 'app/actions' import { VIDEO_SCRUBBER_HIDE_DELAY } from 'app/constants' import { clamp, timestamp } from 'app/utils' import { PlayButton, VolumeControl } from 'app/views/viewer/nav/viewer.icons' class VideoScrubber extends Component { state = { hovering: false, showing: false, } constructor(props) { super(props) this.scrubberRef = React.createRef() this.handleMouseDown = this.handleMouseDown.bind(this) this.handleMouseMove = this.handleMouseMove.bind(this) this.handleMouseUp = this.handleMouseUp.bind(this) this.handleMouseEnter = this.handleMouseEnter.bind(this) this.handleMouseLeave = this.handleMouseLeave.bind(this) this.handleWindowFocus = this.handleWindowFocus.bind(this) this.hide = this.hide.bind(this) } componentDidMount() { window.addEventListener('mousemove', this.handleMouseMove) window.addEventListener('mouseup', this.handleMouseUp) window.addEventListener('focus', this.handleWindowFocus) // this.show() } componentWillUnmount() { window.removeEventListener('mousemove', this.handleMouseMove) window.removeEventListener('mouseup', this.handleMouseUp) window.removeEventListener('focus', this.handleWindowFocus) clearTimeout(this.hideTimeout) } show() { clearTimeout(this.hideTimeout) this.hideTimeout = setTimeout(this.hide, VIDEO_SCRUBBER_HIDE_DELAY) if (!this.showing) { this.setState({ showing: true }) } } hide() { clearTimeout(this.timeout) this.setState({ showing: false }) this.defer = false } scrub(x, scrubbing) { const { timing, start_ts, video_start_ts, onScrub, duration } = this.props const bounds = this.scrubberRef.current.getBoundingClientRect() // get percent offset from the scrubber const percent = clamp((x - bounds.left) / bounds.width, 0, 1) // this offset in seconds based on the length of the fullscreen element const seconds = percent * duration // we can use this to seek the audio actions.audio.seek(start_ts + seconds) actions.audio.play() // apply the video start offset. // in case the video loops, modulo the length of the original video const video_seek = ((seconds + video_start_ts) % timing.duration) // console.log(start_ts, seconds) onScrub({ seek: video_seek, seconds: seconds, scrubbing, }) } handleMouseDown(e) { e.stopPropagation() this.scrub(e.pageX, true) } handleMouseMove(e) { e.stopPropagation() console.log('move', this.defer) if (this.defer) { this.defer = false this.show() } this.defer = true clearTimeout(this.showTimeout) this.showTimeout = setTimeout(() => { this.defer = false }, 16) if (!this.props.timing.scrubbing) return this.scrub(e.pageX, true) } handleMouseUp(e) { e.stopPropagation() this.props.onScrub({ scrubbing: false }) } handleMouseEnter() { this.setState({ hovering: true }) } handleMouseLeave() { this.setState({ hovering: false }) } handleWindowFocus() { this.setState({ showing: false, hovering: false }) clearTimeout(this.hideTimeout) } render() { const { playing, start_ts, play_ts, volume, timing, video_start_ts, duration } = this.props const { hovering, showing } = this.state // remove video start offset from timing // console.log(start_ts, play_ts) const player_ts = play_ts - start_ts // compute percent from the length of the fullscreen element const percent = clamp(player_ts / duration, 0, 1) // display timestamp from the fullscreen element too const timestampText = timestamp(clamp(player_ts, 0, duration)) // show or hide the scrubber bar const className = (hovering || showing) ? 'video-scrubber show' : 'video-scrubber' // console.log(timing.seconds, video_start_ts, duration) return (