mediamonkeyserver
Version:
MediaMonkey Server
158 lines (138 loc) • 4.15 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import Slider from 'rc-slider'; // We use this non-Material UI Slider until there's one included in the material-ui library.
import { withTheme } from '@material-ui/core/styles';
import PlayIcon from '@material-ui/icons/PlayArrow';
import PauseIcon from '@material-ui/icons/Pause';
import StopIcon from '@material-ui/icons/Stop';
import Playback from 'playback';
import { subscribePlaybackStateChange } from 'actions';
const styles = {
root: {
width: '100%',
},
flex: {
marginLeft: 10,
flex: 1,
},
playButton: {
margin: 0,
},
slider: {
position: 'absolute',
left: 0,
right: 0,
top: -5,
height: 10,
}
};
const SEEK_STEPS = 10000;
class Player extends React.Component {
state = {
playing: false,
playbackActive: false,
trackTitle: '',
seekPosition: 20,
};
componentDidMount() {
subscribePlaybackStateChange(this.playbackStateChange);
}
playbackStateChange = () => {
var mediaItem = Playback.getCurrentMediaItem();
this.setState({
playing: Playback.getPlaying(),
playbackActive: Playback.getActive(),
trackTitle: mediaItem ? (mediaItem.artists ? mediaItem.artists.join('; ') : '') + ' - ' + mediaItem.title : '',
});
this.setSeekUpdater();
}
setSeekUpdater = () => {
var playing = Playback.getPlaying();
if (playing && !this.seekUpdater) {
this.seekUpdater = setInterval(this.updateSeekPosition, 30);
} else {
if (!playing && this.seekUpdater) {
clearInterval(this.seekUpdater);
this.seekUpdater = null;
}
}
}
updateSeekPosition = () => {
var duration = Playback.getDuration();
var position = null;
if (duration) {
var currTime = Playback.getCurrentTime();
position = currTime / duration * SEEK_STEPS;
}
this.setState({ seekPosition: position });
}
handleSeeked = (value) => {
var duration = Playback.getDuration();
if (duration) {
var position = value / SEEK_STEPS * duration;
Playback.setCurrentTime(position);
}
this.updateSeekPosition();
}
handlePlayPauseClick = () => {
Playback.playPause();
}
handleStopClick = () => {
Playback.stop();
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position='static'>
<Toolbar>
{/* Seekbar */}
{this.state.playbackActive ?
<Slider
className={classes.slider}
value={this.state.seekPosition}
max={SEEK_STEPS}
railStyle={{
backgroundColor: this.props.theme.palette.primary.light,
}}
trackStyle={{
backgroundColor: this.props.theme.palette.secondary.main,
}}
handleStyle={{
backgroundColor: this.props.theme.palette.secondary.main,
border: 'none',
width: 12,
height: 12,
marginTop: -4,
}}
onChange={this.handleSeeked} />
: null}
{/* Play button */}
<Button variant='fab' mini color='secondary' aria-label='play' className={classes.playButton} onClick={this.handlePlayPauseClick}>
{this.state.playing ? <PauseIcon /> : <PlayIcon />}
</Button>
{/* Track title */}
<Typography type='title' color='inherit' className={classes.flex}>
{this.state.trackTitle}
</Typography>
{/* Stop button */}
{this.state.playbackActive ?
<Button variant='fab' mini color='secondary' aria-label='stop' className={classes.playButton} onClick={this.handleStopClick}>
<StopIcon />
</Button> : null}
</Toolbar>
</AppBar>
</div>
);
}
}
Player.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withTheme()(withStyles(styles)(Player));