diff --git a/src/components/icon-button/icon-button.css b/src/components/icon-button/icon-button.css index 112fabad23e12136b07450fc56fb394b94d659aa..ebd7fd656b82c23a654db62c000ea9c02cdc4bc0 100644 --- a/src/components/icon-button/icon-button.css +++ b/src/components/icon-button/icon-button.css @@ -8,6 +8,7 @@ transition: 0.2s; font-size: 0.75rem; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + color: $motion-primary; } .container:hover { @@ -20,5 +21,4 @@ .title { margin-top: 0.5rem; - color: $motion-primary; } diff --git a/src/components/sound-editor/icon--echo.svg b/src/components/sound-editor/icon--echo.svg new file mode 100644 index 0000000000000000000000000000000000000000..de8b28a5e53fdb2f6995608509997a518e465514 Binary files /dev/null and b/src/components/sound-editor/icon--echo.svg differ diff --git a/src/components/sound-editor/icon--higher.svg b/src/components/sound-editor/icon--higher.svg new file mode 100644 index 0000000000000000000000000000000000000000..f624f7913b690cae89850600d93803f284ef5d3d Binary files /dev/null and b/src/components/sound-editor/icon--higher.svg differ diff --git a/src/components/sound-editor/icon--louder.svg b/src/components/sound-editor/icon--louder.svg new file mode 100644 index 0000000000000000000000000000000000000000..1d3e2ef6542b3e9fa1845e7cc703fc4fe1eb9a26 Binary files /dev/null and b/src/components/sound-editor/icon--louder.svg differ diff --git a/src/components/sound-editor/icon--lower.svg b/src/components/sound-editor/icon--lower.svg new file mode 100644 index 0000000000000000000000000000000000000000..0f73712d5fda058f1f42a50f7ca73d8ecc34e89e Binary files /dev/null and b/src/components/sound-editor/icon--lower.svg differ diff --git a/src/components/sound-editor/icon--reverse.svg b/src/components/sound-editor/icon--reverse.svg new file mode 100644 index 0000000000000000000000000000000000000000..ae86227182527c8281fddacce6a48b6b949dcb77 Binary files /dev/null and b/src/components/sound-editor/icon--reverse.svg differ diff --git a/src/components/sound-editor/icon--robot.svg b/src/components/sound-editor/icon--robot.svg new file mode 100644 index 0000000000000000000000000000000000000000..3d6c011e8f753dabbe40c68ed2cd5b066061fc41 Binary files /dev/null and b/src/components/sound-editor/icon--robot.svg differ diff --git a/src/components/sound-editor/icon--softer.svg b/src/components/sound-editor/icon--softer.svg new file mode 100644 index 0000000000000000000000000000000000000000..996bed23c91af44ba64f845c6c14e60e2d045f97 Binary files /dev/null and b/src/components/sound-editor/icon--softer.svg differ diff --git a/src/components/sound-editor/sound-editor.css b/src/components/sound-editor/sound-editor.css index 1d67886da3674e57240139e4fdaede6d581ab443..c209d507a64955fd60733301458a008af5609f00 100644 --- a/src/components/sound-editor/sound-editor.css +++ b/src/components/sound-editor/sound-editor.css @@ -69,3 +69,17 @@ display: flex; 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; +} diff --git a/src/components/sound-editor/sound-editor.jsx b/src/components/sound-editor/sound-editor.jsx index 7ac6811abfb4c6219608f84ab541bbc533123278..240e427194aba238e7eddd5f5c254307046ff860 100644 --- a/src/components/sound-editor/sound-editor.jsx +++ b/src/components/sound-editor/sound-editor.jsx @@ -6,14 +6,23 @@ import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-int import Waveform from '../waveform/waveform.jsx'; import Label from '../forms/label.jsx'; import Input from '../forms/input.jsx'; + import BufferedInputHOC from '../forms/buffered-input-hoc.jsx'; import AudioTrimmer from '../../containers/audio-trimmer.jsx'; +import IconButton from '../icon-button/icon-button.jsx'; import styles from './sound-editor.css'; import playIcon from '../record-modal/icon--play.svg'; import stopIcon from '../record-modal/icon--stop-playback.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); @@ -42,6 +51,41 @@ const messages = defineMessages({ id: 'soundEditor.save', description: 'Title of the button to save trimmed sound', 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 => ( /> </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> ); @@ -123,9 +211,16 @@ SoundEditor.propTypes = { name: PropTypes.string.isRequired, onActivateTrim: PropTypes.func, onChangeName: PropTypes.func.isRequired, + onEcho: PropTypes.func.isRequired, + onFaster: PropTypes.func.isRequired, + onLouder: PropTypes.func.isRequired, onPlay: PropTypes.func.isRequired, + onReverse: PropTypes.func.isRequired, + onRobot: PropTypes.func.isRequired, onSetTrimEnd: PropTypes.func, onSetTrimStart: PropTypes.func, + onSlower: PropTypes.func.isRequired, + onSofter: PropTypes.func.isRequired, onStop: PropTypes.func.isRequired, playhead: PropTypes.number, trimEnd: PropTypes.number, diff --git a/src/containers/sound-editor.jsx b/src/containers/sound-editor.jsx index d18678273bf183ab1eea7298a3a82b9c41938e63..6f3bb484135379d973d7ad3f1ec38a124d3fa4da 100644 --- a/src/containers/sound-editor.jsx +++ b/src/containers/sound-editor.jsx @@ -20,7 +20,8 @@ class SoundEditor extends React.Component { 'handleUpdatePlayhead', 'handleActivateTrim', 'handleUpdateTrimEnd', - 'handleUpdateTrimStart' + 'handleUpdateTrimStart', + 'handleEffect' ]); this.state = { chunkLevels: computeChunkedRMS(this.props.samples), @@ -94,6 +95,12 @@ class SoundEditor extends React.Component { handleUpdateTrimStart (trimStart) { this.setState({trimStart}); } + effectFactory (name) { + return () => this.handleEffect(name); + } + handleEffect (/* name */) { + // @todo implement effects + } render () { return ( <SoundEditorComponent @@ -104,9 +111,16 @@ class SoundEditor extends React.Component { trimStart={this.state.trimStart} onActivateTrim={this.handleActivateTrim} onChangeName={this.handleChangeName} + onEcho={this.effectFactory('echo')} + onFaster={this.effectFactory('faster')} + onLouder={this.effectFactory('louder')} onPlay={this.handlePlay} + onReverse={this.effectFactory('reverse')} + onRobot={this.effectFactory('robot')} onSetTrimEnd={this.handleUpdateTrimEnd} onSetTrimStart={this.handleUpdateTrimStart} + onSlower={this.effectFactory('slower')} + onSofter={this.effectFactory('softer')} onStop={this.handleStopPlaying} /> ); diff --git a/test/unit/components/__snapshots__/sound-editor.test.jsx.snap b/test/unit/components/__snapshots__/sound-editor.test.jsx.snap index c757bc5d5679537c6125e4e7ed3b5a97be4d88ae..076dd860b6b9a08d9b5536f93739a274947526a2 100644 --- a/test/unit/components/__snapshots__/sound-editor.test.jsx.snap +++ b/test/unit/components/__snapshots__/sound-editor.test.jsx.snap @@ -309,5 +309,121 @@ exports[`Sound Editor Component matches snapshot 1`] = ` </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> `; diff --git a/test/unit/components/sound-editor.test.jsx b/test/unit/components/sound-editor.test.jsx index 9c98edda9ba2632ad95e1760bc4fdafd12ed1289..b3b744235e827ff35654dbe4150b6647e4888189 100644 --- a/test/unit/components/sound-editor.test.jsx +++ b/test/unit/components/sound-editor.test.jsx @@ -15,6 +15,13 @@ describe('Sound Editor Component', () => { onActivateTrim: jest.fn(), onChangeName: 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(), onSetTrimStart: jest.fn(), onStop: jest.fn() @@ -57,4 +64,28 @@ describe('Sound Editor Component', () => { .simulate('blur'); 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(); + }); }); diff --git a/test/unit/containers/sound-editor.test.jsx b/test/unit/containers/sound-editor.test.jsx index 39f1e19b07b2f3a9a24aee00136fdb7a2eefa0c3..0f22da439b2db50992785157a4551be45f658fa6 100644 --- a/test/unit/containers/sound-editor.test.jsx +++ b/test/unit/containers/sound-editor.test.jsx @@ -3,7 +3,7 @@ import React from 'react'; // eslint-disable-line no-unused-vars import {mountWithIntl} from '../../helpers/intl-helpers'; import configureStore from 'redux-mock-store'; 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 // eslint-disable-next-line no-unused-vars import SoundEditorComponent from '../../../src/components/sound-editor/sound-editor';