mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Refactor project opening/saving into ProjectsStorage with StorageProviders.
This commit is contained in:
@@ -36,15 +36,16 @@ const updateResources = (project, baseUrl) => {
|
||||
project.exposeResources(worker);
|
||||
};
|
||||
|
||||
const writeBrowserExampleFilesJsFile = exampleNames => {
|
||||
const writeInternalExampleFilesJsFile = exampleNames => {
|
||||
let importsCode = [];
|
||||
let internalFilesObjectCode = [];
|
||||
exampleNames.forEach((exampleName, index) => {
|
||||
importsCode.push(`import exampleFile${index} from '../fixtures/${exampleName}/${exampleName}.json';`);
|
||||
importsCode.push(`import exampleFile${index} from '../../fixtures/${exampleName}/${exampleName}.json';`);
|
||||
internalFilesObjectCode.push(` 'example://${exampleName}': exampleFile${index},`);
|
||||
});
|
||||
|
||||
const content = [
|
||||
`// @flow`,
|
||||
`// This file is generated by update-fixtures-from-resources-examples.js script`,
|
||||
``,
|
||||
importsCode.join('\n'),
|
||||
@@ -58,7 +59,7 @@ const writeBrowserExampleFilesJsFile = exampleNames => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(
|
||||
'../src/ProjectsStorage/BrowserExampleFiles.js',
|
||||
'../src/ProjectsStorage/InternalFileStorageProvider/InternalExampleFiles.js',
|
||||
content,
|
||||
'utf8',
|
||||
err => {
|
||||
@@ -110,14 +111,14 @@ extensionsLoader
|
||||
});
|
||||
})
|
||||
)
|
||||
.then(() => writeBrowserExampleFilesJsFile(exampleNames))
|
||||
.then(() => writeInternalExampleFilesJsFile(exampleNames))
|
||||
.then(
|
||||
() => {
|
||||
console.error(`✅ BrowserExampleFiles.js written.`);
|
||||
console.error(`✅ InternalExampleFiles.js written.`);
|
||||
},
|
||||
error => {
|
||||
console.error(
|
||||
`❌ Error caught while writing BrowserExampleFiles.js:`,
|
||||
`❌ Error caught while writing InternalExampleFiles.js:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// @flow
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import MainFrame from './MainFrame';
|
||||
import Window from './Utils/Window';
|
||||
import ExportDialog from './Export/ExportDialog';
|
||||
@@ -10,8 +10,6 @@ import './UI/iconmoon-font.css'; // Styles for Iconmoon font.
|
||||
// Import for browser only IDE
|
||||
import BrowserExamples from './ProjectCreation/BrowserExamples';
|
||||
import BrowserStarters from './ProjectCreation/BrowserStarters';
|
||||
import BrowserProjectOpener from './ProjectsStorage/BrowserProjectOpener';
|
||||
import BrowserSaveDialog from './ProjectsStorage/BrowserSaveDialog';
|
||||
import BrowserIntroDialog from './MainFrame/BrowserIntroDialog';
|
||||
import browserResourceSources from './ResourcesList/BrowserResourceSources';
|
||||
import browserResourceExternalEditors from './ResourcesList/BrowserResourceExternalEditors';
|
||||
@@ -22,6 +20,8 @@ import ObjectsEditorService from './ObjectEditor/ObjectsEditorService';
|
||||
import ObjectsRenderingService from './ObjectsRendering/ObjectsRenderingService';
|
||||
import { makeBrowserS3EventsFunctionCodeWriter } from './EventsFunctionsExtensionsLoader/CodeWriters/BrowserS3EventsFunctionCodeWriter';
|
||||
import Providers from './MainFrame/Providers';
|
||||
import ProjectsStorage from './ProjectsStorage';
|
||||
import InternalFileStorageProvider from './ProjectsStorage/InternalFileStorageProvider';
|
||||
|
||||
export const create = (authentification: Authentification) => {
|
||||
Window.setUpContextMenu();
|
||||
@@ -38,30 +38,38 @@ export const create = (authentification: Authentification) => {
|
||||
eventsFunctionsExtensionOpener={null}
|
||||
>
|
||||
{({ i18n, eventsFunctionsExtensionsState }) => (
|
||||
<MainFrame
|
||||
i18n={i18n}
|
||||
eventsFunctionsExtensionsState={eventsFunctionsExtensionsState}
|
||||
previewLauncher={<BrowserS3PreviewLauncher />}
|
||||
renderExportDialog={(props) => <ExportDialog {...props} exporters={getBrowserExporters()} />}
|
||||
createDialog={
|
||||
<CreateProjectDialog
|
||||
examplesComponent={BrowserExamples}
|
||||
startersComponent={BrowserStarters}
|
||||
<ProjectsStorage
|
||||
storageProviders={[InternalFileStorageProvider]}
|
||||
defaultStorageProvider={InternalFileStorageProvider}
|
||||
>
|
||||
{projectsStorageProps => (
|
||||
<MainFrame
|
||||
i18n={i18n}
|
||||
eventsFunctionsExtensionsState={eventsFunctionsExtensionsState}
|
||||
previewLauncher={<BrowserS3PreviewLauncher />}
|
||||
renderExportDialog={props => (
|
||||
<ExportDialog {...props} exporters={getBrowserExporters()} />
|
||||
)}
|
||||
createDialog={
|
||||
<CreateProjectDialog
|
||||
examplesComponent={BrowserExamples}
|
||||
startersComponent={BrowserStarters}
|
||||
/>
|
||||
}
|
||||
introDialog={<BrowserIntroDialog />}
|
||||
projectsStorage={projectsStorageProps}
|
||||
resourceSources={browserResourceSources}
|
||||
resourceExternalEditors={browserResourceExternalEditors}
|
||||
authentification={authentification}
|
||||
extensionsLoader={makeExtensionsLoader({
|
||||
objectsEditorService: ObjectsEditorService,
|
||||
objectsRenderingService: ObjectsRenderingService,
|
||||
filterExamples: !Window.isDev(),
|
||||
})}
|
||||
initialPathsOrURLsToOpen={appArguments['_']}
|
||||
/>
|
||||
}
|
||||
introDialog={<BrowserIntroDialog />}
|
||||
saveDialog={<BrowserSaveDialog />}
|
||||
onReadFromPathOrURL={BrowserProjectOpener.readInternalFile}
|
||||
resourceSources={browserResourceSources}
|
||||
resourceExternalEditors={browserResourceExternalEditors}
|
||||
authentification={authentification}
|
||||
extensionsLoader={makeExtensionsLoader({
|
||||
objectsEditorService: ObjectsEditorService,
|
||||
objectsRenderingService: ObjectsRenderingService,
|
||||
filterExamples: !Window.isDev(),
|
||||
})}
|
||||
initialPathsOrURLsToOpen={appArguments['_']}
|
||||
/>
|
||||
)}
|
||||
</ProjectsStorage>
|
||||
)}
|
||||
</Providers>
|
||||
);
|
||||
|
@@ -13,8 +13,6 @@ import LocalExamples from './ProjectCreation/LocalExamples';
|
||||
import LocalStarters from './ProjectCreation/LocalStarters';
|
||||
import localResourceSources from './ResourcesList/LocalResourceSources';
|
||||
import localResourceExternalEditors from './ResourcesList/LocalResourceExternalEditors';
|
||||
import LocalProjectWriter from './ProjectsStorage/LocalProjectWriter';
|
||||
import LocalProjectOpener from './ProjectsStorage/LocalProjectOpener';
|
||||
import LocalPreviewLauncher from './Export/LocalExporters/LocalPreviewLauncher';
|
||||
import { getLocalExporters } from './Export/LocalExporters';
|
||||
import ElectronMainMenu from './MainFrame/ElectronMainMenu';
|
||||
@@ -25,6 +23,8 @@ import ObjectsRenderingService from './ObjectsRendering/ObjectsRenderingService'
|
||||
import Providers from './MainFrame/Providers';
|
||||
import LocalEventsFunctionsExtensionWriter from './EventsFunctionsExtensionsLoader/Storage/LocalEventsFunctionsExtensionWriter';
|
||||
import LocalEventsFunctionsExtensionOpener from './EventsFunctionsExtensionsLoader/Storage/LocalEventsFunctionsExtensionOpener';
|
||||
import ProjectsStorage from './ProjectsStorage';
|
||||
import LocalFileStorageProvider from './ProjectsStorage/LocalFileStorageProvider';
|
||||
const gd = global.gd;
|
||||
|
||||
export const create = (authentification: Authentification) => {
|
||||
@@ -43,24 +43,28 @@ export const create = (authentification: Authentification) => {
|
||||
eventsFunctionsExtensionOpener={null}
|
||||
>
|
||||
{({ i18n, eventsFunctionsExtensionsState }) => (
|
||||
<ExternalEditor
|
||||
serverPort={appArguments['server-port']}
|
||||
isIntegrated={appArguments['mode'] === 'integrated'}
|
||||
editor={appArguments['editor']}
|
||||
editedElementName={appArguments['edited-element-name']}
|
||||
>
|
||||
<MainFrame
|
||||
i18n={i18n}
|
||||
eventsFunctionsExtensionsState={eventsFunctionsExtensionsState}
|
||||
resourceSources={localResourceSources}
|
||||
authentification={authentification}
|
||||
onReadFromPathOrURL={() =>
|
||||
Promise.reject('Should never be called')
|
||||
}
|
||||
resourceExternalEditors={localResourceExternalEditors}
|
||||
initialPathsOrURLsToOpen={[]}
|
||||
/>
|
||||
</ExternalEditor>
|
||||
<ProjectsStorage storageProviders={[]}>
|
||||
{projectsStorageProps => (
|
||||
<ExternalEditor
|
||||
serverPort={appArguments['server-port']}
|
||||
isIntegrated={appArguments['mode'] === 'integrated'}
|
||||
editor={appArguments['editor']}
|
||||
editedElementName={appArguments['edited-element-name']}
|
||||
>
|
||||
<MainFrame
|
||||
i18n={i18n}
|
||||
eventsFunctionsExtensionsState={
|
||||
eventsFunctionsExtensionsState
|
||||
}
|
||||
resourceSources={localResourceSources}
|
||||
authentification={authentification}
|
||||
projectsStorage={projectsStorageProps}
|
||||
resourceExternalEditors={localResourceExternalEditors}
|
||||
initialPathsOrURLsToOpen={[]}
|
||||
/>
|
||||
</ExternalEditor>
|
||||
)}
|
||||
</ProjectsStorage>
|
||||
)}
|
||||
</Providers>
|
||||
);
|
||||
@@ -74,36 +78,42 @@ export const create = (authentification: Authentification) => {
|
||||
eventsFunctionsExtensionOpener={LocalEventsFunctionsExtensionOpener}
|
||||
>
|
||||
{({ i18n, eventsFunctionsExtensionsState }) => (
|
||||
<ElectronMainMenu i18n={i18n}>
|
||||
<MainFrame
|
||||
i18n={i18n}
|
||||
eventsFunctionsExtensionsState={eventsFunctionsExtensionsState}
|
||||
previewLauncher={<LocalPreviewLauncher />}
|
||||
renderExportDialog={(props) => <ExportDialog {...props} exporters={getLocalExporters()} />}
|
||||
createDialog={
|
||||
<CreateProjectDialog
|
||||
examplesComponent={LocalExamples}
|
||||
startersComponent={LocalStarters}
|
||||
<ProjectsStorage
|
||||
storageProviders={[LocalFileStorageProvider]}
|
||||
defaultStorageProvider={LocalFileStorageProvider}
|
||||
>
|
||||
{projectsStorageProps => (
|
||||
<ElectronMainMenu i18n={i18n}>
|
||||
<MainFrame
|
||||
i18n={i18n}
|
||||
eventsFunctionsExtensionsState={
|
||||
eventsFunctionsExtensionsState
|
||||
}
|
||||
previewLauncher={<LocalPreviewLauncher />}
|
||||
renderExportDialog={props => (
|
||||
<ExportDialog {...props} exporters={getLocalExporters()} />
|
||||
)}
|
||||
createDialog={
|
||||
<CreateProjectDialog
|
||||
examplesComponent={LocalExamples}
|
||||
startersComponent={LocalStarters}
|
||||
/>
|
||||
}
|
||||
projectsStorage={projectsStorageProps}
|
||||
resourceSources={localResourceSources}
|
||||
resourceExternalEditors={localResourceExternalEditors}
|
||||
authentification={authentification}
|
||||
extensionsLoader={makeExtensionsLoader({
|
||||
gd,
|
||||
objectsEditorService: ObjectsEditorService,
|
||||
objectsRenderingService: ObjectsRenderingService,
|
||||
filterExamples: !Window.isDev(),
|
||||
})}
|
||||
initialPathsOrURLsToOpen={appArguments['_']}
|
||||
/>
|
||||
}
|
||||
onSaveProject={LocalProjectWriter.saveProject}
|
||||
onSaveProjectAs={LocalProjectWriter.saveProjectAs}
|
||||
onAutoSaveProject={LocalProjectWriter.autoSaveProject}
|
||||
onChooseProject={LocalProjectOpener.chooseProjectFile}
|
||||
onReadFromPathOrURL={LocalProjectOpener.readProjectFile}
|
||||
shouldOpenAutosave={LocalProjectOpener.shouldOpenAutosave}
|
||||
resourceSources={localResourceSources}
|
||||
resourceExternalEditors={localResourceExternalEditors}
|
||||
authentification={authentification}
|
||||
extensionsLoader={makeExtensionsLoader({
|
||||
gd,
|
||||
objectsEditorService: ObjectsEditorService,
|
||||
objectsRenderingService: ObjectsRenderingService,
|
||||
filterExamples: !Window.isDev(),
|
||||
})}
|
||||
initialPathsOrURLsToOpen={appArguments['_']}
|
||||
/>
|
||||
</ElectronMainMenu>
|
||||
</ElectronMainMenu>
|
||||
)}
|
||||
</ProjectsStorage>
|
||||
)}
|
||||
</Providers>
|
||||
);
|
||||
|
@@ -84,6 +84,7 @@ import PreferencesContext from './Preferences/PreferencesContext';
|
||||
import { getFunctionNameFromType } from '../EventsFunctionsExtensionsLoader';
|
||||
import { type ExportDialogWithoutExportsProps } from '../Export/ExportDialog';
|
||||
import { getStartupTimesSummary } from '../Utils/StartupTimes';
|
||||
import { type ProjectsStorageProps } from '../ProjectsStorage';
|
||||
const GD_STARTUP_TIMES = global.GD_STARTUP_TIMES || [];
|
||||
|
||||
const gd = global.gd;
|
||||
@@ -101,7 +102,6 @@ type State = {|
|
||||
createDialogOpen: boolean,
|
||||
exportDialogOpen: boolean,
|
||||
introDialogOpen: boolean,
|
||||
saveDialogOpen: boolean,
|
||||
genericDialogOpen: boolean,
|
||||
loadingProject: boolean,
|
||||
previewLoading: boolean,
|
||||
@@ -125,21 +125,11 @@ type State = {|
|
||||
type Props = {
|
||||
integratedEditor?: boolean,
|
||||
introDialog?: React.Element<*>,
|
||||
onReadFromPathOrURL: (url: string) => Promise<any>,
|
||||
previewLauncher?: React.Element<PreviewLauncher>,
|
||||
onEditObject?: gdObject => void,
|
||||
projectsStorage: ProjectsStorageProps,
|
||||
resourceSources: Array<ResourceSource>,
|
||||
resourceExternalEditors: Array<ResourceExternalEditor>,
|
||||
onChooseProject?: () => Promise<?string>,
|
||||
saveDialog?: React.Element<*>,
|
||||
onSaveProject?: gdProject => Promise<any>,
|
||||
onSaveProjectAs?: gdProject => Promise<any>,
|
||||
onAutoSaveProject?: (project: gdProject) => void,
|
||||
shouldOpenAutosave?: (
|
||||
filePath: string,
|
||||
autoSavePath: string,
|
||||
compareLastModified: boolean
|
||||
) => boolean,
|
||||
loading?: boolean,
|
||||
requestUpdate?: () => void,
|
||||
renderExportDialog?: ExportDialogWithoutExportsProps => React.Node,
|
||||
@@ -156,7 +146,6 @@ class MainFrame extends React.Component<Props, State> {
|
||||
createDialogOpen: false,
|
||||
exportDialogOpen: false,
|
||||
introDialogOpen: false,
|
||||
saveDialogOpen: false,
|
||||
genericDialogOpen: false,
|
||||
loadingProject: false,
|
||||
previewLoading: false,
|
||||
@@ -179,7 +168,6 @@ class MainFrame extends React.Component<Props, State> {
|
||||
toolbar = null;
|
||||
_resourceSourceDialogs = {};
|
||||
_previewLauncher: ?PreviewLauncher = null;
|
||||
_providers = null;
|
||||
|
||||
componentWillMount() {
|
||||
if (!this.props.integratedEditor) this.openStartPage();
|
||||
@@ -300,11 +288,14 @@ class MainFrame extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
openFromPathOrURL = (url: string, cb: Function) => {
|
||||
const { i18n, shouldOpenAutosave } = this.props;
|
||||
const { i18n, projectsStorage } = this.props;
|
||||
|
||||
const projectFilePath = url;
|
||||
const autoSavePath = url + '.autosave';
|
||||
if (shouldOpenAutosave && shouldOpenAutosave(url, autoSavePath, true)) {
|
||||
if (
|
||||
projectsStorage.shouldOpenAutosave &&
|
||||
projectsStorage.shouldOpenAutosave(url, autoSavePath, true)
|
||||
) {
|
||||
//eslint-disable-next-line
|
||||
const answer = confirm(
|
||||
i18n._(
|
||||
@@ -314,7 +305,7 @@ class MainFrame extends React.Component<Props, State> {
|
||||
if (answer) url = autoSavePath;
|
||||
}
|
||||
|
||||
this.props.onReadFromPathOrURL(url).then(
|
||||
projectsStorage.onOpen(url).then(
|
||||
projectObject => {
|
||||
this.setState({ loadingProject: true }, () =>
|
||||
setTimeout(() => {
|
||||
@@ -339,8 +330,12 @@ class MainFrame extends React.Component<Props, State> {
|
||||
},
|
||||
err => {
|
||||
if (
|
||||
shouldOpenAutosave &&
|
||||
shouldOpenAutosave(projectFilePath, autoSavePath, false)
|
||||
projectsStorage.shouldOpenAutosave &&
|
||||
projectsStorage.shouldOpenAutosave(
|
||||
projectFilePath,
|
||||
autoSavePath,
|
||||
false
|
||||
)
|
||||
) {
|
||||
//eslint-disable-next-line
|
||||
const answer = confirm(
|
||||
@@ -811,7 +806,7 @@ class MainFrame extends React.Component<Props, State> {
|
||||
openSceneEditor = true,
|
||||
}: { openEventsEditor: boolean, openSceneEditor: boolean } = {}
|
||||
) => {
|
||||
const { i18n, onAutoSaveProject } = this.props;
|
||||
const { i18n, projectsStorage } = this.props;
|
||||
const sceneEditorOptions = {
|
||||
name,
|
||||
renderEditor: ({ isActive, editorRef }) => (
|
||||
@@ -823,8 +818,11 @@ class MainFrame extends React.Component<Props, State> {
|
||||
setToolbar={this.setEditorToolbar}
|
||||
onPreview={(project, layout, options) => {
|
||||
this._launchLayoutPreview(project, layout, options);
|
||||
if (values.autosaveOnPreview && onAutoSaveProject) {
|
||||
onAutoSaveProject(project);
|
||||
if (
|
||||
values.autosaveOnPreview &&
|
||||
projectsStorage.onAutoSaveProject
|
||||
) {
|
||||
projectsStorage.onAutoSaveProject(project);
|
||||
}
|
||||
}}
|
||||
showPreviewButton={!!this.props.previewLauncher}
|
||||
@@ -856,8 +854,11 @@ class MainFrame extends React.Component<Props, State> {
|
||||
setToolbar={this.setEditorToolbar}
|
||||
onPreview={(project, layout, options) => {
|
||||
this._launchLayoutPreview(project, layout, options);
|
||||
if (values.autosaveOnPreview && onAutoSaveProject) {
|
||||
onAutoSaveProject(project);
|
||||
if (
|
||||
values.autosaveOnPreview &&
|
||||
projectsStorage.onAutoSaveProject
|
||||
) {
|
||||
projectsStorage.onAutoSaveProject(project);
|
||||
}
|
||||
}}
|
||||
showPreviewButton={!!this.props.previewLauncher}
|
||||
@@ -936,6 +937,7 @@ class MainFrame extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
openExternalLayout = (name: string) => {
|
||||
const { projectsStorage } = this.props;
|
||||
this.setState(
|
||||
{
|
||||
editorTabs: openEditorTab(this.state.editorTabs, {
|
||||
@@ -956,9 +958,9 @@ class MainFrame extends React.Component<Props, State> {
|
||||
);
|
||||
if (
|
||||
values.autosaveOnPreview &&
|
||||
this.props.onAutoSaveProject
|
||||
projectsStorage.onAutoSaveProject
|
||||
) {
|
||||
this.props.onAutoSaveProject(project);
|
||||
projectsStorage.onAutoSaveProject(project);
|
||||
}
|
||||
}}
|
||||
showPreviewButton={!!this.props.previewLauncher}
|
||||
@@ -1069,7 +1071,7 @@ class MainFrame extends React.Component<Props, State> {
|
||||
<StartPage
|
||||
project={this.state.currentProject}
|
||||
setToolbar={this.setEditorToolbar}
|
||||
canOpen={!!this.props.onChooseProject}
|
||||
canOpen={!!this.props.projectsStorage.onOpenWithPicker}
|
||||
onOpen={this.chooseProject}
|
||||
onCreate={() => this.openCreateDialog()}
|
||||
onOpenProjectManager={() => this.openProjectManager()}
|
||||
@@ -1191,10 +1193,11 @@ class MainFrame extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
chooseProject = () => {
|
||||
if (!this.props.onChooseProject) return;
|
||||
const { projectsStorage } = this.props;
|
||||
if (!projectsStorage.onOpenWithPicker) return;
|
||||
|
||||
this.props
|
||||
.onChooseProject()
|
||||
projectsStorage
|
||||
.onOpenWithPicker()
|
||||
.then(filepath => {
|
||||
if (!filepath) return;
|
||||
|
||||
@@ -1210,14 +1213,14 @@ class MainFrame extends React.Component<Props, State> {
|
||||
|
||||
const { currentProject } = this.state;
|
||||
if (!currentProject) return;
|
||||
const { i18n } = this.props;
|
||||
const { i18n, projectsStorage } = this.props;
|
||||
|
||||
if (this.props.saveDialog) {
|
||||
this._openSaveDialog();
|
||||
} else if (this.props.onSaveProject) {
|
||||
this.props.onSaveProject(currentProject).then(
|
||||
() => {
|
||||
this._showSnackMessage(i18n._(t`Project properly saved`));
|
||||
if (projectsStorage.onSaveProject) {
|
||||
projectsStorage.onSaveProject(currentProject).then(
|
||||
(saveDone: boolean) => {
|
||||
if (saveDone) {
|
||||
this._showSnackMessage(i18n._(t`Project properly saved`));
|
||||
}
|
||||
},
|
||||
err => {
|
||||
showErrorBox(
|
||||
@@ -1236,12 +1239,10 @@ class MainFrame extends React.Component<Props, State> {
|
||||
|
||||
const { currentProject } = this.state;
|
||||
if (!currentProject) return;
|
||||
const { i18n } = this.props;
|
||||
const { i18n, projectsStorage } = this.props;
|
||||
|
||||
if (this.props.saveDialog) {
|
||||
this._openSaveDialog();
|
||||
} else if (this.props.onSaveProjectAs) {
|
||||
this.props.onSaveProjectAs(currentProject).then(
|
||||
if (projectsStorage.onSaveProjectAs) {
|
||||
projectsStorage.onSaveProjectAs(currentProject).then(
|
||||
saveDone => {
|
||||
if (saveDone)
|
||||
this._showSnackMessage(i18n._(t`Project properly saved`));
|
||||
@@ -1300,12 +1301,6 @@ class MainFrame extends React.Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
_openSaveDialog = (open: boolean = true) => {
|
||||
this.setState({
|
||||
saveDialogOpen: open,
|
||||
});
|
||||
};
|
||||
|
||||
_openGenericDialog = (open: boolean = true) => {
|
||||
this.setState({
|
||||
genericDialogOpen: open,
|
||||
@@ -1476,7 +1471,6 @@ class MainFrame extends React.Component<Props, State> {
|
||||
renderExportDialog,
|
||||
createDialog,
|
||||
introDialog,
|
||||
saveDialog,
|
||||
resourceSources,
|
||||
authentification,
|
||||
previewLauncher,
|
||||
@@ -1639,12 +1633,6 @@ class MainFrame extends React.Component<Props, State> {
|
||||
open: this.state.introDialogOpen,
|
||||
onClose: () => this._openIntroDialog(false),
|
||||
})}
|
||||
{!!saveDialog &&
|
||||
React.cloneElement(saveDialog, {
|
||||
project: this.state.currentProject,
|
||||
open: this.state.saveDialogOpen,
|
||||
onClose: () => this._openSaveDialog(false),
|
||||
})}
|
||||
{!!this.state.currentProject &&
|
||||
this.state.platformSpecificAssetsDialogOpen && (
|
||||
<PlatformSpecificAssetsDialog
|
||||
|
@@ -1,220 +0,0 @@
|
||||
// This file is generated by update-fixtures-from-resources-examples.js script
|
||||
|
||||
import exampleFile0 from '../fixtures/admob/admob.json';
|
||||
import exampleFile1 from '../fixtures/advanced-shape-based-painter/advanced-shape-based-painter.json';
|
||||
import exampleFile2 from '../fixtures/animation-speed-scale/animation-speed-scale.json';
|
||||
import exampleFile3 from '../fixtures/asteroids/asteroids.json';
|
||||
import exampleFile4 from '../fixtures/basic-ai-with-pathfinding/basic-ai-with-pathfinding.json';
|
||||
import exampleFile5 from '../fixtures/basic-artificial-intelligence/basic-artificial-intelligence.json';
|
||||
import exampleFile6 from '../fixtures/basic-topdown-car-driving/basic-topdown-car-driving.json';
|
||||
import exampleFile7 from '../fixtures/betabox-basics-learning-experience/betabox-basics-learning-experience.json';
|
||||
import exampleFile8 from '../fixtures/bomb-the-crate/bomb-the-crate.json';
|
||||
import exampleFile9 from '../fixtures/bouncing-ball-and-rope/bouncing-ball-and-rope.json';
|
||||
import exampleFile10 from '../fixtures/breakout/breakout.json';
|
||||
import exampleFile11 from '../fixtures/buttons/buttons.json';
|
||||
import exampleFile12 from '../fixtures/car-physics/car-physics.json';
|
||||
import exampleFile13 from '../fixtures/center-object-within-another/center-object-within-another.json';
|
||||
import exampleFile14 from '../fixtures/change-position-of-object/change-position-of-object.json';
|
||||
import exampleFile15 from '../fixtures/change-scale-of-sprites/change-scale-of-sprites.json';
|
||||
import exampleFile16 from '../fixtures/change-sprite-animation/change-sprite-animation.json';
|
||||
import exampleFile17 from '../fixtures/change-sprite-color/change-sprite-color.json';
|
||||
import exampleFile18 from '../fixtures/character-selection/character-selection.json';
|
||||
import exampleFile19 from '../fixtures/create-object-with-mouseclick/create-object-with-mouseclick.json';
|
||||
import exampleFile20 from '../fixtures/custom-font/custom-font.json';
|
||||
import exampleFile21 from '../fixtures/custom-mouse-pointer/custom-mouse-pointer.json';
|
||||
import exampleFile22 from '../fixtures/customize-keys-with-lastpressedkey/customize-keys-with-lastpressedkey.json';
|
||||
import exampleFile23 from '../fixtures/device-orientation-ballgame/device-orientation-ballgame.json';
|
||||
import exampleFile24 from '../fixtures/device-orientation-compass/device-orientation-compass.json';
|
||||
import exampleFile25 from '../fixtures/device-vibration/device-vibration.json';
|
||||
import exampleFile26 from '../fixtures/dialogue-tree-with-yarn/dialogue-tree-with-yarn.json';
|
||||
import exampleFile27 from '../fixtures/downhill-bike-physics-demo/downhill-bike-physics-demo.json';
|
||||
import exampleFile28 from '../fixtures/drag-camera-with-mouse/drag-camera-with-mouse.json';
|
||||
import exampleFile29 from '../fixtures/drop-collect-items-from-storage/drop-collect-items-from-storage.json';
|
||||
import exampleFile30 from '../fixtures/endless-up-runner/endless-up-runner.json';
|
||||
import exampleFile31 from '../fixtures/exit-app/exit-app.json';
|
||||
import exampleFile32 from '../fixtures/facebook-instant-game/facebook-instant-game.json';
|
||||
import exampleFile33 from '../fixtures/filesystem-create-directory/filesystem-create-directory.json';
|
||||
import exampleFile34 from '../fixtures/find-diagonals/find-diagonals.json';
|
||||
import exampleFile35 from '../fixtures/geodash/geodash.json';
|
||||
import exampleFile36 from '../fixtures/health-bar/health-bar.json';
|
||||
import exampleFile37 from '../fixtures/infinite-scrolling-background/infinite-scrolling-background.json';
|
||||
import exampleFile38 from '../fixtures/inventory-system/inventory-system.json';
|
||||
import exampleFile39 from '../fixtures/isometric-game/isometric-game.json';
|
||||
import exampleFile40 from '../fixtures/javascript-blocks-in-platformer/javascript-blocks-in-platformer.json';
|
||||
import exampleFile41 from '../fixtures/keyboard-practice/keyboard-practice.json';
|
||||
import exampleFile42 from '../fixtures/level-editor/level-editor.json';
|
||||
import exampleFile43 from '../fixtures/load-image-from-url/load-image-from-url.json';
|
||||
import exampleFile44 from '../fixtures/magnet/magnet.json';
|
||||
import exampleFile45 from '../fixtures/manipulate-text-object/manipulate-text-object.json';
|
||||
import exampleFile46 from '../fixtures/menu-with-functions-and-text-effects/menu-with-functions-and-text-effects.json';
|
||||
import exampleFile47 from '../fixtures/move-camera-to-position/move-camera-to-position.json';
|
||||
import exampleFile48 from '../fixtures/move-object-back-and-forth/move-object-back-and-forth.json';
|
||||
import exampleFile49 from '../fixtures/move-object-in-circle/move-object-in-circle.json';
|
||||
import exampleFile50 from '../fixtures/move-object-toward-position/move-object-toward-position.json';
|
||||
import exampleFile51 from '../fixtures/move-object-with-mouse-joint/move-object-with-mouse-joint.json';
|
||||
import exampleFile52 from '../fixtures/move-object-with-physics/move-object-with-physics.json';
|
||||
import exampleFile53 from '../fixtures/multiplayer-platformer-with-gamepads/multiplayer-platformer-with-gamepads.json';
|
||||
import exampleFile54 from '../fixtures/multitouch/multitouch.json';
|
||||
import exampleFile55 from '../fixtures/object-gravity/object-gravity.json';
|
||||
import exampleFile56 from '../fixtures/object-selection/object-selection.json';
|
||||
import exampleFile57 from '../fixtures/objects-timers/objects-timers.json';
|
||||
import exampleFile58 from '../fixtures/open-url-in-browser/open-url-in-browser.json';
|
||||
import exampleFile59 from '../fixtures/pairs/pairs.json';
|
||||
import exampleFile60 from '../fixtures/parallax/parallax.json';
|
||||
import exampleFile61 from '../fixtures/parallax-scrolling/parallax-scrolling.json';
|
||||
import exampleFile62 from '../fixtures/parse-json-from-api/parse-json-from-api.json';
|
||||
import exampleFile63 from '../fixtures/parse-json-string/parse-json-string.json';
|
||||
import exampleFile64 from '../fixtures/particles-explosions/particles-explosions.json';
|
||||
import exampleFile65 from '../fixtures/particles-various-effects/particles-various-effects.json';
|
||||
import exampleFile66 from '../fixtures/pathfinding/pathfinding.json';
|
||||
import exampleFile67 from '../fixtures/pathfinding-basics/pathfinding-basics.json';
|
||||
import exampleFile68 from '../fixtures/physics/physics.json';
|
||||
import exampleFile69 from '../fixtures/physics-joints-demo/physics-joints-demo.json';
|
||||
import exampleFile70 from '../fixtures/physics-joints-settings-demo/physics-joints-settings-demo.json';
|
||||
import exampleFile71 from '../fixtures/pin-object-to-another/pin-object-to-another.json';
|
||||
import exampleFile72 from '../fixtures/pin-object-to-another-multiple-parents/pin-object-to-another-multiple-parents.json';
|
||||
import exampleFile73 from '../fixtures/pixel-perfect-platform-game/pixel-perfect-platform-game.json';
|
||||
import exampleFile74 from '../fixtures/plane-and-clouds/plane-and-clouds.json';
|
||||
import exampleFile75 from '../fixtures/platformer/platformer.json';
|
||||
import exampleFile76 from '../fixtures/platformer-double-jump/platformer-double-jump.json';
|
||||
import exampleFile77 from '../fixtures/play-music-on-mobile/play-music-on-mobile.json';
|
||||
import exampleFile78 from '../fixtures/play-stop-sprite-animation/play-stop-sprite-animation.json';
|
||||
import exampleFile79 from '../fixtures/racing-game/racing-game.json';
|
||||
import exampleFile80 from '../fixtures/ragdoll/ragdoll.json';
|
||||
import exampleFile81 from '../fixtures/rain/rain.json';
|
||||
import exampleFile82 from '../fixtures/random-color-picker/random-color-picker.json';
|
||||
import exampleFile83 from '../fixtures/rotate-toward-mouse/rotate-toward-mouse.json';
|
||||
import exampleFile84 from '../fixtures/rotate-toward-position/rotate-toward-position.json';
|
||||
import exampleFile85 from '../fixtures/rotate-with-keypress/rotate-with-keypress.json';
|
||||
import exampleFile86 from '../fixtures/save-load/save-load.json';
|
||||
import exampleFile87 from '../fixtures/screen-shake/screen-shake.json';
|
||||
import exampleFile88 from '../fixtures/shoot-bullet-in-parabola/shoot-bullet-in-parabola.json';
|
||||
import exampleFile89 from '../fixtures/shoot-bullets/shoot-bullets.json';
|
||||
import exampleFile90 from '../fixtures/shooting-bullets-explanation/shooting-bullets-explanation.json';
|
||||
import exampleFile91 from '../fixtures/simple-space-shooter/simple-space-shooter.json';
|
||||
import exampleFile92 from '../fixtures/skeletal-animation-demo/skeletal-animation-demo.json';
|
||||
import exampleFile93 from '../fixtures/snap-object-to-grid/snap-object-to-grid.json';
|
||||
import exampleFile94 from '../fixtures/space-invaders/space-invaders.json';
|
||||
import exampleFile95 from '../fixtures/space-shooter/space-shooter.json';
|
||||
import exampleFile96 from '../fixtures/splash-screen/splash-screen.json';
|
||||
import exampleFile97 from '../fixtures/sprite-fade-in-out/sprite-fade-in-out.json';
|
||||
import exampleFile98 from '../fixtures/take-screenshot/take-screenshot.json';
|
||||
import exampleFile99 from '../fixtures/text-entry-object/text-entry-object.json';
|
||||
import exampleFile100 from '../fixtures/text-fade-in-out/text-fade-in-out.json';
|
||||
import exampleFile101 from '../fixtures/text-to-speech/text-to-speech.json';
|
||||
import exampleFile102 from '../fixtures/toggle-music-play-sound/toggle-music-play-sound.json';
|
||||
import exampleFile103 from '../fixtures/type-on-text-effect/type-on-text-effect.json';
|
||||
import exampleFile104 from '../fixtures/video-player/video-player.json';
|
||||
import exampleFile105 from '../fixtures/z-depth/z-depth.json';
|
||||
import exampleFile106 from '../fixtures/zombie-laser/zombie-laser.json';
|
||||
|
||||
// prettier-ignore
|
||||
export default {
|
||||
'example://admob': exampleFile0,
|
||||
'example://advanced-shape-based-painter': exampleFile1,
|
||||
'example://animation-speed-scale': exampleFile2,
|
||||
'example://asteroids': exampleFile3,
|
||||
'example://basic-ai-with-pathfinding': exampleFile4,
|
||||
'example://basic-artificial-intelligence': exampleFile5,
|
||||
'example://basic-topdown-car-driving': exampleFile6,
|
||||
'example://betabox-basics-learning-experience': exampleFile7,
|
||||
'example://bomb-the-crate': exampleFile8,
|
||||
'example://bouncing-ball-and-rope': exampleFile9,
|
||||
'example://breakout': exampleFile10,
|
||||
'example://buttons': exampleFile11,
|
||||
'example://car-physics': exampleFile12,
|
||||
'example://center-object-within-another': exampleFile13,
|
||||
'example://change-position-of-object': exampleFile14,
|
||||
'example://change-scale-of-sprites': exampleFile15,
|
||||
'example://change-sprite-animation': exampleFile16,
|
||||
'example://change-sprite-color': exampleFile17,
|
||||
'example://character-selection': exampleFile18,
|
||||
'example://create-object-with-mouseclick': exampleFile19,
|
||||
'example://custom-font': exampleFile20,
|
||||
'example://custom-mouse-pointer': exampleFile21,
|
||||
'example://customize-keys-with-lastpressedkey': exampleFile22,
|
||||
'example://device-orientation-ballgame': exampleFile23,
|
||||
'example://device-orientation-compass': exampleFile24,
|
||||
'example://device-vibration': exampleFile25,
|
||||
'example://dialogue-tree-with-yarn': exampleFile26,
|
||||
'example://downhill-bike-physics-demo': exampleFile27,
|
||||
'example://drag-camera-with-mouse': exampleFile28,
|
||||
'example://drop-collect-items-from-storage': exampleFile29,
|
||||
'example://endless-up-runner': exampleFile30,
|
||||
'example://exit-app': exampleFile31,
|
||||
'example://facebook-instant-game': exampleFile32,
|
||||
'example://filesystem-create-directory': exampleFile33,
|
||||
'example://find-diagonals': exampleFile34,
|
||||
'example://geodash': exampleFile35,
|
||||
'example://health-bar': exampleFile36,
|
||||
'example://infinite-scrolling-background': exampleFile37,
|
||||
'example://inventory-system': exampleFile38,
|
||||
'example://isometric-game': exampleFile39,
|
||||
'example://javascript-blocks-in-platformer': exampleFile40,
|
||||
'example://keyboard-practice': exampleFile41,
|
||||
'example://level-editor': exampleFile42,
|
||||
'example://load-image-from-url': exampleFile43,
|
||||
'example://magnet': exampleFile44,
|
||||
'example://manipulate-text-object': exampleFile45,
|
||||
'example://menu-with-functions-and-text-effects': exampleFile46,
|
||||
'example://move-camera-to-position': exampleFile47,
|
||||
'example://move-object-back-and-forth': exampleFile48,
|
||||
'example://move-object-in-circle': exampleFile49,
|
||||
'example://move-object-toward-position': exampleFile50,
|
||||
'example://move-object-with-mouse-joint': exampleFile51,
|
||||
'example://move-object-with-physics': exampleFile52,
|
||||
'example://multiplayer-platformer-with-gamepads': exampleFile53,
|
||||
'example://multitouch': exampleFile54,
|
||||
'example://object-gravity': exampleFile55,
|
||||
'example://object-selection': exampleFile56,
|
||||
'example://objects-timers': exampleFile57,
|
||||
'example://open-url-in-browser': exampleFile58,
|
||||
'example://pairs': exampleFile59,
|
||||
'example://parallax': exampleFile60,
|
||||
'example://parallax-scrolling': exampleFile61,
|
||||
'example://parse-json-from-api': exampleFile62,
|
||||
'example://parse-json-string': exampleFile63,
|
||||
'example://particles-explosions': exampleFile64,
|
||||
'example://particles-various-effects': exampleFile65,
|
||||
'example://pathfinding': exampleFile66,
|
||||
'example://pathfinding-basics': exampleFile67,
|
||||
'example://physics': exampleFile68,
|
||||
'example://physics-joints-demo': exampleFile69,
|
||||
'example://physics-joints-settings-demo': exampleFile70,
|
||||
'example://pin-object-to-another': exampleFile71,
|
||||
'example://pin-object-to-another-multiple-parents': exampleFile72,
|
||||
'example://pixel-perfect-platform-game': exampleFile73,
|
||||
'example://plane-and-clouds': exampleFile74,
|
||||
'example://platformer': exampleFile75,
|
||||
'example://platformer-double-jump': exampleFile76,
|
||||
'example://play-music-on-mobile': exampleFile77,
|
||||
'example://play-stop-sprite-animation': exampleFile78,
|
||||
'example://racing-game': exampleFile79,
|
||||
'example://ragdoll': exampleFile80,
|
||||
'example://rain': exampleFile81,
|
||||
'example://random-color-picker': exampleFile82,
|
||||
'example://rotate-toward-mouse': exampleFile83,
|
||||
'example://rotate-toward-position': exampleFile84,
|
||||
'example://rotate-with-keypress': exampleFile85,
|
||||
'example://save-load': exampleFile86,
|
||||
'example://screen-shake': exampleFile87,
|
||||
'example://shoot-bullet-in-parabola': exampleFile88,
|
||||
'example://shoot-bullets': exampleFile89,
|
||||
'example://shooting-bullets-explanation': exampleFile90,
|
||||
'example://simple-space-shooter': exampleFile91,
|
||||
'example://skeletal-animation-demo': exampleFile92,
|
||||
'example://snap-object-to-grid': exampleFile93,
|
||||
'example://space-invaders': exampleFile94,
|
||||
'example://space-shooter': exampleFile95,
|
||||
'example://splash-screen': exampleFile96,
|
||||
'example://sprite-fade-in-out': exampleFile97,
|
||||
'example://take-screenshot': exampleFile98,
|
||||
'example://text-entry-object': exampleFile99,
|
||||
'example://text-fade-in-out': exampleFile100,
|
||||
'example://text-to-speech': exampleFile101,
|
||||
'example://toggle-music-play-sound': exampleFile102,
|
||||
'example://type-on-text-effect': exampleFile103,
|
||||
'example://video-player': exampleFile104,
|
||||
'example://z-depth': exampleFile105,
|
||||
'example://zombie-laser': exampleFile106,
|
||||
};
|
@@ -1,10 +0,0 @@
|
||||
import browserExampleFiles from './BrowserExampleFiles';
|
||||
|
||||
export default class BrowserProjectOpener {
|
||||
static readInternalFile(url) {
|
||||
if (browserExampleFiles[url])
|
||||
return Promise.resolve(browserExampleFiles[url]);
|
||||
|
||||
return Promise.reject(`Unknown built-in game with URL ${url}`);
|
||||
}
|
||||
}
|
@@ -1,15 +1,21 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
import React, { Component } from 'react';
|
||||
import Dialog from '../UI/Dialog';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
import { Column, Line } from '../UI/Grid';
|
||||
import Window from '../Utils/Window';
|
||||
import { serializeToJSObject } from '../Utils/Serializer';
|
||||
import { showErrorBox } from '../UI/Messages/MessageBox';
|
||||
import Text from '../UI/Text';
|
||||
import * as React from 'react';
|
||||
import Dialog from '../../UI/Dialog';
|
||||
import FlatButton from '../../UI/FlatButton';
|
||||
import RaisedButton from '../../UI/RaisedButton';
|
||||
import { Column, Line } from '../../UI/Grid';
|
||||
import Window from '../../Utils/Window';
|
||||
import { serializeToJSObject } from '../../Utils/Serializer';
|
||||
import { showErrorBox } from '../../UI/Messages/MessageBox';
|
||||
import Text from '../../UI/Text';
|
||||
|
||||
export default class BrowserSaveDialog extends Component {
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
onDone: () => void,
|
||||
|};
|
||||
|
||||
export default class DownloadSaveDialog extends React.Component<Props> {
|
||||
_download = () => {
|
||||
let content = '';
|
||||
try {
|
||||
@@ -24,14 +30,16 @@ export default class BrowserSaveDialog extends Component {
|
||||
downloadLink.href = uri;
|
||||
downloadLink.download = 'game.json';
|
||||
|
||||
document.body.appendChild(downloadLink);
|
||||
const { body } = document;
|
||||
if (!body) return;
|
||||
|
||||
body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
body.removeChild(downloadLink);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { open, onClose, project } = this.props;
|
||||
if (!open || !project) return null;
|
||||
const { onDone } = this.props;
|
||||
|
||||
const actions = [
|
||||
<FlatButton
|
||||
@@ -44,12 +52,12 @@ export default class BrowserSaveDialog extends Component {
|
||||
key="close"
|
||||
label={<Trans>Close</Trans>}
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
onClick={onDone}
|
||||
/>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog actions={actions} open={open} onRequestClose={onClose}>
|
||||
<Dialog actions={actions} open onRequestClose={onDone}>
|
||||
<Column noMargin>
|
||||
<Line>
|
||||
<Text>
|
@@ -0,0 +1,221 @@
|
||||
// @flow
|
||||
// This file is generated by update-fixtures-from-resources-examples.js script
|
||||
|
||||
import exampleFile0 from '../../fixtures/admob/admob.json';
|
||||
import exampleFile1 from '../../fixtures/advanced-shape-based-painter/advanced-shape-based-painter.json';
|
||||
import exampleFile2 from '../../fixtures/animation-speed-scale/animation-speed-scale.json';
|
||||
import exampleFile3 from '../../fixtures/asteroids/asteroids.json';
|
||||
import exampleFile4 from '../../fixtures/basic-ai-with-pathfinding/basic-ai-with-pathfinding.json';
|
||||
import exampleFile5 from '../../fixtures/basic-artificial-intelligence/basic-artificial-intelligence.json';
|
||||
import exampleFile6 from '../../fixtures/basic-topdown-car-driving/basic-topdown-car-driving.json';
|
||||
import exampleFile7 from '../../fixtures/betabox-basics-learning-experience/betabox-basics-learning-experience.json';
|
||||
import exampleFile8 from '../../fixtures/bomb-the-crate/bomb-the-crate.json';
|
||||
import exampleFile9 from '../../fixtures/bouncing-ball-and-rope/bouncing-ball-and-rope.json';
|
||||
import exampleFile10 from '../../fixtures/breakout/breakout.json';
|
||||
import exampleFile11 from '../../fixtures/buttons/buttons.json';
|
||||
import exampleFile12 from '../../fixtures/car-physics/car-physics.json';
|
||||
import exampleFile13 from '../../fixtures/center-object-within-another/center-object-within-another.json';
|
||||
import exampleFile14 from '../../fixtures/change-position-of-object/change-position-of-object.json';
|
||||
import exampleFile15 from '../../fixtures/change-scale-of-sprites/change-scale-of-sprites.json';
|
||||
import exampleFile16 from '../../fixtures/change-sprite-animation/change-sprite-animation.json';
|
||||
import exampleFile17 from '../../fixtures/change-sprite-color/change-sprite-color.json';
|
||||
import exampleFile18 from '../../fixtures/character-selection/character-selection.json';
|
||||
import exampleFile19 from '../../fixtures/create-object-with-mouseclick/create-object-with-mouseclick.json';
|
||||
import exampleFile20 from '../../fixtures/custom-font/custom-font.json';
|
||||
import exampleFile21 from '../../fixtures/custom-mouse-pointer/custom-mouse-pointer.json';
|
||||
import exampleFile22 from '../../fixtures/customize-keys-with-lastpressedkey/customize-keys-with-lastpressedkey.json';
|
||||
import exampleFile23 from '../../fixtures/device-orientation-ballgame/device-orientation-ballgame.json';
|
||||
import exampleFile24 from '../../fixtures/device-orientation-compass/device-orientation-compass.json';
|
||||
import exampleFile25 from '../../fixtures/device-vibration/device-vibration.json';
|
||||
import exampleFile26 from '../../fixtures/dialogue-tree-with-yarn/dialogue-tree-with-yarn.json';
|
||||
import exampleFile27 from '../../fixtures/downhill-bike-physics-demo/downhill-bike-physics-demo.json';
|
||||
import exampleFile28 from '../../fixtures/drag-camera-with-mouse/drag-camera-with-mouse.json';
|
||||
import exampleFile29 from '../../fixtures/drop-collect-items-from-storage/drop-collect-items-from-storage.json';
|
||||
import exampleFile30 from '../../fixtures/endless-up-runner/endless-up-runner.json';
|
||||
import exampleFile31 from '../../fixtures/exit-app/exit-app.json';
|
||||
import exampleFile32 from '../../fixtures/facebook-instant-game/facebook-instant-game.json';
|
||||
import exampleFile33 from '../../fixtures/filesystem-create-directory/filesystem-create-directory.json';
|
||||
import exampleFile34 from '../../fixtures/find-diagonals/find-diagonals.json';
|
||||
import exampleFile35 from '../../fixtures/geodash/geodash.json';
|
||||
import exampleFile36 from '../../fixtures/health-bar/health-bar.json';
|
||||
import exampleFile37 from '../../fixtures/infinite-scrolling-background/infinite-scrolling-background.json';
|
||||
import exampleFile38 from '../../fixtures/inventory-system/inventory-system.json';
|
||||
import exampleFile39 from '../../fixtures/isometric-game/isometric-game.json';
|
||||
import exampleFile40 from '../../fixtures/javascript-blocks-in-platformer/javascript-blocks-in-platformer.json';
|
||||
import exampleFile41 from '../../fixtures/keyboard-practice/keyboard-practice.json';
|
||||
import exampleFile42 from '../../fixtures/level-editor/level-editor.json';
|
||||
import exampleFile43 from '../../fixtures/load-image-from-url/load-image-from-url.json';
|
||||
import exampleFile44 from '../../fixtures/magnet/magnet.json';
|
||||
import exampleFile45 from '../../fixtures/manipulate-text-object/manipulate-text-object.json';
|
||||
import exampleFile46 from '../../fixtures/menu-with-functions-and-text-effects/menu-with-functions-and-text-effects.json';
|
||||
import exampleFile47 from '../../fixtures/move-camera-to-position/move-camera-to-position.json';
|
||||
import exampleFile48 from '../../fixtures/move-object-back-and-forth/move-object-back-and-forth.json';
|
||||
import exampleFile49 from '../../fixtures/move-object-in-circle/move-object-in-circle.json';
|
||||
import exampleFile50 from '../../fixtures/move-object-toward-position/move-object-toward-position.json';
|
||||
import exampleFile51 from '../../fixtures/move-object-with-mouse-joint/move-object-with-mouse-joint.json';
|
||||
import exampleFile52 from '../../fixtures/move-object-with-physics/move-object-with-physics.json';
|
||||
import exampleFile53 from '../../fixtures/multiplayer-platformer-with-gamepads/multiplayer-platformer-with-gamepads.json';
|
||||
import exampleFile54 from '../../fixtures/multitouch/multitouch.json';
|
||||
import exampleFile55 from '../../fixtures/object-gravity/object-gravity.json';
|
||||
import exampleFile56 from '../../fixtures/object-selection/object-selection.json';
|
||||
import exampleFile57 from '../../fixtures/objects-timers/objects-timers.json';
|
||||
import exampleFile58 from '../../fixtures/open-url-in-browser/open-url-in-browser.json';
|
||||
import exampleFile59 from '../../fixtures/pairs/pairs.json';
|
||||
import exampleFile60 from '../../fixtures/parallax/parallax.json';
|
||||
import exampleFile61 from '../../fixtures/parallax-scrolling/parallax-scrolling.json';
|
||||
import exampleFile62 from '../../fixtures/parse-json-from-api/parse-json-from-api.json';
|
||||
import exampleFile63 from '../../fixtures/parse-json-string/parse-json-string.json';
|
||||
import exampleFile64 from '../../fixtures/particles-explosions/particles-explosions.json';
|
||||
import exampleFile65 from '../../fixtures/particles-various-effects/particles-various-effects.json';
|
||||
import exampleFile66 from '../../fixtures/pathfinding/pathfinding.json';
|
||||
import exampleFile67 from '../../fixtures/pathfinding-basics/pathfinding-basics.json';
|
||||
import exampleFile68 from '../../fixtures/physics/physics.json';
|
||||
import exampleFile69 from '../../fixtures/physics-joints-demo/physics-joints-demo.json';
|
||||
import exampleFile70 from '../../fixtures/physics-joints-settings-demo/physics-joints-settings-demo.json';
|
||||
import exampleFile71 from '../../fixtures/pin-object-to-another/pin-object-to-another.json';
|
||||
import exampleFile72 from '../../fixtures/pin-object-to-another-multiple-parents/pin-object-to-another-multiple-parents.json';
|
||||
import exampleFile73 from '../../fixtures/pixel-perfect-platform-game/pixel-perfect-platform-game.json';
|
||||
import exampleFile74 from '../../fixtures/plane-and-clouds/plane-and-clouds.json';
|
||||
import exampleFile75 from '../../fixtures/platformer/platformer.json';
|
||||
import exampleFile76 from '../../fixtures/platformer-double-jump/platformer-double-jump.json';
|
||||
import exampleFile77 from '../../fixtures/play-music-on-mobile/play-music-on-mobile.json';
|
||||
import exampleFile78 from '../../fixtures/play-stop-sprite-animation/play-stop-sprite-animation.json';
|
||||
import exampleFile79 from '../../fixtures/racing-game/racing-game.json';
|
||||
import exampleFile80 from '../../fixtures/ragdoll/ragdoll.json';
|
||||
import exampleFile81 from '../../fixtures/rain/rain.json';
|
||||
import exampleFile82 from '../../fixtures/random-color-picker/random-color-picker.json';
|
||||
import exampleFile83 from '../../fixtures/rotate-toward-mouse/rotate-toward-mouse.json';
|
||||
import exampleFile84 from '../../fixtures/rotate-toward-position/rotate-toward-position.json';
|
||||
import exampleFile85 from '../../fixtures/rotate-with-keypress/rotate-with-keypress.json';
|
||||
import exampleFile86 from '../../fixtures/save-load/save-load.json';
|
||||
import exampleFile87 from '../../fixtures/screen-shake/screen-shake.json';
|
||||
import exampleFile88 from '../../fixtures/shoot-bullet-in-parabola/shoot-bullet-in-parabola.json';
|
||||
import exampleFile89 from '../../fixtures/shoot-bullets/shoot-bullets.json';
|
||||
import exampleFile90 from '../../fixtures/shooting-bullets-explanation/shooting-bullets-explanation.json';
|
||||
import exampleFile91 from '../../fixtures/simple-space-shooter/simple-space-shooter.json';
|
||||
import exampleFile92 from '../../fixtures/skeletal-animation-demo/skeletal-animation-demo.json';
|
||||
import exampleFile93 from '../../fixtures/snap-object-to-grid/snap-object-to-grid.json';
|
||||
import exampleFile94 from '../../fixtures/space-invaders/space-invaders.json';
|
||||
import exampleFile95 from '../../fixtures/space-shooter/space-shooter.json';
|
||||
import exampleFile96 from '../../fixtures/splash-screen/splash-screen.json';
|
||||
import exampleFile97 from '../../fixtures/sprite-fade-in-out/sprite-fade-in-out.json';
|
||||
import exampleFile98 from '../../fixtures/take-screenshot/take-screenshot.json';
|
||||
import exampleFile99 from '../../fixtures/text-entry-object/text-entry-object.json';
|
||||
import exampleFile100 from '../../fixtures/text-fade-in-out/text-fade-in-out.json';
|
||||
import exampleFile101 from '../../fixtures/text-to-speech/text-to-speech.json';
|
||||
import exampleFile102 from '../../fixtures/toggle-music-play-sound/toggle-music-play-sound.json';
|
||||
import exampleFile103 from '../../fixtures/type-on-text-effect/type-on-text-effect.json';
|
||||
import exampleFile104 from '../../fixtures/video-player/video-player.json';
|
||||
import exampleFile105 from '../../fixtures/z-depth/z-depth.json';
|
||||
import exampleFile106 from '../../fixtures/zombie-laser/zombie-laser.json';
|
||||
|
||||
// prettier-ignore
|
||||
export default {
|
||||
'example://admob': exampleFile0,
|
||||
'example://advanced-shape-based-painter': exampleFile1,
|
||||
'example://animation-speed-scale': exampleFile2,
|
||||
'example://asteroids': exampleFile3,
|
||||
'example://basic-ai-with-pathfinding': exampleFile4,
|
||||
'example://basic-artificial-intelligence': exampleFile5,
|
||||
'example://basic-topdown-car-driving': exampleFile6,
|
||||
'example://betabox-basics-learning-experience': exampleFile7,
|
||||
'example://bomb-the-crate': exampleFile8,
|
||||
'example://bouncing-ball-and-rope': exampleFile9,
|
||||
'example://breakout': exampleFile10,
|
||||
'example://buttons': exampleFile11,
|
||||
'example://car-physics': exampleFile12,
|
||||
'example://center-object-within-another': exampleFile13,
|
||||
'example://change-position-of-object': exampleFile14,
|
||||
'example://change-scale-of-sprites': exampleFile15,
|
||||
'example://change-sprite-animation': exampleFile16,
|
||||
'example://change-sprite-color': exampleFile17,
|
||||
'example://character-selection': exampleFile18,
|
||||
'example://create-object-with-mouseclick': exampleFile19,
|
||||
'example://custom-font': exampleFile20,
|
||||
'example://custom-mouse-pointer': exampleFile21,
|
||||
'example://customize-keys-with-lastpressedkey': exampleFile22,
|
||||
'example://device-orientation-ballgame': exampleFile23,
|
||||
'example://device-orientation-compass': exampleFile24,
|
||||
'example://device-vibration': exampleFile25,
|
||||
'example://dialogue-tree-with-yarn': exampleFile26,
|
||||
'example://downhill-bike-physics-demo': exampleFile27,
|
||||
'example://drag-camera-with-mouse': exampleFile28,
|
||||
'example://drop-collect-items-from-storage': exampleFile29,
|
||||
'example://endless-up-runner': exampleFile30,
|
||||
'example://exit-app': exampleFile31,
|
||||
'example://facebook-instant-game': exampleFile32,
|
||||
'example://filesystem-create-directory': exampleFile33,
|
||||
'example://find-diagonals': exampleFile34,
|
||||
'example://geodash': exampleFile35,
|
||||
'example://health-bar': exampleFile36,
|
||||
'example://infinite-scrolling-background': exampleFile37,
|
||||
'example://inventory-system': exampleFile38,
|
||||
'example://isometric-game': exampleFile39,
|
||||
'example://javascript-blocks-in-platformer': exampleFile40,
|
||||
'example://keyboard-practice': exampleFile41,
|
||||
'example://level-editor': exampleFile42,
|
||||
'example://load-image-from-url': exampleFile43,
|
||||
'example://magnet': exampleFile44,
|
||||
'example://manipulate-text-object': exampleFile45,
|
||||
'example://menu-with-functions-and-text-effects': exampleFile46,
|
||||
'example://move-camera-to-position': exampleFile47,
|
||||
'example://move-object-back-and-forth': exampleFile48,
|
||||
'example://move-object-in-circle': exampleFile49,
|
||||
'example://move-object-toward-position': exampleFile50,
|
||||
'example://move-object-with-mouse-joint': exampleFile51,
|
||||
'example://move-object-with-physics': exampleFile52,
|
||||
'example://multiplayer-platformer-with-gamepads': exampleFile53,
|
||||
'example://multitouch': exampleFile54,
|
||||
'example://object-gravity': exampleFile55,
|
||||
'example://object-selection': exampleFile56,
|
||||
'example://objects-timers': exampleFile57,
|
||||
'example://open-url-in-browser': exampleFile58,
|
||||
'example://pairs': exampleFile59,
|
||||
'example://parallax': exampleFile60,
|
||||
'example://parallax-scrolling': exampleFile61,
|
||||
'example://parse-json-from-api': exampleFile62,
|
||||
'example://parse-json-string': exampleFile63,
|
||||
'example://particles-explosions': exampleFile64,
|
||||
'example://particles-various-effects': exampleFile65,
|
||||
'example://pathfinding': exampleFile66,
|
||||
'example://pathfinding-basics': exampleFile67,
|
||||
'example://physics': exampleFile68,
|
||||
'example://physics-joints-demo': exampleFile69,
|
||||
'example://physics-joints-settings-demo': exampleFile70,
|
||||
'example://pin-object-to-another': exampleFile71,
|
||||
'example://pin-object-to-another-multiple-parents': exampleFile72,
|
||||
'example://pixel-perfect-platform-game': exampleFile73,
|
||||
'example://plane-and-clouds': exampleFile74,
|
||||
'example://platformer': exampleFile75,
|
||||
'example://platformer-double-jump': exampleFile76,
|
||||
'example://play-music-on-mobile': exampleFile77,
|
||||
'example://play-stop-sprite-animation': exampleFile78,
|
||||
'example://racing-game': exampleFile79,
|
||||
'example://ragdoll': exampleFile80,
|
||||
'example://rain': exampleFile81,
|
||||
'example://random-color-picker': exampleFile82,
|
||||
'example://rotate-toward-mouse': exampleFile83,
|
||||
'example://rotate-toward-position': exampleFile84,
|
||||
'example://rotate-with-keypress': exampleFile85,
|
||||
'example://save-load': exampleFile86,
|
||||
'example://screen-shake': exampleFile87,
|
||||
'example://shoot-bullet-in-parabola': exampleFile88,
|
||||
'example://shoot-bullets': exampleFile89,
|
||||
'example://shooting-bullets-explanation': exampleFile90,
|
||||
'example://simple-space-shooter': exampleFile91,
|
||||
'example://skeletal-animation-demo': exampleFile92,
|
||||
'example://snap-object-to-grid': exampleFile93,
|
||||
'example://space-invaders': exampleFile94,
|
||||
'example://space-shooter': exampleFile95,
|
||||
'example://splash-screen': exampleFile96,
|
||||
'example://sprite-fade-in-out': exampleFile97,
|
||||
'example://take-screenshot': exampleFile98,
|
||||
'example://text-entry-object': exampleFile99,
|
||||
'example://text-fade-in-out': exampleFile100,
|
||||
'example://text-to-speech': exampleFile101,
|
||||
'example://toggle-music-play-sound': exampleFile102,
|
||||
'example://type-on-text-effect': exampleFile103,
|
||||
'example://video-player': exampleFile104,
|
||||
'example://z-depth': exampleFile105,
|
||||
'example://zombie-laser': exampleFile106,
|
||||
};
|
@@ -0,0 +1,31 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { type StorageProvider } from '../index';
|
||||
import internalExampleFiles from './InternalExampleFiles';
|
||||
import DownloadSaveDialog from './DownloadSaveDialog';
|
||||
|
||||
/**
|
||||
* "Internal" storage giving access to embedded examples.
|
||||
* Used for the web-app.
|
||||
*/
|
||||
export default (({ setDialog, closeDialog }) => ({
|
||||
onOpen: (url: string) => {
|
||||
if (internalExampleFiles[url])
|
||||
return Promise.resolve(internalExampleFiles[url]);
|
||||
|
||||
return Promise.reject(new Error(`Unknown built-in game with URL ${url}`));
|
||||
},
|
||||
onSaveProject: (project: gdProject) => {
|
||||
return new Promise(resolve => {
|
||||
setDialog(() => (
|
||||
<DownloadSaveDialog
|
||||
onDone={() => {
|
||||
closeDialog();
|
||||
resolve(false);
|
||||
}}
|
||||
project={project}
|
||||
/>
|
||||
));
|
||||
});
|
||||
},
|
||||
}): StorageProvider);
|
@@ -0,0 +1,89 @@
|
||||
// @flow
|
||||
import optionalRequire from '../../Utils/OptionalRequire.js';
|
||||
import { unsplit } from '../../Utils/ObjectSplitter.js';
|
||||
const fs = optionalRequire('fs');
|
||||
const path = optionalRequire('path');
|
||||
const electron = optionalRequire('electron');
|
||||
const dialog = electron ? electron.remote.dialog : null;
|
||||
|
||||
const readJSONFile = (filepath: string): Promise<Object> => {
|
||||
if (!fs) return Promise.reject('Filesystem is not supported.');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(filepath, { encoding: 'utf8' }, (err, data) => {
|
||||
if (err) return reject(err);
|
||||
|
||||
try {
|
||||
const dataObject = JSON.parse(data);
|
||||
return resolve(dataObject);
|
||||
} catch (ex) {
|
||||
return reject(filepath + ' is a corrupted/malformed file.');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const onOpenWithPicker = (): Promise<?string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!dialog) return reject('Not supported');
|
||||
|
||||
const browserWindow = electron.remote.getCurrentWindow();
|
||||
dialog.showOpenDialog(
|
||||
browserWindow,
|
||||
{
|
||||
title: 'Open a project',
|
||||
properties: ['openFile'],
|
||||
message:
|
||||
'If you want to open your GDevelop 4 project, be sure to save it as a .json file',
|
||||
filters: [{ name: 'GDevelop 5 project', extensions: ['json'] }],
|
||||
},
|
||||
paths => {
|
||||
if (!paths || !paths.length) return resolve(null);
|
||||
|
||||
return resolve(paths[0]);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const onOpen = (filepath: string): Object => {
|
||||
const projectPath = path.dirname(filepath);
|
||||
return readJSONFile(filepath).then(object => {
|
||||
return unsplit(object, {
|
||||
getReferencePartialObject: referencePath => {
|
||||
return readJSONFile(path.join(projectPath, referencePath) + '.json');
|
||||
},
|
||||
isReferenceMagicPropertyName: '__REFERENCE_TO_SPLIT_OBJECT',
|
||||
// Limit unsplitting to depth 3 (which would allow properties of layouts/external layouts/external events
|
||||
// to be un-splitted, but not the content of these properties), to avoid very slow processing
|
||||
// of large game files.
|
||||
maxUnsplitDepth: 3,
|
||||
}).then(() => {
|
||||
return object;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const shouldOpenAutosave = (
|
||||
filePath: string,
|
||||
autoSavePath: string,
|
||||
compareLastModified: boolean
|
||||
): boolean => {
|
||||
if (fs.existsSync(autoSavePath)) {
|
||||
if (!compareLastModified) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const autoSavedTime = fs.statSync(autoSavePath).mtime.getTime();
|
||||
const saveTime = fs.statSync(filePath).mtime.getTime();
|
||||
if (autoSavedTime > saveTime) {
|
||||
return true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Unable to compare *.autosave to project', err);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
@@ -1,12 +1,12 @@
|
||||
// @flow
|
||||
import { serializeToJSObject } from '../Utils/Serializer';
|
||||
import optionalRequire from '../Utils/OptionalRequire.js';
|
||||
import { serializeToJSObject } from '../../Utils/Serializer';
|
||||
import optionalRequire from '../../Utils/OptionalRequire.js';
|
||||
import {
|
||||
split,
|
||||
splitPaths,
|
||||
getSlugifiedUniqueNameFromProperty,
|
||||
} from '../Utils/ObjectSplitter';
|
||||
import localFileSystem from '../Export/LocalExporters/LocalFileSystem';
|
||||
} from '../../Utils/ObjectSplitter';
|
||||
import localFileSystem from '../../Export/LocalExporters/LocalFileSystem';
|
||||
import assignIn from 'lodash/assignIn';
|
||||
|
||||
const gd = global.gd;
|
||||
@@ -85,62 +85,60 @@ const writeProjectFiles = (
|
||||
}
|
||||
};
|
||||
|
||||
export default class LocalProjectWriter {
|
||||
static saveProject = (project: gdProject): Promise<boolean> => {
|
||||
const filePath = project.getProjectFile();
|
||||
const projectPath = path.dirname(project.getProjectFile());
|
||||
if (!filePath) {
|
||||
return Promise.reject(
|
||||
'Project file is empty, "Save as" should have been called?'
|
||||
);
|
||||
}
|
||||
|
||||
return writeProjectFiles(project, filePath, projectPath).then(() => {
|
||||
return true; // Save was properly done
|
||||
});
|
||||
};
|
||||
|
||||
static saveProjectAs = (project: gdProject): Promise<boolean> => {
|
||||
const defaultPath = project.getProjectFile();
|
||||
const fileSystem = assignIn(new gd.AbstractFileSystemJS(), localFileSystem);
|
||||
const browserWindow = electron.remote.getCurrentWindow();
|
||||
const options = {
|
||||
defaultPath,
|
||||
filters: [{ name: 'GDevelop 5 project', extensions: ['json'] }],
|
||||
};
|
||||
|
||||
if (!dialog) {
|
||||
return Promise.reject('Unsupported');
|
||||
}
|
||||
const filePath = dialog.showSaveDialog(browserWindow, options);
|
||||
if (!filePath) {
|
||||
return Promise.resolve(false); // Nothing was saved.
|
||||
}
|
||||
const projectPath = path.dirname(filePath);
|
||||
|
||||
// TODO: Ideally, errors while copying resources should be reported.
|
||||
gd.ProjectResourcesCopier.copyAllResourcesTo(
|
||||
project,
|
||||
fileSystem,
|
||||
projectPath,
|
||||
true, // Update the project with the new resource paths
|
||||
false, // Don't move absolute files
|
||||
true // Keep relative files folders structure.
|
||||
export const onSaveProject = (project: gdProject): Promise<boolean> => {
|
||||
const filePath = project.getProjectFile();
|
||||
const projectPath = path.dirname(project.getProjectFile());
|
||||
if (!filePath) {
|
||||
return Promise.reject(
|
||||
'Project file is empty, "Save as" should have been called?'
|
||||
);
|
||||
}
|
||||
|
||||
// Update the project with the new file path (resources have already been updated)
|
||||
project.setProjectFile(filePath);
|
||||
return writeProjectFiles(project, filePath, projectPath).then(() => {
|
||||
return true; // Save was properly done
|
||||
});
|
||||
};
|
||||
|
||||
return writeProjectFiles(project, filePath, projectPath).then(() => {
|
||||
return true; // Save was properly done
|
||||
});
|
||||
export const onSaveProjectAs = (project: gdProject): Promise<boolean> => {
|
||||
const defaultPath = project.getProjectFile();
|
||||
const fileSystem = assignIn(new gd.AbstractFileSystemJS(), localFileSystem);
|
||||
const browserWindow = electron.remote.getCurrentWindow();
|
||||
const options = {
|
||||
defaultPath,
|
||||
filters: [{ name: 'GDevelop 5 project', extensions: ['json'] }],
|
||||
};
|
||||
|
||||
static autoSaveProject = (project: gdProject) => {
|
||||
const autoSavePath = project.getProjectFile() + '.autosave';
|
||||
writeJSONFile(serializeToJSObject(project), autoSavePath).catch(err => {
|
||||
console.error(`Unable to write ${autoSavePath}:`, err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
}
|
||||
if (!dialog) {
|
||||
return Promise.reject('Unsupported');
|
||||
}
|
||||
const filePath = dialog.showSaveDialog(browserWindow, options);
|
||||
if (!filePath) {
|
||||
return Promise.resolve(false); // Nothing was saved.
|
||||
}
|
||||
const projectPath = path.dirname(filePath);
|
||||
|
||||
// TODO: Ideally, errors while copying resources should be reported.
|
||||
gd.ProjectResourcesCopier.copyAllResourcesTo(
|
||||
project,
|
||||
fileSystem,
|
||||
projectPath,
|
||||
true, // Update the project with the new resource paths
|
||||
false, // Don't move absolute files
|
||||
true // Keep relative files folders structure.
|
||||
);
|
||||
|
||||
// Update the project with the new file path (resources have already been updated)
|
||||
project.setProjectFile(filePath);
|
||||
|
||||
return writeProjectFiles(project, filePath, projectPath).then(() => {
|
||||
return true; // Save was properly done
|
||||
});
|
||||
};
|
||||
|
||||
export const onAutoSaveProject = (project: gdProject) => {
|
||||
const autoSavePath = project.getProjectFile() + '.autosave';
|
||||
writeJSONFile(serializeToJSObject(project), autoSavePath).catch(err => {
|
||||
console.error(`Unable to write ${autoSavePath}:`, err);
|
||||
throw err;
|
||||
});
|
||||
};
|
@@ -0,0 +1,25 @@
|
||||
// @flow
|
||||
import { type StorageProvider } from '../index';
|
||||
import {
|
||||
onOpenWithPicker,
|
||||
onOpen,
|
||||
shouldOpenAutosave,
|
||||
} from './LocalProjectOpener';
|
||||
import {
|
||||
onSaveProject,
|
||||
onSaveProjectAs,
|
||||
onAutoSaveProject,
|
||||
} from './LocalProjectWriter';
|
||||
|
||||
/**
|
||||
* Use the Electron APIs to provide access to the native
|
||||
* file system (with native save/open dialogs).
|
||||
*/
|
||||
export default (() => ({
|
||||
onOpenWithPicker,
|
||||
onOpen,
|
||||
shouldOpenAutosave,
|
||||
onSaveProject,
|
||||
onSaveProjectAs,
|
||||
onAutoSaveProject,
|
||||
}): StorageProvider);
|
@@ -1,91 +0,0 @@
|
||||
// @flow
|
||||
import optionalRequire from '../Utils/OptionalRequire.js';
|
||||
import { unsplit } from '../Utils/ObjectSplitter.js';
|
||||
const fs = optionalRequire('fs');
|
||||
const path = optionalRequire('path');
|
||||
const electron = optionalRequire('electron');
|
||||
const dialog = electron ? electron.remote.dialog : null;
|
||||
|
||||
const readJSONFile = (filepath: string): Promise<Object> => {
|
||||
if (!fs) return Promise.reject('Filesystem is not supported.');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(filepath, { encoding: 'utf8' }, (err, data) => {
|
||||
if (err) return reject(err);
|
||||
|
||||
try {
|
||||
const dataObject = JSON.parse(data);
|
||||
return resolve(dataObject);
|
||||
} catch (ex) {
|
||||
return reject(filepath + ' is a corrupted/malformed file.');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default class LocalProjectOpener {
|
||||
static chooseProjectFile = (): Promise<?string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!dialog) return reject('Not supported');
|
||||
|
||||
const browserWindow = electron.remote.getCurrentWindow();
|
||||
dialog.showOpenDialog(
|
||||
browserWindow,
|
||||
{
|
||||
title: 'Open a project',
|
||||
properties: ['openFile'],
|
||||
message:
|
||||
'If you want to open your GDevelop 4 project, be sure to save it as a .json file',
|
||||
filters: [{ name: 'GDevelop 5 project', extensions: ['json'] }],
|
||||
},
|
||||
paths => {
|
||||
if (!paths || !paths.length) return resolve(null);
|
||||
|
||||
return resolve(paths[0]);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
static readProjectFile = (filepath: string): Object => {
|
||||
const projectPath = path.dirname(filepath);
|
||||
return readJSONFile(filepath).then(object => {
|
||||
return unsplit(object, {
|
||||
getReferencePartialObject: referencePath => {
|
||||
return readJSONFile(path.join(projectPath, referencePath) + '.json');
|
||||
},
|
||||
isReferenceMagicPropertyName: '__REFERENCE_TO_SPLIT_OBJECT',
|
||||
// Limit unsplitting to depth 3 (which would allow properties of layouts/external layouts/external events
|
||||
// to be un-splitted, but not the content of these properties), to avoid very slow processing
|
||||
// of large game files.
|
||||
maxUnsplitDepth: 3,
|
||||
}).then(() => {
|
||||
return object;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
static shouldOpenAutosave = (
|
||||
filePath: string,
|
||||
autoSavePath: string,
|
||||
compareLastModified: boolean
|
||||
): boolean => {
|
||||
if (fs.existsSync(autoSavePath)) {
|
||||
if (!compareLastModified) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const autoSavedTime = fs.statSync(autoSavePath).mtime.getTime();
|
||||
const saveTime = fs.statSync(filePath).mtime.getTime();
|
||||
if (autoSavedTime > saveTime) {
|
||||
return true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Unable to compare *.autosave to project', err);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
79
newIDE/app/src/ProjectsStorage/index.js
Normal file
79
newIDE/app/src/ProjectsStorage/index.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
|
||||
export type ProjectsStorageProps = {|
|
||||
onOpenWithPicker?: () => Promise<?string>,
|
||||
onOpen: (filepath: string) => Object,
|
||||
onSaveProject: gdProject => Promise<boolean>,
|
||||
onSaveProjectAs?: gdProject => Promise<boolean>,
|
||||
onAutoSaveProject?: (project: gdProject) => void,
|
||||
shouldOpenAutosave?: (
|
||||
filePath: string,
|
||||
autoSavePath: string,
|
||||
compareLastModified: boolean
|
||||
) => boolean,
|
||||
|};
|
||||
|
||||
export type StorageProvider = ({
|
||||
setDialog: (() => React.Node) => void,
|
||||
closeDialog: () => void,
|
||||
}) => ProjectsStorageProps;
|
||||
|
||||
const emptyStorageProvider: StorageProvider = () => ({
|
||||
onOpenWithPicker: () => Promise.reject('No storage provider set up'),
|
||||
onOpen: () => ({}),
|
||||
shouldOpenAutosave: () => false,
|
||||
onSaveProject: (project: gdProject) =>
|
||||
Promise.reject('No storage provider set up'),
|
||||
onSaveProjectAs: (project: gdProject) =>
|
||||
Promise.reject('No storage provider set up'),
|
||||
onAutoSaveProject: (project: gdProject) => {},
|
||||
});
|
||||
|
||||
type Props = {|
|
||||
storageProviders: Array<StorageProvider>,
|
||||
defaultStorageProvider?: StorageProvider,
|
||||
children: (storage: ProjectsStorageProps) => React.Node,
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
currentStorageProvider: ?StorageProvider,
|
||||
renderDialog: ?() => React.Node,
|
||||
|};
|
||||
|
||||
export default class ProjectsStorage extends React.Component<Props, State> {
|
||||
state = {
|
||||
currentStorageProvider: this.props.defaultStorageProvider,
|
||||
renderDialog: null,
|
||||
};
|
||||
|
||||
_setDialog = (renderDialog: () => React.Node) => {
|
||||
this.setState({
|
||||
renderDialog,
|
||||
});
|
||||
};
|
||||
_closeDialog = () => {
|
||||
this.setState({
|
||||
renderDialog: null,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const { renderDialog } = this.state;
|
||||
const currentStorageProvider =
|
||||
this.state.currentStorageProvider || emptyStorageProvider;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{children(
|
||||
currentStorageProvider({
|
||||
setDialog: this._setDialog,
|
||||
closeDialog: this._closeDialog,
|
||||
})
|
||||
)}
|
||||
{renderDialog && renderDialog()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user