diff --git a/js/Volume.jsx b/js/Volume.jsx new file mode 100644 index 00000000..15c7144f --- /dev/null +++ b/js/Volume.jsx @@ -0,0 +1,51 @@ +// Single line text display that can animate and hold multiple registers +import React from 'react'; +import {connect} from 'react-redux'; + + +class Volume extends React.Component { + constructor(props) { + super(props); + this.setVolume = this.setVolume.bind(this); + this.showMarquee = this.showMarquee.bind(this); + this.hideMarquee = this.hideMarquee.bind(this); + } + + setVolume(e) { + this.props.dispatch({type: 'SET_VOLUME', volume: e.target.value}); + } + + showMarquee() { + this.props.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'volume'}); + } + + hideMarquee() { + this.props.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'songTitle'}); + } + + render() { + const volume = this.props.volume; + const percent = volume / 100; + const sprite = Math.round(percent * 28); + const offset = (sprite - 1) * 15; + + const style = { + backgroundPosition: '0 -' + offset + 'px' + }; + + return ; + } +} + +module.exports = connect(state => state.media)(Volume); diff --git a/js/hotkeys.js b/js/hotkeys.js index a35077a8..a60bc29b 100644 --- a/js/hotkeys.js +++ b/js/hotkeys.js @@ -1,4 +1,4 @@ -module.exports = function(winamp) { +module.exports = function(winamp, store) { var keylog = []; var trigger = [78, 85, 76, 27, 76, 27, 83, 79, 70, 84]; document.addEventListener('keydown', function(e){ @@ -8,25 +8,33 @@ module.exports = function(winamp) { // XXX FIXME case 76: winamp.openOptionMenu(); break; // CTRL+L // CTRL+T - case 84: winamp.dispath({type: 'TOGGLE_TIME_MODE'}); break; + case 84: store.dispath({type: 'TOGGLE_TIME_MODE'}); break; } } else { switch (e.keyCode) { case 37: winamp.seekForwardBy(-5); break; // left arrow - case 38: winamp.incrementVolumeBy(1); break; // up arrow + // up arrow + case 38: + const incrementedVolume = Math.min(100, store.getState().media.volume + 1); + store.dispatch({type: 'SET_VOLUME', volume: incrementedVolume}); + break; case 39: winamp.seekForwardBy(5); break; // right arrow - case 40: winamp.incrementVolumeBy(-1); break; // down arrow + // down arrow + case 40: + const decrementedVolume = Math.max(0, store.getState().media.volume - 1); + store.dispatch({type: 'SET_VOLUME', volume: decrementedVolume}); + break; case 66: winamp.next(); break; // B case 67: winamp.pause(); break; // C // L - case 76: winamp.dispatch({type: 'OPEN_FILE_DIALOG'}); break; + case 76: store.dispatch({type: 'OPEN_FILE_DIALOG'}); break; case 82: winamp.toggleRepeat(); break; // R case 83: winamp.toggleShuffle(); break; // S case 86: winamp.stop(); break; // V case 88: winamp.play(); break; // X case 90: winamp.previous(); break; // Z // numpad 0 - case 96: winamp.dispatch({type: 'OPEN_FILE_DIALOG'}); break; + case 96: store.dispatch({type: 'OPEN_FILE_DIALOG'}); break; case 97: winamp.previous(10); break; // numpad 1 case 98: winamp.incrementVolumeBy(-1); break; // numpad 2 case 99: winamp.next(10); break; // numpad 3 diff --git a/js/main-window-dom.js b/js/main-window-dom.js index fddbe670..436bca36 100644 --- a/js/main-window-dom.js +++ b/js/main-window-dom.js @@ -52,7 +52,7 @@ module.exports = el('div', {id: 'main-window', class: 'loading stop'}, [ el('div', {id: 'stereo'}) ]) ]), - el('input', {id: 'volume', type: 'range', min: '0', max: '100', step: '1', value: '50'}), + el('div', {id: 'volume-holder'}), el('input', {id: 'balance', type: 'range', min: '-100', max: '100', step: '2', value: '0'}), el('div', {class: 'windows'}, [ el('div', {id: 'equalizer-button'}), diff --git a/js/main-window.js b/js/main-window.js index 62b19df0..304f24cf 100644 --- a/js/main-window.js +++ b/js/main-window.js @@ -5,6 +5,7 @@ import Time from './Time.jsx'; import ShadeTime from './ShadeTime.jsx'; import Kbps from './Kbps.jsx'; import Khz from './Khz.jsx'; +import Volume from './Volume.jsx'; import '../css/main-window.css'; @@ -20,7 +21,6 @@ module.exports = { eject: document.getElementById('eject'), repeat: document.getElementById('repeat'), shuffle: document.getElementById('shuffle'), - volume: document.getElementById('volume'), mono: document.getElementById('mono'), stereo: document.getElementById('stereo'), balance: document.getElementById('balance'), @@ -38,6 +38,7 @@ module.exports = { this.winamp.renderTo(, document.getElementById('shade-time-holder')); this.winamp.renderTo(, document.getElementById('kbps-holder')); this.winamp.renderTo(, document.getElementById('khz-holder')); + this.winamp.renderTo(, document.getElementById('volume-holder')); this._registerListeners(); return this; @@ -110,18 +111,6 @@ module.exports = { self.winamp.toggleShuffle(); }; - this.nodes.volume.onmousedown = function() { - self.winamp.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'volume'}); - }; - - this.nodes.volume.onmouseup = function() { - self.winamp.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'songTitle'}); - }; - - this.nodes.volume.oninput = function() { - self.winamp.setVolume(this.value); - }; - this.nodes.balance.onmousedown = function() { self.winamp.dispatch({type: 'SHOW_MARQUEE_REGISTER', register: 'balance'}); }; @@ -165,9 +154,6 @@ module.exports = { window.addEventListener('channelCountUpdated', function() { self.updateChannelCount(); }); - window.addEventListener('volumeChanged', function() { - self.updateVolume(); - }); window.addEventListener('balanceChanged', function() { self.setBalance(); }); @@ -238,21 +224,6 @@ module.exports = { this.nodes.window.classList.remove('loading'); }, - updateVolume: function() { - var volume = this.winamp.getVolume(); - var percent = volume / 100; - var sprite = Math.round(percent * 28); - var offset = (sprite - 1) * 15; - this.nodes.volume.style.backgroundPosition = '0 -' + offset + 'px'; - - var message = 'Volume: ' + volume + '%'; - this.winamp.dispatch({type: 'SET_MARQUEE_REGISTER', register: 'volume', text: message}); - - // This shouldn't trigger an infinite loop with volume.onchange(), - // since the value will be the same - this.nodes.volume.value = volume; - }, - setBalance: function() { var balance = this.winamp.getBalance(); var string = ''; diff --git a/js/main.js b/js/main.js index e61f77a7..beb04016 100644 --- a/js/main.js +++ b/js/main.js @@ -41,9 +41,7 @@ if (new Browser(window).isCompatible) { skinUrl: 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz' }); - - - new Hotkeys(winamp); + new Hotkeys(winamp, store); winamp.renderTo(, document.getElementById('context-menu-holder')); } else { document.getElementById('winamp').style.display = 'none'; diff --git a/js/media.js b/js/media.js index 04e27dfc..9c17e33e 100644 --- a/js/media.js +++ b/js/media.js @@ -174,11 +174,11 @@ module.exports = { // From 0-1 setVolume: function(volume) { - this._gainNode.gain.value = volume; + this._gainNode.gain.value = volume / 100; }, getVolume: function() { - return this._gainNode.gain.value; + return this._gainNode.gain.value * 100; }, // From -100 to 100 diff --git a/js/reducers.js b/js/reducers.js index 08c45fa6..3e237655 100644 --- a/js/reducers.js +++ b/js/reducers.js @@ -15,6 +15,12 @@ const register = (state, action) => { return Object.assign({}, state, {step: 0, text: action.text}); } return state; + case 'SET_VOLUME': + if (state.id === 'volume') { + const text = 'Volume: ' + action.volume + '%'; + return Object.assign({}, state, {step: 0, text: text}); + } + return state; case 'STEP_MARQUEE': return Object.assign({}, state, {step: (state.step + 1) % state.text.length}); default: @@ -75,7 +81,8 @@ const media = (state, action) => { timeElapsed: 0, length: null, kbps: null, - khz: null + khz: null, + volume: 50 }; } switch (action.type) { @@ -90,6 +97,8 @@ const media = (state, action) => { return Object.assign({}, state, {kbps: action.kbps}); case 'SET_MEDIA_KHZ': return Object.assign({}, state, {khz: action.khz}); + case 'SET_VOLUME': + return Object.assign({}, state, {volume: action.volume}); default: return state; } @@ -116,6 +125,9 @@ const createReducer = (winamp) => { case 'STOP': winamp.stop(); return state; + case 'SET_VOLUME': + winamp.setVolume(action.volume); + return state; case 'CLOSE_WINAMP': winamp.close(); return state; diff --git a/js/winamp.js b/js/winamp.js index f3e7d3ff..a59bfa28 100755 --- a/js/winamp.js +++ b/js/winamp.js @@ -29,7 +29,6 @@ module.exports = { changeState: new Event('changeState'), titleUpdated: new Event('titleUpdated'), channelCountUpdated: new Event('channelCountUpdated'), - volumeChanged: new Event('volumeChanged'), balanceChanged: new Event('balanceChanged'), doubledModeToggled: new Event('doubledModeToggled'), repeatToggled: new Event('repeatToggled'), @@ -37,7 +36,7 @@ module.exports = { close: new Event('close') }; - this.setVolume(options.volume); + this.dispatch({type: 'SET_VOLUME', volume: options.volume}); this.setBalance(options.balance); this.loadFromUrl(options.mediaFile.url, options.mediaFile.name); var skinFile = new MyFile(); @@ -116,7 +115,7 @@ module.exports = { }, getVolume: function() { - return Math.round(this.media.getVolume() * 100); + return Math.round(this.media.getVolume()); }, seekToPercentComplete: function(percent) { @@ -150,14 +149,11 @@ module.exports = { volume = Math.max(volume, 0); volume = Math.min(volume, 100); - var percent = volume / 100; - - this.media.setVolume(percent); - window.dispatchEvent(this.events.volumeChanged); + this.media.setVolume(volume); }, incrementVolumeBy: function(ammount) { - this.setVolume((this.media.getVolume() * 100) + ammount); + this.setVolume((this.media.getVolume()) + ammount); }, toggleDoubledMode: function() {