diff --git a/web/apps/photos/src/components/Collections/CollectionHeader.tsx b/web/apps/photos/src/components/Collections/CollectionHeader.tsx index 70a8c7e7f15..8b2de60df7e 100644 --- a/web/apps/photos/src/components/Collections/CollectionHeader.tsx +++ b/web/apps/photos/src/components/Collections/CollectionHeader.tsx @@ -40,6 +40,7 @@ import { CollectionSubType, type Collection, } from "ente-media/collection"; +import type { EnteFile } from "ente-media/file"; import { ItemVisibility } from "ente-media/file-metadata"; import type { RemotePullOpts } from "ente-new/photos/components/gallery"; import { @@ -94,6 +95,7 @@ export interface CollectionHeaderProps > { collectionSummary: CollectionSummary; activeCollection: Collection | undefined; + files: EnteFile[]; setActiveCollectionID: (collectionID: number) => void; isActiveCollectionDownloadInProgress: () => boolean; /** @@ -158,6 +160,7 @@ const shouldShowOptions = (type: CollectionSummaryType) => const CollectionHeaderOptions: React.FC = ({ activeCollection, collectionSummary, + files, setActiveCollectionID, onRemotePull, onCollectionShare, @@ -789,6 +792,7 @@ const CollectionHeaderOptions: React.FC = ({ {...mapDialogVisibilityProps} collectionSummary={collectionSummary} activeCollection={activeCollection} + files={files} onRemotePull={onRemotePull} onAddSaveGroup={onAddSaveGroup} onMarkTempDeleted={onMarkTempDeleted} diff --git a/web/apps/photos/src/components/Collections/CollectionMapDialog.tsx b/web/apps/photos/src/components/Collections/CollectionMapDialog.tsx index 94f083205ff..a0531749cfc 100644 --- a/web/apps/photos/src/components/Collections/CollectionMapDialog.tsx +++ b/web/apps/photos/src/components/Collections/CollectionMapDialog.tsx @@ -30,8 +30,6 @@ import { import type { RemotePullOpts } from "ente-new/photos/components/gallery"; import { addToFavoritesCollection, - isArchivedCollection, - isHiddenCollection, removeFromFavoritesCollection, } from "ente-new/photos/services/collection"; import { type CollectionSummary } from "ente-new/photos/services/collection-summary"; @@ -74,6 +72,7 @@ interface CollectionMapDialogProps > { collectionSummary: CollectionSummary; activeCollection: Collection | undefined; + files: EnteFile[]; onRemotePull?: (opts?: RemotePullOpts) => Promise; } @@ -440,7 +439,7 @@ const getLatestFileIdFromPoints = (points: MapIndexPoint[]) => function useMapData( open: boolean, collectionSummary: CollectionSummary, - activeCollection: Collection | undefined, + files: EnteFile[], onGenericError: (e: unknown) => void, ): MapDataResult { const [state, setState] = useState({ @@ -466,9 +465,9 @@ function useMapData( // Include fileCount to detect when collection content changes const loadedCollectionRef = useRef<{ summaryId: number; - collectionId: number | undefined; fileCount: number; updationTime: number | null; + files: EnteFile[]; } | null>(null); //Syncing the refs with the state for the stale closure prevention. @@ -569,7 +568,6 @@ function useMapData( // Skip reload if we already have data for this collection with same file count const currentSummaryId = collectionSummary.id; - const currentCollectionId = activeCollection?.id; const currentFileCount = collectionSummary.fileCount; const currentUpdationTime = collectionSummary.updationTime ?? null; const loaded = loadedCollectionRef.current; @@ -578,9 +576,9 @@ function useMapData( if ( loaded && loaded.summaryId === currentSummaryId && - loaded.collectionId === currentCollectionId && loaded.fileCount === currentFileCount && - loaded.updationTime === currentUpdationTime + loaded.updationTime === currentUpdationTime && + loaded.files === files ) { return; } @@ -591,18 +589,17 @@ function useMapData( setState((prev) => ({ ...prev, isLoading: true, error: null })); try { - const files = await getFilesForCollection( - collectionSummary, - activeCollection, - ); + const uniqueFiles = uniqueFilesByID(files); //Creating a id <- file mapping to drive renders and update the UI, changes to this will result in UI re-renders - const filesByID = new Map(files.map((file) => [file.id, file])); + const filesByID = new Map( + uniqueFiles.map((file) => [file.id, file]), + ); //ref mirrow for using in the useCallbacks filesByIDRef.current = filesByID; const { points, latestFileId } = - await buildMapIndexPoints(files); + await buildMapIndexPoints(uniqueFiles); //mapIndex has the SuperCluster Spatial Index const mapIndex = buildMapIndex(points); @@ -628,9 +625,9 @@ function useMapData( // Mark this collection as loaded loadedCollectionRef.current = { summaryId: currentSummaryId, - collectionId: currentCollectionId, fileCount: currentFileCount, updationTime: currentUpdationTime, + files, }; const coverId = collectionSummary.coverFile?.id ?? latestFileId; @@ -655,13 +652,7 @@ function useMapData( }; void loadMapData(); - }, [ - open, - collectionSummary, - activeCollection, - onGenericError, - queueThumbnailFetch, - ]); + }, [open, collectionSummary, files, onGenericError, queueThumbnailFetch]); /** * This function is used to update the map view, after a file has been @@ -1131,70 +1122,6 @@ function createClusterIcon( // Helper Functions // ============================================================================ -/** - * Returns true if the file is visible (not archived or hidden). - */ -function isFileVisible(file: EnteFile): boolean { - const visibility = file.magicMetadata?.data.visibility; - // Files without visibility metadata are considered visible (default state) - return visibility === undefined || visibility === ItemVisibility.visible; -} - -/** - * Loads every locally stored file, filters those belonging to the - * target collection, removes duplicates by ID, filters out hidden/archived - * files, and returns the unique set of visible files. For "All", it also - * excludes files that belong to hidden or archived collections. - */ -async function getFilesForCollection( - collectionSummary: CollectionSummary, - activeCollection: Collection | undefined, -): Promise { - if (collectionSummary.type === "all") { - const [allFiles, collections] = await Promise.all([ - savedCollectionFiles(), - savedCollections(), - ]); - // Filter out hidden and archived files to prevent leaking items users expect to remain hidden. - const visibleFiles = allFiles.filter(isFileVisible); - const hiddenCollectionIDs = new Set( - collections - .filter(isHiddenCollection) - .map((collection) => collection.id), - ); - const archivedCollectionIDs = new Set( - collections - .filter(isArchivedCollection) - .map((collection) => collection.id), - ); - const hiddenFileIDs = new Set( - allFiles - .filter((file) => hiddenCollectionIDs.has(file.collectionID)) - .map((file) => file.id), - ); - const archivedFileIDs = new Set( - allFiles - .filter((file) => archivedCollectionIDs.has(file.collectionID)) - .map((file) => file.id), - ); - const filtered = visibleFiles.filter( - (file) => - !hiddenFileIDs.has(file.id) && !archivedFileIDs.has(file.id), - ); - return uniqueFilesByID(filtered); - } - const allFiles = await savedCollectionFiles(); - // Filter out hidden and archived files to prevent leaking items users expect to remain hidden. - const visibleFiles = allFiles.filter(isFileVisible); - if (!activeCollection) { - return []; - } - const filtered = visibleFiles.filter( - (file) => file.collectionID === activeCollection.id, - ); - return uniqueFilesByID(filtered); -} - // ============================================================================ // Main Component // ============================================================================ @@ -1208,6 +1135,7 @@ export const CollectionMapDialog: React.FC = ({ onClose, collectionSummary, activeCollection, + files, onRemotePull, onAddSaveGroup, onMarkTempDeleted, @@ -1237,7 +1165,7 @@ export const CollectionMapDialog: React.FC = ({ removeFiles: removeFilesFromMap, updateFileVisibility, queueThumbnailFetch, - } = useMapData(open, collectionSummary, activeCollection, onGenericError); + } = useMapData(open, collectionSummary, files, onGenericError); const { visiblePhotos, diff --git a/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx b/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx index 054f7fe43a2..30074e0af04 100644 --- a/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx +++ b/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx @@ -65,6 +65,7 @@ type GalleryBarAndListHeaderProps = Omit< saveGroups: SaveGroup[]; } & Pick< CollectionHeaderProps, + | "files" | "onRemotePull" | "onAddSaveGroup" | "onMarkTempDeleted" @@ -115,6 +116,7 @@ export const GalleryBarAndListHeader: React.FC< setBlockingLoad, people, saveGroups, + files, activePerson, emailByUserID, shareSuggestionEmails, @@ -210,6 +212,7 @@ export const GalleryBarAndListHeader: React.FC< = ({ {...mapDialogVisibilityProps} collectionSummary={activeCollectionSummary} activeCollection={activeCollection} + files={files} onRemotePull={onRemotePull} {...{ onAddSaveGroup, diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 6ed981f9bf1..01b5314a78c 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -1895,6 +1895,9 @@ const Page: React.FC = () => { // component need to be updated. activeCollection: activeCollection!, activeCollectionID: activeCollectionID!, + files: activeCollection + ? activeCollectionFiles + : filteredFiles, activePerson, setFileListHeader, saveGroups,