Skip to content

Commit 7e9fce5

Browse files
committed
Adding in a volume control
1 parent 2d0870f commit 7e9fce5

File tree

9 files changed

+134
-4
lines changed

9 files changed

+134
-4
lines changed

app/actions/setVolume.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use strict';
2+
3+
export const SET_VOLUME = 'SET_VOLUME';
4+
5+
export function setVolume(value) {
6+
return {
7+
type: SET_VOLUME,
8+
volume: value
9+
};
10+
}

app/components/Volume.jsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
import React, { Component } from 'react';
4+
5+
class Volume extends Component {
6+
constructor(props) {
7+
super(props);
8+
}
9+
10+
render() {
11+
return (
12+
<input type="range" value={this.props.value} min={this.props.min} max={this.props.max} step={this.props.step} onChange={this.props.onChange} />
13+
);
14+
}
15+
}
16+
17+
Volume.defaultProps = {
18+
min: 0,
19+
max: 11,
20+
step: 1
21+
};
22+
23+
Volume.propTypes = {
24+
onChange: React.PropTypes.func.isRequired,
25+
value: React.PropTypes.number,
26+
min: React.PropTypes.number,
27+
max: React.PropTypes.number,
28+
step: React.PropTypes.number
29+
};
30+
31+
export default Volume;

app/containers/PlaybackControls.jsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import { connect } from 'react-redux';
77

88
import { isPlaying } from '../actions/isPlaying';
99
import { hasStopped } from '../actions/hasStopped';
10+
import { setVolume } from '../actions/setVolume';
1011

1112
import Button from '../components/Button.jsx';
13+
import Volume from '../components/Volume.jsx';
1214

