soiz1's picture
Upload 2891 files
6bcb42f verified
import PropTypes from 'prop-types';
import React from 'react';
import {compose} from 'redux';
import {connect} from 'react-redux';
import ReactModal from 'react-modal';
import VM from 'scratch-vm';
import {injectIntl, intlShape} from 'react-intl';
import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
import {
getIsError,
getIsShowingProject
} from '../reducers/project-state';
import {
activateTab,
BLOCKS_TAB_INDEX,
COSTUMES_TAB_INDEX,
SOUNDS_TAB_INDEX,
VARIABLES_TAB_INDEX,
FILES_TAB_INDEX
} from '../reducers/editor-tab';
import {
closeCostumeLibrary,
closeBackdropLibrary,
closeTelemetryModal,
openExtensionLibrary
} from '../reducers/modals';
import FontLoaderHOC from '../lib/font-loader-hoc.jsx';
import LocalizationHOC from '../lib/localization-hoc.jsx';
import SBFileUploaderHOC from '../lib/sb-file-uploader-hoc.jsx';
import ProjectFetcherHOC from '../lib/project-fetcher-hoc.jsx';
import TitledHOC from '../lib/titled-hoc.jsx';
import ProjectSaverHOC from '../lib/project-saver-hoc.jsx';
import QueryParserHOC from '../lib/query-parser-hoc.jsx';
import storage from '../lib/storage';
import vmListenerHOC from '../lib/vm-listener-hoc.jsx';
import vmManagerHOC from '../lib/vm-manager-hoc.jsx';
import cloudManagerHOC from '../lib/cloud-manager-hoc.jsx';
import TWFullScreenResizerHOC from '../lib/tw-fullscreen-resizer-hoc.jsx';
import GUIComponent from '../components/gui/gui.jsx';
import HomeCommunication from './home-communication.jsx';
import {setIsScratchDesktop} from '../lib/isScratchDesktop.js';
class GUI extends React.Component {
componentDidMount () {
setIsScratchDesktop(this.props.isScratchDesktop);
this.props.onStorageInit(storage);
this.props.onVmInit(this.props.vm);
}
componentDidUpdate (prevProps) {
if (this.props.projectId !== prevProps.projectId && this.props.projectId !== null) {
this.props.onUpdateProjectId(this.props.projectId);
}
if (this.props.isShowingProject && !prevProps.isShowingProject) {
// this only notifies container when a project changes from not yet loaded to loaded
// At this time the project view in www doesn't need to know when a project is unloaded
this.props.onProjectLoaded();
}
}
render () {
if (this.props.isError) {
console.log('the below error was caught by the gui');
throw this.props.error;
}
const {
/* eslint-disable no-unused-vars */
assetHost,
cloudHost,
error,
isError,
isScratchDesktop,
isShowingProject,
onProjectLoaded,
onStorageInit,
onUpdateProjectId,
onVmInit,
projectHost,
projectId,
/* eslint-enable no-unused-vars */
children,
fetchingProject,
isLoading,
loadingStateVisible,
isPlayground,
...componentProps
} = this.props;
return (<>
<GUIComponent
loading={fetchingProject || isLoading || loadingStateVisible}
isPlayground={isPlayground}
{...componentProps}
>
{children}
</GUIComponent>
<HomeCommunication
projectId={projectId}
isPlayground={isPlayground}
/>
</>);
}
}
GUI.propTypes = {
assetHost: PropTypes.string,
children: PropTypes.node,
cloudHost: PropTypes.string,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
fetchingProject: PropTypes.bool,
intl: intlShape,
isError: PropTypes.bool,
isEmbedded: PropTypes.bool,
isFullScreen: PropTypes.bool,
isLoading: PropTypes.bool,
isScratchDesktop: PropTypes.bool,
isShowingProject: PropTypes.bool,
isPlayground: PropTypes.bool,
loadingStateVisible: PropTypes.bool,
onProjectLoaded: PropTypes.func,
onSeeCommunity: PropTypes.func,
onStorageInit: PropTypes.func,
onUpdateProjectId: PropTypes.func,
onVmInit: PropTypes.func,
projectHost: PropTypes.string,
projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
telemetryModalVisible: PropTypes.bool,
vm: PropTypes.instanceOf(VM).isRequired
};
GUI.defaultProps = {
isScratchDesktop: false,
isPlayground: false,
onStorageInit: storageInstance => storageInstance.addOfficialScratchWebStores(),
onProjectLoaded: () => {},
onUpdateProjectId: () => {},
onVmInit: (/* vm */) => {}
};
const mapStateToProps = state => {
const loadingState = state.scratchGui.projectState.loadingState;
return {
activeTabIndex: state.scratchGui.editorTab.activeTabIndex,
alertsVisible: state.scratchGui.alerts.visible,
backdropLibraryVisible: state.scratchGui.modals.backdropLibrary,
blocksTabVisible: state.scratchGui.editorTab.activeTabIndex === BLOCKS_TAB_INDEX,
cardsVisible: state.scratchGui.cards.visible,
connectionModalVisible: state.scratchGui.modals.connectionModal,
costumeLibraryVisible: state.scratchGui.modals.costumeLibrary,
costumesTabVisible: state.scratchGui.editorTab.activeTabIndex === COSTUMES_TAB_INDEX,
error: state.scratchGui.projectState.error,
isError: getIsError(loadingState),
isEmbedded: state.scratchGui.mode.isEmbedded,
isFullScreen: state.scratchGui.mode.isFullScreen || state.scratchGui.mode.isEmbedded,
isPlayerOnly: state.scratchGui.mode.isPlayerOnly,
isRtl: state.locales.isRtl,
isShowingProject: getIsShowingProject(loadingState),
loadingStateVisible: state.scratchGui.modals.loadingProject,
projectId: state.scratchGui.projectState.projectId,
soundsTabVisible: state.scratchGui.editorTab.activeTabIndex === SOUNDS_TAB_INDEX,
variablesTabVisible: state.scratchGui.editorTab.activeTabIndex === VARIABLES_TAB_INDEX,
filesTabVisible: state.scratchGui.editorTab.activeTabIndex === FILES_TAB_INDEX,
targetIsStage: (
state.scratchGui.targets.stage &&
state.scratchGui.targets.stage.id === state.scratchGui.targets.editingTarget
),
telemetryModalVisible: state.scratchGui.modals.telemetryModal,
tipsLibraryVisible: state.scratchGui.modals.tipsLibrary,
usernameModalVisible: state.scratchGui.modals.usernameModal,
settingsModalVisible: state.scratchGui.modals.settingsModal,
customExtensionModalVisible: state.scratchGui.modals.customExtensionModal,
fontsModalVisible: state.scratchGui.modals.fontsModal,
vm: state.scratchGui.vm
};
};
const mapDispatchToProps = dispatch => ({
onExtensionButtonClick: () => dispatch(openExtensionLibrary()),
onActivateTab: tab => dispatch(activateTab(tab)),
onActivateCostumesTab: () => dispatch(activateTab(COSTUMES_TAB_INDEX)),
onActivateSoundsTab: () => dispatch(activateTab(SOUNDS_TAB_INDEX)),
onActivateVariablesTab: () => dispatch(activateTab(VARIABLES_TAB_INDEX)),
onActivateFilesTab: () => dispatch(activateTab(FILES_TAB_INDEX)),
onRequestCloseBackdropLibrary: () => dispatch(closeBackdropLibrary()),
onRequestCloseCostumeLibrary: () => dispatch(closeCostumeLibrary()),
onRequestCloseTelemetryModal: () => dispatch(closeTelemetryModal())
});
const ConnectedGUI = injectIntl(connect(
mapStateToProps,
mapDispatchToProps,
)(GUI));
// note that redux's 'compose' function is just being used as a general utility to make
// the hierarchy of HOC constructor calls clearer here; it has nothing to do with redux's
// ability to compose reducers.
const WrappedGui = compose(
LocalizationHOC,
ErrorBoundaryHOC('Top Level App'),
FontLoaderHOC,
// QueryParserHOC, // tw: HOC is unused
ProjectFetcherHOC,
TitledHOC,
ProjectSaverHOC,
vmListenerHOC,
vmManagerHOC,
SBFileUploaderHOC,
cloudManagerHOC,
TWFullScreenResizerHOC
)(ConnectedGUI);
WrappedGui.setAppElement = ReactModal.setAppElement;
export default WrappedGui;