mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-08-25 12:23:58 -04:00
Fix asset store pagination when navigating folders and correctly installing visible assets (#8466)
This commit is contained in:
@@ -111,17 +111,28 @@ const getPageBreakAssetLowerIndex = (pageBreakIndex: number) =>
|
||||
const getPageBreakAssetUpperIndex = (pageBreakIndex: number) =>
|
||||
ASSETS_DISPLAY_LIMIT * (pageBreakIndex + 1);
|
||||
|
||||
export const filterAssetShortHeadersByFolders = (
|
||||
allAssetShortHeaders: AssetShortHeader[],
|
||||
selectedFolders: string[]
|
||||
): AssetShortHeader[] => {
|
||||
if (!selectedFolders.length) return allAssetShortHeaders;
|
||||
return allAssetShortHeaders.filter(assetShortHeader =>
|
||||
// Check that the asset has all the selected folders tags.
|
||||
selectedFolders.every(folderTag =>
|
||||
assetShortHeader.tags.includes(folderTag)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getAssetShortHeadersToDisplay = (
|
||||
allAssetShortHeaders: AssetShortHeader[],
|
||||
selectedFolders: string[],
|
||||
pageBreakIndex: number = 0
|
||||
): AssetShortHeader[] => {
|
||||
let assetShortHeaders = allAssetShortHeaders.filter(assetShortHeader => {
|
||||
if (!selectedFolders.length) return true;
|
||||
const allAssetTags = assetShortHeader.tags;
|
||||
// Check that the asset has all the selected folders tags.
|
||||
return selectedFolders.every(folderTag => allAssetTags.includes(folderTag));
|
||||
});
|
||||
let assetShortHeaders = filterAssetShortHeadersByFolders(
|
||||
allAssetShortHeaders,
|
||||
selectedFolders
|
||||
);
|
||||
// Limit the number of displayed assets to avoid performance issues
|
||||
const pageBreakAssetLowerIndex = getPageBreakAssetLowerIndex(pageBreakIndex);
|
||||
const pageBreakAssetUpperIndex = Math.min(
|
||||
@@ -154,6 +165,8 @@ const styles = {
|
||||
scrollView: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
// Prevent horizontal scrollbars.
|
||||
overflowX: 'hidden',
|
||||
},
|
||||
previewImageContainer: {
|
||||
display: 'flex',
|
||||
@@ -341,6 +354,25 @@ const AssetsList: React.ComponentType<{
|
||||
},
|
||||
[currentPage]
|
||||
);
|
||||
React.useEffect(
|
||||
() => {
|
||||
setPageBreakIndex(0);
|
||||
if (currentPage) currentPage.pageBreakIndex = 0;
|
||||
},
|
||||
// selectedFolders is a new array reference each time a folder is selected,
|
||||
// so this resets pagination whenever the folder selection changes.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[selectedFolders]
|
||||
);
|
||||
const folderFilteredAssetShortHeaders = React.useMemo<
|
||||
Array<AssetShortHeader>
|
||||
>(
|
||||
() =>
|
||||
assetShortHeaders
|
||||
? filterAssetShortHeadersByFolders(assetShortHeaders, selectedFolders)
|
||||
: [],
|
||||
[assetShortHeaders, selectedFolders]
|
||||
);
|
||||
const { windowSize, isLandscape } = useResponsiveWindowSize();
|
||||
const scrollView = React.useRef<?ScrollViewInterface>(null);
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
@@ -973,13 +1005,13 @@ const AssetsList: React.ComponentType<{
|
||||
!isAssetPackAudioOnly(openedAssetPack)) &&
|
||||
noResultComponent}
|
||||
{currentPage &&
|
||||
assetShortHeaders &&
|
||||
assetShortHeaders.length > getPageBreakAssetUpperIndex(0) && (
|
||||
folderFilteredAssetShortHeaders.length >
|
||||
getPageBreakAssetUpperIndex(0) && (
|
||||
<PageBreakNavigation
|
||||
currentPage={currentPage}
|
||||
pageBreakIndex={pageBreakIndex}
|
||||
setPageBreakIndex={setPageBreakIndex}
|
||||
assetShortHeaders={assetShortHeaders}
|
||||
assetShortHeaders={folderFilteredAssetShortHeaders}
|
||||
scrollView={scrollView.current}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -308,9 +308,9 @@ function NewObjectDialog({
|
||||
selectedFolders,
|
||||
} = shopNavigationState.getCurrentPage();
|
||||
const [
|
||||
isAssetPackDialogInstallOpen,
|
||||
setIsAssetPackDialogInstallOpen,
|
||||
] = React.useState(false);
|
||||
assetShortHeadersToInstall,
|
||||
setAssetShortHeadersToInstall,
|
||||
] = React.useState<?Array<AssetShortHeader>>(null);
|
||||
// Avoid memoizing the result of enumerateAssetStoreIds, as it does not get updated
|
||||
// when adding assets.
|
||||
const existingAssetStoreIds = enumerateAssetStoreIds(
|
||||
@@ -423,6 +423,22 @@ function NewObjectDialog({
|
||||
[assetShortHeadersSearchResults, selectedFolders]
|
||||
);
|
||||
|
||||
const openAssetPackInstallDialog = React.useCallback(
|
||||
() => {
|
||||
const currentPage = shopNavigationState.getCurrentPage();
|
||||
setAssetShortHeadersToInstall(
|
||||
assetShortHeadersSearchResults
|
||||
? getAssetShortHeadersToDisplay(
|
||||
assetShortHeadersSearchResults,
|
||||
currentPage.selectedFolders,
|
||||
currentPage.pageBreakIndex || 0
|
||||
)
|
||||
: []
|
||||
);
|
||||
},
|
||||
[shopNavigationState, assetShortHeadersSearchResults]
|
||||
);
|
||||
|
||||
const mainAction =
|
||||
currentTab === 'asset-store' ? (
|
||||
openedAssetPack ? (
|
||||
@@ -436,7 +452,7 @@ function NewObjectDialog({
|
||||
<Trans>Add these assets to my scene</Trans>
|
||||
)
|
||||
}
|
||||
onClick={() => setIsAssetPackDialogInstallOpen(true)}
|
||||
onClick={openAssetPackInstallDialog}
|
||||
disabled={
|
||||
!displayedAssetShortHeaders ||
|
||||
displayedAssetShortHeaders.length === 0
|
||||
@@ -543,7 +559,7 @@ function NewObjectDialog({
|
||||
onRequestClose={handleClose}
|
||||
onApply={
|
||||
openedAssetPack
|
||||
? () => setIsAssetPackDialogInstallOpen(true)
|
||||
? openAssetPackInstallDialog
|
||||
: openedAssetShortHeader
|
||||
? async () => {
|
||||
await onInstallAsset(openedAssetShortHeader);
|
||||
@@ -603,16 +619,16 @@ function NewObjectDialog({
|
||||
))}
|
||||
</Dialog>
|
||||
{isAssetBeingInstalled && <LoaderModal showImmediately />}
|
||||
{isAssetPackDialogInstallOpen &&
|
||||
displayedAssetShortHeaders &&
|
||||
{assetShortHeadersToInstall &&
|
||||
!!assetShortHeadersToInstall.length &&
|
||||
openedAssetPack && (
|
||||
<AssetPackInstallDialog
|
||||
assetPack={openedAssetPack}
|
||||
assetShortHeaders={displayedAssetShortHeaders}
|
||||
assetShortHeaders={assetShortHeadersToInstall}
|
||||
addedAssetIds={existingAssetStoreIds}
|
||||
onClose={() => setIsAssetPackDialogInstallOpen(false)}
|
||||
onClose={() => setAssetShortHeadersToInstall(null)}
|
||||
onAssetsAdded={installAssetOutput => {
|
||||
setIsAssetPackDialogInstallOpen(false);
|
||||
setAssetShortHeadersToInstall(null);
|
||||
onObjectsAddedFromAssets(installAssetOutput);
|
||||
}}
|
||||
project={project}
|
||||
|
||||
@@ -10,7 +10,10 @@ import { AssetStoreContext } from '../../../../AssetStore/AssetStoreContext';
|
||||
import AssetPackInstallDialog from '../../../../AssetStore/AssetPackInstallDialog';
|
||||
import { enumerateAssetStoreIds } from '../../../../AssetStore/EnumerateAssetStoreIds';
|
||||
import { type PrivateGameTemplateListingData } from '../../../../Utils/GDevelopServices/Shop';
|
||||
import { type Course } from '../../../../Utils/GDevelopServices/Asset';
|
||||
import {
|
||||
type AssetShortHeader,
|
||||
type Course,
|
||||
} from '../../../../Utils/GDevelopServices/Asset';
|
||||
import ErrorBoundary from '../../../../UI/ErrorBoundary';
|
||||
import { getAssetShortHeadersToDisplay } from '../../../../AssetStore/AssetsList';
|
||||
import { AssetStoreNavigatorContext } from '../../../../AssetStore/AssetStoreNavigator';
|
||||
@@ -42,9 +45,9 @@ const StoreSection = ({
|
||||
getCourseCompletion,
|
||||
}: Props) => {
|
||||
const [
|
||||
isAssetPackDialogInstallOpen,
|
||||
setIsAssetPackDialogInstallOpen,
|
||||
] = React.useState(false);
|
||||
assetShortHeadersToInstall,
|
||||
setAssetShortHeadersToInstall,
|
||||
] = React.useState<?Array<AssetShortHeader>>(null);
|
||||
const shopNavigationState = React.useContext(AssetStoreNavigatorContext);
|
||||
const { assetShortHeadersSearchResults } = React.useContext(
|
||||
AssetStoreContext
|
||||
@@ -71,7 +74,7 @@ const StoreSection = ({
|
||||
|
||||
const existingAssetStoreIds = React.useMemo(
|
||||
() => {
|
||||
if (!project || !isAssetPackDialogInstallOpen) {
|
||||
if (!project || !assetShortHeadersToInstall) {
|
||||
return new Set<string>();
|
||||
}
|
||||
|
||||
@@ -82,7 +85,29 @@ const StoreSection = ({
|
||||
// Force recompute existing installed asset ids when the dialog to install them is
|
||||
// opened/closed, so that this list of ids is always up-to-date (but not recomputed at each render,
|
||||
// just when you're likely to need it).
|
||||
isAssetPackDialogInstallOpen,
|
||||
assetShortHeadersToInstall,
|
||||
]
|
||||
);
|
||||
|
||||
const openAssetPackInstallDialog = React.useCallback(
|
||||
() => {
|
||||
const currentPage = shopNavigationState.getCurrentPage();
|
||||
setAssetShortHeadersToInstall(
|
||||
openedAssetShortHeader
|
||||
? [openedAssetShortHeader]
|
||||
: assetShortHeadersSearchResults
|
||||
? getAssetShortHeadersToDisplay(
|
||||
assetShortHeadersSearchResults,
|
||||
currentPage.selectedFolders,
|
||||
currentPage.pageBreakIndex || 0
|
||||
)
|
||||
: []
|
||||
);
|
||||
},
|
||||
[
|
||||
shopNavigationState,
|
||||
openedAssetShortHeader,
|
||||
assetShortHeadersSearchResults,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -107,7 +132,7 @@ const StoreSection = ({
|
||||
return; // TODO: create a project, await, and then show dialog.
|
||||
}
|
||||
|
||||
setIsAssetPackDialogInstallOpen(true);
|
||||
openAssetPackInstallDialog();
|
||||
}}
|
||||
disabled={!project || !displayedAssetShortHeaders.length}
|
||||
label={
|
||||
@@ -131,15 +156,15 @@ const StoreSection = ({
|
||||
</Line>
|
||||
)}
|
||||
{project &&
|
||||
isAssetPackDialogInstallOpen &&
|
||||
!!displayedAssetShortHeaders.length && (
|
||||
assetShortHeadersToInstall &&
|
||||
!!assetShortHeadersToInstall.length && (
|
||||
<AssetPackInstallDialog
|
||||
assetPack={openedAssetPack}
|
||||
assetShortHeaders={displayedAssetShortHeaders}
|
||||
assetShortHeaders={assetShortHeadersToInstall}
|
||||
addedAssetIds={existingAssetStoreIds}
|
||||
onClose={() => setIsAssetPackDialogInstallOpen(false)}
|
||||
onClose={() => setAssetShortHeadersToInstall(null)}
|
||||
onAssetsAdded={() => {
|
||||
setIsAssetPackDialogInstallOpen(false);
|
||||
setAssetShortHeadersToInstall(null);
|
||||
}}
|
||||
project={project}
|
||||
objectsContainer={null}
|
||||
|
||||
Reference in New Issue
Block a user