From bbf0ba4e25aedb5fd7afc5f8463c34492a236de3 Mon Sep 17 00:00:00 2001 From: Paul Kaplan <pkaplan@media.mit.edu> Date: Tue, 19 Jun 2018 09:30:05 -0400 Subject: [PATCH] Add drag payload for backpack contents and drop handlers for editor tabs --- src/components/backpack/backpack.jsx | 10 ++++++++++ src/containers/backpack.jsx | 9 +++++++++ src/containers/costume-tab.jsx | 19 +++++++++++++++++-- src/containers/sound-tab.jsx | 19 +++++++++++++++++-- src/containers/sprite-selector-item.jsx | 8 +++++++- src/lib/drag-constants.js | 7 ++++++- 6 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/components/backpack/backpack.jsx b/src/components/backpack/backpack.jsx index 3711cafd4..563ec84a3 100644 --- a/src/components/backpack/backpack.jsx +++ b/src/components/backpack/backpack.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {FormattedMessage} from 'react-intl'; +import DragConstants from '../../lib/drag-constants'; import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx'; import SpriteSelectorItem from '../../containers/sprite-selector-item.jsx'; import styles from './backpack.css'; @@ -8,6 +9,13 @@ import styles from './backpack.css'; // TODO make sprite selector item not require onClick const noop = () => {}; +const dragTypeMap = { + costume: DragConstants.BACKPACK_COSTUME, + sound: DragConstants.BACKPACK_SOUND, + code: DragConstants.BACKPACK_CODE, + sprite: DragConstants.BACKPACK_SPRITE +}; + const Backpack = ({contents, error, expanded, loading, onToggle}) => ( <div className={styles.backpackContainer}> <div @@ -60,6 +68,8 @@ const Backpack = ({contents, error, expanded, loading, onToggle}) => ( className={styles.backpackItem} costumeURL={item.thumbnailUrl} details={item.name} + dragPayload={item} + dragType={dragTypeMap[item.type]} key={item.id} name={item.type} selected={false} diff --git a/src/containers/backpack.jsx b/src/containers/backpack.jsx index 878a6cd5f..a489279b2 100644 --- a/src/containers/backpack.jsx +++ b/src/containers/backpack.jsx @@ -4,6 +4,7 @@ import bindAll from 'lodash.bindall'; import BackpackComponent from '../components/backpack/backpack.jsx'; import {getBackpackContents} from '../lib/backpack-api'; import {connect} from 'react-redux'; +import storage from '../lib/storage'; class Backpack extends React.Component { constructor (props) { @@ -20,6 +21,14 @@ class Backpack extends React.Component { expanded: false, contents: [] }; + + // If a host is given, add it as a web source to the storage module + if (props.host) { + storage.addWebSource( + [storage.AssetType.ImageVector, storage.AssetType.ImageBitmap, storage.AssetType.Sound], + asset => `${props.host}/${asset.assetId}.${asset.dataFormat}` + ); + } } handleToggle () { const newState = !this.state.expanded; diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx index 965f81abe..9cf6051a2 100644 --- a/src/containers/costume-tab.jsx +++ b/src/containers/costume-tab.jsx @@ -19,6 +19,11 @@ import { openBackdropLibrary } from '../reducers/modals'; +import { + activateTab, + SOUNDS_TAB_INDEX +} from '../reducers/editor-tab'; + import addLibraryBackdropIcon from '../components/asset-panel/icon--add-backdrop-lib.svg'; import addLibraryCostumeIcon from '../components/asset-panel/icon--add-costume-lib.svg'; import fileUploadIcon from '../components/action-menu/icon--file-upload.svg'; @@ -191,14 +196,22 @@ class CostumeTab extends React.Component { this.fileInput.click(); } handleDrop (dropInfo) { - // Eventually will handle other kinds of drop events, right now just - // the reordering events. if (dropInfo.dragType === DragConstants.COSTUME) { const sprite = this.props.vm.editingTarget.sprite; const activeCostume = sprite.costumes[this.state.selectedCostumeIndex]; this.props.vm.reorderCostume(this.props.vm.editingTarget.id, dropInfo.index, dropInfo.newIndex); this.setState({selectedCostumeIndex: sprite.costumes.indexOf(activeCostume)}); + } else if (dropInfo.dragType === DragConstants.BACKPACK_COSTUME) { + this.props.vm.addCostume(dropInfo.payload.body, { + name: dropInfo.payload.name + }); + } else if (dropInfo.dragType === DragConstants.BACKPACK_SOUND) { + this.props.onActivateSoundsTab(); + this.props.vm.addSound({ + md5: dropInfo.payload.body, + name: dropInfo.payload.name + }); } } setFileInput (input) { @@ -303,6 +316,7 @@ CostumeTab.propTypes = { cameraModalVisible: PropTypes.bool, editingTarget: PropTypes.string, intl: intlShape, + onActivateSoundsTab: PropTypes.func.isRequired, onNewCostumeFromCameraClick: PropTypes.func.isRequired, onNewLibraryBackdropClick: PropTypes.func.isRequired, onNewLibraryCostumeClick: PropTypes.func.isRequired, @@ -333,6 +347,7 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ + onActivateSoundsTab: () => dispatch(activateTab(SOUNDS_TAB_INDEX)), onNewLibraryBackdropClick: e => { e.preventDefault(); dispatch(openBackdropLibrary()); diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx index 097457d8a..74b1eb5d4 100644 --- a/src/containers/sound-tab.jsx +++ b/src/containers/sound-tab.jsx @@ -28,6 +28,11 @@ import { openSoundRecorder } from '../reducers/modals'; +import { + activateTab, + COSTUMES_TAB_INDEX +} from '../reducers/editor-tab'; + class SoundTab extends React.Component { constructor (props) { super(props); @@ -120,8 +125,6 @@ class SoundTab extends React.Component { } handleDrop (dropInfo) { - // Eventually will handle other kinds of drop events, right now just - // the reordering events. if (dropInfo.dragType === DragConstants.SOUND) { const sprite = this.props.vm.editingTarget.sprite; const activeSound = sprite.sounds[this.state.selectedSoundIndex]; @@ -130,6 +133,16 @@ class SoundTab extends React.Component { dropInfo.index, dropInfo.newIndex); this.setState({selectedSoundIndex: sprite.sounds.indexOf(activeSound)}); + } else if (dropInfo.dragType === DragConstants.BACKPACK_COSTUME) { + this.props.onActivateCostumesTab(); + this.props.vm.addCostume(dropInfo.payload.body, { + name: dropInfo.payload.name + }); + } else if (dropInfo.dragType === DragConstants.BACKPACK_SOUND) { + this.props.vm.addSound({ + md5: dropInfo.payload.body, + name: dropInfo.payload.name + }).then(this.handleNewSound); } } @@ -235,6 +248,7 @@ class SoundTab extends React.Component { SoundTab.propTypes = { editingTarget: PropTypes.string, intl: intlShape, + onActivateCostumesTab: PropTypes.func.isRequired, onNewSoundFromLibraryClick: PropTypes.func.isRequired, onNewSoundFromRecordingClick: PropTypes.func.isRequired, onRequestCloseSoundLibrary: PropTypes.func.isRequired, @@ -264,6 +278,7 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ + onActivateCostumesTab: () => dispatch(activateTab(COSTUMES_TAB_INDEX)), onNewSoundFromLibraryClick: e => { e.preventDefault(); dispatch(openSoundLibrary()); diff --git a/src/containers/sprite-selector-item.jsx b/src/containers/sprite-selector-item.jsx index 5efe49428..4c968f827 100644 --- a/src/containers/sprite-selector-item.jsx +++ b/src/containers/sprite-selector-item.jsx @@ -52,7 +52,8 @@ class SpriteSelectorItem extends React.Component { currentOffset: currentOffset, dragging: true, dragType: this.props.dragType, - index: this.props.index + index: this.props.index, + payload: this.props.dragPayload }); this.noClick = true; } @@ -98,6 +99,7 @@ class SpriteSelectorItem extends React.Component { onClick, onDeleteButtonClick, onDuplicateButtonClick, + dragPayload, receivedBlocks, /* eslint-enable no-unused-vars */ ...props @@ -120,6 +122,10 @@ SpriteSelectorItem.propTypes = { assetId: PropTypes.string, costumeURL: PropTypes.string, dispatchSetHoveredSprite: PropTypes.func.isRequired, + dragPayload: PropTypes.shape({ + name: PropTypes.string, + body: PropTypes.string + }), dragType: PropTypes.string, id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), index: PropTypes.number, diff --git a/src/lib/drag-constants.js b/src/lib/drag-constants.js index 86f064da9..ce4da5af2 100644 --- a/src/lib/drag-constants.js +++ b/src/lib/drag-constants.js @@ -1,5 +1,10 @@ export default { SOUND: 'SOUND', COSTUME: 'COSTUME', - SPRITE: 'SPRITE' + SPRITE: 'SPRITE', + + BACKPACK_SOUND: 'BACKPACK_SOUND', + BACKPACK_COSTUME: 'BACKPACK_COSTUME', + BACKPACK_SPRITE: 'BACKPACK_SPRITE', + BACKPACK_CODE: 'BACKPACK_CODE' }; -- GitLab