mirror of
https://github.com/scratchfoundation/scratch-desktop.git
synced 2024-12-22 13:42:27 -05:00
use project state system to load initial project
This commit is contained in:
parent
05e8b26a34
commit
a9933242e0
1 changed files with 87 additions and 25 deletions
|
@ -1,16 +1,33 @@
|
|||
import {ipcRenderer, shell} from 'electron';
|
||||
import bindAll from 'lodash.bindall';
|
||||
import omit from 'lodash.omit';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {connect} from 'react-redux';
|
||||
import {compose} from 'redux';
|
||||
import GUI, {AppStateHOC} from 'scratch-gui';
|
||||
import GUI from 'scratch-gui/src/index';
|
||||
import VM from 'scratch-vm';
|
||||
|
||||
import AppStateHOC from 'scratch-gui/src/lib/app-state-hoc.jsx';
|
||||
import {
|
||||
LoadingStates,
|
||||
onFetchedProjectData,
|
||||
onLoadedProject,
|
||||
defaultProjectId,
|
||||
requestNewProject,
|
||||
requestProjectUpload,
|
||||
setProjectId
|
||||
} from 'scratch-gui/src/reducers/project-state';
|
||||
import {
|
||||
openLoadingProject,
|
||||
closeLoadingProject
|
||||
} from 'scratch-gui/src/reducers/modals';
|
||||
|
||||
import ElectronStorageHelper from '../common/ElectronStorageHelper';
|
||||
|
||||
import styles from './app.css';
|
||||
|
||||
const defaultProjectId = 0;
|
||||
|
||||
// override window.open so that it uses the OS's default browser, not an electron browser
|
||||
window.open = function (url, target) {
|
||||
if (target === '_blank') {
|
||||
|
@ -38,16 +55,29 @@ const ScratchDesktopHOC = function (WrappedComponent) {
|
|||
'handleTelemetryModalOptOut',
|
||||
'handleUpdateProjectTitle'
|
||||
]);
|
||||
this.state = {
|
||||
projectTitle: null,
|
||||
projectLoading: true
|
||||
};
|
||||
this.props.onLoadingStarted();
|
||||
ipcRenderer.invoke('get-initial-project-data').then(initialProjectData => {
|
||||
const hasInitialProject = initialProjectData && (initialProjectData.length > 0);
|
||||
this.props.onHasInitialProject(hasInitialProject, this.props.loadingState);
|
||||
if (!hasInitialProject) {
|
||||
this.props.onLoadingCompleted();
|
||||
return;
|
||||
}
|
||||
this.props.vm.loadProject(initialProjectData).then(
|
||||
() => {
|
||||
this.props.onLoadingCompleted();
|
||||
this.props.onLoadedProject(this.props.loadingState, true);
|
||||
},
|
||||
e => {
|
||||
this.props.onLoadingCompleted();
|
||||
console.error(e); // TODO: dialog box reporting the error?
|
||||
|
||||
ipcRenderer.invoke('get-initial-project-data').then(projectData => {
|
||||
this.setState({
|
||||
projectData,
|
||||
projectLoading: false
|
||||
});
|
||||
// abandon this load and instead fetch+load the default project
|
||||
// WARNING: this stuff doesn't currently work correctly!
|
||||
this.props.onLoadedProject(this.props.loadingState, false);
|
||||
this.props.onRequestNewProject();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
componentDidMount () {
|
||||
|
@ -80,15 +110,12 @@ const ScratchDesktopHOC = function (WrappedComponent) {
|
|||
render () {
|
||||
const shouldShowTelemetryModal = (typeof ipcRenderer.sendSync('getTelemetryDidOptIn') !== 'boolean');
|
||||
|
||||
if (this.state.projectLoading) {
|
||||
return <p className="splash">Loading File...</p>;
|
||||
}
|
||||
const childProps = omit(this.props, Object.keys(ScratchDesktopComponent.propTypes));
|
||||
|
||||
return (<WrappedComponent
|
||||
canEditTitle
|
||||
canModifyCloudData={false}
|
||||
isScratchDesktop
|
||||
projectId={defaultProjectId}
|
||||
projectTitle={this.state.projectTitle}
|
||||
showTelemetryModal={shouldShowTelemetryModal}
|
||||
onClickLogo={this.handleClickLogo}
|
||||
onProjectTelemetryEvent={this.handleProjectTelemetryEvent}
|
||||
|
@ -97,25 +124,60 @@ const ScratchDesktopHOC = function (WrappedComponent) {
|
|||
onTelemetryModalOptOut={this.handleTelemetryModalOptOut}
|
||||
onUpdateProjectTitle={this.handleUpdateProjectTitle}
|
||||
|
||||
// completely omit the projectData prop if we have no project data
|
||||
// passing an empty projectData causes a GUI error
|
||||
{...(this.state.projectData ? {projectData: this.state.projectData} : {})}
|
||||
|
||||
// allow passed-in props to override any of the above
|
||||
{...this.props}
|
||||
{...childProps}
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
return ScratchDesktopComponent;
|
||||
ScratchDesktopComponent.propTypes = {
|
||||
loadingState: PropTypes.oneOf(LoadingStates),
|
||||
onFetchedInitialProjectData: PropTypes.func,
|
||||
onHasInitialProject: PropTypes.func,
|
||||
onLoadedProject: PropTypes.func,
|
||||
onLoadingCompleted: PropTypes.func,
|
||||
onLoadingStarted: PropTypes.func,
|
||||
onRequestNewProject: PropTypes.func,
|
||||
vm: PropTypes.instanceOf(VM).isRequired
|
||||
};
|
||||
const mapStateToProps = state => {
|
||||
const loadingState = state.scratchGui.projectState.loadingState;
|
||||
return {
|
||||
loadingState: loadingState,
|
||||
vm: state.scratchGui.vm
|
||||
};
|
||||
};
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onLoadingStarted: () => dispatch(openLoadingProject()),
|
||||
onLoadingCompleted: () => dispatch(closeLoadingProject()),
|
||||
onHasInitialProject: (hasInitialProject, loadingState) => {
|
||||
if (hasInitialProject) {
|
||||
// emulate sb-file-uploader
|
||||
return dispatch(requestProjectUpload(loadingState));
|
||||
}
|
||||
|
||||
// `createProject()` might seem more appropriate but it's not a valid state transition here
|
||||
// setting the default project ID is a valid transition from NOT_LOADED and acts like "create new"
|
||||
return dispatch(setProjectId(defaultProjectId));
|
||||
},
|
||||
onFetchedInitialProjectData: (projectData, loadingState) =>
|
||||
dispatch(onFetchedProjectData(projectData, loadingState)),
|
||||
onLoadedProject: (loadingState, loadSuccess) => {
|
||||
const canSaveToServer = false;
|
||||
return dispatch(onLoadedProject(loadingState, canSaveToServer, loadSuccess));
|
||||
},
|
||||
onRequestNewProject: () => dispatch(requestNewProject(false))
|
||||
});
|
||||
|
||||
return connect(mapStateToProps, mapDispatchToProps)(ScratchDesktopComponent);
|
||||
};
|
||||
|
||||
// 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(
|
||||
ScratchDesktopHOC,
|
||||
AppStateHOC
|
||||
AppStateHOC,
|
||||
ScratchDesktopHOC
|
||||
)(GUI);
|
||||
|
||||
ReactDOM.render(<WrappedGui />, appTarget);
|
||||
|
|
Loading…
Reference in a new issue