Skip to content
Snippets Groups Projects
Commit 5d8da505 authored by Paul Kaplan's avatar Paul Kaplan
Browse files

Add effect buttons and tests for the component

parent a06a839e
No related branches found
No related tags found
No related merge requests found
Showing
with 273 additions and 3 deletions
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
transition: 0.2s; transition: 0.2s;
font-size: 0.75rem; font-size: 0.75rem;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: $motion-primary;
} }
.container:hover { .container:hover {
...@@ -20,5 +21,4 @@ ...@@ -20,5 +21,4 @@
.title { .title {
margin-top: 0.5rem; margin-top: 0.5rem;
color: $motion-primary;
} }
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
...@@ -69,3 +69,17 @@ ...@@ -69,3 +69,17 @@
display: flex; display: flex;
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.effect-button {
flex-basis: 150px;
color: #575e75; /* @todo discuss the multiple font colors with Carl, move to variable */
}
.effect-button + .effect-button {
margin: 0;
}
.effect-button img {
width: 60px;
height: 60px;
}
...@@ -6,14 +6,23 @@ import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-int ...@@ -6,14 +6,23 @@ import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-int
import Waveform from '../waveform/waveform.jsx'; import Waveform from '../waveform/waveform.jsx';
import Label from '../forms/label.jsx'; import Label from '../forms/label.jsx';
import Input from '../forms/input.jsx'; import Input from '../forms/input.jsx';
import BufferedInputHOC from '../forms/buffered-input-hoc.jsx'; import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
import AudioTrimmer from '../../containers/audio-trimmer.jsx'; import AudioTrimmer from '../../containers/audio-trimmer.jsx';
import IconButton from '../icon-button/icon-button.jsx';
import styles from './sound-editor.css'; import styles from './sound-editor.css';
import playIcon from '../record-modal/icon--play.svg'; import playIcon from '../record-modal/icon--play.svg';
import stopIcon from '../record-modal/icon--stop-playback.svg'; import stopIcon from '../record-modal/icon--stop-playback.svg';
import trimIcon from './icon--trim.svg'; import trimIcon from './icon--trim.svg';
import echoIcon from './icon--echo.svg';
import higherIcon from './icon--higher.svg';
import lowerIcon from './icon--lower.svg';
import louderIcon from './icon--louder.svg';
import softerIcon from './icon--softer.svg';
import robotIcon from './icon--robot.svg';
import reverseIcon from './icon--reverse.svg';
const BufferedInput = BufferedInputHOC(Input); const BufferedInput = BufferedInputHOC(Input);
...@@ -42,6 +51,41 @@ const messages = defineMessages({ ...@@ -42,6 +51,41 @@ const messages = defineMessages({
id: 'soundEditor.save', id: 'soundEditor.save',
description: 'Title of the button to save trimmed sound', description: 'Title of the button to save trimmed sound',
defaultMessage: 'Save' defaultMessage: 'Save'
},
faster: {
id: 'soundEditor.faster',
description: 'Title of the button to apply the faster effect',
defaultMessage: 'Faster'
},
slower: {
id: 'soundEditor.slower',
description: 'Title of the button to apply the slower effect',
defaultMessage: 'Slower'
},
echo: {
id: 'soundEditor.echo',
description: 'Title of the button to apply the echo effect',
defaultMessage: 'Echo'
},
robot: {
id: 'soundEditor.robot',
description: 'Title of the button to apply the robot effect',
defaultMessage: 'Robot'
},
louder: {
id: 'soundEditor.louder',
description: 'Title of the button to apply the louder effect',
defaultMessage: 'Louder'
},
softer: {
id: 'soundEditor.softer',
description: 'Title of the button to apply thr.softer effect',
defaultMessage: 'Softer'
},
reverse: {
id: 'soundEditor.reverse',
description: 'Title of the button to apply the reverse effect',
defaultMessage: 'Reverse'
} }
}); });
...@@ -114,6 +158,50 @@ const SoundEditor = props => ( ...@@ -114,6 +158,50 @@ const SoundEditor = props => (
/> />
</div> </div>
</div> </div>
<div className={styles.row}>
<IconButton
className={styles.effectButton}
img={higherIcon}
title={<FormattedMessage {...messages.faster} />}
onClick={props.onFaster}
/>
<IconButton
className={styles.effectButton}
img={lowerIcon}
title={<FormattedMessage {...messages.slower} />}
onClick={props.onSlower}
/>
<IconButton
className={styles.effectButton}
img={echoIcon}
title={<FormattedMessage {...messages.echo} />}
onClick={props.onEcho}
/>
<IconButton
className={styles.effectButton}
img={robotIcon}
title={<FormattedMessage {...messages.robot} />}
onClick={props.onRobot}
/>
<IconButton
className={styles.effectButton}
img={louderIcon}
title={<FormattedMessage {...messages.louder} />}
onClick={props.onLouder}
/>
<IconButton
className={styles.effectButton}
img={softerIcon}
title={<FormattedMessage {...messages.softer} />}
onClick={props.onSofter}
/>
<IconButton
className={styles.effectButton}
img={reverseIcon}
title={<FormattedMessage {...messages.reverse} />}
onClick={props.onReverse}
/>
</div>
</div> </div>
); );
...@@ -123,9 +211,16 @@ SoundEditor.propTypes = { ...@@ -123,9 +211,16 @@ SoundEditor.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
onActivateTrim: PropTypes.func, onActivateTrim: PropTypes.func,
onChangeName: PropTypes.func.isRequired, onChangeName: PropTypes.func.isRequired,
onEcho: PropTypes.func.isRequired,
onFaster: PropTypes.func.isRequired,
onLouder: PropTypes.func.isRequired,
onPlay: PropTypes.func.isRequired, onPlay: PropTypes.func.isRequired,
onReverse: PropTypes.func.isRequired,
onRobot: PropTypes.func.isRequired,
onSetTrimEnd: PropTypes.func, onSetTrimEnd: PropTypes.func,
onSetTrimStart: PropTypes.func, onSetTrimStart: PropTypes.func,
onSlower: PropTypes.func.isRequired,
onSofter: PropTypes.func.isRequired,
onStop: PropTypes.func.isRequired, onStop: PropTypes.func.isRequired,
playhead: PropTypes.number, playhead: PropTypes.number,
trimEnd: PropTypes.number, trimEnd: PropTypes.number,
......
...@@ -20,7 +20,8 @@ class SoundEditor extends React.Component { ...@@ -20,7 +20,8 @@ class SoundEditor extends React.Component {
'handleUpdatePlayhead', 'handleUpdatePlayhead',
'handleActivateTrim', 'handleActivateTrim',
'handleUpdateTrimEnd', 'handleUpdateTrimEnd',
'handleUpdateTrimStart' 'handleUpdateTrimStart',
'handleEffect'
]); ]);
this.state = { this.state = {
chunkLevels: computeChunkedRMS(this.props.samples), chunkLevels: computeChunkedRMS(this.props.samples),
...@@ -94,6 +95,12 @@ class SoundEditor extends React.Component { ...@@ -94,6 +95,12 @@ class SoundEditor extends React.Component {
handleUpdateTrimStart (trimStart) { handleUpdateTrimStart (trimStart) {
this.setState({trimStart}); this.setState({trimStart});
} }
effectFactory (name) {
return () => this.handleEffect(name);
}
handleEffect (/* name */) {
// @todo implement effects
}
render () { render () {
return ( return (
<SoundEditorComponent <SoundEditorComponent
...@@ -104,9 +111,16 @@ class SoundEditor extends React.Component { ...@@ -104,9 +111,16 @@ class SoundEditor extends React.Component {
trimStart={this.state.trimStart} trimStart={this.state.trimStart}
onActivateTrim={this.handleActivateTrim} onActivateTrim={this.handleActivateTrim}
onChangeName={this.handleChangeName} onChangeName={this.handleChangeName}
onEcho={this.effectFactory('echo')}
onFaster={this.effectFactory('faster')}
onLouder={this.effectFactory('louder')}
onPlay={this.handlePlay} onPlay={this.handlePlay}
onReverse={this.effectFactory('reverse')}
onRobot={this.effectFactory('robot')}
onSetTrimEnd={this.handleUpdateTrimEnd} onSetTrimEnd={this.handleUpdateTrimEnd}
onSetTrimStart={this.handleUpdateTrimStart} onSetTrimStart={this.handleUpdateTrimStart}
onSlower={this.effectFactory('slower')}
onSofter={this.effectFactory('softer')}
onStop={this.handleStopPlaying} onStop={this.handleStopPlaying}
/> />
); );
......
...@@ -309,5 +309,121 @@ exports[`Sound Editor Component matches snapshot 1`] = ` ...@@ -309,5 +309,121 @@ exports[`Sound Editor Component matches snapshot 1`] = `
</div> </div>
</div> </div>
</div> </div>
<div
className={undefined}
>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Faster
</span>
</div>
</div>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Slower
</span>
</div>
</div>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Echo
</span>
</div>
</div>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Robot
</span>
</div>
</div>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Louder
</span>
</div>
</div>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Softer
</span>
</div>
</div>
<div
className=""
onClick={[Function]}
>
<img
className={undefined}
src="test-file-stub"
/>
<div
className={undefined}
>
<span>
Reverse
</span>
</div>
</div>
</div>
</div> </div>
`; `;
...@@ -15,6 +15,13 @@ describe('Sound Editor Component', () => { ...@@ -15,6 +15,13 @@ describe('Sound Editor Component', () => {
onActivateTrim: jest.fn(), onActivateTrim: jest.fn(),
onChangeName: jest.fn(), onChangeName: jest.fn(),
onPlay: jest.fn(), onPlay: jest.fn(),
onReverse: jest.fn(),
onSofter: jest.fn(),
onLouder: jest.fn(),
onRobot: jest.fn(),
onEcho: jest.fn(),
onFaster: jest.fn(),
onSlower: jest.fn(),
onSetTrimEnd: jest.fn(), onSetTrimEnd: jest.fn(),
onSetTrimStart: jest.fn(), onSetTrimStart: jest.fn(),
onStop: jest.fn() onStop: jest.fn()
...@@ -57,4 +64,28 @@ describe('Sound Editor Component', () => { ...@@ -57,4 +64,28 @@ describe('Sound Editor Component', () => {
.simulate('blur'); .simulate('blur');
expect(props.onChangeName).toHaveBeenCalled(); expect(props.onChangeName).toHaveBeenCalled();
}); });
test('effect buttons call the correct callbacks', () => {
const wrapper = mountWithIntl(<SoundEditor {...props} />);
wrapper.find('[children="Reverse"]').simulate('click');
expect(props.onReverse).toHaveBeenCalled();
wrapper.find('[children="Echo"]').simulate('click');
expect(props.onEcho).toHaveBeenCalled();
wrapper.find('[children="Robot"]').simulate('click');
expect(props.onRobot).toHaveBeenCalled();
wrapper.find('[children="Faster"]').simulate('click');
expect(props.onFaster).toHaveBeenCalled();
wrapper.find('[children="Slower"]').simulate('click');
expect(props.onSlower).toHaveBeenCalled();
wrapper.find('[children="Louder"]').simulate('click');
expect(props.onLouder).toHaveBeenCalled();
wrapper.find('[children="Softer"]').simulate('click');
expect(props.onSofter).toHaveBeenCalled();
});
}); });
...@@ -3,7 +3,7 @@ import React from 'react'; // eslint-disable-line no-unused-vars ...@@ -3,7 +3,7 @@ import React from 'react'; // eslint-disable-line no-unused-vars
import {mountWithIntl} from '../../helpers/intl-helpers'; import {mountWithIntl} from '../../helpers/intl-helpers';
import configureStore from 'redux-mock-store'; import configureStore from 'redux-mock-store';
import mockAudioBufferPlayer from '../../__mocks__/audio-buffer-player.js'; import mockAudioBufferPlayer from '../../__mocks__/audio-buffer-player.js';
import {IntlProvider as Intl} from 'react-intl'; // eslint-disable-line no-unused-vars
import SoundEditor from '../../../src/containers/sound-editor'; // eslint-disable-line no-unused-vars import SoundEditor from '../../../src/containers/sound-editor'; // eslint-disable-line no-unused-vars
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
import SoundEditorComponent from '../../../src/components/sound-editor/sound-editor'; import SoundEditorComponent from '../../../src/components/sound-editor/sound-editor';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment