mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
15 Commits
v5.0.0-bet
...
v5.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0e3f70627b | ||
![]() |
a814a07105 | ||
![]() |
c49af90a9c | ||
![]() |
24afa155c8 | ||
![]() |
9e5a431516 | ||
![]() |
182a94285c | ||
![]() |
442c2c8dd9 | ||
![]() |
f8fd0dd353 | ||
![]() |
faad9e23ac | ||
![]() |
d2af0da1b1 | ||
![]() |
c65e5c3e49 | ||
![]() |
24a8dfc5f0 | ||
![]() |
9c6790ac37 | ||
![]() |
18ef7460ba | ||
![]() |
63cd0e76c3 |
@@ -945,7 +945,7 @@ void ResourcesEditor::Refresh()
|
||||
gd::ResourceFolder & folder = project.GetResourcesManager().GetFolder(folders[i]);
|
||||
wxTreeItemId folderItem = resourcesTree->AppendItem( resourcesTree->GetRootItem(), folders[i], -1, -1, new gd::TreeItemStringData("Folder", folders[i] ));
|
||||
|
||||
std::vector<gd::String> resources = folder.GetAllResourcesList();
|
||||
std::vector<gd::String> resources = folder.GetAllResourceNames();
|
||||
for (std::size_t j=0;j<resources.size();++j)
|
||||
{
|
||||
gd::Resource & resource = folder.GetResource(resources[j]);
|
||||
@@ -959,7 +959,7 @@ void ResourcesEditor::Refresh()
|
||||
|
||||
//All images
|
||||
allImagesItem = resourcesTree->AppendItem( resourcesTree->GetRootItem(), _("All images"), -1,-1, new gd::TreeItemStringData("BaseFolder", "" ));
|
||||
std::vector<gd::String> resources = project.GetResourcesManager().GetAllResourcesList();
|
||||
std::vector<gd::String> resources = project.GetResourcesManager().GetAllResourceNames();
|
||||
for ( std::size_t i = 0;i <resources.size();i++ )
|
||||
{
|
||||
gd::Resource & resource = project.GetResourcesManager().GetResource(resources[i]);
|
||||
|
@@ -51,7 +51,7 @@ void ArbitraryResourceWorker::ExposeResources(gd::ResourcesManager * resourcesMa
|
||||
|
||||
resourcesManagers.push_back(resourcesManager);
|
||||
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourcesList();
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourceNames();
|
||||
for ( std::size_t i = 0;i < resources.size() ;i++ )
|
||||
{
|
||||
if ( resourcesManager->GetResource(resources[i]).UseFile() )
|
||||
|
@@ -45,7 +45,7 @@ std::vector<gd::String> ProjectResourcesAdder::GetAllUselessImages(gd::Project &
|
||||
std::set<gd::String> & usedImages = inventorizer.GetAllUsedImages();
|
||||
|
||||
//Search all images resources not used
|
||||
std::vector<gd::String> resources = project.GetResourcesManager().GetAllResourcesList();
|
||||
std::vector<gd::String> resources = project.GetResourcesManager().GetAllResourceNames();
|
||||
for (std::size_t i = 0;i < resources.size();i++)
|
||||
{
|
||||
if (project.GetResourcesManager().GetResource(resources[i]).GetKind() != "image")
|
||||
|
@@ -141,7 +141,7 @@ void ImageManager::LoadPermanentImages()
|
||||
//so as not to unload images that could be still present.
|
||||
std::map < gd::String, std::shared_ptr<SFMLTextureWrapper> > newPermanentlyLoadedImages;
|
||||
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourcesList();
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourceNames();
|
||||
for ( std::size_t i = 0;i <resources.size();i++ )
|
||||
{
|
||||
try
|
||||
|
@@ -131,6 +131,7 @@ gd::Layer & Layout::GetLayer(const gd::String & name)
|
||||
|
||||
return badLayer;
|
||||
}
|
||||
|
||||
const gd::Layer & Layout::GetLayer(const gd::String & name) const
|
||||
{
|
||||
std::vector<gd::Layer>::const_iterator layer = find_if(initialLayers.begin(), initialLayers.end(), bind2nd(gd::LayerHasName(), name));
|
||||
@@ -140,14 +141,17 @@ const gd::Layer & Layout::GetLayer(const gd::String & name) const
|
||||
|
||||
return badLayer;
|
||||
}
|
||||
|
||||
gd::Layer & Layout::GetLayer(std::size_t index)
|
||||
{
|
||||
return initialLayers[index];
|
||||
}
|
||||
|
||||
const gd::Layer & Layout::GetLayer (std::size_t index) const
|
||||
{
|
||||
return initialLayers[index];
|
||||
}
|
||||
|
||||
std::size_t Layout::GetLayersCount() const
|
||||
{
|
||||
return initialLayers.size();
|
||||
|
@@ -172,37 +172,37 @@ public:
|
||||
|
||||
/** \name Layout layers management
|
||||
* Members functions related to layout layers management.
|
||||
* TODO: This should be moved to a separate class
|
||||
* TODO: This could be moved to a separate class
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Must return true if the layer called "name" exists.
|
||||
* \brief Return true if the layer called "name" exists.
|
||||
*/
|
||||
bool HasLayerNamed(const gd::String & name) const;
|
||||
|
||||
/**
|
||||
* Must return a reference to the layer called "name".
|
||||
* \brief Return a reference to the layer called "name".
|
||||
*/
|
||||
Layer & GetLayer(const gd::String & name);
|
||||
|
||||
/**
|
||||
* Must return a reference to the layer called "name".
|
||||
* \brief Return a reference to the layer called "name".
|
||||
*/
|
||||
const Layer & GetLayer(const gd::String & name) const;
|
||||
|
||||
/**
|
||||
* Must return a reference to the layer at position "index" in the layers list
|
||||
* \brief Return a reference to the layer at position "index" in the layers list
|
||||
*/
|
||||
Layer & GetLayer(std::size_t index);
|
||||
|
||||
/**
|
||||
* Must return a reference to the layer at position "index" in the layers list
|
||||
* \brief Return a reference to the layer at position "index" in the layers list
|
||||
*/
|
||||
const Layer & GetLayer (std::size_t index) const;
|
||||
const Layer & GetLayer(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* Must return the position of the layer called "name" in the layers list
|
||||
* \brief Return the position of the layer called "name" in the layers list
|
||||
*/
|
||||
std::size_t GetLayerPosition(const gd::String & name) const;
|
||||
|
||||
|
@@ -105,7 +105,7 @@ bool ResourcesManager::HasResource(const gd::String & name) const
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<gd::String> ResourcesManager::GetAllResourcesList()
|
||||
std::vector<gd::String> ResourcesManager::GetAllResourceNames()
|
||||
{
|
||||
std::vector<gd::String> allResources;
|
||||
for (std::size_t i = 0;i<resources.size();++i)
|
||||
@@ -146,7 +146,7 @@ bool ResourcesManager::AddResource(const gd::String & name, const gd::String & f
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<gd::String> ResourceFolder::GetAllResourcesList()
|
||||
std::vector<gd::String> ResourceFolder::GetAllResourceNames()
|
||||
{
|
||||
std::vector<gd::String> allResources;
|
||||
for (std::size_t i = 0;i<resources.size();++i)
|
||||
@@ -351,6 +351,25 @@ bool ResourcesManager::MoveResourceDownInList(const gd::String & name)
|
||||
return gd::MoveResourceDownInList(resources, name);
|
||||
}
|
||||
|
||||
std::size_t ResourcesManager::GetResourcePosition(const gd::String & name) const
|
||||
{
|
||||
for (std::size_t i = 0;i<resources.size();++i)
|
||||
{
|
||||
if (resources[i]->GetName() == name) return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
void ResourcesManager::MoveResource(std::size_t oldIndex, std::size_t newIndex)
|
||||
{
|
||||
if ( oldIndex >= resources.size() || newIndex >= resources.size() )
|
||||
return;
|
||||
|
||||
auto resource = resources[oldIndex];
|
||||
resources.erase(resources.begin() + oldIndex);
|
||||
resources.insert(resources.begin() + newIndex, resource);
|
||||
}
|
||||
|
||||
bool ResourcesManager::MoveFolderUpInList(const gd::String & name)
|
||||
{
|
||||
for (std::size_t i =1;i<folders.size();++i)
|
||||
|
@@ -293,9 +293,9 @@ public:
|
||||
std::shared_ptr<Resource> CreateResource(const gd::String & kind);
|
||||
|
||||
/**
|
||||
* \brief Get a list containing the name of all of the resources.
|
||||
* \brief Get a list containing the names of all resources.
|
||||
*/
|
||||
std::vector<gd::String> GetAllResourcesList();
|
||||
std::vector<gd::String> GetAllResourceNames();
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
@@ -324,6 +324,11 @@ public:
|
||||
*/
|
||||
void RenameResource(const gd::String & oldName, const gd::String & newName);
|
||||
|
||||
/**
|
||||
* \brief Return the position of the layer called "name" in the layers list
|
||||
*/
|
||||
std::size_t GetResourcePosition(const gd::String & name) const;
|
||||
|
||||
/**
|
||||
* \brief Move a resource up in the list
|
||||
*/
|
||||
@@ -334,6 +339,11 @@ public:
|
||||
*/
|
||||
bool MoveResourceDownInList(const gd::String & name);
|
||||
|
||||
/**
|
||||
* Change the position of the specified resource.
|
||||
*/
|
||||
void MoveResource(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Return true if the folder exists.
|
||||
*/
|
||||
@@ -445,7 +455,7 @@ public:
|
||||
/**
|
||||
* Get a list containing the name of all of the resources.
|
||||
*/
|
||||
virtual std::vector<gd::String> GetAllResourcesList();
|
||||
virtual std::vector<gd::String> GetAllResourceNames();
|
||||
|
||||
/**
|
||||
* Move a resource up in the list
|
||||
|
@@ -84,7 +84,7 @@ TEST_CASE( "Resources", "[common][resources]" ) {
|
||||
|
||||
gd::ProjectResourcesAdder::RemoveAllUselessImages(project);
|
||||
std::vector<gd::String> remainingResources =
|
||||
project.GetResourcesManager().GetAllResourcesList();
|
||||
project.GetResourcesManager().GetAllResourceNames();
|
||||
REQUIRE(remainingResources.size() == 2);
|
||||
REQUIRE(remainingResources[0] == "res1");
|
||||
REQUIRE(remainingResources[1] == "res4");
|
||||
|
@@ -17,7 +17,7 @@ This project is released under the MIT License.
|
||||
class ScenePhysicsDatas : public gd::BehaviorsSharedData
|
||||
{
|
||||
public:
|
||||
ScenePhysicsDatas() : BehaviorsSharedData(), gravityX(0), gravityY(0), scaleX(100), scaleY(100)
|
||||
ScenePhysicsDatas() : BehaviorsSharedData(), gravityX(0), gravityY(9), scaleX(100), scaleY(100)
|
||||
{
|
||||
};
|
||||
virtual ~ScenePhysicsDatas() {};
|
||||
|
1
newIDE/app/flow-typed/libGD.js
vendored
1
newIDE/app/flow-typed/libGD.js
vendored
@@ -13,6 +13,7 @@ declare type gdExternalEvents = EmscriptenObject;
|
||||
declare type gdSerializerElement = EmscriptenObject;
|
||||
declare type gdInitialInstance = EmscriptenObject;
|
||||
declare type gdBaseEvent = EmscriptenObject;
|
||||
declare type gdResource = EmscriptenObject;
|
||||
|
||||
//Represents all objects that have serializeTo and unserializeFrom methods.
|
||||
declare type gdSerializable = EmscriptenObject;
|
||||
|
@@ -25,27 +25,8 @@
|
||||
<meta name="theme-color" content="#4ab0e4">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
|
||||
<!-- Fullstory user analytics -->
|
||||
<script>
|
||||
window['_fs_debug'] = false;
|
||||
window['_fs_host'] = 'fullstory.com';
|
||||
window['_fs_org'] = '8DWZ1';
|
||||
window['_fs_namespace'] = 'FS';
|
||||
(function(m,n,e,t,l,o,g,y){
|
||||
if (e in m) {if(m.console && m.console.log) { m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].');} return;}
|
||||
g=m[e]=function(a,b){g.q?g.q.push([a,b]):g._api(a,b);};g.q=[];
|
||||
o=n.createElement(t);o.async=1;o.src='https://'+_fs_host+'/s/fs.js';
|
||||
y=n.getElementsByTagName(t)[0];y.parentNode.insertBefore(o,y);
|
||||
g.identify=function(i,v){g(l,{uid:i});if(v)g(l,v)};g.setUserVars=function(v){g(l,v)};
|
||||
g.identifyAccount=function(i,v){o='account';v=v||{};v.acctId=i;g(o,v)};
|
||||
g.clearUserCookie=function(c,d,i){if(!c || document.cookie.match('fs_uid=[`;`]*`[`;`]*`[`;`]*`')){
|
||||
d=n.domain;while(1){n.cookie='fs_uid=;domain='+d+
|
||||
';path=/;expires='+new Date(0).toUTCString();i=d.indexOf('.');if(i<0)break;d=d.slice(i+1)}}};
|
||||
})(window,document,window['_fs_namespace'],'script','user');
|
||||
</script>
|
||||
|
||||
<!-- Stripe.com Checkout -->
|
||||
<script src="https://checkout.stripe.com/checkout.js"></script>
|
||||
<!-- Stripe.com Checkout -->
|
||||
<script src="https://checkout.stripe.com/checkout.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
21
newIDE/app/src/MainFrame/Editors/ResourcesEditor.js
Normal file
21
newIDE/app/src/MainFrame/Editors/ResourcesEditor.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import BaseEditor from './BaseEditor';
|
||||
import ResourcesFullEditor from '../../ResourcesEditor';
|
||||
|
||||
export default class ResourcesEditor extends BaseEditor {
|
||||
updateToolbar() {
|
||||
if (this.editor) this.editor.updateToolbar();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { project } = this.props;
|
||||
|
||||
return (
|
||||
<ResourcesFullEditor
|
||||
{...this.props}
|
||||
ref={editor => (this.editor = editor)}
|
||||
project={project}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@@ -47,6 +47,7 @@ import ExternalEventsEditor from './Editors/ExternalEventsEditor';
|
||||
import SceneEditor from './Editors/SceneEditor';
|
||||
import ExternalLayoutEditor from './Editors/ExternalLayoutEditor';
|
||||
import StartPage from './Editors/StartPage';
|
||||
import ResourcesEditor from './Editors/ResourcesEditor';
|
||||
import {
|
||||
type PreferencesState,
|
||||
getThemeName,
|
||||
@@ -545,6 +546,36 @@ export default class MainFrame extends Component<*, State> {
|
||||
);
|
||||
};
|
||||
|
||||
openResources = () => {
|
||||
this.setState(
|
||||
{
|
||||
editorTabs: openEditorTab(this.state.editorTabs, {
|
||||
name: 'Resources',
|
||||
editorCreator: () => (
|
||||
<ResourcesEditor
|
||||
project={this.state.currentProject}
|
||||
setToolbar={this.setEditorToolbar}
|
||||
onDeleteResource={(resource: gdResource, cb: boolean => void) => {
|
||||
// TODO: Project wide refactoring of objects/events using the resource
|
||||
cb(true);
|
||||
}}
|
||||
onRenameResource={(
|
||||
resource: gdResource,
|
||||
newName: string,
|
||||
cb: boolean => void
|
||||
) => {
|
||||
// TODO: Project wide refactoring of objects/events using the resource
|
||||
cb(true);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
key: 'resources',
|
||||
}),
|
||||
},
|
||||
() => this.updateToolbar()
|
||||
);
|
||||
};
|
||||
|
||||
openStartPage = () => {
|
||||
this.setState(
|
||||
{
|
||||
@@ -814,6 +845,7 @@ export default class MainFrame extends Component<*, State> {
|
||||
onCloseProject={this.askToCloseProject}
|
||||
onExportProject={this.openExportDialog}
|
||||
onOpenPreferences={() => this.openPreferences(true)}
|
||||
onOpenResources={() => this.openResources()}
|
||||
/>
|
||||
)}
|
||||
</Drawer>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import ResourcesLoader from '../ObjectsRendering/ResourcesLoader';
|
||||
import ResourceSelector from '../ResourcesEditor/ResourceSelector';
|
||||
import ResourceSelector from '../ResourcesList/ResourceSelector';
|
||||
import ImageThumbnail from './ImageThumbnail';
|
||||
|
||||
export default ({
|
||||
|
@@ -22,7 +22,7 @@ export default class PixiResourcesLoader {
|
||||
const resourcesManager = project.getResourcesManager();
|
||||
const loader = PIXI.loader;
|
||||
|
||||
const resourcesList = resourcesManager.getAllResourcesList().toJSArray();
|
||||
const resourcesList = resourcesManager.getAllResourceNames().toJSArray();
|
||||
const allResources = {};
|
||||
resourcesList.forEach(resourceName => {
|
||||
const resource = resourcesManager.getResource(resourceName);
|
||||
|
@@ -1,21 +1,6 @@
|
||||
// @flow
|
||||
import { mapFor } from '../Utils/MapFor';
|
||||
|
||||
//TODO: Layout, ExternalEvents and ExternalLayout should be moved to a common type definition file
|
||||
//for all GDevelop.js
|
||||
type Layout = {
|
||||
getName: Function,
|
||||
setName: Function,
|
||||
};
|
||||
type ExternalLayout = {
|
||||
getName: Function,
|
||||
setName: Function,
|
||||
};
|
||||
type ExternalEvents = {
|
||||
getName: Function,
|
||||
setName: Function,
|
||||
};
|
||||
|
||||
export const enumerateLayouts = (project: any) =>
|
||||
mapFor(0, project.getLayoutsCount(), i => project.getLayoutAt(i));
|
||||
|
||||
@@ -30,7 +15,7 @@ export const enumerateExternalLayouts = (project: any) =>
|
||||
);
|
||||
|
||||
export const filterProjectItemsList = (
|
||||
list: Array<Layout> | Array<ExternalLayout> | Array<ExternalEvents>,
|
||||
list: Array<gdLayout> | Array<gdExternalLayout> | Array<gdExternalEvents>,
|
||||
searchText: string
|
||||
) => {
|
||||
if (!searchText) return list;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { List, ListItem } from 'material-ui/List';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import SearchBar from 'material-ui-search-bar';
|
||||
@@ -65,7 +66,10 @@ const ThemableProjectStructureItem = ({ muiTheme, ...otherProps }) => (
|
||||
|
||||
const ProjectStructureItem = muiThemeable()(ThemableProjectStructureItem);
|
||||
|
||||
class ThemableItem extends Component {
|
||||
class ThemableItem extends React.Component<*, *> {
|
||||
textField: ?Object;
|
||||
_iconMenu: ?Object;
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!prevProps.editingName && this.props.editingName) {
|
||||
setTimeout(() => {
|
||||
@@ -126,7 +130,7 @@ class ThemableItem extends Component {
|
||||
onKeyPress={event => {
|
||||
if (event.charCode === 13) {
|
||||
// enter key pressed
|
||||
this.textField.blur();
|
||||
if (this.textField) this.textField.blur();
|
||||
this.props.onRename(event.target.value);
|
||||
}
|
||||
}}
|
||||
@@ -157,33 +161,64 @@ const Item = muiThemeable()(ThemableItem);
|
||||
|
||||
const AddItem = makeAddItem(ListItem);
|
||||
|
||||
export default class ProjectManager extends React.Component {
|
||||
type Props = {
|
||||
project: gdProject,
|
||||
onDeleteLayout: (gdLayout) => void,
|
||||
onDeleteExternalEvents: (gdExternalEvents) => void,
|
||||
onDeleteExternalLayout: (gdExternalLayout) => void,
|
||||
onRenameLayout: (string, string) => void,
|
||||
onRenameExternalEvents: (string, string) => void,
|
||||
onRenameExternalLayout: (string, string) => void,
|
||||
onOpenLayout: (string) => void,
|
||||
onOpenExternalEvents: (string) => void,
|
||||
onOpenExternalLayout: (string) => void,
|
||||
onSaveProject: () => void,
|
||||
onCloseProject: () => void,
|
||||
onExportProject: () => void,
|
||||
onOpenPreferences: () => void,
|
||||
onOpenResources: () => void,
|
||||
onAddLayout: () => void,
|
||||
onAddExternalEvents: () => void,
|
||||
onAddExternalLayout: () => void,
|
||||
};
|
||||
|
||||
type State = {|
|
||||
renamedItemKind: ?string,
|
||||
renamedItemName: string,
|
||||
searchText: string,
|
||||
projectPropertiesDialogOpen: boolean,
|
||||
variablesEditorOpen: boolean,
|
||||
|};
|
||||
|
||||
export default class ProjectManager extends React.Component<Props, State> {
|
||||
state = {
|
||||
renamedItemKind: null,
|
||||
renamedItemName: '',
|
||||
searchText: '',
|
||||
projectPropertiesDialogOpen: false,
|
||||
variablesEditorOpen: false,
|
||||
};
|
||||
|
||||
_onEditName = (kind, name) => {
|
||||
_onEditName = (kind: ?string, name: string) => {
|
||||
this.setState({
|
||||
renamedItemKind: kind,
|
||||
renamedItemName: name,
|
||||
});
|
||||
};
|
||||
|
||||
_copyLayout = layout => {
|
||||
_copyLayout = (layout: gdLayout) => {
|
||||
Clipboard.set(LAYOUT_CLIPBOARD_KIND, {
|
||||
layout: serializeToJSObject(layout),
|
||||
name: layout.getName(),
|
||||
});
|
||||
};
|
||||
|
||||
_cutLayout = layout => {
|
||||
_cutLayout = (layout: gdLayout) => {
|
||||
this._copyLayout(layout);
|
||||
this.props.onDeleteLayout(layout);
|
||||
};
|
||||
|
||||
_pasteLayout = index => {
|
||||
_pasteLayout = (index: number) => {
|
||||
if (!Clipboard.has(LAYOUT_CLIPBOARD_KIND)) return;
|
||||
|
||||
const { layout: copiedLayout, name } = Clipboard.get(LAYOUT_CLIPBOARD_KIND);
|
||||
@@ -207,19 +242,19 @@ export default class ProjectManager extends React.Component {
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
_copyExternalEvents = externalEvents => {
|
||||
_copyExternalEvents = (externalEvents: gdExternalEvents) => {
|
||||
Clipboard.set(EXTERNAL_EVENTS_CLIPBOARD_KIND, {
|
||||
externalEvents: serializeToJSObject(externalEvents),
|
||||
name: externalEvents.getName(),
|
||||
});
|
||||
};
|
||||
|
||||
_cutExternalEvents = externalEvents => {
|
||||
_cutExternalEvents = (externalEvents: gdExternalEvents) => {
|
||||
this._copyExternalEvents(externalEvents);
|
||||
this.props.onDeleteExternalEvents(externalEvents);
|
||||
};
|
||||
|
||||
_pasteExternalEvents = index => {
|
||||
_pasteExternalEvents = (index: number) => {
|
||||
if (!Clipboard.has(EXTERNAL_EVENTS_CLIPBOARD_KIND)) return;
|
||||
|
||||
const { externalEvents: copiedExternalEvents, name } = Clipboard.get(
|
||||
@@ -244,19 +279,19 @@ export default class ProjectManager extends React.Component {
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
_copyExternalLayout = externalLayout => {
|
||||
_copyExternalLayout = (externalLayout: gdExternalLayout) => {
|
||||
Clipboard.set(EXTERNAL_LAYOUT_CLIPBOARD_KIND, {
|
||||
externalLayout: serializeToJSObject(externalLayout),
|
||||
name: externalLayout.getName(),
|
||||
});
|
||||
};
|
||||
|
||||
_cutExternalLayout = externalLayout => {
|
||||
_cutExternalLayout = (externalLayout: gdExternalLayout) => {
|
||||
this._copyExternalLayout(externalLayout);
|
||||
this.props.onDeleteExternalLayout(externalLayout);
|
||||
};
|
||||
|
||||
_pasteExternalLayout = index => {
|
||||
_pasteExternalLayout = (index: number) => {
|
||||
if (!Clipboard.has(EXTERNAL_LAYOUT_CLIPBOARD_KIND)) return;
|
||||
|
||||
const { externalLayout: copiedExternalLayout, name } = Clipboard.get(
|
||||
@@ -328,10 +363,6 @@ export default class ProjectManager extends React.Component {
|
||||
<div style={styles.container}>
|
||||
<List style={styles.list}>
|
||||
{this._renderMenu()}
|
||||
{/* <ProjectStructureItem
|
||||
primaryText="Resources"
|
||||
leftIcon={<ListIcon src="res/ribbon_default/image32.png" />}
|
||||
/> */}
|
||||
<ProjectStructureItem
|
||||
primaryText="Game settings"
|
||||
leftIcon={
|
||||
@@ -354,6 +385,12 @@ export default class ProjectManager extends React.Component {
|
||||
leftIcon={<ListIcon src="res/ribbon_default/editname32.png" />}
|
||||
onClick={() => this.setState({ variablesEditorOpen: true })}
|
||||
/>,
|
||||
<ListItem
|
||||
key="resources"
|
||||
primaryText="Resources"
|
||||
leftIcon={<ListIcon src="res/ribbon_default/image32.png" />}
|
||||
onClick={() => this.props.onOpenResources()}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
<ProjectStructureItem
|
||||
@@ -367,7 +404,7 @@ export default class ProjectManager extends React.Component {
|
||||
enumerateLayouts(project),
|
||||
searchText
|
||||
)
|
||||
.map((layout, i) => {
|
||||
.map((layout: gdLayout, i: number) => {
|
||||
const name = layout.getName();
|
||||
return (
|
||||
<Item
|
||||
|
52
newIDE/app/src/PropertiesEditor/SemiControlledTextField.js
Normal file
52
newIDE/app/src/PropertiesEditor/SemiControlledTextField.js
Normal file
@@ -0,0 +1,52 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import TextField from 'material-ui/TextField';
|
||||
|
||||
type State = {
|
||||
focused: boolean,
|
||||
text: ?string,
|
||||
};
|
||||
|
||||
/**
|
||||
* This component works like a material-ui TextField, except that
|
||||
* the value passed as props is not forced into the text field when the user
|
||||
* is typing. This is useful if the parent component can do modifications on the value:
|
||||
* the user won't be interrupted or have the value changed until he blurs the field.
|
||||
*/
|
||||
export default class SemiControlledTextField extends React.Component<*, State> {
|
||||
state = {
|
||||
focused: false,
|
||||
text: null,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value, onChange, ...otherProps } = this.props;
|
||||
|
||||
return (
|
||||
<TextField
|
||||
{...otherProps}
|
||||
value={this.state.focused ? this.state.text : value}
|
||||
onFocus={() => {
|
||||
this.setState({
|
||||
focused: true,
|
||||
text: this.props.value,
|
||||
});
|
||||
}}
|
||||
onChange={(event, newValue) => {
|
||||
this.setState({
|
||||
text: newValue,
|
||||
});
|
||||
|
||||
onChange(newValue);
|
||||
}}
|
||||
onBlur={event => {
|
||||
onChange(event.target.value);
|
||||
this.setState({
|
||||
focused: false,
|
||||
text: null,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import SemiControlledTextField from './SemiControlledTextField';
|
||||
import Checkbox from 'material-ui/Checkbox';
|
||||
import Subheader from 'material-ui/Subheader';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
@@ -53,13 +53,13 @@ export default class PropertiesEditor extends Component {
|
||||
);
|
||||
} else if (field.valueType === 'number') {
|
||||
return (
|
||||
<TextField
|
||||
<SemiControlledTextField
|
||||
value={this._getFieldValue(this.props.instances, field)}
|
||||
key={field.name}
|
||||
id={field.name}
|
||||
floatingLabelText={field.name}
|
||||
floatingLabelFixed={true}
|
||||
onChange={(event, newValue) => {
|
||||
floatingLabelFixed
|
||||
onChange={newValue => {
|
||||
this.props.instances.forEach(i =>
|
||||
field.setValue(i, parseFloat(newValue) || 0)
|
||||
);
|
||||
@@ -72,16 +72,17 @@ export default class PropertiesEditor extends Component {
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<TextField
|
||||
<SemiControlledTextField
|
||||
value={this._getFieldValue(
|
||||
this.props.instances,
|
||||
field,
|
||||
'(Multiple values)'
|
||||
)}
|
||||
key={field.name}
|
||||
id={field.name}
|
||||
floatingLabelText={field.name}
|
||||
floatingLabelFixed={true}
|
||||
onChange={(event, newValue) => {
|
||||
floatingLabelFixed
|
||||
onChange={newValue => {
|
||||
this.props.instances.forEach(i =>
|
||||
field.setValue(i, newValue || '')
|
||||
);
|
||||
@@ -107,7 +108,7 @@ export default class PropertiesEditor extends Component {
|
||||
value={this._getFieldValue(this.props.instances, field)}
|
||||
key={field.name}
|
||||
floatingLabelText={field.name}
|
||||
floatingLabelFixed={true}
|
||||
floatingLabelFixed
|
||||
onChange={(event, index, newValue) => {
|
||||
this.props.instances.forEach(i =>
|
||||
field.setValue(i, parseFloat(newValue) || 0)
|
||||
@@ -130,7 +131,7 @@ export default class PropertiesEditor extends Component {
|
||||
)}
|
||||
key={field.name}
|
||||
floatingLabelText={field.name}
|
||||
floatingLabelFixed={true}
|
||||
floatingLabelFixed
|
||||
onChange={(event, index, newValue) => {
|
||||
this.props.instances.forEach(i =>
|
||||
field.setValue(i, newValue || '')
|
||||
|
101
newIDE/app/src/ResourcesEditor/ResourcePropertiesEditor/index.js
Normal file
101
newIDE/app/src/ResourcesEditor/ResourcePropertiesEditor/index.js
Normal file
@@ -0,0 +1,101 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import Paper from 'material-ui/Paper';
|
||||
import EmptyMessage from '../../UI/EmptyMessage';
|
||||
import PropertiesEditor from '../../PropertiesEditor';
|
||||
import ImagePreview from '../../ObjectEditor/ImagePreview'; //TODO: Move ImagePreview out of ObjectEditor
|
||||
import ResourceLoader from '../../ObjectsRendering/ResourcesLoader';
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
},
|
||||
imagePreview: { flex: 1 },
|
||||
propertiesContainer: {
|
||||
padding: 10,
|
||||
overflowY: 'scroll',
|
||||
overflowX: 'hidden',
|
||||
flex: 2,
|
||||
},
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
resourcesLoader: ResourceLoader,
|
||||
resources: Array<gdResource>,
|
||||
|};
|
||||
|
||||
export default class ResourcePropertiesEditor extends React.Component<
|
||||
Props,
|
||||
{}
|
||||
> {
|
||||
schema = [
|
||||
{
|
||||
name: 'Resource name',
|
||||
valueType: 'string',
|
||||
disabled: true,
|
||||
getValue: (resource: gdResource) => resource.getName(),
|
||||
setValue: (resource: gdResource, newValue: string) =>
|
||||
resource.setName(newValue),
|
||||
},
|
||||
{
|
||||
name: 'File',
|
||||
valueType: 'string',
|
||||
getValue: (resource: gdResource) => resource.getFile(),
|
||||
setValue: (resource: gdResource, newValue: string) =>
|
||||
resource.setFile(newValue),
|
||||
},
|
||||
];
|
||||
|
||||
_renderEmpty() {
|
||||
return (
|
||||
<EmptyMessage>
|
||||
Resources are automatically added to your project whenever you add an
|
||||
image to an object. Choose a resource to display its properties.
|
||||
</EmptyMessage>
|
||||
);
|
||||
}
|
||||
|
||||
_renderResourcesProperties() {
|
||||
const { resources } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={styles.propertiesContainer}
|
||||
key={resources.map(resource => '' + resource.ptr).join(';')}
|
||||
>
|
||||
<PropertiesEditor schema={this.schema} instances={resources} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
_renderPreview() {
|
||||
const { resources, project, resourcesLoader } = this.props;
|
||||
if (!resources || !resources.length) return;
|
||||
|
||||
return (
|
||||
<ImagePreview
|
||||
style={styles.imagePreview}
|
||||
resourceName={resources[0].getName()}
|
||||
resourcesLoader={resourcesLoader}
|
||||
project={project}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { resources } = this.props;
|
||||
|
||||
return (
|
||||
<Paper style={styles.container}>
|
||||
{this._renderPreview()}
|
||||
{!resources || !resources.length
|
||||
? this._renderEmpty()
|
||||
: this._renderResourcesProperties()}
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
}
|
39
newIDE/app/src/ResourcesEditor/Toolbar.js
Normal file
39
newIDE/app/src/ResourcesEditor/Toolbar.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// @flow
|
||||
import React, { PureComponent } from 'react';
|
||||
import { translate, type TranslatorProps } from 'react-i18next';
|
||||
import { ToolbarGroup } from 'material-ui/Toolbar';
|
||||
import ToolbarIcon from '../UI/ToolbarIcon';
|
||||
import ToolbarSeparator from '../UI/ToolbarSeparator';
|
||||
|
||||
type Props = {|
|
||||
onDeleteSelection: () => void,
|
||||
canDelete: boolean,
|
||||
onOpenProperties: () => void,
|
||||
|} & TranslatorProps;
|
||||
|
||||
type State = {||};
|
||||
|
||||
export class Toolbar extends PureComponent<Props, State> {
|
||||
render() {
|
||||
const { t, canDelete } = this.props;
|
||||
|
||||
return (
|
||||
<ToolbarGroup lastChild>
|
||||
<ToolbarIcon
|
||||
onClick={this.props.onOpenProperties}
|
||||
src="res/ribbon_default/editprop32.png"
|
||||
tooltip={t('Open the properties panel')}
|
||||
/>
|
||||
<ToolbarSeparator />
|
||||
<ToolbarIcon
|
||||
onClick={this.props.onDeleteSelection}
|
||||
src="res/ribbon_default/deleteselected32.png"
|
||||
disabled={!canDelete}
|
||||
tooltip={t('Delete the selected resource')}
|
||||
/>
|
||||
</ToolbarGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate()(Toolbar);
|
156
newIDE/app/src/ResourcesEditor/index.js
Normal file
156
newIDE/app/src/ResourcesEditor/index.js
Normal file
@@ -0,0 +1,156 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import ResourcesList from '../ResourcesList';
|
||||
import ResourcePropertiesEditor from './ResourcePropertiesEditor';
|
||||
import Toolbar from './Toolbar';
|
||||
import EditorMosaic, { MosaicWindow } from '../UI/EditorMosaic';
|
||||
import InfoBar from '../UI/Messages/InfoBar';
|
||||
import ResourcesLoader from '../ObjectsRendering/ResourcesLoader';
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
};
|
||||
|
||||
type State = {
|
||||
showPropertiesInfoBar: boolean,
|
||||
selectedResource: ?gdResource,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
setToolbar: React.Node => void,
|
||||
project: gdProject,
|
||||
onDeleteResource: (resource: gdResource, cb: (boolean) => void) => void,
|
||||
onRenameResource: (
|
||||
resource: gdResource,
|
||||
newName: string,
|
||||
cb: (boolean) => void
|
||||
) => void,
|
||||
};
|
||||
|
||||
export default class InstancesFullEditor extends React.Component<Props, State> {
|
||||
static defaultProps = {
|
||||
setToolbar: () => {},
|
||||
};
|
||||
|
||||
editorMosaic: ?EditorMosaic = null;
|
||||
_propertiesEditor: ?ResourcePropertiesEditor = null;
|
||||
_resourcesList: ?ResourcesList = null;
|
||||
resourcesLoader = ResourcesLoader;
|
||||
state = {
|
||||
showPropertiesInfoBar: false,
|
||||
selectedResource: null,
|
||||
};
|
||||
|
||||
updateToolbar() {
|
||||
this.props.setToolbar(
|
||||
<Toolbar
|
||||
onOpenProperties={this.openProperties}
|
||||
canDelete={!!this.state.selectedResource}
|
||||
onDeleteSelection={() =>
|
||||
this.deleteResource(this.state.selectedResource)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
deleteResource = (resource: ?gdResource) => {
|
||||
const { project, onDeleteResource } = this.props;
|
||||
if (!resource) return;
|
||||
|
||||
//eslint-disable-next-line
|
||||
const answer = confirm(
|
||||
"Are you sure you want to remove this resource? This can't be undone."
|
||||
);
|
||||
if (!answer) return;
|
||||
|
||||
onDeleteResource(resource, doRemove => {
|
||||
if (!doRemove || !resource) return;
|
||||
|
||||
project.getResourcesManager().removeResource(resource.getName());
|
||||
this.setState(
|
||||
{
|
||||
selectedResource: null,
|
||||
},
|
||||
() => {
|
||||
if (this._resourcesList) this._resourcesList.forceUpdateList();
|
||||
this.updateToolbar();
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
openProperties = () => {
|
||||
if (!this.editorMosaic) return;
|
||||
if (!this.editorMosaic.openEditor('properties')) {
|
||||
this.setState({
|
||||
showPropertiesInfoBar: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
_onResourceSelected = (selectedResource: ?gdResource) => {
|
||||
this.setState(
|
||||
{
|
||||
selectedResource,
|
||||
},
|
||||
() => {
|
||||
if (this._propertiesEditor) this._propertiesEditor.forceUpdate();
|
||||
this.updateToolbar();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { project, onRenameResource } = this.props;
|
||||
const { selectedResource } = this.state;
|
||||
|
||||
console.log(selectedResource);
|
||||
|
||||
const editors = {
|
||||
properties: (
|
||||
<MosaicWindow
|
||||
title="Properties"
|
||||
// Pass resources to force MosaicWindow update when selectedResource is changed
|
||||
resources={selectedResource ? [selectedResource] : []}
|
||||
>
|
||||
<ResourcePropertiesEditor
|
||||
key={selectedResource ? selectedResource.ptr : undefined}
|
||||
resources={selectedResource ? [selectedResource] : []}
|
||||
project={project}
|
||||
resourcesLoader={this.resourcesLoader}
|
||||
ref={propertiesEditor =>
|
||||
(this._propertiesEditor = propertiesEditor)}
|
||||
/>
|
||||
</MosaicWindow>
|
||||
),
|
||||
'resources-list': (
|
||||
<ResourcesList
|
||||
project={project}
|
||||
onDeleteResource={this.deleteResource}
|
||||
onRenameResource={onRenameResource}
|
||||
onSelectResource={this._onResourceSelected}
|
||||
selectedResource={selectedResource}
|
||||
ref={resourcesList => (this._resourcesList = resourcesList)}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={styles.container}>
|
||||
<EditorMosaic
|
||||
editors={editors}
|
||||
ref={editorMosaic => (this.editorMosaic = editorMosaic)}
|
||||
initialEditorNames={['properties', 'resources-list']}
|
||||
/>
|
||||
<InfoBar
|
||||
message="Properties panel is already opened"
|
||||
show={!!this.state.showPropertiesInfoBar}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
19
newIDE/app/src/ResourcesList/EnumerateResources.js
Normal file
19
newIDE/app/src/ResourcesList/EnumerateResources.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// @flow
|
||||
|
||||
export const filterResourcesList = (
|
||||
list: Array<gdResource>,
|
||||
searchText: string
|
||||
): Array<gdResource> => {
|
||||
if (!searchText) return list;
|
||||
|
||||
const lowercaseSearchText = searchText.toLowerCase();
|
||||
|
||||
return list.filter((resource: gdResource) => {
|
||||
return (
|
||||
resource
|
||||
.getName()
|
||||
.toLowerCase()
|
||||
.indexOf(lowercaseSearchText) !== -1
|
||||
);
|
||||
});
|
||||
};
|
@@ -40,7 +40,7 @@ export default class ResourceSelector extends Component {
|
||||
}
|
||||
|
||||
_loadFrom(resourcesManager) {
|
||||
this.allResourcesNames = resourcesManager.getAllResourcesList().toJSArray();
|
||||
this.allResourcesNames = resourcesManager.getAllResourceNames().toJSArray();
|
||||
if (this.props.resourceKind) {
|
||||
this.allResourcesNames = this.allResourcesNames.filter(resourceName => {
|
||||
return (
|
187
newIDE/app/src/ResourcesList/index.js
Normal file
187
newIDE/app/src/ResourcesList/index.js
Normal file
@@ -0,0 +1,187 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { AutoSizer } from 'react-virtualized';
|
||||
import SortableVirtualizedItemList from '../UI/SortableVirtualizedItemList';
|
||||
import Paper from 'material-ui/Paper';
|
||||
import SearchBar from 'material-ui-search-bar';
|
||||
import { showWarningBox } from '../UI/Messages/MessageBox';
|
||||
import { filterResourcesList } from './EnumerateResources';
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
listContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
};
|
||||
|
||||
type State = {|
|
||||
renamedResource: ?gdResource,
|
||||
searchText: string,
|
||||
|};
|
||||
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
selectedResource: ?gdResource,
|
||||
onSelectResource: (resource: gdResource) => void,
|
||||
onDeleteResource: (resource: gdResource) => void,
|
||||
onRenameResource: (
|
||||
resource: gdResource,
|
||||
newName: string,
|
||||
cb: (boolean) => void
|
||||
) => void,
|
||||
|};
|
||||
|
||||
export default class ResourcesList extends React.Component<Props, State> {
|
||||
static defaultProps = {
|
||||
onDeleteResource: (resource: gdResource, cb: boolean => void) => cb(true),
|
||||
onRenameResource: (
|
||||
resource: gdResource,
|
||||
newName: string,
|
||||
cb: boolean => void
|
||||
) => cb(true),
|
||||
};
|
||||
|
||||
sortableList: any;
|
||||
state: State = {
|
||||
renamedResource: null,
|
||||
searchText: '',
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||
// The component is costly to render, so avoid any re-rendering as much
|
||||
// as possible.
|
||||
// We make the assumption that no changes to resources list is made outside
|
||||
// from the component.
|
||||
// If a change is made, the component won't notice it: you have to manually
|
||||
// call forceUpdate.
|
||||
|
||||
if (
|
||||
this.state.renamedResource !== nextState.renamedResource ||
|
||||
this.state.searchText !== nextState.searchText
|
||||
)
|
||||
return true;
|
||||
|
||||
if (
|
||||
this.props.project !== nextProps.project ||
|
||||
this.props.selectedResource !== nextProps.selectedResource
|
||||
)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_deleteResource = (resource: gdResource) => {
|
||||
this.props.onDeleteResource(resource);
|
||||
};
|
||||
|
||||
_editName = (resource: ?gdResource) => {
|
||||
this.setState(
|
||||
{
|
||||
renamedResource: resource,
|
||||
},
|
||||
() => this.sortableList.getWrappedInstance().forceUpdateGrid()
|
||||
);
|
||||
};
|
||||
|
||||
_rename = (resource: gdResource, newName: string) => {
|
||||
const { project } = this.props;
|
||||
this.setState({
|
||||
renamedResource: null,
|
||||
});
|
||||
|
||||
if (resource.getName() === newName) return;
|
||||
|
||||
if (project.getResourcesManager().hasResource(newName)) {
|
||||
showWarningBox('Another resource with this name already exists');
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onRenameResource(resource, newName, doRename => {
|
||||
if (!doRename) return;
|
||||
resource.setName(newName);
|
||||
this.forceUpdate();
|
||||
});
|
||||
};
|
||||
|
||||
_move = (oldIndex: number, newIndex: number) => {
|
||||
const { project } = this.props;
|
||||
|
||||
project.getResourcesManager().moveResource(oldIndex, newIndex);
|
||||
this.forceUpdateList();
|
||||
};
|
||||
|
||||
forceUpdateList = () => {
|
||||
this.forceUpdate();
|
||||
this.sortableList.getWrappedInstance().forceUpdateGrid();
|
||||
};
|
||||
|
||||
_renderResourceMenuTemplate = (resource: gdResource) => {
|
||||
return [
|
||||
{
|
||||
label: 'Rename',
|
||||
click: () => this._editName(resource),
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
click: () => this._deleteResource(resource),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
render() {
|
||||
const { project, selectedResource, onSelectResource } = this.props;
|
||||
const { searchText } = this.state;
|
||||
|
||||
const resourcesManager = project.getResourcesManager();
|
||||
const allResourcesList = resourcesManager
|
||||
.getAllResourceNames()
|
||||
.toJSArray()
|
||||
.map(resourceName => resourcesManager.getResource(resourceName));
|
||||
const filteredList = filterResourcesList(allResourcesList, searchText);
|
||||
|
||||
// Force List component to be mounted again if project or objectsContainer
|
||||
// has been changed. Avoid accessing to invalid objects that could
|
||||
// crash the app.
|
||||
const listKey = project.ptr;
|
||||
|
||||
return (
|
||||
<Paper style={styles.container}>
|
||||
<div style={styles.listContainer}>
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
<SortableVirtualizedItemList
|
||||
key={listKey}
|
||||
ref={sortableList => (this.sortableList = sortableList)}
|
||||
fullList={filteredList}
|
||||
width={width}
|
||||
height={height}
|
||||
selectedItem={selectedResource}
|
||||
onItemSelected={onSelectResource}
|
||||
renamedItem={this.state.renamedResource}
|
||||
onRename={this._rename}
|
||||
onSortEnd={({ oldIndex, newIndex }) =>
|
||||
this._move(oldIndex, newIndex)}
|
||||
helperClass="sortable-helper"
|
||||
distance={30}
|
||||
buildMenuTemplate={this._renderResourceMenuTemplate}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
<SearchBar
|
||||
value={searchText}
|
||||
onRequestSearch={() => {}}
|
||||
onChange={text =>
|
||||
this.setState({
|
||||
searchText: text,
|
||||
})}
|
||||
/>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
}
|
@@ -8,7 +8,6 @@ import EmptyMessage from '../../UI/EmptyMessage';
|
||||
import PropertiesEditor from '../../PropertiesEditor';
|
||||
import propertiesMapToSchema from '../../PropertiesEditor/PropertiesMapToSchema';
|
||||
import some from 'lodash/some';
|
||||
const gd = global.gd;
|
||||
|
||||
export default class ScenePropertiesDialog extends Component {
|
||||
constructor(props) {
|
||||
@@ -60,6 +59,7 @@ export default class ScenePropertiesDialog extends Component {
|
||||
// />,
|
||||
<FlatButton
|
||||
label="Ok"
|
||||
key="ok"
|
||||
primary={true}
|
||||
keyboardFocused={true}
|
||||
onClick={this._onApply}
|
||||
|
116
newIDE/app/src/UI/SortableVirtualizedItemList/ItemRow.js
Normal file
116
newIDE/app/src/UI/SortableVirtualizedItemList/ItemRow.js
Normal file
@@ -0,0 +1,116 @@
|
||||
import React from 'react';
|
||||
import { ListItem } from 'material-ui/List';
|
||||
import IconMenu from '../Menu/IconMenu';
|
||||
import ListIcon from '../ListIcon';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert';
|
||||
import muiThemeable from 'material-ui/styles/muiThemeable';
|
||||
import { type Item } from '.';
|
||||
|
||||
const styles = {
|
||||
itemName: {
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
},
|
||||
textField: {
|
||||
top: -16,
|
||||
},
|
||||
};
|
||||
|
||||
type Props = {
|
||||
index: number,
|
||||
item: Item,
|
||||
onRename: (string) => void,
|
||||
editingName: boolean,
|
||||
getThumbnail?: () => string,
|
||||
selected: true,
|
||||
onItemSelected: () => void,
|
||||
buildMenuTemplate: Item => any,
|
||||
};
|
||||
|
||||
class ThemableItemRow extends React.Component<Props, *> {
|
||||
_renderItemMenu(item) {
|
||||
return (
|
||||
<IconMenu
|
||||
ref={iconMenu => (this._iconMenu = iconMenu)}
|
||||
iconButtonElement={
|
||||
<IconButton>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
}
|
||||
buildMenuTemplate={() => this.props.buildMenuTemplate(item)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!prevProps.editingName && this.props.editingName) {
|
||||
setTimeout(() => {
|
||||
if (this.textField) this.textField.focus();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
_onContextMenu = event => {
|
||||
if (this._iconMenu) this._iconMenu.open(event);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { item, selected, style, getThumbnail, muiTheme } = this.props;
|
||||
|
||||
const itemName = item.getName();
|
||||
const label = this.props.editingName ? (
|
||||
<TextField
|
||||
id="rename-item-field"
|
||||
ref={textField => (this.textField = textField)}
|
||||
defaultValue={itemName}
|
||||
onBlur={e => this.props.onRename(e.target.value)}
|
||||
onKeyPress={event => {
|
||||
if (event.charCode === 13) {
|
||||
// enter key pressed
|
||||
this.textField.blur();
|
||||
}
|
||||
}}
|
||||
fullWidth
|
||||
style={styles.textField}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
...styles.itemName,
|
||||
color: selected ? muiTheme.listItem.selectedTextColor : undefined,
|
||||
}}
|
||||
>
|
||||
{itemName}
|
||||
</div>
|
||||
);
|
||||
|
||||
const itemStyle = {
|
||||
borderBottom: `1px solid ${muiTheme.listItem.separatorColor}`,
|
||||
backgroundColor: selected
|
||||
? muiTheme.listItem.selectedBackgroundColor
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
style={{ ...itemStyle, ...style }}
|
||||
onContextMenu={this._onContextMenu}
|
||||
primaryText={label}
|
||||
leftIcon={getThumbnail && <ListIcon src={getThumbnail()} />}
|
||||
rightIconButton={this._renderItemMenu(item)}
|
||||
onClick={() => {
|
||||
if (!this.props.onItemSelected) return;
|
||||
if (this.props.editingName) return;
|
||||
|
||||
this.props.onItemSelected(selected ? null : item);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ItemRow = muiThemeable()(ThemableItemRow);
|
||||
export default ItemRow;
|
108
newIDE/app/src/UI/SortableVirtualizedItemList/index.js
Normal file
108
newIDE/app/src/UI/SortableVirtualizedItemList/index.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { List } from 'react-virtualized';
|
||||
import { ListItem } from 'material-ui/List';
|
||||
import ItemRow from './ItemRow';
|
||||
import { makeAddItem } from '../ListAddItem';
|
||||
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
||||
|
||||
const listItemHeight = 48; // TODO: Move this into theme?
|
||||
|
||||
const AddItemRow = makeAddItem(ListItem);
|
||||
|
||||
const SortableItemRow = SortableElement(props => {
|
||||
const { style, ...otherProps } = props;
|
||||
return (
|
||||
<div style={style}>
|
||||
<ItemRow {...otherProps} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const SortableAddItemRow = SortableElement(props => {
|
||||
return <AddItemRow {...props} />;
|
||||
});
|
||||
|
||||
export type Item = {
|
||||
key: string | number,
|
||||
getName: () => string,
|
||||
};
|
||||
|
||||
type ItemsListProps = {
|
||||
height: number,
|
||||
width: number,
|
||||
fullList: Array<Item>,
|
||||
selectedItem: ?Item,
|
||||
onAddNewItem?: () => void,
|
||||
onRename: (Item, string) => void,
|
||||
getThumbnail?: Item => string,
|
||||
onItemSelected: ?Item => void,
|
||||
renamedItem: ?Item,
|
||||
addNewItemLabel: React.Node | string,
|
||||
buildMenuTemplate: Item => any,
|
||||
};
|
||||
|
||||
class ItemsList extends React.Component<ItemsListProps, *> {
|
||||
list: any;
|
||||
|
||||
forceUpdateGrid() {
|
||||
if (this.list) this.list.forceUpdateGrid();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
height,
|
||||
width,
|
||||
fullList,
|
||||
selectedItem,
|
||||
addNewItemLabel,
|
||||
renamedItem,
|
||||
getThumbnail,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<List
|
||||
ref={list => (this.list = list)}
|
||||
height={height}
|
||||
rowCount={fullList.length}
|
||||
rowHeight={listItemHeight}
|
||||
rowRenderer={({ index, key, style }) => {
|
||||
const item = fullList[index];
|
||||
if (item.key === 'add-item-row') {
|
||||
return (
|
||||
<SortableAddItemRow
|
||||
index={fullList.length}
|
||||
key={key}
|
||||
style={style}
|
||||
disabled
|
||||
onClick={this.props.onAddNewItem}
|
||||
primaryText={addNewItemLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const nameBeingEdited = renamedItem === item;
|
||||
|
||||
return (
|
||||
<SortableItemRow
|
||||
index={index}
|
||||
key={key}
|
||||
item={item}
|
||||
style={style}
|
||||
onRename={newName => this.props.onRename(item, newName)}
|
||||
editingName={nameBeingEdited}
|
||||
getThumbnail={getThumbnail ? () => getThumbnail(item) : undefined}
|
||||
selected={item === selectedItem}
|
||||
onItemSelected={this.props.onItemSelected}
|
||||
buildMenuTemplate={this.props.buildMenuTemplate}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SortableItemsList = SortableContainer(ItemsList, { withRef: true });
|
||||
export default SortableItemsList;
|
@@ -1,89 +1,109 @@
|
||||
// @flow
|
||||
import Keen from 'keen-tracking';
|
||||
import Window from '../Window';
|
||||
import { getUserUUID } from './UserUUID';
|
||||
import Authentification from '../GDevelopServices/Authentification';
|
||||
import {
|
||||
getProgramOpeningCount,
|
||||
incrementProgramOpeningCount,
|
||||
} from './LocalStats';
|
||||
|
||||
const sessionCookie = Keen.utils.cookie('visitor-stats');
|
||||
const sessionTimer = Keen.utils.timer();
|
||||
sessionTimer.start();
|
||||
const isDev = Window.isDev();
|
||||
let client = null;
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
export const installAnalyticsEvents = (authentification: Authentification) => {
|
||||
const sessionCookie = Keen.utils.cookie('visitor-stats');
|
||||
const sessionTimer = Keen.utils.timer();
|
||||
sessionTimer.start();
|
||||
|
||||
var client = new Keen({
|
||||
projectId: '593d9f0595cfc907a1f8126a',
|
||||
writeKey:
|
||||
'B917F1DB50EE4C8949DBB374D2962845A22838B425AA43322A37138691A5270EB0358AEE45A4F61AFA7713B9765B4980517A1E276D4973A2E546EA851BF7757523706367ED430C041D2728A63BF61B5D1B2079C75E455DDDFAAC4324128AC2DB',
|
||||
});
|
||||
client = new Keen({
|
||||
projectId: '593d9f0595cfc907a1f8126a',
|
||||
writeKey:
|
||||
'B917F1DB50EE4C8949DBB374D2962845A22838B425AA43322A37138691A5270EB0358AEE45A4F61AFA7713B9765B4980517A1E276D4973A2E546EA851BF7757523706367ED430C041D2728A63BF61B5D1B2079C75E455DDDFAAC4324128AC2DB',
|
||||
});
|
||||
|
||||
client.extendEvents(function() {
|
||||
return {
|
||||
user: {
|
||||
uuid: getUserUUID(),
|
||||
},
|
||||
page: {
|
||||
title: document.title,
|
||||
url: document.location.href,
|
||||
// info: {} (add-on)
|
||||
},
|
||||
referrer: {
|
||||
url: document.referrer,
|
||||
// info: {} (add-on)
|
||||
},
|
||||
tech: {
|
||||
browser: Keen.helpers.getBrowserProfile(),
|
||||
// info: {} (add-on)
|
||||
ip: '${keen.ip}', // eslint-disable-line
|
||||
ua: '${keen.user_agent}', // eslint-disable-line
|
||||
},
|
||||
time: Keen.helpers.getDatetimeIndex(),
|
||||
visitor: {
|
||||
id: sessionCookie.get('user_id'),
|
||||
time_on_page: sessionTimer.value(),
|
||||
},
|
||||
// geo: {} (add-on)
|
||||
keen: {
|
||||
timestamp: new Date().toISOString(),
|
||||
addons: [
|
||||
{
|
||||
name: 'keen:ip_to_geo',
|
||||
input: {
|
||||
ip: 'tech.ip',
|
||||
client.extendEvents(function() {
|
||||
const userProfile = authentification.getUserProfileSync();
|
||||
|
||||
return {
|
||||
user: {
|
||||
uuid: getUserUUID(),
|
||||
uid: userProfile ? userProfile.uid : undefined,
|
||||
providerId: userProfile ? userProfile.providerId : undefined,
|
||||
email: userProfile ? userProfile.email : undefined,
|
||||
emailVerified: userProfile ? userProfile.emailVerified : undefined,
|
||||
},
|
||||
localStats: {
|
||||
programOpeningCount: getProgramOpeningCount(),
|
||||
},
|
||||
page: {
|
||||
title: document.title,
|
||||
url: document.location.href,
|
||||
// info: {} (add-on)
|
||||
},
|
||||
referrer: {
|
||||
url: document.referrer,
|
||||
// info: {} (add-on)
|
||||
},
|
||||
tech: {
|
||||
browser: Keen.helpers.getBrowserProfile(),
|
||||
// info: {} (add-on)
|
||||
ip: '${keen.ip}', // eslint-disable-line
|
||||
ua: '${keen.user_agent}', // eslint-disable-line
|
||||
},
|
||||
time: Keen.helpers.getDatetimeIndex(),
|
||||
visitor: {
|
||||
id: sessionCookie.get('user_id'),
|
||||
time_on_page: sessionTimer.value(),
|
||||
},
|
||||
// geo: {} (add-on)
|
||||
keen: {
|
||||
timestamp: new Date().toISOString(),
|
||||
addons: [
|
||||
{
|
||||
name: 'keen:ip_to_geo',
|
||||
input: {
|
||||
ip: 'tech.ip',
|
||||
},
|
||||
output: 'geo',
|
||||
},
|
||||
output: 'geo',
|
||||
},
|
||||
{
|
||||
name: 'keen:ua_parser',
|
||||
input: {
|
||||
ua_string: 'tech.ua',
|
||||
{
|
||||
name: 'keen:ua_parser',
|
||||
input: {
|
||||
ua_string: 'tech.ua',
|
||||
},
|
||||
output: 'tech.info',
|
||||
},
|
||||
output: 'tech.info',
|
||||
},
|
||||
{
|
||||
name: 'keen:url_parser',
|
||||
input: {
|
||||
url: 'page.url',
|
||||
{
|
||||
name: 'keen:url_parser',
|
||||
input: {
|
||||
url: 'page.url',
|
||||
},
|
||||
output: 'page.info',
|
||||
},
|
||||
output: 'page.info',
|
||||
},
|
||||
{
|
||||
name: 'keen:referrer_parser',
|
||||
input: {
|
||||
page_url: 'page.url',
|
||||
referrer_url: 'referrer.url',
|
||||
{
|
||||
name: 'keen:referrer_parser',
|
||||
input: {
|
||||
page_url: 'page.url',
|
||||
referrer_url: 'referrer.url',
|
||||
},
|
||||
output: 'referrer.info',
|
||||
},
|
||||
output: 'referrer.info',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
});
|
||||
],
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const sendProgramOpening = () => {
|
||||
if (isDev) return;
|
||||
if (isDev || !client) return;
|
||||
|
||||
incrementProgramOpeningCount();
|
||||
client.recordEvent('program_opening');
|
||||
};
|
||||
|
||||
export const sendExportLaunched = exportKind => {
|
||||
if (isDev) return;
|
||||
export const sendExportLaunched = (exportKind: string) => {
|
||||
if (isDev || !client) return;
|
||||
|
||||
client.recordEvent('export_launched', {
|
||||
platform: 'GDevelop JS Platform', // Hardcoded here for now
|
||||
@@ -91,8 +111,8 @@ export const sendExportLaunched = exportKind => {
|
||||
});
|
||||
};
|
||||
|
||||
export const sendNewGameCreated = templateName => {
|
||||
if (isDev) return;
|
||||
export const sendNewGameCreated = (templateName: string) => {
|
||||
if (isDev || !client) return;
|
||||
|
||||
client.recordEvent('new_game_creation', {
|
||||
platform: 'GDevelop JS Platform', // Hardcoded here for now
|
||||
@@ -100,16 +120,20 @@ export const sendNewGameCreated = templateName => {
|
||||
});
|
||||
};
|
||||
|
||||
export const sendTutorialOpened = tutorialName => {
|
||||
if (isDev) return;
|
||||
export const sendTutorialOpened = (tutorialName: string) => {
|
||||
if (isDev || !client) return;
|
||||
|
||||
client.recordEvent('tutorial_opened', {
|
||||
tutorialName,
|
||||
});
|
||||
};
|
||||
|
||||
export const sendErrorMessage = (errorMessage, type, rawError) => {
|
||||
if (isDev) return;
|
||||
export const sendErrorMessage = (
|
||||
errorMessage: string,
|
||||
type: string,
|
||||
rawError: any
|
||||
) => {
|
||||
if (isDev || !client) return;
|
||||
|
||||
client.recordEvent('error_message', {
|
||||
message: errorMessage,
|
||||
@@ -118,8 +142,8 @@ export const sendErrorMessage = (errorMessage, type, rawError) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const sendSignupDone = email => {
|
||||
if (isDev) return;
|
||||
export const sendSignupDone = (email: string) => {
|
||||
if (isDev || !client) return;
|
||||
|
||||
client.recordEvent('signup', {
|
||||
email,
|
||||
|
@@ -1,9 +1,32 @@
|
||||
import { getUserUUID } from './UserUUID';
|
||||
const FS = global.FS;
|
||||
import optionalRequire from '../OptionalRequire';
|
||||
import Window from '../Window';
|
||||
const electron = optionalRequire('electron');
|
||||
|
||||
export const installFullstory = () => {
|
||||
if (FS) {
|
||||
FS.identify(getUserUUID(), {
|
||||
// prettier-ignore
|
||||
if (!electron && !Window.isDev()) {
|
||||
window['_fs_debug'] = false;
|
||||
window['_fs_host'] = 'fullstory.com';
|
||||
window['_fs_org'] = '8DWZ1';
|
||||
window['_fs_namespace'] = 'FS';
|
||||
(function(m,n,e,t,l,o,g,y){
|
||||
if (e in m) {if(m.console && m.console.log) { m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].');} return;}
|
||||
g=m[e]=function(a,b){g.q?g.q.push([a,b]):g._api(a,b);};g.q=[];
|
||||
o=n.createElement(t);o.async=1;o.src='https://'+_fs_host+'/s/fs.js'; //eslint-disable-line
|
||||
y=n.getElementsByTagName(t)[0];y.parentNode.insertBefore(o,y);
|
||||
g.identify=function(i,v){g(l,{uid:i});if(v)g(l,v)};g.setUserVars=function(v){g(l,v)};
|
||||
g.identifyAccount=function(i,v){o='account';v=v||{};v.acctId=i;g(o,v)};
|
||||
g.clearUserCookie=function(c,d,i){if(!c || document.cookie.match('fs_uid=[`;`]*`[`;`]*`[`;`]*`')){
|
||||
d=n.domain;while(1){n.cookie='fs_uid=;domain='+d+
|
||||
';path=/;expires='+new Date(0).toUTCString();i=d.indexOf('.');if(i<0)break;d=d.slice(i+1)}}};
|
||||
})(window,document,window['_fs_namespace'],'script','user');
|
||||
} else {
|
||||
console.info("Electron or development build - Fullstory disabled");
|
||||
}
|
||||
|
||||
if (window.FS) {
|
||||
window.FS.identify(getUserUUID(), {
|
||||
// displayName: 'Daniel Falko',
|
||||
// email: 'danielfalko@example.com',
|
||||
});
|
||||
|
23
newIDE/app/src/Utils/Analytics/LocalStats.js
Normal file
23
newIDE/app/src/Utils/Analytics/LocalStats.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// @flow
|
||||
const localStoragePrefix = 'gd-local-stats';
|
||||
|
||||
export const getProgramOpeningCount = (): number => {
|
||||
try {
|
||||
const count = localStorage.getItem(`${localStoragePrefix}-program-opening`);
|
||||
if (count !== null) return parseInt(count, 10);
|
||||
} catch (e) {
|
||||
console.warn('Unable to load stored program opening count', e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
export const incrementProgramOpeningCount = () => {
|
||||
const count = getProgramOpeningCount() + 1;
|
||||
|
||||
try {
|
||||
localStorage.setItem(`${localStoragePrefix}-program-opening`, '' + count);
|
||||
} catch (e) {
|
||||
console.warn('Unable to store program opening count', e);
|
||||
}
|
||||
};
|
@@ -4,7 +4,7 @@ import { GDevelopFirebaseConfig } from './ApiConfigs';
|
||||
|
||||
export type Profile = {
|
||||
uid: string, // This represents the userId
|
||||
picture: string,
|
||||
providerId: string,
|
||||
email: string,
|
||||
emailVerified: boolean,
|
||||
};
|
||||
@@ -76,6 +76,10 @@ export default class Authentification {
|
||||
cb(null, this.user);
|
||||
};
|
||||
|
||||
getUserProfileSync = (): ?Profile => {
|
||||
return this.user;
|
||||
};
|
||||
|
||||
logout = () => {
|
||||
firebase
|
||||
.auth()
|
||||
|
@@ -8,7 +8,7 @@ import { type Profile } from '../Utils/GDevelopServices/Authentification';
|
||||
|
||||
export const profileForIndieUser: Profile = {
|
||||
uid: 'indie-user',
|
||||
picture: '',
|
||||
providerId: 'fake-provider.com',
|
||||
email: 'indie-user@example.com',
|
||||
emailVerified: true,
|
||||
};
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// @flow
|
||||
import 'element-closest';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
@@ -6,10 +7,10 @@ import Window from './Utils/Window';
|
||||
import ExportDialog from './Export/ExportDialog';
|
||||
import CreateProjectDialog from './ProjectCreation/CreateProjectDialog';
|
||||
import Authentification from './Utils/GDevelopServices/Authentification';
|
||||
import { sendProgramOpening } from './Utils/Analytics/EventSender';
|
||||
import { sendProgramOpening, installAnalyticsEvents } from './Utils/Analytics/EventSender';
|
||||
import { installRaven } from './Utils/Analytics/Raven';
|
||||
import { installFullstory } from './Utils/Analytics/Fullstory';
|
||||
import registerServiceWorker from './registerServiceWorker';
|
||||
import { unregister } from './registerServiceWorker';
|
||||
import './UI/iconmoon-font.css'; // Styles for Iconmoon font.
|
||||
import 'react-virtualized/styles.css'; // Styles for react-virtualized Table
|
||||
|
||||
@@ -18,7 +19,7 @@ import BrowserExamples from './ProjectCreation/BrowserExamples';
|
||||
import BrowserProjectOpener from './ProjectsStorage/BrowserProjectOpener';
|
||||
import BrowserSaveDialog from './ProjectsStorage/BrowserSaveDialog';
|
||||
import BrowserIntroDialog from './MainFrame/BrowserIntroDialog';
|
||||
import browserResourceSources from './ResourcesEditor/BrowserResourceSources';
|
||||
import browserResourceSources from './ResourcesList/BrowserResourceSources';
|
||||
import BrowserS3PreviewLauncher from './Export/BrowserExporters/BrowserS3PreviewLauncher';
|
||||
import { getBrowserExporters } from './Export/BrowserExporters';
|
||||
|
||||
@@ -26,7 +27,7 @@ import { getBrowserExporters } from './Export/BrowserExporters';
|
||||
import ExternalEditor from './ExternalEditor';
|
||||
import optionalRequire from './Utils/OptionalRequire.js';
|
||||
import LocalExamples from './ProjectCreation/LocalExamples';
|
||||
import localResourceSources from './ResourcesEditor/LocalResourceSources';
|
||||
import localResourceSources from './ResourcesList/LocalResourceSources';
|
||||
import LocalProjectWriter from './ProjectsStorage/LocalProjectWriter';
|
||||
import LocalProjectOpener from './ProjectsStorage/LocalProjectOpener';
|
||||
import LocalPreviewLauncher from './Export/LocalExporters/LocalPreviewLauncher';
|
||||
@@ -35,12 +36,14 @@ import ElectronEventsBridge from './MainFrame/ElectronEventsBridge';
|
||||
import LocalIntroDialog from './MainFrame/LocalIntroDialog';
|
||||
const electron = optionalRequire('electron');
|
||||
|
||||
|
||||
const authentification = new Authentification();
|
||||
installAnalyticsEvents(authentification);
|
||||
installRaven();
|
||||
installFullstory();
|
||||
|
||||
Window.setUpContextMenu();
|
||||
|
||||
const authentification = new Authentification();
|
||||
let app = null;
|
||||
|
||||
if (electron) {
|
||||
@@ -97,6 +100,10 @@ if (electron) {
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(app, document.getElementById('root'));
|
||||
registerServiceWorker();
|
||||
const rootElement = document.getElementById('root');
|
||||
if (rootElement) ReactDOM.render(app, rootElement);
|
||||
else console.error("No root element defined in index.html");
|
||||
|
||||
// registerServiceWorker();
|
||||
unregister();
|
||||
sendProgramOpening();
|
||||
|
@@ -539,8 +539,6 @@ storiesOf('ProfileDetails', module)
|
||||
<ProfileDetails
|
||||
profile={{
|
||||
email: 'test@example.com',
|
||||
picture:
|
||||
'"https://s.gravatar.com/avatar/d6fc8df7ddfe938cc379c53bfb5645fc?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Ffl.png',
|
||||
}}
|
||||
/>
|
||||
))
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "gdevelop",
|
||||
"productName": "GDevelop 5",
|
||||
"description": "GDevelop 5 IDE running on the Electron runtime",
|
||||
"version": "5.0.0-beta22",
|
||||
"version": "5.0.0-beta24",
|
||||
"author": "Florian Rival",
|
||||
"license": "MIT",
|
||||
"homepage": "http://compilgames.net",
|
||||
|
Reference in New Issue
Block a user