import React from 'react';
import { Lbry } from 'lbry-redux';
import {
DeviceEventEmitter,
NativeModules,
PanResponder,
Text,
View,
ScrollView,
TouchableOpacity
} from 'react-native';
import Video from 'react-native-video';
import Icon from 'react-native-vector-icons/FontAwesome5';
import FileItemMedia from '../fileItemMedia';
import mediaPlayerStyle from '../../styles/mediaPlayer';
class MediaPlayer extends React.PureComponent {
static ControlsTimeout = 3000;
seekResponder = null;
seekerWidth = 0;
trackingOffset = 0;
tracking = null;
video = null;
constructor(props) {
super(props);
this.state = {
encodedFilePath: null,
rate: 1,
volume: 1,
muted: false,
resizeMode: 'contain',
duration: 0.0,
currentTime: 0.0,
paused: !props.autoPlay,
fullscreenMode: false,
areControlsVisible: true,
controlsTimeout: -1,
seekerOffset: 0,
seekerPosition: 0,
firstPlay: true,
seekTimeout: -1
};
}
formatTime(time) {
let str = '';
let minutes = 0, hours = 0, seconds = parseInt(time, 10);
if (seconds > 60) {
minutes = parseInt(seconds / 60, 10);
seconds = seconds % 60;
if (minutes > 60) {
hours = parseInt(minutes / 60, 10);
minutes = minutes % 60;
}
str = (hours > 0 ? this.pad(hours) + ':' : '') + this.pad(minutes) + ':' + this.pad(seconds);
} else {
str = '00:' + this.pad(seconds);
}
return str;
}
pad(value) {
if (value < 10) {
return '0' + String(value);
}
return value;
}
onLoad = (data) => {
this.setState({
duration: data.duration
});
if (this.props.onMediaLoaded) {
this.props.onMediaLoaded();
}
}
onProgress = (data) => {
this.setState({ currentTime: data.currentTime });
if (!this.state.seeking) {
this.setSeekerPosition(this.calculateSeekerPosition());
}
if (this.state.firstPlay) {
if (this.props.onPlaybackStarted) {
this.props.onPlaybackStarted();
}
this.setState({ firstPlay: false });
this.hidePlayerControls();
}
}
clearControlsTimeout = () => {
if (this.state.controlsTimeout > -1) {
clearTimeout(this.state.controlsTimeout)
}
}
showPlayerControls = () => {
this.clearControlsTimeout();
if (!this.state.areControlsVisible) {
this.setState({ areControlsVisible: true });
}
this.hidePlayerControls();
}
hidePlayerControls() {
const player = this;
let timeout = setTimeout(() => {
player.setState({ areControlsVisible: false });
}, MediaPlayer.ControlsTimeout);
player.setState({ controlsTimeout: timeout });
}
togglePlay = () => {
this.showPlayerControls();
this.setState({ paused: !this.state.paused });
}
toggleFullscreenMode = () => {
this.showPlayerControls();
const { onFullscreenToggled } = this.props;
this.setState({ fullscreenMode: !this.state.fullscreenMode }, () => {
if (onFullscreenToggled) {
onFullscreenToggled(this.state.fullscreenMode);
}
});
}
onEnd = () => {
this.setState({ paused: true });
this.video.seek(0);
}
setSeekerPosition(position = 0) {
position = this.checkSeekerPosition(position);
this.setState({ seekerPosition: position });
if (!this.state.seeking) {
this.setState({ seekerOffset: position });
}
}
checkSeekerPosition(val = 0) {
if (val < 0) {
val = 0;
} else if (val >= this.seekerWidth) {
return this.seekerWidth;
}
return val;
}
seekTo(time = 0) {
if (time > this.state.duration) {
return;
}
this.video.seek(time);
this.setState({ currentTime: time });
}
initSeeker() {
this.seekResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
this.clearControlsTimeout();
if (this.state.seekTimeout > 0) {
clearTimeout(this.state.seekTimeout);
}
this.setState({ seeking: true });
},
onPanResponderMove: (evt, gestureState) => {
const position = this.state.seekerOffset + gestureState.dx;
this.setSeekerPosition(position);
},
onPanResponderRelease: (evt, gestureState) => {
const time = this.getCurrentTimeForSeekerPosition();
if (time >= this.state.duration) {
this.setState({ paused: true });
this.onEnd();
} else {
this.seekTo(time);
this.setState({ seekTimeout: setTimeout(() => { this.setState({ seeking: false }); }, 100) });
}
this.hidePlayerControls();
}
});
}
getTrackingOffset() {
return this.state.fullscreenMode ? this.trackingOffset : 0;
}
getCurrentTimeForSeekerPosition() {
return this.state.duration * (this.state.seekerPosition / this.seekerWidth);
}
calculateSeekerPosition() {
return this.seekerWidth * this.getCurrentTimePercentage();
}
getCurrentTimePercentage() {
if (this.state.currentTime > 0) {
return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
}
return 0;
};
componentWillMount() {
this.initSeeker();
}
componentDidMount() {
this.setSeekerPosition(this.calculateSeekerPosition());
DeviceEventEmitter.addListener('onBackgroundPlayPressed', this.play);
DeviceEventEmitter.addListener('onBackgroundPausePressed', this.pause);
}
componentWillUnmount() {
DeviceEventEmitter.removeListener('onBackgroundPlayPressed', this.play);
DeviceEventEmitter.removeListener('onBackgroundPausePressed', this.pause);
this.clearControlsTimeout();
this.setState({ paused: true, fullscreenMode: false });
const { onFullscreenToggled } = this.props;
if (onFullscreenToggled) {
onFullscreenToggled(false);
}
}
play = () => {
this.setState({ paused: false }, this.updateBackgroundMediaNotification);
}
pause = () => {
this.setState({ paused: true }, this.updateBackgroundMediaNotification);
}
updateBackgroundMediaNotification = () => {
const { backgroundPlayEnabled } = this.props;
if (backgroundPlayEnabled) {
if (NativeModules.BackgroundMedia && window.currentMediaInfo) {
const { title, channel } = window.currentMediaInfo;
NativeModules.BackgroundMedia.showPlaybackNotification(title, channel, null, this.state.paused);
}
}
}
renderPlayerControls() {
if (this.state.areControlsVisible) {
return (
{this.state.paused && }
{!this.state.paused && }
{this.state.fullscreenMode && }
{!this.state.fullscreenMode && }
{this.formatTime(this.state.currentTime)}
{this.formatTime(this.state.duration)}
);
}
return null;
}
getEncodedDownloadPath = (fileInfo) => {
if (this.state.encodedFilePath) {
return this.state.encodedFilePath;
}
const { file_name: fileName } = fileInfo;
const encodedFileName = encodeURIComponent(fileName).replace(/!/g, '%21');
const encodedFilePath = fileInfo.download_path.replace(fileName, encodedFileName);
this.setState({ encodedFilePath });
return encodedFilePath;
}
render() {
const { backgroundPlayEnabled, fileInfo, thumbnail, onLayout, style } = this.props;
const completedWidth = this.getCurrentTimePercentage() * this.seekerWidth;
const remainingWidth = this.seekerWidth - completedWidth;
let styles = [this.state.fullscreenMode ? mediaPlayerStyle.fullscreenContainer : mediaPlayerStyle.container];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
const trackingStyle = [mediaPlayerStyle.trackingControls, this.state.fullscreenMode ?
mediaPlayerStyle.fullscreenTrackingControls : mediaPlayerStyle.containedTrackingControls];
return (
);
}
}
export default MediaPlayer;