From 1965879bcdaba08dd7fc99bef3dd012bdf80f348 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Fri, 22 Jul 2016 08:11:09 -0700 Subject: [PATCH] Move Position to react/redux --- css/main-window.css | 5 +++ js/Position.jsx | 77 +++++++++++++++++++++++++++++++++++++++++++ js/main-window-dom.js | 2 +- js/main-window.js | 57 ++------------------------------ js/reducers.js | 5 ++- 5 files changed, 89 insertions(+), 57 deletions(-) create mode 100644 js/Position.jsx diff --git a/css/main-window.css b/css/main-window.css index bc53e21b..69a5206b 100755 --- a/css/main-window.css +++ b/css/main-window.css @@ -364,6 +364,11 @@ #winamp2-js .stop #position::-webkit-slider-thumb { visibility: hidden; } #winamp2-js .stop #position::-moz-range-thumb { visibility: hidden; } +/* For some reason this is needed for the position slider to show up now that + * we are using React. + */ +#winamp2-js .play #position::-webkit-slider-thumb { visibility: visible; } + #winamp2-js .actions div { height: 18px; width: 23px; diff --git a/js/Position.jsx b/js/Position.jsx new file mode 100644 index 00000000..8b83bfb9 --- /dev/null +++ b/js/Position.jsx @@ -0,0 +1,77 @@ +// Single line text display that can animate and hold multiple registers +import React from 'react'; +import {connect} from 'react-redux'; + +import {getTimeStr} from './utils'; + +class Position extends React.Component { + constructor(props) { + super(props); + // Consider moving to global state. Currently nobody else cares. + this.state = { + mouseIsDown: false, + currentPosition: 0 + }; + this.setPosition = this.setPosition.bind(this); + this.showMarquee = this.showMarquee.bind(this); + this.hideMarquee = this.hideMarquee.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + } + + setPosition(e) { + this.props.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'message'}); + this.setState({ + mouseIsDown: true, + currentPosition: e.target.value + }); + var newPercentComplete = e.target.value; + var newElapsed = getTimeStr(this.props.length * newPercentComplete / 100); + var duration = getTimeStr(this.props.length); + var message = `Seek to: ${newElapsed}/${duration} (${newPercentComplete}%)`; + this.props.dispatch({type: 'SET_MARQUEE_REGISTER', register: 'message', text: message}); + } + + onMouseUp(e) { + this.props.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'songTitle'}); + this.props.dispatch({type: 'SET_POSITION', position: e.target.value}); + this.setState({mouseIsDown: false}); + } + + showMarquee() { + } + + hideMarquee() { + } + + render() { + const position = this.props.length ? + (this.props.timeElapsed / this.props.length) * 100 : + 0; + + // In shade mode, the position slider shows up differently depending on if + // it's near the start, middle or end of its progress + let className = ''; + if (position <= 33) { + className = 'left'; + } else if (position >= 66) { + className = 'right'; + } + + const displayedPosition = this.state.mouseIsDown ? this.state.currentPosition : position; + return ; + } +} + +module.exports = connect(state => state.media)(Position); diff --git a/js/main-window-dom.js b/js/main-window-dom.js index cfb8c7d3..cafad569 100644 --- a/js/main-window-dom.js +++ b/js/main-window-dom.js @@ -58,7 +58,7 @@ module.exports = el('div', {id: 'main-window', class: 'loading stop'}, [ el('div', {id: 'equalizer-button'}), el('div', {id: 'playlist-button'}) ]), - el('input', {id: 'position', type: 'range', min: '0', max: '100', step: '1', value: '0'}), + el('div', {id: 'position-holder'}), el('div', {id: 'actions-holder'}), el('div', {id: 'eject'}), el('div', {class: 'shuffle-repeat'}, [ diff --git a/js/main-window.js b/js/main-window.js index 8da08497..b38a189b 100644 --- a/js/main-window.js +++ b/js/main-window.js @@ -7,6 +7,7 @@ import Kbps from './Kbps.jsx'; import Khz from './Khz.jsx'; import Volume from './Volume.jsx'; import Balance from './Balance.jsx'; +import Position from './Position.jsx'; import '../css/main-window.css'; @@ -17,7 +18,6 @@ module.exports = { close: document.getElementById('close'), shade: document.getElementById('shade'), buttonD: document.getElementById('button-d'), - position: document.getElementById('position'), visualizer: document.getElementById('visualizer'), eject: document.getElementById('eject'), repeat: document.getElementById('repeat'), @@ -40,6 +40,7 @@ module.exports = { this.winamp.renderTo(, document.getElementById('khz-holder')); this.winamp.renderTo(, document.getElementById('volume-holder')); this.winamp.renderTo(, document.getElementById('balance-holder')); + this.winamp.renderTo(, document.getElementById('position-holder')); this._registerListeners(); return this; @@ -73,33 +74,6 @@ module.exports = { self.winamp.toggleDoubledMode(); }; - this.nodes.position.onmousedown = function() { - if (!self.nodes.window.classList.contains('stop')){ - self.winamp.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'position'}); - self.nodes.window.classList.add('setting-position'); - } - }; - - this.nodes.position.onmouseup = function() { - self.winamp.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'songTitle'}); - self.nodes.window.classList.remove('setting-position'); - }; - - this.nodes.position.oninput = function() { - var newPercentComplete = self.nodes.position.value; - var newFractionComplete = newPercentComplete / 100; - var newElapsed = self._timeString(self.winamp.getDuration() * newFractionComplete); - var duration = self._timeString(self.winamp.getDuration()); - var message = 'Seek to: ' + newElapsed + '/' + duration + ' (' + newPercentComplete + '%)'; - self.winamp.dispatch({type: 'SET_MARQUEE_REGISTER', register: 'message', text: message}); - }; - - this.nodes.position.onchange = function() { - if (self.winamp.getState() !== 'stop'){ - self.winamp.seekToPercentComplete(this.value); - } - }; - this.nodes.eject.onclick = function() { self.winamp.dispatch({type: 'OPEN_FILE_DIALOG'}); }; @@ -116,9 +90,6 @@ module.exports = { self.winamp.toggleVisualizer(); }; - window.addEventListener('timeUpdated', function() { - self.updateTime(); - }); window.addEventListener('startWaiting', function() { self.setWorkingIndicator(); }); @@ -167,30 +138,6 @@ module.exports = { this.nodes.window.classList.add('closed'); }, - updatePosition: function() { - if (!this.nodes.window.classList.contains('setting-position')) { - this.nodes.position.value = this.winamp.getPercentComplete(); - } - }, - - // In shade mode, the position slider shows up differently depending on if - // it's near the start, middle or end of its progress - updateShadePositionClass: function() { - var position = this.nodes.position; - - position.removeAttribute('class'); - if (position.value <= 33) { - position.classList.add('left'); - } else if (position.value >= 66) { - position.classList.add('right'); - } - }, - - updateTime: function() { - this.updateShadePositionClass(); - this.updatePosition(); - }, - setWorkingIndicator: function() { this.nodes.workIndicator.classList.add('selected'); }, diff --git a/js/reducers.js b/js/reducers.js index ae9cf952..3781edb2 100644 --- a/js/reducers.js +++ b/js/reducers.js @@ -91,7 +91,7 @@ const media = (state, action) => { return { timeMode: 'ELAPSED', timeElapsed: 0, - length: null, + length: null, // Consider renaming to "duration" kbps: null, khz: null, volume: 50, @@ -146,6 +146,9 @@ const createReducer = (winamp) => { case 'SET_BALANCE': winamp.setBalance(action.balance); return state; + case 'SET_POSITION': + winamp.seekToPercentComplete(action.position); + return state; case 'CLOSE_WINAMP': winamp.close(); return state;