[web] Reduce flicker when resizing gallery window (#5519)
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
"react-dom": "^19.0.0",
|
||||
"react-select": "^5.10.1",
|
||||
"react-top-loading-bar": "^3.0.2",
|
||||
"react-virtualized-auto-sizer": "^1.0.25",
|
||||
"react-virtualized-auto-sizer": "^1.0.26",
|
||||
"react-window": "^1.8.11",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"similarity-transformation": "^0.0.1",
|
||||
|
||||
@@ -21,15 +21,11 @@ import {
|
||||
import type { CollectionSummary } from "ente-new/photos/services/collection/ui";
|
||||
import { CollectionsSortBy } from "ente-new/photos/services/collection/ui";
|
||||
import { FlexWrapper, FluidContainer } from "ente-shared/components/Container";
|
||||
import useWindowSize from "ente-shared/hooks/useWindowSize";
|
||||
import { t } from "i18next";
|
||||
import memoize from "memoize-one";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
areEqual,
|
||||
FixedSizeList as List,
|
||||
ListChildComponentProps,
|
||||
} from "react-window";
|
||||
import AutoSizer from "react-virtualized-auto-sizer";
|
||||
import { areEqual, FixedSizeList, ListChildComponentProps } from "react-window";
|
||||
|
||||
interface AllAlbums {
|
||||
open: boolean;
|
||||
@@ -84,7 +80,7 @@ export const AllAlbums: React.FC<AllAlbums> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const AllCollectionMobileBreakpoint = 559;
|
||||
const Column3To2Breakpoint = 559;
|
||||
|
||||
const AllAlbumsDialog = styled(Dialog)(({ theme }) => ({
|
||||
"& .MuiDialog-container": { justifyContent: "flex-end" },
|
||||
@@ -94,7 +90,7 @@ const AllAlbumsDialog = styled(Dialog)(({ theme }) => ({
|
||||
paddingRight: theme.spacing(1),
|
||||
},
|
||||
"& .MuiDialogContent-root": { padding: theme.spacing(2) },
|
||||
[theme.breakpoints.down(AllCollectionMobileBreakpoint)]: {
|
||||
[theme.breakpoints.down(Column3To2Breakpoint)]: {
|
||||
"& .MuiPaper-root": { width: "324px" },
|
||||
"& .MuiDialogContent-root": { padding: 6 },
|
||||
},
|
||||
@@ -142,20 +138,8 @@ const Title = ({
|
||||
</DialogTitle>
|
||||
);
|
||||
|
||||
const MobileColumns = 2;
|
||||
const DesktopColumns = 3;
|
||||
|
||||
const CollectionRowItemSize = 154;
|
||||
|
||||
const getCollectionRowListHeight = (
|
||||
collectionRowList: CollectionSummary[][],
|
||||
windowSize: { height: number; width: number },
|
||||
) =>
|
||||
Math.min(
|
||||
collectionRowList.length * CollectionRowItemSize + 32,
|
||||
windowSize?.height - 177,
|
||||
) || 0;
|
||||
|
||||
interface ItemData {
|
||||
collectionRowList: CollectionSummary[][];
|
||||
onCollectionClick: (id?: number) => void;
|
||||
@@ -211,15 +195,21 @@ const AllAlbumsContent: React.FC<AllAlbumsContentProps> = ({
|
||||
collectionSummaries,
|
||||
onCollectionClick,
|
||||
}) => {
|
||||
const isTwoColumn = useMediaQuery(`(width < ${Column3To2Breakpoint}px)`);
|
||||
|
||||
const refreshInProgress = useRef(false);
|
||||
const shouldRefresh = useRef(false);
|
||||
|
||||
const [collectionRowList, setCollectionRowList] = useState([]);
|
||||
|
||||
const windowSize = useWindowSize();
|
||||
const columns = isTwoColumn ? 2 : 3;
|
||||
const maxListContentHeight =
|
||||
Math.ceil(collectionSummaries.length / columns) *
|
||||
CollectionRowItemSize +
|
||||
32; /* padding above first and below last row */
|
||||
|
||||
useEffect(() => {
|
||||
if (!windowSize.width || !collectionSummaries) {
|
||||
if (!collectionSummaries) {
|
||||
return;
|
||||
}
|
||||
const main = async () => {
|
||||
@@ -231,10 +221,6 @@ const AllAlbumsContent: React.FC<AllAlbumsContentProps> = ({
|
||||
|
||||
const collectionRowList: CollectionSummary[][] = [];
|
||||
let index = 0;
|
||||
const columns =
|
||||
windowSize.width > AllCollectionMobileBreakpoint
|
||||
? DesktopColumns
|
||||
: MobileColumns;
|
||||
while (index < collectionSummaries.length) {
|
||||
const collectionRow: CollectionSummary[] = [];
|
||||
for (
|
||||
@@ -254,7 +240,7 @@ const AllAlbumsContent: React.FC<AllAlbumsContentProps> = ({
|
||||
}
|
||||
};
|
||||
main();
|
||||
}, [collectionSummaries, windowSize]);
|
||||
}, [collectionSummaries, columns]);
|
||||
|
||||
// Bundle additional data to list items using the "itemData" prop.
|
||||
// It will be accessible to item renderers as props.data.
|
||||
@@ -262,19 +248,29 @@ const AllAlbumsContent: React.FC<AllAlbumsContentProps> = ({
|
||||
const itemData = createItemData(collectionRowList, onCollectionClick);
|
||||
|
||||
return (
|
||||
<DialogContent sx={{ "&&": { padding: 0 } }}>
|
||||
<List
|
||||
height={getCollectionRowListHeight(
|
||||
collectionRowList,
|
||||
windowSize,
|
||||
<DialogContent
|
||||
sx={{
|
||||
"&&": { padding: 0 },
|
||||
height: "min(80svh, var(--et-max-list-content-height))",
|
||||
}}
|
||||
style={
|
||||
{
|
||||
"--et-max-list-content-height": `${maxListContentHeight}px`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<FixedSizeList
|
||||
{...{ width, height }}
|
||||
itemCount={collectionRowList.length}
|
||||
itemSize={CollectionRowItemSize}
|
||||
itemData={itemData}
|
||||
>
|
||||
{AlbumsRow}
|
||||
</FixedSizeList>
|
||||
)}
|
||||
width={"100%"}
|
||||
itemCount={collectionRowList.length}
|
||||
itemSize={CollectionRowItemSize}
|
||||
itemData={itemData}
|
||||
>
|
||||
{AlbumsRow}
|
||||
</List>
|
||||
</AutoSizer>
|
||||
</DialogContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// https://usehooks.com/useWindowSize/
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
// Hook
|
||||
export default function useWindowSize() {
|
||||
// Initialize state with undefined width/height so server and client renders match
|
||||
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
|
||||
const [windowSize, setWindowSize] = useState<{
|
||||
width: number;
|
||||
height: number;
|
||||
}>({ width: undefined, height: undefined });
|
||||
|
||||
useEffect(() => {
|
||||
// Handler to call on window resize
|
||||
function handleResize() {
|
||||
// Set window width/height to state
|
||||
setWindowSize({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
}
|
||||
|
||||
// Add event listener
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// Call handler right away so state gets updated with initial window size
|
||||
handleResize();
|
||||
|
||||
// Remove event listener on cleanup
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}, []); // Empty array ensures that effect is only run on mount
|
||||
|
||||
return windowSize;
|
||||
}
|
||||
@@ -3381,10 +3381,10 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.5:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react-virtualized-auto-sizer@^1.0.25:
|
||||
version "1.0.25"
|
||||
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.25.tgz#b13cbc528ac200be2bd1ffa40c8bb19bcc60ac3f"
|
||||
integrity sha512-YHsksEGDfsHbHuaBVDYwJmcktblcHGafz4ZVuYPQYuSHMUGjpwmUCrAOcvMSGMwwk1eFWj1M/1GwYpNPuyhaBg==
|
||||
react-virtualized-auto-sizer@^1.0.26:
|
||||
version "1.0.26"
|
||||
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz#e9470ef6a778dc4f1d5fd76305fa2d8b610c357a"
|
||||
integrity sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==
|
||||
|
||||
react-window@^1.8.11:
|
||||
version "1.8.11"
|
||||
|
||||
Reference in New Issue
Block a user