mirror of
https://github.com/ente-io/ente.git
synced 2025-08-13 17:57:31 +00:00
delegate
This commit is contained in:
@@ -396,7 +396,7 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
//
|
//
|
||||||
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
||||||
const handleDownloadMenuAction = () => {
|
const handleDownloadMenuAction = () => {
|
||||||
handleMoreMenuClose();
|
handleMoreMenuCloseIfNeeded();
|
||||||
onDownload!(activeAnnotatedFile!.file);
|
onDownload!(activeAnnotatedFile!.file);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -413,9 +413,9 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMoreMenuClose = useCallback(() => {
|
const handleMoreMenuCloseIfNeeded = useCallback(() => {
|
||||||
setMoreMenuAnchorEl((el) => {
|
setMoreMenuAnchorEl((el) => {
|
||||||
resetMoreMenuButtonOnMenuClose(el);
|
if (el) resetMoreMenuButtonOnMenuClose(el);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -423,11 +423,11 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
const handleConfirmDelete = useMemo(() => {
|
const handleConfirmDelete = useMemo(() => {
|
||||||
return onDelete
|
return onDelete
|
||||||
? () => {
|
? () => {
|
||||||
handleMoreMenuClose();
|
handleMoreMenuCloseIfNeeded();
|
||||||
showConfirmDelete();
|
showConfirmDelete();
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
}, [onDelete, showConfirmDelete, handleMoreMenuClose]);
|
}, [onDelete, showConfirmDelete, handleMoreMenuCloseIfNeeded]);
|
||||||
|
|
||||||
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
@@ -455,8 +455,8 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
||||||
const handleCopyImage = () => {
|
const handleCopyImage = useCallback(() => {
|
||||||
handleMoreMenuClose();
|
handleMoreMenuCloseIfNeeded();
|
||||||
// Safari does not copy if we do not call `navigator.clipboard.write`
|
// Safari does not copy if we do not call `navigator.clipboard.write`
|
||||||
// synchronously within the click event handler, but it does supports
|
// synchronously within the click event handler, but it does supports
|
||||||
// passing a promise in lieu of the blob.
|
// passing a promise in lieu of the blob.
|
||||||
@@ -467,16 +467,16 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
.catch(onGenericError);
|
.catch(onGenericError);
|
||||||
};
|
}, [onGenericError, handleMoreMenuCloseIfNeeded, activeImageURL]);
|
||||||
|
|
||||||
const handleEditImage = useMemo(() => {
|
const handleEditImage = useMemo(() => {
|
||||||
return onSaveEditedImageCopy
|
return onSaveEditedImageCopy
|
||||||
? () => {
|
? () => {
|
||||||
handleMoreMenuClose();
|
handleMoreMenuCloseIfNeeded();
|
||||||
setOpenImageEditor(true);
|
setOpenImageEditor(true);
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
}, [onSaveEditedImageCopy, handleMoreMenuClose]);
|
}, [onSaveEditedImageCopy, handleMoreMenuCloseIfNeeded]);
|
||||||
|
|
||||||
const handleImageEditorClose = useCallback(
|
const handleImageEditorClose = useCallback(
|
||||||
() => setOpenImageEditor(false),
|
() => setOpenImageEditor(false),
|
||||||
@@ -616,22 +616,49 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleToggleFullscreen = useCallback(() => {
|
const handleToggleFullscreen = useCallback(() => {
|
||||||
handleMoreMenuClose();
|
handleMoreMenuCloseIfNeeded();
|
||||||
void (
|
void (
|
||||||
document.fullscreenElement
|
document.fullscreenElement
|
||||||
? document.exitFullscreen()
|
? document.exitFullscreen()
|
||||||
: document.body.requestFullscreen()
|
: document.body.requestFullscreen()
|
||||||
).then(updateFullscreenStatus);
|
).then(updateFullscreenStatus);
|
||||||
}, [handleMoreMenuClose, updateFullscreenStatus]);
|
}, [handleMoreMenuCloseIfNeeded, updateFullscreenStatus]);
|
||||||
|
|
||||||
const handleShortcuts = useCallback(() => {
|
const handleShortcuts = useCallback(() => {
|
||||||
handleMoreMenuClose();
|
handleMoreMenuCloseIfNeeded();
|
||||||
showShortcuts();
|
showShortcuts();
|
||||||
}, [handleMoreMenuClose, showShortcuts]);
|
}, [handleMoreMenuCloseIfNeeded, showShortcuts]);
|
||||||
|
|
||||||
|
const performKeyAction = useCallback(
|
||||||
|
(action): FileViewerPhotoSwipeDelegate["performKeyAction"] => {
|
||||||
|
switch (action) {
|
||||||
|
case "delete":
|
||||||
|
handleConfirmDelete?.();
|
||||||
|
break;
|
||||||
|
case "copy":
|
||||||
|
if (activeImageURL) handleCopyImage();
|
||||||
|
break;
|
||||||
|
case "toggle-fullscreen":
|
||||||
|
handleToggleFullscreen();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
handleConfirmDelete,
|
||||||
|
activeImageURL,
|
||||||
|
handleCopyImage,
|
||||||
|
handleToggleFullscreen,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
// Initial value of delegate.
|
// Initial value of delegate.
|
||||||
if (!delegateRef.current) {
|
if (!delegateRef.current) {
|
||||||
delegateRef.current = { getFiles, isFavorite, toggleFavorite };
|
delegateRef.current = {
|
||||||
|
getFiles,
|
||||||
|
isFavorite,
|
||||||
|
toggleFavorite,
|
||||||
|
performKeyAction,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates to delegate callbacks.
|
// Updates to delegate callbacks.
|
||||||
@@ -640,7 +667,8 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
delegate.getFiles = getFiles;
|
delegate.getFiles = getFiles;
|
||||||
delegate.isFavorite = isFavorite;
|
delegate.isFavorite = isFavorite;
|
||||||
delegate.toggleFavorite = toggleFavorite;
|
delegate.toggleFavorite = toggleFavorite;
|
||||||
}, [getFiles, isFavorite, toggleFavorite]);
|
delegate.performKeyAction = performKeyAction;
|
||||||
|
}, [getFiles, isFavorite, toggleFavorite, performKeyAction]);
|
||||||
|
|
||||||
// Notify the listeners, if any, for updates to files or favorites.
|
// Notify the listeners, if any, for updates to files or favorites.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -717,7 +745,7 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
/>
|
/>
|
||||||
<MoreMenu
|
<MoreMenu
|
||||||
open={!!moreMenuAnchorEl}
|
open={!!moreMenuAnchorEl}
|
||||||
onClose={handleMoreMenuClose}
|
onClose={handleMoreMenuCloseIfNeeded}
|
||||||
anchorEl={moreMenuAnchorEl}
|
anchorEl={moreMenuAnchorEl}
|
||||||
id={moreMenuID}
|
id={moreMenuID}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
|
@@ -73,6 +73,15 @@ export interface FileViewerPhotoSwipeDelegate {
|
|||||||
* > remain in the disabled state (until the file viewer is closed).
|
* > remain in the disabled state (until the file viewer is closed).
|
||||||
*/
|
*/
|
||||||
toggleFavorite: (annotatedFile: FileViewerAnnotatedFile) => Promise<void>;
|
toggleFavorite: (annotatedFile: FileViewerAnnotatedFile) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Called when the user triggers a potential action using a keyboard
|
||||||
|
* shortcut.
|
||||||
|
*
|
||||||
|
* The caller does not check if the action is valid in the current context,
|
||||||
|
* so the delegate must validate and only then perform the action if it is
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
|
performKeyAction: (action: "delete" | "copy" | "toggle-fullscreen") => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileViewerPhotoSwipeOptions = Pick<
|
type FileViewerPhotoSwipeOptions = Pick<
|
||||||
@@ -507,8 +516,16 @@ export class FileViewerPhotoSwipe {
|
|||||||
|
|
||||||
const handleToggleFavorite = () => void toggleFavorite();
|
const handleToggleFavorite = () => void toggleFavorite();
|
||||||
|
|
||||||
|
const handleToggleFavoriteIfEnabled = () => {
|
||||||
|
if (haveUser) handleToggleFavorite();
|
||||||
|
};
|
||||||
|
|
||||||
const handleDownload = () => onDownload(currentAnnotatedFile());
|
const handleDownload = () => onDownload(currentAnnotatedFile());
|
||||||
|
|
||||||
|
const handleDownloadIfEnabled = () => {
|
||||||
|
if (!!currentFileAnnotation().showDownload) handleDownload();
|
||||||
|
};
|
||||||
|
|
||||||
const showIf = (element: HTMLElement, condition: boolean) =>
|
const showIf = (element: HTMLElement, condition: boolean) =>
|
||||||
condition
|
condition
|
||||||
? element.classList.remove("pswp__hidden")
|
? element.classList.remove("pswp__hidden")
|
||||||
@@ -684,16 +701,27 @@ export class FileViewerPhotoSwipe {
|
|||||||
return element;
|
return element;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Some actions routed via the delegate
|
||||||
|
|
||||||
|
const handleDelete = () => delegate.performKeyAction("delete");
|
||||||
|
|
||||||
|
const handleCopy = () => delegate.performKeyAction("copy");
|
||||||
|
|
||||||
|
const handleToggleFullscreen = () =>
|
||||||
|
delegate.performKeyAction("toggle-fullscreen");
|
||||||
|
|
||||||
pswp.on("keydown", (e, z) => {
|
pswp.on("keydown", (e, z) => {
|
||||||
const key = e.originalEvent.key ?? "";
|
const key = e.originalEvent.key ?? "";
|
||||||
const cb = (() => {
|
const cb = (() => {
|
||||||
switch (key.toLowerCase()) {
|
switch (key.toLowerCase()) {
|
||||||
case "l":
|
case "l":
|
||||||
return handleToggleFavorite;
|
return handleToggleFavoriteIfEnabled;
|
||||||
case "d":
|
case "d":
|
||||||
return handleDownload;
|
return handleDownloadIfEnabled;
|
||||||
case "i":
|
case "i":
|
||||||
return handleViewInfo;
|
return handleViewInfo;
|
||||||
|
case "f":
|
||||||
|
return handleToggleFullscreen;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
})();
|
})();
|
||||||
|
Reference in New Issue
Block a user