mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
1 Commits
feat/full-
...
data-url-e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c124da88a3 |
@@ -9,13 +9,16 @@ import {
|
|||||||
} from './ResourceSource';
|
} from './ResourceSource';
|
||||||
import { ResourceStore } from '../AssetStore/ResourceStore';
|
import { ResourceStore } from '../AssetStore/ResourceStore';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Line } from '../UI/Grid';
|
import { Column, Line } from '../UI/Grid';
|
||||||
import { ColumnStackLayout, TextFieldWithButtonLayout } from '../UI/Layout';
|
import { ColumnStackLayout, TextFieldWithButtonLayout } from '../UI/Layout';
|
||||||
import RaisedButton from '../UI/RaisedButton';
|
import RaisedButton from '../UI/RaisedButton';
|
||||||
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
||||||
import { useDebounce } from '../Utils/UseDebounce';
|
import { useDebounce } from '../Utils/UseDebounce';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import AlertMessage from '../UI/AlertMessage';
|
import AlertMessage from '../UI/AlertMessage';
|
||||||
|
import { Accordion, AccordionBody, AccordionHeader } from '../UI/Accordion';
|
||||||
|
import { MiniToolbarText } from '../UI/MiniToolbar';
|
||||||
|
import { MarkdownText } from '../UI/MarkdownText';
|
||||||
|
|
||||||
type ResourceStoreChooserProps = {
|
type ResourceStoreChooserProps = {
|
||||||
options: ChooseResourceOptions,
|
options: ChooseResourceOptions,
|
||||||
@@ -23,6 +26,22 @@ type ResourceStoreChooserProps = {
|
|||||||
createNewResource: () => gdResource,
|
createNewResource: () => gdResource,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getUrlsFromInputValue = (value: string, multiSelection: boolean) => {
|
||||||
|
const urls = value.split('\n').filter(Boolean);
|
||||||
|
|
||||||
|
return multiSelection ? urls : urls.slice(0, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDisplayedListOfErroredIndices = dataUrlsErroredBooleanArray => {
|
||||||
|
return dataUrlsErroredBooleanArray
|
||||||
|
.map((isErrored, index) => {
|
||||||
|
if (isErrored) return '#' + (index + 1);
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(', ');
|
||||||
|
};
|
||||||
|
|
||||||
const ResourceStoreChooser = ({
|
const ResourceStoreChooser = ({
|
||||||
options,
|
options,
|
||||||
onChooseResources,
|
onChooseResources,
|
||||||
@@ -50,45 +69,85 @@ export const UrlChooser = ({
|
|||||||
createNewResource,
|
createNewResource,
|
||||||
}: ResourceStoreChooserProps) => {
|
}: ResourceStoreChooserProps) => {
|
||||||
const [inputValue, setInputValue] = React.useState('');
|
const [inputValue, setInputValue] = React.useState('');
|
||||||
|
const [dataUrlInputValue, setDataUrlInputValue] = React.useState<string>('');
|
||||||
const [error, setError] = React.useState<?Error>(null);
|
const [error, setError] = React.useState<?Error>(null);
|
||||||
|
const [dataUrlError, setDataUrlError] = React.useState<?Error>(null);
|
||||||
const [urlsErroredBooleanArray, setUrlsErroredBooleanArray] = React.useState<
|
const [urlsErroredBooleanArray, setUrlsErroredBooleanArray] = React.useState<
|
||||||
boolean[]
|
boolean[]
|
||||||
>([]);
|
>([]);
|
||||||
|
const [
|
||||||
|
dataUrlsErroredBooleanArray,
|
||||||
|
setDataUrlsErroredBooleanArray,
|
||||||
|
] = React.useState<boolean[]>([]);
|
||||||
const hasErroredUrls = !!urlsErroredBooleanArray.filter(Boolean).length;
|
const hasErroredUrls = !!urlsErroredBooleanArray.filter(Boolean).length;
|
||||||
|
const hasErroredDataUrls = !!dataUrlsErroredBooleanArray.filter(Boolean)
|
||||||
|
.length;
|
||||||
|
|
||||||
const validateInputValue = useDebounce(async (inputValue: string) => {
|
const validateInputValue = useDebounce(
|
||||||
const urls = options.multiSelection
|
async ({ value, isDataUrl }: { value: string, isDataUrl: boolean }) => {
|
||||||
? inputValue.split('\n').filter(Boolean)
|
const urls = getUrlsFromInputValue(value, options.multiSelection);
|
||||||
: [inputValue];
|
const setValidationError = isDataUrl ? setDataUrlError : setError;
|
||||||
setError(null);
|
const setValidationArrayError = isDataUrl
|
||||||
setUrlsErroredBooleanArray([]);
|
? setDataUrlsErroredBooleanArray
|
||||||
|
: setUrlsErroredBooleanArray;
|
||||||
|
|
||||||
try {
|
setValidationError(null);
|
||||||
const responses = await Promise.all(
|
setValidationArrayError([]);
|
||||||
urls.map(async url => {
|
|
||||||
return await axios.get(url, {
|
|
||||||
timeout: 1000,
|
|
||||||
validateStatus: status => true,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
setUrlsErroredBooleanArray(
|
try {
|
||||||
responses.map(
|
const responses = await Promise.all(
|
||||||
response => !(response.status >= 200 && response.status < 400)
|
urls.map(async url => {
|
||||||
)
|
return await axios.get(url, {
|
||||||
);
|
timeout: 1000,
|
||||||
} catch (error) {
|
validateStatus: status => true,
|
||||||
setError(error);
|
});
|
||||||
}
|
})
|
||||||
}, 500);
|
);
|
||||||
|
|
||||||
|
setValidationArrayError(
|
||||||
|
responses.map(
|
||||||
|
response => !(response.status >= 200 && response.status < 400)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
setValidationError(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
500
|
||||||
|
);
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
const urls = getUrlsFromInputValue(
|
||||||
|
`${inputValue}\n${dataUrlInputValue}`,
|
||||||
|
options.multiSelection
|
||||||
|
);
|
||||||
|
onChooseResources(
|
||||||
|
urls.map(url => {
|
||||||
|
const newResource = createNewResource();
|
||||||
|
newResource.setFile(url);
|
||||||
|
newResource.setName(path.basename(url));
|
||||||
|
newResource.setOrigin('url', url);
|
||||||
|
|
||||||
|
return newResource;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
() => {
|
() => {
|
||||||
validateInputValue(inputValue);
|
validateInputValue({ value: inputValue, isDataUrl: false });
|
||||||
},
|
},
|
||||||
[inputValue, validateInputValue]
|
[inputValue, validateInputValue]
|
||||||
);
|
);
|
||||||
|
React.useEffect(
|
||||||
|
() => {
|
||||||
|
validateInputValue({ value: dataUrlInputValue, isDataUrl: true });
|
||||||
|
},
|
||||||
|
[dataUrlInputValue, validateInputValue]
|
||||||
|
);
|
||||||
|
|
||||||
|
const canApply =
|
||||||
|
!error && !dataUrlError && !hasErroredDataUrls && !hasErroredUrls;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColumnStackLayout noMargin expand>
|
<ColumnStackLayout noMargin expand>
|
||||||
@@ -96,26 +155,11 @@ export const UrlChooser = ({
|
|||||||
<TextFieldWithButtonLayout
|
<TextFieldWithButtonLayout
|
||||||
renderButton={style => (
|
renderButton={style => (
|
||||||
<RaisedButton
|
<RaisedButton
|
||||||
onClick={() => {
|
onClick={onClick}
|
||||||
const urls = options.multiSelection
|
|
||||||
? inputValue.split('\n').filter(Boolean)
|
|
||||||
: [inputValue];
|
|
||||||
|
|
||||||
onChooseResources(
|
|
||||||
urls.map(url => {
|
|
||||||
const newResource = createNewResource();
|
|
||||||
newResource.setFile(url);
|
|
||||||
newResource.setName(path.basename(url));
|
|
||||||
newResource.setOrigin('url', url);
|
|
||||||
|
|
||||||
return newResource;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
primary
|
primary
|
||||||
label={<Trans>Choose</Trans>}
|
label={<Trans>Choose</Trans>}
|
||||||
style={style}
|
style={style}
|
||||||
disabled={!!error || hasErroredUrls}
|
disabled={!canApply}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
renderTextField={() => (
|
renderTextField={() => (
|
||||||
@@ -142,14 +186,8 @@ export const UrlChooser = ({
|
|||||||
) : hasErroredUrls ? (
|
) : hasErroredUrls ? (
|
||||||
<Trans>
|
<Trans>
|
||||||
Unable to verify URLs{' '}
|
Unable to verify URLs{' '}
|
||||||
{urlsErroredBooleanArray
|
{getDisplayedListOfErroredIndices(urlsErroredBooleanArray)}.
|
||||||
.map((isErrored, index) => {
|
Please check they are correct.
|
||||||
if (isErrored) return '#' + (index + 1);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(', ')}
|
|
||||||
. Please check they are correct.
|
|
||||||
</Trans>
|
</Trans>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
@@ -165,6 +203,68 @@ export const UrlChooser = ({
|
|||||||
stored inside the game.
|
stored inside the game.
|
||||||
</Trans>
|
</Trans>
|
||||||
</AlertMessage>
|
</AlertMessage>
|
||||||
|
<Accordion>
|
||||||
|
<AccordionHeader>
|
||||||
|
<MiniToolbarText firstChild>
|
||||||
|
<Trans>Advanced options</Trans>{' '}
|
||||||
|
</MiniToolbarText>
|
||||||
|
</AccordionHeader>
|
||||||
|
<AccordionBody>
|
||||||
|
<Column noMargin expand>
|
||||||
|
<Line>
|
||||||
|
<TextFieldWithButtonLayout
|
||||||
|
renderButton={style => (
|
||||||
|
<RaisedButton
|
||||||
|
onClick={onClick}
|
||||||
|
primary
|
||||||
|
label={<Trans>Choose</Trans>}
|
||||||
|
style={style}
|
||||||
|
disabled={!canApply}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
renderTextField={() => (
|
||||||
|
<SemiControlledTextField
|
||||||
|
floatingLabelText={
|
||||||
|
options.multiSelection ? (
|
||||||
|
<Trans>Data URL(s) (one per line)</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Data URL</Trans>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
value={dataUrlInputValue}
|
||||||
|
onChange={setDataUrlInputValue}
|
||||||
|
multiline={options.multiSelection}
|
||||||
|
rows={1}
|
||||||
|
rowsMax={5}
|
||||||
|
fullWidth
|
||||||
|
errorText={
|
||||||
|
dataUrlError ? (
|
||||||
|
<Trans>
|
||||||
|
There was an error verifying the data URL(s). Please
|
||||||
|
check they are correct.
|
||||||
|
</Trans>
|
||||||
|
) : hasErroredDataUrls ? (
|
||||||
|
<Trans>
|
||||||
|
Unable to verify data URLs{' '}
|
||||||
|
{getDisplayedListOfErroredIndices(
|
||||||
|
dataUrlsErroredBooleanArray
|
||||||
|
)}
|
||||||
|
. Please check they are correct.
|
||||||
|
</Trans>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Line>
|
||||||
|
<AlertMessage kind="info">
|
||||||
|
<MarkdownText
|
||||||
|
translatableSource={t`You can also specify [Data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs). The resource will be stored in the project file so we recommend you only use this method to add small resources (< 10kB).`}
|
||||||
|
/>
|
||||||
|
</AlertMessage>
|
||||||
|
</Column>
|
||||||
|
</AccordionBody>
|
||||||
|
</Accordion>
|
||||||
</ColumnStackLayout>
|
</ColumnStackLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user