scratch-gui
Version:
GraphicaL User Interface for creating and running Scratch 3.0 projects
270 lines (260 loc) • 9.62 kB
JSX
import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
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 trimConfirmIcon from './icon--trim-confirm.svg';
import redoIcon from './icon--redo.svg';
import undoIcon from './icon--undo.svg';
import echoIcon from './icon--echo.svg';
import fasterIcon from './icon--faster.svg';
import slowerIcon from './icon--slower.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 messages = defineMessages({
sound: {
id: 'gui.soundEditor.sound',
description: 'Label for the name of the sound',
defaultMessage: 'Sound'
},
play: {
id: 'gui.soundEditor.play',
description: 'Title of the button to start playing the sound',
defaultMessage: 'Play'
},
stop: {
id: 'gui.soundEditor.stop',
description: 'Title of the button to stop the sound',
defaultMessage: 'Stop'
},
trim: {
id: 'gui.soundEditor.trim',
description: 'Title of the button to start trimminging the sound',
defaultMessage: 'Trim'
},
save: {
id: 'gui.soundEditor.save',
description: 'Title of the button to save trimmed sound',
defaultMessage: 'Save'
},
undo: {
id: 'gui.soundEditor.undo',
description: 'Title of the button to undo',
defaultMessage: 'Undo'
},
redo: {
id: 'gui.soundEditor.redo',
description: 'Title of the button to redo',
defaultMessage: 'Redo'
},
faster: {
id: 'gui.soundEditor.faster',
description: 'Title of the button to apply the faster effect',
defaultMessage: 'Faster'
},
slower: {
id: 'gui.soundEditor.slower',
description: 'Title of the button to apply the slower effect',
defaultMessage: 'Slower'
},
echo: {
id: 'gui.soundEditor.echo',
description: 'Title of the button to apply the echo effect',
defaultMessage: 'Echo'
},
robot: {
id: 'gui.soundEditor.robot',
description: 'Title of the button to apply the robot effect',
defaultMessage: 'Robot'
},
louder: {
id: 'gui.soundEditor.louder',
description: 'Title of the button to apply the louder effect',
defaultMessage: 'Louder'
},
softer: {
id: 'gui.soundEditor.softer',
description: 'Title of the button to apply thr.softer effect',
defaultMessage: 'Softer'
},
reverse: {
id: 'gui.soundEditor.reverse',
description: 'Title of the button to apply the reverse effect',
defaultMessage: 'Reverse'
}
});
const SoundEditor = props => (
<div className={styles.editorContainer}>
<div className={styles.row}>
<div className={styles.inputGroup}>
<Label text={props.intl.formatMessage(messages.sound)}>
<BufferedInput
tabIndex="1"
type="text"
value={props.name}
onSubmit={props.onChangeName}
/>
</Label>
<div className={styles.buttonGroup}>
<button
className={styles.button}
disabled={!props.canUndo}
title={props.intl.formatMessage(messages.undo)}
onClick={props.onUndo}
>
<img
draggable={false}
src={undoIcon}
/>
</button>
<button
className={styles.button}
disabled={!props.canRedo}
title={props.intl.formatMessage(messages.redo)}
onClick={props.onRedo}
>
<img
draggable={false}
src={redoIcon}
/>
</button>
</div>
</div>
<IconButton
className={classNames(styles.trimButton, {
[styles.trimButtonActive]: props.trimStart !== null
})}
img={props.trimStart === null ? trimIcon : trimConfirmIcon}
title={props.trimStart === null ? (
<FormattedMessage {...messages.trim} />
) : (
<FormattedMessage {...messages.save} />
)}
onClick={props.onActivateTrim}
/>
</div>
<div className={styles.row}>
<div className={styles.waveformContainer}>
<Waveform
data={props.chunkLevels}
height={160}
width={600}
/>
<AudioTrimmer
playhead={props.playhead}
trimEnd={props.trimEnd}
trimStart={props.trimStart}
onSetTrimEnd={props.onSetTrimEnd}
onSetTrimStart={props.onSetTrimStart}
/>
</div>
</div>
<div className={styles.row}>
<div className={styles.inputGroup}>
{props.playhead ? (
<button
className={classNames(styles.roundButton, styles.stopButtonn)}
title={props.intl.formatMessage(messages.stop)}
onClick={props.onStop}
>
<img
draggable={false}
src={stopIcon}
/>
</button>
) : (
<button
className={classNames(styles.roundButton, styles.playButton)}
title={props.intl.formatMessage(messages.play)}
onClick={props.onPlay}
>
<img
draggable={false}
src={playIcon}
/>
</button>
)}
</div>
<IconButton
className={styles.effectButton}
img={fasterIcon}
title={<FormattedMessage {...messages.faster} />}
onClick={props.onFaster}
/>
<IconButton
className={styles.effectButton}
img={slowerIcon}
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>
);
SoundEditor.propTypes = {
canRedo: PropTypes.bool.isRequired,
canUndo: PropTypes.bool.isRequired,
chunkLevels: PropTypes.arrayOf(PropTypes.number).isRequired,
intl: intlShape,
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,
onRedo: 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,
onUndo: PropTypes.func.isRequired,
playhead: PropTypes.number,
trimEnd: PropTypes.number,
trimStart: PropTypes.number
};
export default injectIntl(SoundEditor);