Spaces:
Running
Running
import PropTypes from 'prop-types'; | |
import React from 'react'; | |
import bindAll from 'lodash.bindall'; | |
import { defineMessages, intlShape, injectIntl } from 'react-intl'; | |
import VM from 'scratch-vm'; | |
import AssetPanel from '../components/asset-panel/asset-panel.jsx'; | |
import placeholderIcon from '../components/asset-panel/icon--files-placeholder.svg'; | |
// import soundIconRtl from '../components/asset-panel/icon--sound-rtl.svg'; | |
// import addSoundFromLibraryIcon from '../components/asset-panel/icon--add-sound-lib.svg'; | |
// import addSoundFromRecordingIcon from '../components/asset-panel/icon--add-sound-record.svg'; | |
// import fileUploadIcon from '../components/action-menu/icon--file-upload.svg'; | |
// import surpriseIcon from '../components/action-menu/icon--surprise.svg'; | |
// import searchIcon from '../components/action-menu/icon--search.svg'; | |
import nordTheMan from '../components/asset-panel/nord.png'; | |
// import RecordModal from './record-modal.jsx'; | |
// import SoundEditor from './sound-editor.jsx'; | |
// import SoundLibrary from './sound-library.jsx'; | |
// import { getSoundLibrary } from '../lib/libraries/tw-async-libraries'; | |
import { handleFileUpload, externalFileUpload } from '../lib/file-uploader.js'; | |
import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx'; | |
// import DragConstants from '../lib/drag-constants'; | |
import downloadBlob from '../lib/download-blob'; | |
import { connect } from 'react-redux'; | |
// import { | |
// closeSoundLibrary, | |
// openSoundLibrary, | |
// openSoundRecorder | |
// } from '../reducers/modals'; | |
// import { | |
// activateTab, | |
// COSTUMES_TAB_INDEX | |
// } from '../reducers/editor-tab'; | |
import { setRestore } from '../reducers/restore-deletion'; | |
import { showStandardAlert, closeAlertWithId } from '../reducers/alerts'; | |
class FilesTab extends React.Component { | |
constructor(props) { | |
super(props); | |
bindAll(this, [ | |
'handleSelectFile', | |
'handleDeleteFile', | |
'handleDuplicateFile', | |
'handleDownloadFile', | |
'handleNewFile', | |
// 'handleSurpriseSound', | |
'handleFileUploadClick', | |
'handleExternalFileUpload', | |
// 'handleDrop', | |
'setFileInput' | |
]); | |
this.state = { selectedFileIndex: 0 }; | |
} | |
componentWillReceiveProps(nextProps) { | |
// TODO: handle this | |
// const { | |
// editingTarget, | |
// sprites, | |
// stage | |
// } = nextProps; | |
// const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage; | |
// if (!target || !target.sounds) { | |
// return; | |
// } | |
// // If switching editing targets, reset the sound index | |
// if (this.props.editingTarget !== editingTarget) { | |
// this.setState({ selectedSoundIndex: 0 }); | |
// } else if (this.state.selectedSoundIndex > target.sounds.length - 1) { | |
// this.setState({ selectedSoundIndex: Math.max(target.sounds.length - 1, 0) }); | |
// } | |
} | |
handleSelectFile(fileIndex) { | |
this.setState({ selectedFileIndex: fileIndex }); | |
} | |
handleDeleteFile(fileIndex) { | |
// TODO: deleteFile isnt a function | |
const restoreFun = this.props.vm.deleteFile(fileIndex); | |
if (fileIndex >= this.state.selectedFileIndex) { | |
this.setState({ selectedFileIndex: Math.max(0, fileIndex - 1) }); | |
} | |
this.props.dispatchUpdateRestore({ restoreFun, deletedItem: 'File' }); | |
} | |
handleDownloadFile(fileIndex) { | |
// TODO: vm.files doesnt exist | |
const item = this.props.vm.files[fileIndex]; | |
const blob = new Blob([item.asset.data], { type: item.asset.assetType.contentType }); | |
downloadBlob(`${item.name}.${item.asset.dataFormat}`, blob); | |
} | |
handleDuplicateFile(fileIndex) { | |
// TODO: duplicateFile isnt a function | |
this.props.vm.duplicateFile(fileIndex).then(() => { | |
this.setState({ selectedFileIndex: fileIndex + 1 }); | |
}); | |
} | |
handleNewFile() { | |
if (!this.props.vm.editingTarget) { | |
return null; | |
} | |
// TODO: vm.files doesnt exist | |
const files = this.props.vm.files ? this.props.vm.files : []; | |
this.setState({ selectedFileIndex: Math.max(files.length - 1, 0) }); | |
} | |
handleFileUploadClick() { | |
this.fileInput.click(); | |
} | |
handleExternalFileUpload(e) { | |
const storage = this.props.vm.runtime.storage; | |
const targetId = this.props.vm.editingTarget.id; | |
this.props.onShowImporting(); | |
handleFileUpload(e.target, (buffer, fileType, fileName, fileIndex, fileCount) => { | |
externalFileUpload(buffer, fileType, storage, newFile => { | |
newFile.name = fileName; | |
// TODO: addFile isnt a function | |
this.props.vm.addFile(newFile, targetId).then(() => { | |
this.handleNewFile(); | |
if (fileIndex === fileCount - 1) { | |
this.props.onCloseImporting(); | |
} | |
}); | |
}, this.props.onCloseImporting); | |
}, this.props.onCloseImporting); | |
} | |
// handleDrop(dropInfo) { | |
// if (dropInfo.dragType === DragConstants.SOUND) { | |
// const sprite = this.props.vm.editingTarget.sprite; | |
// const activeSound = sprite.sounds[this.state.selectedSoundIndex]; | |
// this.props.vm.reorderSound(this.props.vm.editingTarget.id, | |
// 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); | |
// } | |
// } | |
setFileInput(input) { | |
this.fileInput = input; | |
} | |
render() { | |
const { | |
dispatchUpdateRestore, // eslint-disable-line no-unused-vars | |
intl, | |
isRtl, | |
vm, | |
// onNewSoundFromLibraryClick, | |
// onNewSoundFromRecordingClick | |
} = this.props; | |
if (!vm.editingTarget) { | |
return null; | |
} | |
const files = vm.files ? vm.files.map(file => ( | |
{ | |
url: isRtl ? fileIconRtl : fileIcon, | |
name: file.name, | |
details: file.size, | |
dragPayload: file | |
} | |
)) : []; | |
const messages = defineMessages({ | |
fileUploadExternal: { | |
defaultMessage: 'Upload File', | |
description: 'Button to upload file in the editor tab', | |
id: 'pm.gui.filesTab.fileUploadExternal' | |
}, | |
fileNew: { | |
defaultMessage: 'New File', | |
description: 'Button to create a new file in the editor tab', | |
id: 'pm.gui.filesTab.fileNew' | |
} | |
}); | |
return ( | |
<AssetPanel | |
buttons={[{ | |
title: intl.formatMessage(messages.fileNew), | |
img: placeholderIcon, | |
onClick: this.handleFileUploadClick // TODO: should make a new TXT file instead | |
}, { | |
title: intl.formatMessage(messages.fileUploadExternal), | |
img: placeholderIcon, | |
onClick: this.handleFileUploadClick, | |
fileAccept: '.txt, .json', | |
fileChange: this.handleExternalFileUpload, | |
fileInput: this.setFileInput, | |
fileMultiple: true | |
}, { | |
title: intl.formatMessage(messages.fileNew), | |
img: placeholderIcon, | |
onClick: this.handleFileUploadClick // TODO: should make a new TXT file instead | |
}]} | |
// dragType={DragConstants.SOUND} | |
isRtl={isRtl} | |
items={files} | |
selectedItemIndex={this.state.selectedFileIndex} | |
onDeleteClick={this.handleDeleteFile} | |
// onDrop={this.handleDrop} | |
onDuplicateClick={this.handleDuplicateFile} | |
onExportClick={this.handleDownloadFile} | |
onItemClick={this.handleSelectFile} | |
> | |
<p>erm, you dont see anything here</p> | |
<img | |
width="40" | |
height="40" | |
src={nordTheMan} | |
alt="Nord" | |
></img> | |
</AssetPanel> | |
); | |
} | |
} | |
FilesTab.propTypes = { | |
dispatchUpdateRestore: PropTypes.func, | |
editingTarget: PropTypes.string, | |
intl: intlShape, | |
isRtl: PropTypes.bool, | |
// onActivateCostumesTab: PropTypes.func.isRequired, | |
onCloseImporting: PropTypes.func.isRequired, | |
// onNewSoundFromLibraryClick: PropTypes.func.isRequired, | |
// onNewSoundFromRecordingClick: PropTypes.func.isRequired, | |
// onRequestCloseSoundLibrary: PropTypes.func.isRequired, | |
onShowImporting: PropTypes.func.isRequired, | |
// soundLibraryVisible: PropTypes.bool, | |
// soundRecorderVisible: PropTypes.bool, | |
// sprites: PropTypes.shape({ | |
// id: PropTypes.shape({ | |
// sounds: PropTypes.arrayOf(PropTypes.shape({ | |
// name: PropTypes.string.isRequired | |
// })) | |
// }) | |
// }), | |
// stage: PropTypes.shape({ | |
// sounds: PropTypes.arrayOf(PropTypes.shape({ | |
// name: PropTypes.string.isRequired | |
// })) | |
// }), | |
vm: PropTypes.instanceOf(VM).isRequired | |
}; | |
const mapStateToProps = state => ({ | |
editingTarget: state.scratchGui.targets.editingTarget, | |
isRtl: state.locales.isRtl, | |
// sprites: state.scratchGui.targets.sprites, | |
// stage: state.scratchGui.targets.stage, | |
// soundLibraryVisible: state.scratchGui.modals.soundLibrary, | |
// soundRecorderVisible: state.scratchGui.modals.soundRecorder | |
}); | |
const mapDispatchToProps = dispatch => ({ | |
// onActivateCostumesTab: () => dispatch(activateTab(COSTUMES_TAB_INDEX)), | |
// onNewSoundFromLibraryClick: e => { | |
// e.preventDefault(); | |
// dispatch(openSoundLibrary()); | |
// }, | |
// onNewSoundFromRecordingClick: () => { | |
// dispatch(openSoundRecorder()); | |
// }, | |
// onRequestCloseSoundLibrary: () => { | |
// dispatch(closeSoundLibrary()); | |
// }, | |
dispatchUpdateRestore: restoreState => { | |
dispatch(setRestore(restoreState)); | |
}, | |
onCloseImporting: () => dispatch(closeAlertWithId('importingAsset')), | |
onShowImporting: () => dispatch(showStandardAlert('importingAsset')) | |
}); | |
export default errorBoundaryHOC('Files Tab')( | |
injectIntl(connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(FilesTab)) | |
); | |