mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Add AudioResourceField
This commit is contained in:
1
newIDE/app/flow-typed/libGD.js
vendored
1
newIDE/app/flow-typed/libGD.js
vendored
@@ -15,6 +15,7 @@ declare type gdInitialInstance = EmscriptenObject;
|
||||
declare type gdBaseEvent = EmscriptenObject;
|
||||
declare type gdResource = EmscriptenObject;
|
||||
declare type gdObject = EmscriptenObject;
|
||||
declare type gdResourcesManager = EmscriptenObject;
|
||||
|
||||
declare type gdInstruction = EmscriptenObject;
|
||||
declare type gdInstructionMetadata = EmscriptenObject;
|
||||
|
@@ -114,6 +114,8 @@ export default class InstructionParametersEditor extends Component {
|
||||
this.forceUpdate();
|
||||
}}
|
||||
parameterRenderingService={ParameterRenderingService}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@@ -0,0 +1,33 @@
|
||||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import ResourceSelector from '../../../ResourcesList/ResourceSelector';
|
||||
import { type ParameterFieldProps } from './ParameterFieldProps.flow';
|
||||
|
||||
export default class AudioResourceField extends Component<
|
||||
ParameterFieldProps,
|
||||
void
|
||||
> {
|
||||
focus() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.resourceSources || !this.props.onChooseResource) {
|
||||
console.error("Missing resourceSources or onChooseResource for AudioResourceField");
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ResourceSelector
|
||||
project={this.props.project}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
resourceKind="audio"
|
||||
fullWidth
|
||||
initialResourceName={this.props.value}
|
||||
onChange={this.props.onChange}
|
||||
floatingLabelText="Choose the audio file to use"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,4 +1,10 @@
|
||||
// @flow
|
||||
import {
|
||||
type ResourceSource,
|
||||
type ChooseResourceFunction,
|
||||
} from '../../../ResourcesList/ResourceSource.flow';
|
||||
|
||||
|
||||
export type ParameterFieldProps = {|
|
||||
parameterMetadata?: gdParameterMetadata,
|
||||
project: gdProject,
|
||||
@@ -10,4 +16,6 @@ export type ParameterFieldProps = {|
|
||||
components: any,
|
||||
getParameterComponent: (type: string) => any,
|
||||
},
|
||||
resourceSources?: Array<ResourceSource>,
|
||||
onChooseResource?: ChooseResourceFunction,
|
||||
|};
|
||||
|
@@ -14,6 +14,7 @@ import SceneVariableField from './ParameterFields/SceneVariableField';
|
||||
import GlobalVariableField from './ParameterFields/GlobalVariableField';
|
||||
import ObjectVariableField from './ParameterFields/ObjectVariableField';
|
||||
import LayerField from './ParameterFields/LayerField';
|
||||
import AudioResourceField from './ParameterFields/AudioResourceField';
|
||||
const gd = global.gd;
|
||||
|
||||
const components = {
|
||||
@@ -33,8 +34,8 @@ const components = {
|
||||
layer: LayerField,
|
||||
key: KeyField,
|
||||
file: DefaultField, //TODO
|
||||
musicfile: DefaultField, //TODO
|
||||
soundfile: DefaultField, //TODO
|
||||
musicfile: AudioResourceField,
|
||||
soundfile: AudioResourceField,
|
||||
color: DefaultField, //TODO
|
||||
police: DefaultField, //TODO
|
||||
joyaxis: DefaultField, //TODO
|
||||
|
@@ -42,6 +42,8 @@ export default class InstructionEditor extends Component {
|
||||
layout={layout}
|
||||
isCondition={isCondition}
|
||||
instruction={instruction}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
/>
|
||||
</Paper>
|
||||
</div>
|
||||
|
@@ -654,6 +654,8 @@ export default class EventsSheet extends Component {
|
||||
this.closeInstructionEditor(true);
|
||||
this._eventsTree.forceEventsUpdate();
|
||||
}}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -45,6 +45,8 @@ export default class EventsEditor extends BaseEditor {
|
||||
events={layout.getEvents()}
|
||||
onPreview={(options) => this.props.onPreview(project, layout, options)}
|
||||
onOpenExternalEvents={this.props.onOpenExternalEvents}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -98,6 +98,8 @@ export default class ExternalEventsEditor extends BaseEditor {
|
||||
onPreview={() => this.props.onPreview(project, layout)}
|
||||
onOpenSettings={this.openLayoutChooser}
|
||||
onOpenExternalEvents={this.props.onOpenExternalEvents}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
/>
|
||||
)}
|
||||
{!layout && (
|
||||
|
@@ -527,8 +527,10 @@ export default class MainFrame extends React.Component<Props, State> {
|
||||
openEventsEditor: true,
|
||||
openSceneEditor: false,
|
||||
})}
|
||||
isActive={isActive}
|
||||
ref={editorRef}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this._onChooseResource}
|
||||
isActive={isActive}
|
||||
ref={editorRef}
|
||||
/>
|
||||
),
|
||||
key: 'layout events ' + name,
|
||||
@@ -563,8 +565,8 @@ export default class MainFrame extends React.Component<Props, State> {
|
||||
openEventsEditor: true,
|
||||
openSceneEditor: false,
|
||||
})}
|
||||
isActive={isActive}
|
||||
ref={editorRef}
|
||||
isActive={isActive}
|
||||
ref={editorRef}
|
||||
/>
|
||||
),
|
||||
key: 'external events ' + name,
|
||||
@@ -941,7 +943,8 @@ export default class MainFrame extends React.Component<Props, State> {
|
||||
hideLabels={!!this.props.integratedEditor}
|
||||
>
|
||||
{getEditors(this.state.editorTabs).map((editorTab, id) => {
|
||||
const isCurrentTab = getCurrentTabIndex(this.state.editorTabs) === id;
|
||||
const isCurrentTab =
|
||||
getCurrentTabIndex(this.state.editorTabs) === id;
|
||||
return (
|
||||
<Tab
|
||||
label={editorTab.name}
|
||||
@@ -952,7 +955,9 @@ export default class MainFrame extends React.Component<Props, State> {
|
||||
closable={editorTab.closable}
|
||||
>
|
||||
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
|
||||
<ErrorBoundary>{editorTab.render(isCurrentTab)}</ErrorBoundary>
|
||||
<ErrorBoundary>
|
||||
{editorTab.render(isCurrentTab)}
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</Tab>
|
||||
);
|
||||
|
@@ -111,9 +111,12 @@ export default class SpritesList extends Component {
|
||||
project,
|
||||
direction,
|
||||
} = this.props;
|
||||
if (!resourceSources || !resourceSources.length) return;
|
||||
if (!resourceSources) return;
|
||||
|
||||
onChooseResource(resourceSources[0].name).then(resources => {
|
||||
const sources = resourceSources.filter(source => source.kind === 'image');
|
||||
if (!sources.length) return;
|
||||
|
||||
onChooseResource(sources[0].name).then(resources => {
|
||||
resources.forEach(resource => {
|
||||
project.getResourcesManager().addResource(resource);
|
||||
|
||||
|
@@ -1,9 +1,25 @@
|
||||
// @flow
|
||||
import React from 'react';
|
||||
import ResourcesLoader from '../ResourcesLoader';
|
||||
import ResourceSelector from '../ResourcesList/ResourceSelector';
|
||||
import {
|
||||
type ResourceSource,
|
||||
type ChooseResourceFunction,
|
||||
type ResourceKind,
|
||||
} from '../ResourcesList/ResourceSource.flow';
|
||||
import ImageThumbnail from './ImageThumbnail';
|
||||
|
||||
export default ({
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
resourceSources: Array<ResourceSource>,
|
||||
onChooseResource: ChooseResourceFunction,
|
||||
resourceKind: ResourceKind,
|
||||
resourceName: string,
|
||||
onChange: (string) => void,
|
||||
floatingLabelText?: string,
|
||||
|};
|
||||
|
||||
const ResourceSelectorWithThumbnail = ({
|
||||
project,
|
||||
resourceSources,
|
||||
onChooseResource,
|
||||
@@ -11,7 +27,7 @@ export default ({
|
||||
resourceName,
|
||||
onChange,
|
||||
floatingLabelText,
|
||||
}) => {
|
||||
}: Props) => {
|
||||
return (
|
||||
<div style={{ flex: 1, display: 'flex', alignItems: 'flex-end' }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
@@ -35,3 +51,5 @@ export default ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResourceSelectorWithThumbnail;
|
||||
|
@@ -219,7 +219,6 @@ export default class PlatformSpecificAssetsDialog extends React.Component<
|
||||
onChooseResource={onChooseResource}
|
||||
resourceKind="image"
|
||||
resourceName={androidIconResourceNames[index]}
|
||||
resourcesLoader={ResourcesLoader}
|
||||
onChange={resourceName => {
|
||||
const newIcons = [...androidIconResourceNames];
|
||||
newIcons[index] = resourceName;
|
||||
@@ -239,7 +238,6 @@ export default class PlatformSpecificAssetsDialog extends React.Component<
|
||||
onChooseResource={onChooseResource}
|
||||
resourceKind="image"
|
||||
resourceName={iosIconResourceNames[index]}
|
||||
resourcesLoader={ResourcesLoader}
|
||||
onChange={resourceName => {
|
||||
const newIcons = [...iosIconResourceNames];
|
||||
newIcons[index] = resourceName;
|
||||
|
@@ -74,119 +74,171 @@ const publicImageUrls = [
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/laserRed11.png',
|
||||
];
|
||||
|
||||
const publicAudioUrls = [
|
||||
// Platformer audio (see platformer.json in fixtures)
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/platformer/jump.wav',
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/platformer/coin.wav',
|
||||
|
||||
// Space shooter audio (see space-shooter.json in fixtures)
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/sfx_laser1.ogg',
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/sfx_twoTone.ogg',
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/sfx_shieldDown.ogg',
|
||||
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/sfx_lose.ogg',
|
||||
];
|
||||
|
||||
const nameFromUrl = (url: string): string => {
|
||||
const urlParts = url.split('/');
|
||||
return urlParts[urlParts.length - 1].replace('.png', '');
|
||||
return urlParts[urlParts.length - 1]
|
||||
.replace('.png', '')
|
||||
.replace('.wav', '')
|
||||
.replace('.ogg', '');
|
||||
};
|
||||
|
||||
class GenericResourcesChooser extends Component {
|
||||
state = {
|
||||
open: false,
|
||||
resolveWithResources: null,
|
||||
chosenResourceUrl: null,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Cache rendered public images list to avoid doing this each time
|
||||
// a rendering is done.
|
||||
this.listItems = props.urls.map((url: string) => {
|
||||
return (
|
||||
<ListItem
|
||||
value={url}
|
||||
key={url}
|
||||
primaryText={nameFromUrl(url)}
|
||||
leftAvatar={props.urlsAreImages && <ListIcon src={url} />}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
chooseResources = (project, multiSelections = true): Promise<Array<any>> => {
|
||||
return new Promise(resolve => {
|
||||
this.setState({
|
||||
open: true,
|
||||
resolveWithResources: resolve,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
_onChoose = () => {
|
||||
const { resolveWithResources, chosenResourceUrl } = this.state;
|
||||
if (!resolveWithResources) return;
|
||||
|
||||
const newResource = this.props.createNewResource();
|
||||
newResource.setFile(chosenResourceUrl);
|
||||
newResource.setName(chosenResourceUrl);
|
||||
|
||||
resolveWithResources([newResource]);
|
||||
this.setState({
|
||||
open: false,
|
||||
resolveWithResources: null,
|
||||
});
|
||||
};
|
||||
|
||||
_onClose = () => {
|
||||
const { resolveWithResources } = this.state;
|
||||
if (!resolveWithResources) return;
|
||||
|
||||
resolveWithResources([]);
|
||||
this.setState({
|
||||
open: false,
|
||||
resolveWithResources: null,
|
||||
});
|
||||
};
|
||||
|
||||
_handleChangeResource = (e, chosenResourceUrl) => {
|
||||
this.setState({
|
||||
chosenResourceUrl,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
// Avoid rendering the dialog if it's not opened.
|
||||
if (!this.state.open) return null;
|
||||
|
||||
const actions = [
|
||||
<FlatButton label="Close" primary={false} onClick={this._onClose} />,
|
||||
<FlatButton
|
||||
label="Choose"
|
||||
primary={false}
|
||||
disabled={!this.state.chosenResourceUrl}
|
||||
onClick={this._onChoose}
|
||||
/>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={this.props.title}
|
||||
actions={actions}
|
||||
open={this.state.open}
|
||||
noMargin
|
||||
autoScrollBodyContent
|
||||
>
|
||||
<div style={styles.explanations}>
|
||||
<p>
|
||||
Adding resources from Dropbox, Google Drive... is coming soon!
|
||||
Download GDevelop desktop version to use your own assets.
|
||||
</p>
|
||||
</div>
|
||||
<SelectableList
|
||||
value={this.state.chosenResourceUrl}
|
||||
onChange={this._handleChangeResource}
|
||||
>
|
||||
{this.listItems}
|
||||
</SelectableList>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default [
|
||||
{
|
||||
name: 'gdResourcesChooser',
|
||||
name: 'publicAudioUrlChooser',
|
||||
displayName: 'Choose an audio file from library',
|
||||
kind: 'audio',
|
||||
component: class AudioResourceChooser extends React.Component {
|
||||
chooseResources = () => {
|
||||
if (this._chooser) return this._chooser.chooseResources();
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<GenericResourcesChooser
|
||||
{...this.props}
|
||||
urls={publicAudioUrls}
|
||||
urlsAreImages={false}
|
||||
createNewResource={() => new gd.AudioResource()}
|
||||
title="Choose an audio file from the library"
|
||||
ref={chooser => (this._chooser = chooser)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'publicImageUrlChooser',
|
||||
displayName: 'Choose an image from library',
|
||||
kind: 'image',
|
||||
component: class GdResourcesChooser extends Component {
|
||||
state = {
|
||||
open: false,
|
||||
resolveWithResources: null,
|
||||
chosenImageUrl: null,
|
||||
component: class AudioResourceChooser extends React.Component {
|
||||
chooseResources = () => {
|
||||
if (this._chooser) return this._chooser.chooseResources();
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Cache rendered public images list to avoid doing this each time
|
||||
// a rendering is done.
|
||||
this.listItems = publicImageUrls.map((url: string) => {
|
||||
return (
|
||||
<ListItem
|
||||
value={url}
|
||||
key={url}
|
||||
primaryText={nameFromUrl(url)}
|
||||
leftAvatar={<ListIcon src={url} />}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
chooseResources = (
|
||||
project,
|
||||
multiSelections = true
|
||||
): Promise<Array<any>> => {
|
||||
return new Promise(resolve => {
|
||||
this.setState({
|
||||
open: true,
|
||||
resolveWithResources: resolve,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
_onChoose = () => {
|
||||
const { resolveWithResources, chosenImageUrl } = this.state;
|
||||
if (!resolveWithResources) return;
|
||||
|
||||
const imageResource = new gd.ImageResource();
|
||||
imageResource.setFile(chosenImageUrl);
|
||||
imageResource.setName(chosenImageUrl);
|
||||
|
||||
resolveWithResources([imageResource]);
|
||||
this.setState({
|
||||
open: false,
|
||||
resolveWithResources: null,
|
||||
});
|
||||
};
|
||||
|
||||
_onClose = () => {
|
||||
const { resolveWithResources } = this.state;
|
||||
if (!resolveWithResources) return;
|
||||
|
||||
resolveWithResources([]);
|
||||
this.setState({
|
||||
open: false,
|
||||
resolveWithResources: null,
|
||||
});
|
||||
};
|
||||
|
||||
_handleChangeImage = (e, chosenImageUrl) => {
|
||||
this.setState({
|
||||
chosenImageUrl,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
// Avoid rendering the dialog if it's not opened.
|
||||
if (!this.state.open) return null;
|
||||
|
||||
const actions = [
|
||||
<FlatButton label="Close" primary={false} onClick={this._onClose} />,
|
||||
<FlatButton
|
||||
label="Choose"
|
||||
primary={false}
|
||||
disabled={!this.state.chosenImageUrl}
|
||||
onClick={this._onChoose}
|
||||
/>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
<GenericResourcesChooser
|
||||
{...this.props}
|
||||
urls={publicImageUrls}
|
||||
urlsAreImages
|
||||
createNewResource={() => new gd.ImageResource()}
|
||||
title="Choose an image from the library"
|
||||
actions={actions}
|
||||
open={this.state.open}
|
||||
noMargin
|
||||
autoScrollBodyContent
|
||||
>
|
||||
<div style={styles.explanations}>
|
||||
<p>
|
||||
Adding images from Dropbox, Google Drive... is coming soon!
|
||||
Download GDevelop desktop version to use your own assets.
|
||||
</p>
|
||||
</div>
|
||||
<SelectableList
|
||||
value={this.state.chosenImageUrl}
|
||||
onChange={this._handleChangeImage}
|
||||
>
|
||||
{this.listItems}
|
||||
</SelectableList>
|
||||
</Dialog>
|
||||
ref={chooser => (this._chooser = chooser)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@@ -6,6 +6,51 @@ const dialog = electron ? electron.remote.dialog : null;
|
||||
const gd = global.gd;
|
||||
|
||||
export default [
|
||||
{
|
||||
name: 'localAudioFileOpener',
|
||||
displayName: 'Choose a new audio file',
|
||||
kind: 'audio',
|
||||
component: class LocalAudioFileOpener extends Component {
|
||||
chooseResources = (
|
||||
project,
|
||||
multiSelections = true
|
||||
): Promise<Array<any>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!dialog) return reject('Not supported');
|
||||
|
||||
const properties = ['openFile'];
|
||||
if (multiSelections) properties.push('multiSelections');
|
||||
|
||||
const browserWindow = electron.remote.getCurrentWindow();
|
||||
dialog.showOpenDialog(
|
||||
browserWindow,
|
||||
{
|
||||
title: 'Choose an audio file',
|
||||
properties,
|
||||
filters: [{ name: 'Audio files', extensions: ['wav', 'mp3', 'ogg'] }],
|
||||
},
|
||||
paths => {
|
||||
if (!paths) return resolve([]);
|
||||
|
||||
const resources = paths.map(resourcePath => {
|
||||
const audioResource = new gd.AudioResource();
|
||||
const projectPath = path.dirname(project.getProjectFile());
|
||||
audioResource.setFile(path.relative(projectPath, resourcePath));
|
||||
audioResource.setName(path.basename(resourcePath));
|
||||
|
||||
return audioResource;
|
||||
});
|
||||
return resolve(resources);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'localFileOpener',
|
||||
displayName: 'Choose a new image',
|
||||
|
@@ -1,12 +1,40 @@
|
||||
import React, { Component } from 'react';
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import AutoComplete from 'material-ui/AutoComplete';
|
||||
import MenuItem from 'material-ui/MenuItem';
|
||||
import Divider from 'material-ui/Divider';
|
||||
import Add from 'material-ui/svg-icons/content/add';
|
||||
import { fuzzyOrEmptyFilter } from '../Utils/FuzzyOrEmptyFilter';
|
||||
import {
|
||||
type ResourceSource,
|
||||
type ChooseResourceFunction,
|
||||
type ResourceKind,
|
||||
} from '../ResourcesList/ResourceSource.flow';
|
||||
|
||||
export default class ResourceSelector extends Component {
|
||||
constructor(props) {
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
resourceSources: Array<ResourceSource>,
|
||||
onChooseResource: ChooseResourceFunction,
|
||||
resourceKind: ResourceKind,
|
||||
fullWidth?: boolean,
|
||||
initialResourceName: string,
|
||||
onChange: (string) => void,
|
||||
floatingLabelText?: string,
|
||||
|};
|
||||
|
||||
type State ={|
|
||||
notExistingError: boolean,
|
||||
resourceName: string,
|
||||
|};
|
||||
|
||||
type AutoCompleteItem = {|
|
||||
text: string,
|
||||
value: React.Node,
|
||||
onClick?: () => void,
|
||||
|} | string;
|
||||
|
||||
export default class ResourceSelector extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
@@ -20,7 +48,11 @@ export default class ResourceSelector extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
allResourcesNames: Array<string>;
|
||||
defaultItems: Array<AutoCompleteItem>;
|
||||
autoCompleteData: ?Array<AutoCompleteItem>;
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.initialResourceName !== this.props.initialResourceName) {
|
||||
this.setState({
|
||||
resourceName: nextProps.initialResourceName || '',
|
||||
@@ -28,7 +60,7 @@ export default class ResourceSelector extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
_getDefaultItems() {
|
||||
_getDefaultItems(): Array<AutoCompleteItem> {
|
||||
const sources = this.props.resourceSources || [];
|
||||
return [
|
||||
...sources
|
||||
@@ -47,7 +79,7 @@ export default class ResourceSelector extends Component {
|
||||
];
|
||||
}
|
||||
|
||||
_loadFrom(resourcesManager) {
|
||||
_loadFrom(resourcesManager: gdResourcesManager) {
|
||||
this.allResourcesNames = resourcesManager.getAllResourceNames().toJSArray();
|
||||
if (this.props.resourceKind) {
|
||||
this.allResourcesNames = this.allResourcesNames.filter(resourceName => {
|
||||
@@ -61,7 +93,7 @@ export default class ResourceSelector extends Component {
|
||||
this.autoCompleteData = [...this.defaultItems, ...this.allResourcesNames];
|
||||
}
|
||||
|
||||
_addFrom = source => {
|
||||
_addFrom = (source: ResourceSource) => {
|
||||
if (!source) return;
|
||||
|
||||
const { project, onChooseResource } = this.props;
|
||||
@@ -70,6 +102,8 @@ export default class ResourceSelector extends Component {
|
||||
if (!resources.length) return;
|
||||
const resource = resources[0];
|
||||
|
||||
// addResource will check if a resource with the same name exists, and if it is
|
||||
// the case, no new resource will be added.
|
||||
project.getResourcesManager().addResource(resource);
|
||||
|
||||
this._loadFrom(project.getResourcesManager());
|
||||
@@ -81,7 +115,7 @@ export default class ResourceSelector extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
_onUpdate = searchText => {
|
||||
_onUpdate = (searchText: string) => {
|
||||
this.setState(
|
||||
{
|
||||
resourceName: searchText,
|
||||
@@ -99,7 +133,11 @@ export default class ResourceSelector extends Component {
|
||||
if (index === -1 || index >= this.defaultItems.length)
|
||||
return this._onUpdate(text);
|
||||
|
||||
this.defaultItems[index].onClick();
|
||||
// We're now sure that onClick is defined
|
||||
// $FlowFixMe
|
||||
const onClick = this.defaultItems[index].onClick;
|
||||
if (onClick)
|
||||
onClick();
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@@ -1,10 +1,12 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
|
||||
export type ResourceKind = 'image' | 'audio';
|
||||
|
||||
export type ResourceSource = {
|
||||
name: string,
|
||||
displayName: string,
|
||||
kind: 'image' | 'audio',
|
||||
kind: ResourceKind,
|
||||
component: React.Component<*, *>,
|
||||
};
|
||||
|
||||
|
@@ -329,6 +329,9 @@ storiesOf('EventsSheet', module)
|
||||
layout={testLayout}
|
||||
events={testLayout.getEvents()}
|
||||
onOpenExternalEvents={action('Open external events')}
|
||||
resourceSources={[]}
|
||||
onChooseResource={source =>
|
||||
action('Choose resource from source', source)}
|
||||
/>
|
||||
</DragDropContextProvider>
|
||||
))
|
||||
@@ -339,6 +342,9 @@ storiesOf('EventsSheet', module)
|
||||
layout={emptyLayout}
|
||||
events={emptyLayout.getEvents()}
|
||||
onOpenExternalEvents={action('Open external events')}
|
||||
resourceSources={[]}
|
||||
onChooseResource={source =>
|
||||
action('Choose resource from source', source)}
|
||||
/>
|
||||
</DragDropContextProvider>
|
||||
));
|
||||
|
Reference in New Issue
Block a user