1315
export class PlaybackControls extends Component {
1416
_onPlayButtonClick() {
@@ -19,13 +21,19 @@ export class PlaybackControls extends Component {
1921
this.props.hasStoppedAction(true);
2022
}
2123

24+
_onVolumeChange(event) {
25+
const volumeValue = event.target.value;
26+
this.props.setVolumeAction(volumeValue);
27+
}
28+
2229
render() {
2330
const text = this.props.isPlaying ? 'pause' : 'play';
2431

2532
return (
2633
<div>
2734
<Button onClick={this._onPlayButtonClick.bind(this)} text={text} />
2835
<Button onClick={this._onStopButtonClick.bind(this)} text="stop" />
36+
<Volume onChange={this._onVolumeChange.bind(this)} />
2937
</div>
3038
);
3139
}
@@ -34,7 +42,8 @@ export class PlaybackControls extends Component {
3442
PlaybackControls.propTypes = {
3543
isPlaying: React.PropTypes.bool,
3644
isPlayingAction: React.PropTypes.func,
37-
hasStoppedAction: React.PropTypes.func
45+
hasStoppedAction: React.PropTypes.func,
46+
setVolumeAction: React.PropTypes.func
3847
};
3948

4049
function mapStateToProps(state) {
@@ -46,7 +55,8 @@ function mapStateToProps(state) {
4655
function mapDispatchToProps(dispatch) {
4756
return {
4857
isPlayingAction: bindActionCreators(isPlaying, dispatch),
49-
hasStoppedAction: bindActionCreators(hasStopped, dispatch)
58+
hasStoppedAction: bindActionCreators(hasStopped, dispatch),
59+
setVolumeAction: bindActionCreators(setVolume, dispatch)
5060
};
5161
}
5262

app/reducers/playback.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import { IS_PLAYING } from '../actions/isPlaying';
44
import { HAS_STOPPED } from '../actions/hasStopped';
5+
import { SET_VOLUME } from '../actions/setVolume';
56

67
const initialState = {
78
isPlaying: false,
8-
hasStopped: true
9+
hasStopped: true,
10+
volume: 7
911
};
1012

1113
function setIsPlayingState(isPlaying) {
@@ -32,12 +34,20 @@ function setHasStoppedState(hasStopped) {
3234
});
3335
}
3436

37+
function setVolumeState(volume) {
38+
return {
39+
volume: volume
40+
};
41+
}
42+
3543
export function playbackReducer(state = initialState, action) {
3644
switch (action.type) {
3745
case IS_PLAYING :
3846
return Object.assign({}, state, setIsPlayingState(action.isPlaying));
3947
case HAS_STOPPED :
4048
return Object.assign({}, state, setHasStoppedState(action.hasStopped));
49+
case SET_VOLUME :
50+
return Object.assign({}, state, setVolumeState(action.volume));
4151
default:
4252
return state;
4353
}

app/store/configurePlayerStore.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import { createStore, combineReducers } from 'redux';
44
import { playbackReducer } from '../reducers/playback';
55

66
export default function configureStore() {
7-
return createStore(
7+
const store = createStore(
88
combineReducers({
99
playback: playbackReducer
1010
})
1111
);
12+
13+
return store;
1214
}

test/actions/setVolume.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict';
2+
3+
import assert from 'assert';
4+
import { SET_VOLUME, setVolume } from '../../app/actions/setVolume';
5+
6+
describe('setVolume', () => {
7+
it('returns an object with the volume: {NUMBER}', () => {
8+
const action = setVolume(1);
9+
10+
assert.equal(action.type, SET_VOLUME);
11+
assert.equal(action.volume, 1);
12+
});
13+
});

test/components/Volume.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
import React from 'react';
4+
import assert from 'assert';
5+
import { shallow } from 'enzyme';
6+
import sinon from 'sinon';
7+
8+
import Volume from '../../app/components/Volume.jsx';
9+
10+
describe('<Volume />', () => {
11+
it('renders the volume control with the correct value', () => {
12+
const value = 5;
13+
const wrapper = shallow(
14+
<Volume value={value} onChange={() => {}} />
15+
);
16+
17+
assert.equal(wrapper.props().value, 5);
18+
});
19+
20+
it('calls the onChange function', () => {
21+
const onChangeSpy = sinon.spy();
22+
const wrapper = shallow(
23+
<Volume onChange={onChangeSpy} />
24+
);
25+
wrapper.find('input').simulate('change');
26+
assert.equal(onChangeSpy.calledOnce, true);
27+
});
28+
});

test/containers/PlaybackControls.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,14 @@ describe('<PlaybackControls />', () => {
5050
assert(hasStoppedActionSpy.calledWith(true));
5151
});
5252
});
53+
54+
describe.only('<Volume />', () => {
55+
it('calls the setVolumeAction', () => {
56+
const setVolumeActionSpy = sinon.spy();
57+
const wrapper = shallow(<PlaybackControls setVolumeAction={setVolumeActionSpy} />);
58+
59+
wrapper.find('Volume').simulate('change');
60+
assert(setVolumeActionSpy.calledOnce);
61+
});
62+
});
5363
});

test/reducers/playback.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import assert from 'assert';
44
import { IS_PLAYING } from '../../app/actions/isPlaying';
55
import { HAS_STOPPED } from '../../app/actions/hasStopped';
6+
import { SET_VOLUME } from '../../app/actions/setVolume';
67
import { playbackReducer } from '../../app/reducers/playback';
78

89
describe('playbackState', () => {
@@ -55,4 +56,19 @@ describe('playbackState', () => {
5556
assert.strictEqual(state.hasStopped, false);
5657
});
5758
});
59+
60+
describe('volume property', () => {
61+
it('defaults to 7', () => {
62+
assert.strictEqual(playbackReducer(undefined, '').volume, 7);
63+
});
64+
65+
it('{volume: 1} when action.volume is 1', () => {
66+
const state = playbackReducer(undefined, {
67+
type: SET_VOLUME,
68+
volume: 1
69+
});
70+
71+
assert.strictEqual(state.volume, 1);
72+
});
73+
});
5874
});

0 commit comments

Comments
 (0)