Also for fav

This commit is contained in:
Manav Rathi
2025-07-01 08:17:18 +05:30
parent c60aed7f0f
commit cfce0bc198
5 changed files with 115 additions and 74 deletions

View File

@@ -130,7 +130,7 @@ import {
SetFilesDownloadProgressAttributes,
SetFilesDownloadProgressAttributesCreator,
} from "types/gallery";
import { getSelectedFiles, handleFileOp } from "utils/file";
import { getSelectedFiles, performFileOp } from "utils/file";
/**
* The default view for logged in users.
@@ -723,45 +723,59 @@ const Page: React.FC = () => {
[createOnSelectForCollectionOp],
);
const fileOpHelper = (op: FileOp) => async () => {
showLoadingBar();
try {
const selectedFiles = getSelectedFiles(
selected,
op == "hide"
? // passing files here instead of filteredData for hide ops
// because we want to move all files copies to hidden collection
state.collectionFiles.filter(
(f) => !state.hiddenFileIDs.has(f.id),
)
: filteredFiles,
);
const toProcessFiles =
op == "download"
? selectedFiles
: selectedFiles.filter((file) => file.ownerID === user.id);
if (toProcessFiles.length > 0) {
await handleFileOp(
op,
toProcessFiles,
handleMarkTempDeleted,
() => dispatch({ type: "clearTempDeleted" }),
(files) => dispatch({ type: "markTempHidden", files }),
() => dispatch({ type: "clearTempHidden" }),
(files) => {
setFixCreationTimeFiles(files);
showFixCreationTime();
},
setFilesDownloadProgressAttributesCreator,
const createFileOpHandler = (op: FileOp) => () => {
void (async () => {
showLoadingBar();
let notifyOthersFiles = false;
try {
const selectedFiles = getSelectedFiles(
selected,
op == "hide"
? // passing files here instead of filteredData for hide since
// we want to move all files copies to hidden collection
state.collectionFiles.filter(
(f) => !state.hiddenFileIDs.has(f.id),
)
: filteredFiles,
);
const toProcessFiles =
op == "download"
? selectedFiles
: selectedFiles.filter(
(file) => file.ownerID == user.id,
);
if (toProcessFiles.length > 0) {
await performFileOp(
op,
toProcessFiles,
handleMarkTempDeleted,
() => dispatch({ type: "clearTempDeleted" }),
(files) => dispatch({ type: "markTempHidden", files }),
() => dispatch({ type: "clearTempHidden" }),
(files) => {
setFixCreationTimeFiles(files);
showFixCreationTime();
},
setFilesDownloadProgressAttributesCreator,
);
}
// Apart from download, the other operations currently only work
// on the user's own files.
//
// See: [Note: Add and move of non-user files].
notifyOthersFiles =
toProcessFiles.length != selectedFiles.length;
clearSelection();
await remotePull({ silent: true });
} catch (e) {
onGenericError(e);
} finally {
hideLoadingBar();
}
clearSelection();
await remotePull({ silent: true });
} catch (e) {
onGenericError(e);
} finally {
hideLoadingBar();
}
if (notifyOthersFiles) {
showMiniDialog(notifyOthersFilesDialogAttributes());
}
})();
};
const handleSelectSearchOption = (
@@ -980,8 +994,8 @@ const Page: React.FC = () => {
{...{
createOnCreateForCollectionOp,
createOnSelectForCollectionOp,
createFileOpHandler,
}}
handleFileOp={fileOpHelper}
/>
) : barMode == "hidden-albums" ? (
<HiddenSectionNavbarContents

View File

@@ -3,7 +3,7 @@ import { apiURL } from "ente-base/origins";
import { sortFiles } from "ente-gallery/utils/file";
import { EnteFile } from "ente-media/file";
import {
addToFavorites,
addToFavoritesCollection,
removeFromOwnCollection,
savedUserFavoritesCollection,
} from "ente-new/photos/services/collection";
@@ -14,7 +14,7 @@ import HTTPService from "ente-shared/network/HTTPService";
import { getToken } from "ente-shared/storage/localStorage/helpers";
export const addToFavorites1 = async (file: EnteFile) => {
await addToFavorites([file]);
await addToFavoritesCollection([file]);
};
export const removeFromFavorites1 = async (file: EnteFile) => {

View File

@@ -16,7 +16,7 @@ import { FileType } from "ente-media/file-type";
import { decodeLivePhoto } from "ente-media/live-photo";
import { type FileOp } from "ente-new/photos/components/SelectedFileOptions";
import {
addToFavorites,
addToFavoritesCollection,
deleteFromTrash,
hideFiles,
moveToTrash,
@@ -313,7 +313,7 @@ export const shouldShowAvatar = (
}
};
export const handleFileOp = async (
export const performFileOp = async (
op: FileOp,
files: EnteFile[],
markTempDeleted: (files: EnteFile[]) => void,
@@ -339,7 +339,7 @@ export const handleFileOp = async (
fixCreationTime(files);
break;
case "favorite":
await addToFavorites(files);
await addToFavoritesCollection(files);
break;
case "archive":
await updateFilesVisibility(files, ItemVisibility.archived);

View File

@@ -24,8 +24,9 @@ import {
} from "ente-new/photos/services/collection-summary";
import { t } from "i18next";
export type CollectionOp = "add" | "move" | "restore" | "unhide";
/**
* Operations on selected files.
*/
export type FileOp =
| "download"
| "fixTime"
@@ -36,6 +37,11 @@ export type FileOp =
| "trash"
| "deletePermanently";
/**
* Operations on selected files that also have an associated collection.
*/
export type CollectionOp = "add" | "move" | "restore" | "unhide";
interface SelectedFileOptionsProps {
barMode?: GalleryBarMode;
isInSearchMode: boolean;
@@ -90,8 +96,8 @@ interface SelectedFileOptionsProps {
* Once the user enters the name and a new album with that name gets
* created, the newly created collection will be passed to G.
*
* @param op The operation that should be performed using the newly created
* collection.
* @param op The operation that should be performed on the selected files
* using the newly created collection.
*
* @returns A function that can be called with to create a new collection
* and then perform {@link op} on successful creation of the new collection.
@@ -108,16 +114,25 @@ interface SelectedFileOptionsProps {
* Once the user selects a collection, then the selected collection will be
* passed to G.
*
* @param op The operation that should be performed using the selected
* collection.
* @param op The operation that should be performed on the selected files,
* using the selected collection.
*
* @returns A function that can be called with a selected collection.
*/
createOnSelectForCollectionOp: (
op: CollectionOp,
) => (selectedCollection: Collection) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleFileOp: (op: FileOp) => (...args: any[]) => void;
/**
* A function called to obtain a handler for the provided {@link op}.
*
* This function will be passed the file operation to be performed. It will
* return a new function G that can be used as a {@link onClick} handler for
* the button. Calling G will trigger the operation on the selected files.
*
* @param op The operation that should be performed on the selected files.
* @returns
*/
createFileOpHandler: (op: FileOp) => () => void;
}
/**
@@ -136,13 +151,23 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
onOpenCollectionSelector,
createOnCreateForCollectionOp,
createOnSelectForCollectionOp,
handleFileOp,
createFileOpHandler,
}) => {
const { showMiniDialog } = useBaseContext();
const isUserFavorites =
!!collectionSummary?.attributes.has("userFavorites");
const handleFavorite = createFileOpHandler("favorite");
const handleFixTime = createFileOpHandler("fixTime");
const handleDownload = createFileOpHandler("download");
const handleArchive = createFileOpHandler("archive");
const handleUnarchive = createFileOpHandler("unarchive");
const handleDelete = () =>
showMiniDialog({
title: t("trash_files_title"),
@@ -150,7 +175,7 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
continue: {
text: t("move_to_trash"),
color: "critical",
action: handleFileOp("trash"),
action: createFileOpHandler("trash"),
},
});
@@ -168,7 +193,7 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
continue: {
text: t("delete"),
color: "critical",
action: handleFileOp("deletePermanently"),
action: createFileOpHandler("deletePermanently"),
},
});
@@ -210,6 +235,8 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
});
};
const handleHide = createFileOpHandler("hide");
const handleUnhide = () => {
onOpenCollectionSelector({
action: "unhide",
@@ -234,19 +261,21 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
{isInSearchMode ? (
<>
<FixTimeButton onClick={handleFileOp("fixTime")} />
<DownloadButton onClick={handleFileOp("download")} />
<FavoriteButton onClick={handleFavorite} />
<FixTimeButton onClick={handleFixTime} />
<DownloadButton onClick={handleDownload} />
<AddToCollectionButton onClick={handleAddToCollection} />
<ArchiveButton onClick={handleFileOp("archive")} />
<HideButton onClick={handleFileOp("hide")} />
<ArchiveButton onClick={handleArchive} />
<HideButton onClick={handleHide} />
<DeleteButton onClick={handleDelete} />
</>
) : barMode == "people" ? (
<>
<DownloadButton onClick={handleFileOp("download")} />
<FavoriteButton onClick={handleFavorite} />
<DownloadButton onClick={handleDownload} />
<AddToCollectionButton onClick={handleAddToCollection} />
<ArchiveButton onClick={handleFileOp("archive")} />
<HideButton onClick={handleFileOp("hide")} />
<ArchiveButton onClick={handleArchive} />
<HideButton onClick={handleHide} />
<DeleteButton onClick={handleDelete} />
</>
) : collectionSummary?.id == PseudoCollectionID.trash ? (
@@ -258,20 +287,20 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
</>
) : collectionSummary?.attributes.has("uncategorized") ? (
<>
<DownloadButton onClick={handleFileOp("download")} />
<DownloadButton onClick={handleDownload} />
<MoveToCollectionButton onClick={handleMoveToCollection} />
<DeleteButton onClick={handleDelete} />
</>
) : collectionSummary?.attributes.has("sharedIncoming") ? (
<>
<DownloadButton onClick={handleFileOp("download")} />
<DownloadButton onClick={handleDownload} />
<RemoveFromCollectionButton
onClick={handleRemoveFromCollection}
/>
</>
) : barMode == "hidden-albums" ? (
<>
<DownloadButton onClick={handleFileOp("download")} />
<DownloadButton onClick={handleDownload} />
<UnhideButton onClick={handleUnhide} />
<DeleteButton onClick={handleDelete} />
</>
@@ -280,18 +309,16 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
{!isUserFavorites &&
collectionSummary?.id !=
PseudoCollectionID.archiveItems && (
<FavoriteButton
onClick={handleFileOp("favorite")}
/>
<FavoriteButton onClick={handleFavorite} />
)}
<FixTimeButton onClick={handleFileOp("fixTime")} />
<DownloadButton onClick={handleFileOp("download")} />
<FixTimeButton onClick={handleFixTime} />
<DownloadButton onClick={handleDownload} />
<AddToCollectionButton onClick={handleAddToCollection} />
{collectionSummary?.id === PseudoCollectionID.all ? (
<ArchiveButton onClick={handleFileOp("archive")} />
<ArchiveButton onClick={handleArchive} />
) : collectionSummary?.id ==
PseudoCollectionID.archiveItems ? (
<UnarchiveButton onClick={handleFileOp("unarchive")} />
<UnarchiveButton onClick={handleUnarchive} />
) : (
!isUserFavorites && (
<>
@@ -304,7 +331,7 @@ export const SelectedFileOptions: React.FC<SelectedFileOptionsProps> = ({
</>
)
)}
<HideButton onClick={handleFileOp("hide")} />
<HideButton onClick={handleHide} />
<DeleteButton onClick={handleDelete} />
</>
)}

View File

@@ -1176,7 +1176,7 @@ export const savedUserFavoritesCollection = async () => {
*
* Reads local state but does not modify it. The effects are on remote.
*/
export const addToFavorites = async (files: EnteFile[]) =>
export const addToFavoritesCollection = async (files: EnteFile[]) =>
addToCollection(await savedOrCreateUserFavoritesCollection(), files);
/**