[web] Gallery reducer nomenclature cleanup (#5345)

This commit is contained in:
Manav Rathi
2025-03-17 20:47:22 +05:30
committed by GitHub
7 changed files with 338 additions and 309 deletions

View File

@@ -79,8 +79,8 @@ export type FileListWithViewerProps = {
| "user"
| "isInIncomingSharedCollection"
| "isInHiddenSection"
| "fileCollectionIDs"
| "allCollectionsNameByID"
| "fileNormalCollectionIDs"
| "collectionNameByID"
| "pendingVisibilityUpdates"
| "onVisualFeedback"
| "onFileVisibilityUpdate"
@@ -108,8 +108,8 @@ export const FileListWithViewer: React.FC<FileListWithViewerProps> = ({
favoriteFileIDs,
isInIncomingSharedCollection,
isInHiddenSection,
fileCollectionIDs,
allCollectionsNameByID,
fileNormalCollectionIDs,
collectionNameByID,
pendingVisibilityUpdates,
setFilesDownloadProgressAttributesCreator,
onFileVisibilityUpdate,
@@ -221,8 +221,8 @@ export const FileListWithViewer: React.FC<FileListWithViewerProps> = ({
isInHiddenSection,
isInIncomingSharedCollection,
favoriteFileIDs,
fileCollectionIDs,
allCollectionsNameByID,
fileNormalCollectionIDs,
collectionNameByID,
pendingVisibilityUpdates,
onVisualFeedback,
onFileVisibilityUpdate,

View File

@@ -254,13 +254,19 @@ const Page: React.FC = () => {
[],
);
// TODO: Temp
const user = state.user;
const familyData = state.familyData;
const collections = state.collections;
const files = state.files;
const hiddenFiles = state.hiddenFiles;
const collectionSummaries = state.collectionSummaries;
// Local aliases.
const {
user,
familyData,
normalCollections,
normalFiles,
hiddenFiles,
normalCollectionSummaries,
isInSearchMode,
filteredFiles,
} = state;
// Derived aliases.
const barMode = state.view?.type ?? "albums";
const activeCollectionID =
state.view?.type == "people"
@@ -271,8 +277,6 @@ const Page: React.FC = () => {
const activePerson =
state.view?.type == "people" ? state.view.activePerson : undefined;
const activePersonID = activePerson?.id;
const isInSearchMode = state.isInSearchMode;
const filteredFiles = state.filteredFiles;
if (process.env.NEXT_PUBLIC_ENTE_TRACE) console.log("render", state);
@@ -322,8 +326,8 @@ const Page: React.FC = () => {
type: "mount",
user,
familyData,
allCollections: await getAllLocalCollections(),
files: await getLocalFiles("normal"),
collections: await getAllLocalCollections(),
normalFiles: await getLocalFiles("normal"),
hiddenFiles: await getLocalFiles("hidden"),
trashedFiles: await getLocalTrashedFiles(),
});
@@ -346,26 +350,35 @@ const Page: React.FC = () => {
};
}, []);
useEffect(
() => setSearchCollectionsAndFiles({ collections, files }),
[collections, files],
);
useEffect(() => {
setSearchCollectionsAndFiles({
collections: normalCollections,
files: normalFiles,
});
}, [normalCollections, normalFiles]);
useEffect(() => {
if (!collections || !user) {
if (!user || !normalCollections) {
return;
}
const userIdToEmailMap = constructUserIDToEmailMap(user, collections);
const userIdToEmailMap = constructUserIDToEmailMap(
user,
normalCollections,
);
setUserIDToEmailMap(userIdToEmailMap);
}, [collections]);
}, [user, normalCollections]);
useEffect(() => {
if (!user || !collections) {
if (!user || !normalCollections) {
return;
}
const emailList = constructEmailList(user, collections, familyData);
const emailList = constructEmailList(
user,
normalCollections,
familyData,
);
setEmailList(emailList);
}, [user, collections, familyData]);
}, [user, normalCollections, familyData]);
useEffect(() => {
collectionNamerAttributes && setCollectionNamerView(true);
@@ -520,22 +533,27 @@ const Page: React.FC = () => {
const handleFileAndCollectionSyncWithRemote = useCallback(async () => {
const didUpdateFiles = await syncCollectionAndFiles({
onSetCollections: (normalCollections, hiddenCollections) =>
onSetCollections: (
collections,
normalCollections,
hiddenCollections,
) =>
dispatch({
type: "setCollections",
collections,
normalCollections,
hiddenCollections,
}),
onResetNormalFiles: (files) =>
dispatch({ type: "setFiles", files }),
dispatch({ type: "setNormalFiles", files }),
onFetchNormalFiles: (files) =>
dispatch({ type: "fetchFiles", files }),
onResetHiddenFiles: (hiddenFiles) =>
dispatch({ type: "setHiddenFiles", hiddenFiles }),
onFetchHiddenFiles: (hiddenFiles) =>
dispatch({ type: "fetchHiddenFiles", hiddenFiles }),
onResetTrashedFiles: (trashedFiles) =>
dispatch({ type: "setTrashedFiles", trashedFiles }),
dispatch({ type: "fetchNormalFiles", files }),
onResetHiddenFiles: (files) =>
dispatch({ type: "setHiddenFiles", files }),
onFetchHiddenFiles: (files) =>
dispatch({ type: "fetchHiddenFiles", files }),
onResetTrashedFiles: (files) =>
dispatch({ type: "setTrashedFiles", files }),
});
if (didUpdateFiles) {
exportService.onLocalFilesUpdated();
@@ -693,7 +711,7 @@ const Page: React.FC = () => {
// passing files here instead of filteredData for hide ops because we want to move all files copies to hidden collection
const selectedFiles = getSelectedFiles(
selected,
ops === FILE_OPS_TYPE.HIDE ? files : filteredFiles,
ops === FILE_OPS_TYPE.HIDE ? normalFiles : filteredFiles,
);
const toProcessFiles =
ops === FILE_OPS_TYPE.DOWNLOAD
@@ -751,7 +769,7 @@ const Page: React.FC = () => {
if (type == "collection" || type == "person") {
if (type == "collection") {
dispatch({
type: "showNormalOrHiddenCollectionSummary",
type: "showCollectionSummary",
collectionSummaryID: searchOption.suggestion.collectionID,
});
} else {
@@ -781,11 +799,7 @@ const Page: React.FC = () => {
const handleSetActiveCollectionID = (
collectionSummaryID: number | undefined,
) =>
dispatch({
type: "showNormalOrHiddenCollectionSummary",
collectionSummaryID,
});
) => dispatch({ type: "showCollectionSummary", collectionSummaryID });
const handleChangeBarMode = (mode: GalleryBarMode) =>
mode == "people"
@@ -840,7 +854,7 @@ const Page: React.FC = () => {
const handleSelectCollection = useCallback(
(collectionID: number) =>
dispatch({
type: "showNormalOrHiddenCollectionSummary",
type: "showCollectionSummary",
collectionSummaryID: collectionID,
}),
[],
@@ -914,10 +928,10 @@ const Page: React.FC = () => {
open={openCollectionSelector}
onClose={handleCloseCollectionSelector}
attributes={collectionSelectorAttributes}
collectionSummaries={collectionSummaries}
collectionSummaries={normalCollectionSummaries}
collectionForCollectionID={(id) =>
findCollectionCreatingUncategorizedIfNeeded(
collections,
normalCollections,
id,
)
}
@@ -957,21 +971,25 @@ const Page: React.FC = () => {
activeCollectionID={activeCollectionID}
selectedCollection={getSelectedCollection(
selected.collectionID,
collections,
normalCollections,
)}
isFavoriteCollection={
collectionSummaries.get(activeCollectionID)
?.type == "favorites"
normalCollectionSummaries.get(
activeCollectionID,
)?.type == "favorites"
}
isUncategorizedCollection={
collectionSummaries.get(activeCollectionID)
?.type == "uncategorized"
normalCollectionSummaries.get(
activeCollectionID,
)?.type == "uncategorized"
}
isIncomingSharedCollection={
collectionSummaries.get(activeCollectionID)
?.type == "incomingShareCollaborator" ||
collectionSummaries.get(activeCollectionID)
?.type == "incomingShareViewer"
normalCollectionSummaries.get(
activeCollectionID,
)?.type == "incomingShareCollaborator" ||
normalCollectionSummaries.get(
activeCollectionID,
)?.type == "incomingShareViewer"
}
isInSearchMode={isInSearchMode}
isInHiddenSection={barMode == "hidden-albums"}
@@ -1001,26 +1019,26 @@ const Page: React.FC = () => {
<GalleryBarAndListHeader
{...{
shouldHide: isInSearchMode,
mode: barMode,
onChangeMode: handleChangeBarMode,
collectionSummaries,
activeCollection,
activeCollectionID,
setActiveCollectionID: handleSetActiveCollectionID,
hiddenCollectionSummaries:
state.hiddenCollectionSummaries,
people:
(state.view.type == "people"
? state.view.visiblePeople
: undefined) ?? [],
activePerson,
onSelectPerson: handleSelectPerson,
setCollectionNamerAttributes,
setPhotoListHeader,
setFilesDownloadProgressAttributesCreator,
filesDownloadProgressAttributesList,
}}
mode={barMode}
shouldHide={isInSearchMode}
collectionSummaries={normalCollectionSummaries}
hiddenCollectionSummaries={state.hiddenCollectionSummaries}
people={
(state.view.type == "people"
? state.view.visiblePeople
: undefined) ?? []
}
onChangeMode={handleChangeBarMode}
setActiveCollectionID={handleSetActiveCollectionID}
onSelectPerson={handleSelectPerson}
/>
<Upload
@@ -1036,14 +1054,14 @@ const Page: React.FC = () => {
setCollectionNamerAttributes={setCollectionNamerAttributes}
setShouldDisableDropzone={setShouldDisableDropzone}
onUploadFile={(file) =>
dispatch({ type: "uploadFile", file })
dispatch({ type: "uploadNormalFile", file })
}
onShowPlanSelector={showPlanSelector}
setCollections={(collections) =>
dispatch({ type: "setNormalCollections", collections })
}
isFirstUpload={areOnlySystemCollections(
collectionSummaries,
normalCollectionSummaries,
)}
showSessionExpiredMessage={showSessionExpiredDialog}
{...{
@@ -1054,7 +1072,7 @@ const Page: React.FC = () => {
/>
<Sidebar
{...sidebarVisibilityProps}
{...{ collectionSummaries }}
collectionSummaries={normalCollectionSummaries}
onShowPlanSelector={showPlanSelector}
onShowExport={showExport}
onAuthenticateUser={authenticateUser}
@@ -1062,7 +1080,7 @@ const Page: React.FC = () => {
<WhatsNew {...whatsNewVisibilityProps} />
{!isInSearchMode &&
!isFirstLoad &&
!files?.length &&
!normalFiles?.length &&
!hiddenFiles?.length &&
activeCollectionID === ALL_SECTION ? (
<GalleryEmptyState openUploader={openUploader} />
@@ -1079,20 +1097,20 @@ const Page: React.FC = () => {
files={filteredFiles}
enableDownload={true}
showAppDownloadBanner={
files.length < 30 && !isInSearchMode
normalFiles.length < 30 && !isInSearchMode
}
selectable={true}
selected={selected}
setSelected={setSelected}
activeCollectionID={activeCollectionID}
activePersonID={activePerson?.id}
fileCollectionIDs={state.fileCollectionIDs}
allCollectionsNameByID={state.allCollectionsNameByID}
fileNormalCollectionIDs={state.fileNormalCollectionIDs}
collectionNameByID={state.collectionNameByID}
isInIncomingSharedCollection={
collectionSummaries.get(activeCollectionID)?.type ==
"incomingShareCollaborator" ||
collectionSummaries.get(activeCollectionID)?.type ==
"incomingShareViewer"
normalCollectionSummaries.get(activeCollectionID)
?.type == "incomingShareCollaborator" ||
normalCollectionSummaries.get(activeCollectionID)
?.type == "incomingShareViewer"
}
isInHiddenSection={barMode == "hidden-albums"}
pendingVisibilityUpdates={
@@ -1118,7 +1136,7 @@ const Page: React.FC = () => {
)}
<Export
{...exportVisibilityProps}
allCollectionsNameByID={state.allCollectionsNameByID}
allCollectionsNameByID={state.collectionNameByID}
/>
<AuthenticateUser
{...authenticateUserVisibilityProps}

View File

@@ -522,8 +522,6 @@ export default function PublicCollectionGallery() {
selected={selected}
setSelected={setSelected}
activeCollectionID={ALL_SECTION}
fileCollectionIDs={undefined}
allCollectionsNameByID={undefined}
setFilesDownloadProgressAttributesCreator={
setFilesDownloadProgressAttributesCreator
}

View File

@@ -128,8 +128,8 @@ export type FileInfoProps = ModalVisibilityProps & {
*/
allowMap?: boolean;
/**
* If set, then a clickable chip will be shown for each collection that this
* file is a part of.
* If set, then a clickable chip will be shown for each normal collection
* that this file is a part of.
*
* Uses {@link fileCollectionIDs}, {@link allCollectionsNameByID} and
* {@link onSelectCollection}, so all of those props should also be set for
@@ -137,17 +137,18 @@ export type FileInfoProps = ModalVisibilityProps & {
*/
showCollections?: boolean;
/**
* A map from file IDs to the IDs of the collections that they're a part of.
* A map from file IDs to the IDs of the normal (non-hidden) collections
* that they're a part of.
*
* Used when {@link showCollections} is set.
*/
fileCollectionIDs?: Map<number, number[]>;
fileNormalCollectionIDs?: Map<number, number[]>;
/**
* A map from collection IDs to their name.
*
* Used when {@link showCollections} is set.
*/
allCollectionsNameByID?: Map<number, string>;
collectionNameByID?: Map<number, string>;
/**
* Called when the action on the file info drawer has changed some the
* metadata for some file, and we need to sync with remote to get our
@@ -188,8 +189,8 @@ export const FileInfo: React.FC<FileInfoProps> = ({
allowEdits,
allowMap,
showCollections,
fileCollectionIDs,
allCollectionsNameByID,
fileNormalCollectionIDs,
collectionNameByID,
onNeedsRemoteSync,
onUpdateCaption,
onSelectCollection,
@@ -338,14 +339,14 @@ export const FileInfo: React.FC<FileInfoProps> = ({
</InfoItem>
)}
{showCollections &&
fileCollectionIDs &&
allCollectionsNameByID &&
fileNormalCollectionIDs &&
collectionNameByID &&
onSelectCollection && (
<Albums
{...{
file,
fileCollectionIDs,
allCollectionsNameByID,
fileNormalCollectionIDs,
collectionNameByID,
onSelectCollection,
}}
/>
@@ -1003,14 +1004,14 @@ const ExifItem = styled("div")`
type AlbumsProps = Required<
Pick<
FileInfoProps,
"fileCollectionIDs" | "allCollectionsNameByID" | "onSelectCollection"
"fileNormalCollectionIDs" | "collectionNameByID" | "onSelectCollection"
>
> & { file: EnteFile };
const Albums: React.FC<AlbumsProps> = ({
file,
fileCollectionIDs,
allCollectionsNameByID,
fileNormalCollectionIDs,
collectionNameByID,
onSelectCollection,
}) => (
<InfoItem icon={<FolderOutlinedIcon />}>
@@ -1023,17 +1024,15 @@ const Albums: React.FC<AlbumsProps> = ({
alignItems: "flex-start",
}}
>
{fileCollectionIDs
{fileNormalCollectionIDs
.get(file.id)
?.filter((collectionID) =>
allCollectionsNameByID.has(collectionID),
)
?.filter((collectionID) => collectionNameByID.has(collectionID))
.map((collectionID) => (
<ChipButton
key={collectionID}
onClick={() => onSelectCollection(collectionID)}
>
{allCollectionsNameByID.get(collectionID)}
{collectionNameByID.get(collectionID)}
</ChipButton>
))}
</Stack>

View File

@@ -256,8 +256,8 @@ export type FileViewerProps = ModalVisibilityProps & {
onSaveEditedImageCopy?: ImageEditorOverlayProps["onSaveEditedCopy"];
} & Pick<
FileInfoProps,
| "fileCollectionIDs"
| "allCollectionsNameByID"
| "fileNormalCollectionIDs"
| "collectionNameByID"
| "onSelectCollection"
| "onSelectPerson"
>;
@@ -277,8 +277,8 @@ export const FileViewer: React.FC<FileViewerProps> = ({
isInHiddenSection,
favoriteFileIDs,
pendingVisibilityUpdates,
fileCollectionIDs,
allCollectionsNameByID,
fileNormalCollectionIDs,
collectionNameByID,
onTriggerSyncWithRemote,
onVisualFeedback,
onToggleFavorite,
@@ -909,7 +909,7 @@ export const FileViewer: React.FC<FileViewerProps> = ({
onUpdateCaption={handleUpdateCaption}
onSelectCollection={handleSelectCollection}
onSelectPerson={handleSelectPerson}
{...{ fileCollectionIDs, allCollectionsNameByID }}
{...{ fileNormalCollectionIDs, collectionNameByID }}
/>
<MoreMenu
open={!!moreMenuAnchorEl}

View File

@@ -124,7 +124,7 @@ export interface GalleryState {
/**
* The user's normal (non-hidden) collections.
*/
collections: Collection[];
normalCollections: Collection[];
/**
* The user's hidden collections.
*/
@@ -136,9 +136,9 @@ export interface GalleryState {
* The list is sorted so that newer files are first.
*
* This property is expected to be of use only internal to the reducer;
* external code likely needs {@link files} instead.
* external code likely needs {@link normalFiles} instead.
*/
lastSyncedFiles: EnteFile[];
lastSyncedNormalFiles: EnteFile[];
/**
* The user's hidden files, without any unsynced modifications applied to
* them.
@@ -150,7 +150,7 @@ export interface GalleryState {
*/
lastSyncedHiddenFiles: EnteFile[];
/**
* The user's files that are in Trash.
* The user's files that are in trash.
*
* The list is sorted so that newer files are first.
*/
@@ -177,7 +177,7 @@ export interface GalleryState {
* happen on the next "file sync", until then they remain as in-memory state
* in the reducer.
*/
files: EnteFile[];
normalFiles: EnteFile[];
/**
* The user's hidden files, with any unsynced modifications also applied to
* them.
@@ -233,21 +233,23 @@ export interface GalleryState {
*
* It will contain entries for all collections (both normal and hidden).
*/
allCollectionsNameByID: Map<number, string>;
collectionNameByID: Map<number, string>;
/**
* A map from file IDs to the IDs of the collections that they're a part of.
* A map from file IDs to the IDs of the normal (non-hidden) collections
* that they're a part of.
*/
fileCollectionIDs: Map<number, number[]>;
fileNormalCollectionIDs: Map<number, number[]>;
/*--< Derived UI state >--*/
/**
* A map of collections massage to a form suitable for being directly
* consumed by the UI, indexed by the collection IDs.
* A map of normal (non-hidden) collections massaged into a form suitable
* for being directly consumed by the UI, indexed by the collection IDs.
*/
collectionSummaries: Map<number, CollectionSummary>;
normalCollectionSummaries: Map<number, CollectionSummary>;
/**
* A version of {@link collectionSummaries} but for hidden collections.
* A variant of {@link normalCollectionSummaries}, but for hidden
* collections.
*/
hiddenCollectionSummaries: Map<number, CollectionSummary>;
@@ -412,23 +414,24 @@ export type GalleryAction =
type: "mount";
user: User;
familyData: FamilyData;
allCollections: Collection[];
files: EnteFile[];
collections: Collection[];
normalFiles: EnteFile[];
hiddenFiles: EnteFile[];
trashedFiles: EnteFile[];
}
| { type: "setNormalCollections"; collections: Collection[] }
| {
type: "setCollections";
collections: Collection[];
normalCollections: Collection[];
hiddenCollections: Collection[];
}
| { type: "setFiles"; files: EnteFile[] }
| { type: "fetchFiles"; files: EnteFile[] }
| { type: "uploadFile"; file: EnteFile }
| { type: "setHiddenFiles"; hiddenFiles: EnteFile[] }
| { type: "fetchHiddenFiles"; hiddenFiles: EnteFile[] }
| { type: "setTrashedFiles"; trashedFiles: EnteFile[] }
| { type: "setNormalCollections"; collections: Collection[] }
| { type: "setNormalFiles"; files: EnteFile[] }
| { type: "fetchNormalFiles"; files: EnteFile[] }
| { type: "uploadNormalFile"; file: EnteFile }
| { type: "setHiddenFiles"; files: EnteFile[] }
| { type: "fetchHiddenFiles"; files: EnteFile[] }
| { type: "setTrashedFiles"; files: EnteFile[] }
| { type: "setPeopleState"; peopleState: PeopleState | undefined }
| { type: "markTempDeleted"; files: EnteFile[] }
| { type: "clearTempDeleted" }
@@ -452,10 +455,7 @@ export type GalleryAction =
| { type: "showAll" }
| { type: "showHidden" }
| { type: "showAlbums" }
| {
type: "showNormalOrHiddenCollectionSummary";
collectionSummaryID: number | undefined;
}
| { type: "showCollectionSummary"; collectionSummaryID: number | undefined }
| { type: "showPeople" }
| { type: "showPerson"; personID: string }
| { type: "enterSearchMode"; searchSuggestion?: SearchSuggestion }
@@ -466,22 +466,22 @@ export type GalleryAction =
const initialGalleryState: GalleryState = {
user: undefined,
familyData: undefined,
collections: [],
normalCollections: [],
hiddenCollections: [],
lastSyncedFiles: [],
lastSyncedNormalFiles: [],
lastSyncedHiddenFiles: [],
trashedFiles: [],
peopleState: undefined,
files: [],
normalFiles: [],
hiddenFiles: [],
archivedCollectionIDs: new Set(),
defaultHiddenCollectionIDs: new Set(),
hiddenFileIDs: new Set(),
archivedFileIDs: new Set(),
favoriteFileIDs: new Set(),
allCollectionsNameByID: new Map(),
fileCollectionIDs: new Map(),
collectionSummaries: new Map(),
collectionNameByID: new Map(),
fileNormalCollectionIDs: new Map(),
normalCollectionSummaries: new Map(),
hiddenCollectionSummaries: new Map(),
tempDeletedFileIDs: new Set(),
tempHiddenFileIDs: new Set(),
@@ -507,42 +507,45 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
if (process.env.NEXT_PUBLIC_ENTE_TRACE) console.log("dispatch", action);
switch (action.type) {
case "mount": {
const lastSyncedFiles = sortFiles(mergeMetadata(action.files));
const lastSyncedNormalFiles = sortFiles(
mergeMetadata(action.normalFiles),
);
const lastSyncedHiddenFiles = sortFiles(
mergeMetadata(action.hiddenFiles),
);
// During mount there are no unsynced updates, and we can directly
// use the provided files.
const files = lastSyncedFiles;
const normalFiles = lastSyncedNormalFiles;
const hiddenFiles = lastSyncedHiddenFiles;
const [hiddenCollections, collections] = splitByPredicate(
action.allCollections,
const [hiddenCollections, normalCollections] = splitByPredicate(
action.collections,
isHiddenCollection,
);
const hiddenFileIDs = deriveHiddenFileIDs(hiddenFiles);
const archivedCollectionIDs =
deriveArchivedCollectionIDs(collections);
deriveArchivedCollectionIDs(normalCollections);
const archivedFileIDs = deriveArchivedFileIDs(
archivedCollectionIDs,
files,
normalFiles,
);
const view = {
type: "albums" as const,
activeCollectionSummaryID: ALL_SECTION,
activeCollection: undefined,
};
return stateByUpdatingFilteredFiles({
...state,
user: action.user,
familyData: action.familyData,
collections,
normalCollections,
hiddenCollections,
lastSyncedFiles,
lastSyncedNormalFiles,
lastSyncedHiddenFiles,
trashedFiles: action.trashedFiles,
files,
normalFiles,
hiddenFiles,
archivedCollectionIDs,
defaultHiddenCollectionIDs:
@@ -550,18 +553,18 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
hiddenFileIDs,
archivedFileIDs,
favoriteFileIDs: deriveFavoriteFileIDs(
collections,
files,
normalCollections,
normalFiles,
state.unsyncedFavoriteUpdates,
),
allCollectionsNameByID: createCollectionNameByID(
action.allCollections,
collectionNameByID: createCollectionNameByID(
action.collections,
),
fileCollectionIDs: createFileCollectionIDs(files),
collectionSummaries: deriveCollectionSummaries(
fileNormalCollectionIDs: createFileCollectionIDs(normalFiles),
normalCollectionSummaries: deriveNormalCollectionSummaries(
action.user,
collections,
files,
normalCollections,
normalFiles,
action.trashedFiles,
archivedFileIDs,
),
@@ -574,71 +577,19 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
});
}
case "setNormalCollections": {
const collections = action.collections;
const archivedCollectionIDs =
deriveArchivedCollectionIDs(collections);
const archivedFileIDs = deriveArchivedFileIDs(
archivedCollectionIDs,
state.files,
);
const collectionSummaries = deriveCollectionSummaries(
state.user!,
collections,
state.files,
state.trashedFiles,
archivedFileIDs,
);
// Revalidate the active view if needed.
let view = state.view;
let selectedCollectionSummaryID = state.selectedCollectionSummaryID;
if (state.view?.type == "albums") {
({ view, selectedCollectionSummaryID } =
deriveAlbumsViewAndSelectedID(
collections,
collectionSummaries,
selectedCollectionSummaryID,
));
}
return stateByUpdatingFilteredFiles({
...state,
collections,
archivedCollectionIDs,
archivedFileIDs,
favoriteFileIDs: deriveFavoriteFileIDs(
collections,
state.files,
state.unsyncedFavoriteUpdates,
),
allCollectionsNameByID: createCollectionNameByID(
collections.concat(state.hiddenCollections),
),
collectionSummaries,
selectedCollectionSummaryID,
pendingSearchSuggestions:
enqueuePendingSearchSuggestionsIfNeeded(
state.searchSuggestion,
state.pendingSearchSuggestions,
state.isInSearchMode,
),
view,
});
}
case "setCollections": {
const { normalCollections, hiddenCollections } = action;
const { collections, normalCollections, hiddenCollections } =
action;
const archivedCollectionIDs =
deriveArchivedCollectionIDs(normalCollections);
const archivedFileIDs = deriveArchivedFileIDs(
archivedCollectionIDs,
state.files,
state.normalFiles,
);
const collectionSummaries = deriveCollectionSummaries(
const normalCollectionSummaries = deriveNormalCollectionSummaries(
state.user!,
normalCollections,
state.files,
state.normalFiles,
state.trashedFiles,
archivedFileIDs,
);
@@ -655,7 +606,7 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
({ view, selectedCollectionSummaryID } =
deriveAlbumsViewAndSelectedID(
normalCollections,
collectionSummaries,
normalCollectionSummaries,
selectedCollectionSummaryID,
));
} else if (state.view?.type == "hidden-albums") {
@@ -669,7 +620,7 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
return stateByUpdatingFilteredFiles({
...state,
collections: normalCollections,
normalCollections,
hiddenCollections,
archivedCollectionIDs,
defaultHiddenCollectionIDs:
@@ -677,13 +628,11 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
archivedFileIDs,
favoriteFileIDs: deriveFavoriteFileIDs(
normalCollections,
state.files,
state.normalFiles,
state.unsyncedFavoriteUpdates,
),
allCollectionsNameByID: createCollectionNameByID(
normalCollections.concat(hiddenCollections),
),
collectionSummaries,
collectionNameByID: createCollectionNameByID(collections),
normalCollectionSummaries,
hiddenCollectionSummaries,
selectedCollectionSummaryID,
pendingSearchSuggestions:
@@ -696,68 +645,121 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
});
}
case "setFiles": {
case "setNormalCollections": {
const normalCollections = action.collections;
const archivedCollectionIDs =
deriveArchivedCollectionIDs(normalCollections);
const archivedFileIDs = deriveArchivedFileIDs(
archivedCollectionIDs,
state.normalFiles,
);
const normalCollectionSummaries = deriveNormalCollectionSummaries(
state.user!,
normalCollections,
state.normalFiles,
state.trashedFiles,
archivedFileIDs,
);
// Revalidate the active view if needed.
let view = state.view;
let selectedCollectionSummaryID = state.selectedCollectionSummaryID;
if (state.view?.type == "albums") {
({ view, selectedCollectionSummaryID } =
deriveAlbumsViewAndSelectedID(
normalCollections,
normalCollectionSummaries,
selectedCollectionSummaryID,
));
}
return stateByUpdatingFilteredFiles({
...state,
normalCollections,
archivedCollectionIDs,
archivedFileIDs,
favoriteFileIDs: deriveFavoriteFileIDs(
normalCollections,
state.normalFiles,
state.unsyncedFavoriteUpdates,
),
collectionNameByID: createCollectionNameByID(
normalCollections.concat(state.hiddenCollections),
),
normalCollectionSummaries,
selectedCollectionSummaryID,
pendingSearchSuggestions:
enqueuePendingSearchSuggestionsIfNeeded(
state.searchSuggestion,
state.pendingSearchSuggestions,
state.isInSearchMode,
),
view,
});
}
case "setNormalFiles": {
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
action.files,
);
const lastSyncedFiles = sortFiles(mergeMetadata(action.files));
const files = deriveNormalOrHiddenFiles(
lastSyncedFiles,
const lastSyncedNormalFiles = sortFiles(
mergeMetadata(action.files),
);
const normalFiles = deriveFiles(
lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
...stateForUpdatedFiles(state, files),
lastSyncedFiles,
...stateForUpdatedNormalFiles(state, normalFiles),
lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
});
}
case "fetchFiles": {
case "fetchNormalFiles": {
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
action.files,
);
const lastSyncedFiles = sortFiles(
const lastSyncedNormalFiles = sortFiles(
mergeMetadata(
getLatestVersionFiles(
state.lastSyncedFiles.concat(action.files),
state.lastSyncedNormalFiles.concat(action.files),
),
),
);
const files = deriveNormalOrHiddenFiles(
lastSyncedFiles,
const normalFiles = deriveFiles(
lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
...stateForUpdatedFiles(state, files),
lastSyncedFiles,
...stateForUpdatedNormalFiles(state, normalFiles),
lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
});
}
case "uploadFile": {
case "uploadNormalFile": {
// TODO: Consider batching this instead of doing it per file
// upload to speed up uploads. Perf test first though.
const lastSyncedFiles = sortFiles([
...state.lastSyncedFiles,
const lastSyncedNormalFiles = sortFiles([
...state.lastSyncedNormalFiles,
action.file,
]);
const files = deriveNormalOrHiddenFiles(
lastSyncedFiles,
const normalFiles = deriveFiles(
lastSyncedNormalFiles,
state.unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
...stateForUpdatedFiles(state, files),
lastSyncedFiles,
...stateForUpdatedNormalFiles(state, normalFiles),
lastSyncedNormalFiles,
});
}
@@ -765,13 +767,12 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
action.hiddenFiles,
action.files,
);
const lastSyncedHiddenFiles = sortFiles(
mergeMetadata(action.hiddenFiles),
mergeMetadata(action.files),
);
const hiddenFiles = deriveNormalOrHiddenFiles(
const hiddenFiles = deriveFiles(
lastSyncedHiddenFiles,
unsyncedPrivateMagicMetadataUpdates,
);
@@ -787,17 +788,16 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
action.hiddenFiles,
action.files,
);
const lastSyncedHiddenFiles = sortFiles(
mergeMetadata(
getLatestVersionFiles(
state.lastSyncedHiddenFiles.concat(action.hiddenFiles),
state.lastSyncedHiddenFiles.concat(action.files),
),
),
);
const hiddenFiles = deriveNormalOrHiddenFiles(
const hiddenFiles = deriveFiles(
lastSyncedHiddenFiles,
unsyncedPrivateMagicMetadataUpdates,
);
@@ -812,12 +812,12 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
case "setTrashedFiles":
return stateByUpdatingFilteredFiles({
...state,
trashedFiles: action.trashedFiles,
collectionSummaries: deriveCollectionSummaries(
trashedFiles: action.files,
normalCollectionSummaries: deriveNormalCollectionSummaries(
state.user!,
state.collections,
state.files,
action.trashedFiles,
state.normalCollections,
state.normalFiles,
action.files,
state.archivedFileIDs,
),
});
@@ -901,12 +901,13 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
action.fileID,
action.privateMagicMetadata,
);
const files = deriveNormalOrHiddenFiles(
state.lastSyncedFiles,
const normalFiles = deriveFiles(
state.lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
...stateForUpdatedFiles(state, files),
...stateForUpdatedNormalFiles(state, normalFiles),
unsyncedPrivateMagicMetadataUpdates,
});
}
@@ -925,8 +926,8 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
return {
...state,
favoriteFileIDs: deriveFavoriteFileIDs(
state.collections,
state.files,
state.normalCollections,
state.normalFiles,
unsyncedFavoriteUpdates,
),
unsyncedFavoriteUpdates,
@@ -937,18 +938,18 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
const unsyncedPrivateMagicMetadataUpdates: GalleryState["unsyncedPrivateMagicMetadataUpdates"] =
new Map();
const files = deriveNormalOrHiddenFiles(
state.lastSyncedFiles,
const normalFiles = deriveFiles(
state.lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
const hiddenFiles = deriveNormalOrHiddenFiles(
const hiddenFiles = deriveFiles(
state.lastSyncedHiddenFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles(
stateForUpdatedHiddenFiles(
stateForUpdatedFiles(
stateForUpdatedNormalFiles(
{
...state,
tempDeletedFileIDs: new Set(),
@@ -957,7 +958,7 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
unsyncedPrivateMagicMetadataUpdates,
unsyncedFavoriteUpdates: new Map(),
},
files,
normalFiles,
),
hiddenFiles,
),
@@ -1001,10 +1002,11 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
case "showAlbums": {
const { view, selectedCollectionSummaryID } =
deriveAlbumsViewAndSelectedID(
state.collections,
state.collectionSummaries,
state.normalCollections,
state.normalCollectionSummaries,
state.selectedCollectionSummaryID,
);
return stateByUpdatingFilteredFiles({
...state,
selectedCollectionSummaryID,
@@ -1018,7 +1020,7 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
});
}
case "showNormalOrHiddenCollectionSummary":
case "showCollectionSummary":
return stateByUpdatingFilteredFiles({
...state,
selectedCollectionSummaryID: action.collectionSummaryID,
@@ -1037,7 +1039,7 @@ const galleryReducer: React.Reducer<GalleryState, GalleryAction> = (
: "albums",
activeCollectionSummaryID:
action.collectionSummaryID ?? ALL_SECTION,
activeCollection: state.collections
activeCollection: state.normalCollections
.concat(state.hiddenCollections)
.find(({ id }) => id === action.collectionSummaryID),
},
@@ -1135,7 +1137,7 @@ export const useGalleryReducer = () =>
* Compute the effective files that we should use by overlaying the files we
* read from disk by any temporary unsynced updates.
*/
const deriveNormalOrHiddenFiles = (
const deriveFiles = (
files: EnteFile[],
unsyncedPrivateMagicMetadataUpdates: GalleryState["unsyncedPrivateMagicMetadataUpdates"],
) => {
@@ -1181,7 +1183,7 @@ const deriveHiddenFileIDs = (hiddenFiles: EnteFile[]) =>
*/
const deriveArchivedFileIDs = (
archivedCollectionIDs: GalleryState["archivedCollectionIDs"],
files: GalleryState["files"],
files: GalleryState["normalFiles"],
) =>
new Set(
files
@@ -1220,26 +1222,26 @@ const deriveFavoriteFileIDs = (
};
/**
* Compute collection summaries from their dependencies.
* Compute normal (non-hidden) collection summaries from their dependencies.
*/
const deriveCollectionSummaries = (
const deriveNormalCollectionSummaries = (
user: User,
collections: Collection[],
files: EnteFile[],
normalCollections: Collection[],
normalFiles: EnteFile[],
trashedFiles: EnteFile[],
archivedFileIDs: Set<number>,
) => {
const collectionSummaries = createCollectionSummaries(
const normalCollectionSummaries = createCollectionSummaries(
user,
collections,
files,
normalCollections,
normalFiles,
);
const uncategorizedCollection = collections.find(
const uncategorizedCollection = normalCollections.find(
({ type }) => type === CollectionType.uncategorized,
);
if (!uncategorizedCollection) {
collectionSummaries.set(DUMMY_UNCATEGORIZED_COLLECTION, {
normalCollectionSummaries.set(DUMMY_UNCATEGORIZED_COLLECTION, {
...pseudoCollectionOptionsForFiles([]),
id: DUMMY_UNCATEGORIZED_COLLECTION,
type: "uncategorized",
@@ -1248,15 +1250,18 @@ const deriveCollectionSummaries = (
});
}
const allSectionFiles = findAllSectionVisibleFiles(files, archivedFileIDs);
collectionSummaries.set(ALL_SECTION, {
const allSectionFiles = findAllSectionVisibleFiles(
normalFiles,
archivedFileIDs,
);
normalCollectionSummaries.set(ALL_SECTION, {
...pseudoCollectionOptionsForFiles(allSectionFiles),
id: ALL_SECTION,
type: "all",
attributes: ["all"],
name: t("section_all"),
});
collectionSummaries.set(TRASH_SECTION, {
normalCollectionSummaries.set(TRASH_SECTION, {
...pseudoCollectionOptionsForFiles(trashedFiles),
id: TRASH_SECTION,
name: t("section_trash"),
@@ -1265,9 +1270,9 @@ const deriveCollectionSummaries = (
coverFile: undefined,
});
const archivedFiles = uniqueFilesByID(
files.filter((file) => isArchivedFile(file)),
normalFiles.filter((file) => isArchivedFile(file)),
);
collectionSummaries.set(ARCHIVE_SECTION, {
normalCollectionSummaries.set(ARCHIVE_SECTION, {
...pseudoCollectionOptionsForFiles(archivedFiles),
id: ARCHIVE_SECTION,
name: t("section_archive"),
@@ -1276,7 +1281,7 @@ const deriveCollectionSummaries = (
coverFile: undefined,
});
return collectionSummaries;
return normalCollectionSummaries;
};
const pseudoCollectionOptionsForFiles = (files: EnteFile[]) => ({
@@ -1492,8 +1497,8 @@ const findAllSectionVisibleFiles = (
* changed.
*/
const deriveAlbumsViewAndSelectedID = (
collections: GalleryState["collections"],
collectionSummaries: GalleryState["collectionSummaries"],
collections: GalleryState["normalCollections"],
collectionSummaries: GalleryState["normalCollectionSummaries"],
selectedCollectionSummaryID: GalleryState["selectedCollectionSummaryID"],
) => {
// Make sure that the last selected ID is still valid by searching for it.
@@ -1631,30 +1636,34 @@ const derivePeopleView = (
/**
* Return a new state from the given {@link state} by recomputing all properties
* that depend on file using the provided {@link files}.
* that depend on normal (non-hidden) files, using the provided
* {@link normalFiles}.
*
* Usually, we update state by manually dependency tracking on a fine grained
* basis, but it results in a duplicate code when the files themselves change,
* since they effect many things. This is a convenience function for updating
* everything that needs to change when the files themselves change.
* everything that needs to change when the normal files themselves change.
*/
const stateForUpdatedFiles = (
const stateForUpdatedNormalFiles = (
state: GalleryState,
files: GalleryState["files"],
) => ({
normalFiles: GalleryState["normalFiles"],
): GalleryState => ({
...state,
files,
archivedFileIDs: deriveArchivedFileIDs(state.archivedCollectionIDs, files),
normalFiles,
archivedFileIDs: deriveArchivedFileIDs(
state.archivedCollectionIDs,
normalFiles,
),
favoriteFileIDs: deriveFavoriteFileIDs(
state.collections,
files,
state.normalCollections,
normalFiles,
state.unsyncedFavoriteUpdates,
),
fileCollectionIDs: createFileCollectionIDs(files),
collectionSummaries: deriveCollectionSummaries(
fileNormalCollectionIDs: createFileCollectionIDs(normalFiles),
normalCollectionSummaries: deriveNormalCollectionSummaries(
state.user!,
state.collections,
files,
state.normalCollections,
normalFiles,
state.trashedFiles,
state.archivedFileIDs,
),
@@ -1667,17 +1676,17 @@ const stateForUpdatedFiles = (
/**
* Return a new state from the given {@link state} by recomputing all properties
* that depend on file using the provided {@link hiddenFiles}.
* that depend on hidden files, using the provided {@link hiddenFiles}.
*
* Usually, we update state by manually dependency tracking on a fine grained
* basis, but it results in a duplicate code when the hidden files themselves
* change, since they effect a few things. This is a convenience function for
* updating everything that needs to change when the hiddenFiles change.
* updating everything that needs to change when the hidden files change.
*/
const stateForUpdatedHiddenFiles = (
state: GalleryState,
hiddenFiles: GalleryState["hiddenFiles"],
) => ({
): GalleryState => ({
...state,
hiddenFiles,
hiddenFileIDs: deriveHiddenFileIDs(hiddenFiles),
@@ -1704,7 +1713,7 @@ const stateByUpdatingFilteredFiles = (state: GalleryState) => {
return { ...state, filteredFiles };
} else if (state.view?.type == "albums") {
const filteredFiles = deriveAlbumsFilteredFiles(
state.files,
state.normalFiles,
state.trashedFiles,
state.hiddenFileIDs,
state.archivedCollectionIDs,
@@ -1724,7 +1733,7 @@ const stateByUpdatingFilteredFiles = (state: GalleryState) => {
return { ...state, filteredFiles };
} else if (state.view?.type == "people") {
const filteredFiles = derivePeopleFilteredFiles(
state.files,
state.normalFiles,
state.view,
);
return { ...state, filteredFiles };
@@ -1738,7 +1747,7 @@ const stateByUpdatingFilteredFiles = (state: GalleryState) => {
* the dependencies change.
*/
const deriveAlbumsFilteredFiles = (
files: GalleryState["files"],
normalFiles: GalleryState["normalFiles"],
trashedFiles: GalleryState["trashedFiles"],
hiddenFileIDs: GalleryState["hiddenFileIDs"],
archivedCollectionIDs: GalleryState["archivedCollectionIDs"],
@@ -1753,11 +1762,11 @@ const deriveAlbumsFilteredFiles = (
if (activeCollectionSummaryID === TRASH_SECTION) {
return uniqueFilesByID([
...trashedFiles,
...files.filter((file) => tempDeletedFileIDs.has(file.id)),
...normalFiles.filter((file) => tempDeletedFileIDs.has(file.id)),
]);
}
const filteredFiles = files.filter((file) => {
const filteredFiles = normalFiles.filter((file) => {
if (tempDeletedFileIDs.has(file.id)) return false;
if (hiddenFileIDs.has(file.id)) return false;
if (tempHiddenFileIDs.has(file.id)) return false;
@@ -1851,12 +1860,12 @@ const sortAndUniqueFilteredFiles = (
* the dependencies change.
*/
const derivePeopleFilteredFiles = (
files: GalleryState["files"],
normalFiles: GalleryState["normalFiles"],
view: Extract<GalleryView, { type: "people" }>,
) => {
const pfSet = new Set(view.activePerson?.fileIDs ?? []);
return uniqueFilesByID(
files.filter(({ id }) => {
normalFiles.filter(({ id }) => {
if (!pfSet.has(id)) return false;
return true;
}),

View File

@@ -63,8 +63,13 @@ interface SyncCallectionAndFilesOpts {
/**
* Called when saved collections, both normal and hidden, are (potentially)
* updated.
*
* The callback is passed all the collections (as {@link collections}), and
* also their splits into normal ({@link normalCollections}) and hidden
* ({@link hiddenCollections}).
*/
onSetCollections: (
collections: Collection[],
normalCollections: Collection[],
hiddenCollections: Collection[],
) => void;
@@ -118,7 +123,7 @@ export const syncCollectionAndFiles = async (
collections,
isHiddenCollection,
);
opts?.onSetCollections(normalCollections, hiddenCollections);
opts?.onSetCollections(collections, normalCollections, hiddenCollections);
const didUpdateNormalFiles = await syncFiles(
"normal",
normalCollections,