mirror of
https://github.com/ente-io/ente.git
synced 2025-08-13 17:57:31 +00:00
pseudo focus
This commit is contained in:
@@ -17,10 +17,7 @@ import { isDesktop } from "@/base/app";
|
|||||||
import { SpacedRow } from "@/base/components/containers";
|
import { SpacedRow } from "@/base/components/containers";
|
||||||
import { DialogCloseIconButton } from "@/base/components/mui/DialogCloseIconButton";
|
import { DialogCloseIconButton } from "@/base/components/mui/DialogCloseIconButton";
|
||||||
import { useIsSmallWidth } from "@/base/components/utils/hooks";
|
import { useIsSmallWidth } from "@/base/components/utils/hooks";
|
||||||
import {
|
import { type ModalVisibilityProps } from "@/base/components/utils/modal";
|
||||||
useModalVisibility,
|
|
||||||
type ModalVisibilityProps,
|
|
||||||
} from "@/base/components/utils/modal";
|
|
||||||
import { useBaseContext } from "@/base/context";
|
import { useBaseContext } from "@/base/context";
|
||||||
import { lowercaseExtension } from "@/base/file-name";
|
import { lowercaseExtension } from "@/base/file-name";
|
||||||
import { pt } from "@/base/i18n";
|
import { pt } from "@/base/i18n";
|
||||||
@@ -319,14 +316,11 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
const [moreMenuAnchorEl, setMoreMenuAnchorEl] =
|
const [moreMenuAnchorEl, setMoreMenuAnchorEl] =
|
||||||
useState<HTMLElement | null>(null);
|
useState<HTMLElement | null>(null);
|
||||||
const [openImageEditor, setOpenImageEditor] = useState(false);
|
const [openImageEditor, setOpenImageEditor] = useState(false);
|
||||||
|
const [openConfirmDelete, setOpenConfirmDelete] = useState(false);
|
||||||
|
const [openShortcuts, setOpenShortcuts] = useState(false);
|
||||||
|
|
||||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
const { show: showConfirmDelete, props: confirmDeleteVisibilityProps } =
|
|
||||||
useModalVisibility();
|
|
||||||
|
|
||||||
const { show: showShortcuts, props: shortcutsVisibilityProps } =
|
|
||||||
useModalVisibility();
|
|
||||||
|
|
||||||
// Callbacks to be invoked (only once) the next time we get an update to the
|
// Callbacks to be invoked (only once) the next time we get an update to the
|
||||||
// `files` or `favoriteFileIDs` props.
|
// `files` or `favoriteFileIDs` props.
|
||||||
//
|
//
|
||||||
@@ -359,10 +353,12 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
setOpenFileInfo(false);
|
setOpenFileInfo(false);
|
||||||
setOpenImageEditor(false);
|
|
||||||
// No need to `resetMoreMenuButtonOnMenuClose` since we're closing
|
// No need to `resetMoreMenuButtonOnMenuClose` since we're closing
|
||||||
// anyway and it'll be removed from the DOM.
|
// anyway and it'll be removed from the DOM.
|
||||||
setMoreMenuAnchorEl(null);
|
setMoreMenuAnchorEl(null);
|
||||||
|
setOpenImageEditor(false);
|
||||||
|
setOpenConfirmDelete(false);
|
||||||
|
setOpenShortcuts(false);
|
||||||
onClose();
|
onClose();
|
||||||
}, [onTriggerSyncWithRemote, onClose]);
|
}, [onTriggerSyncWithRemote, onClose]);
|
||||||
|
|
||||||
@@ -424,10 +420,15 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
return onDelete
|
return onDelete
|
||||||
? () => {
|
? () => {
|
||||||
handleMoreMenuCloseIfNeeded();
|
handleMoreMenuCloseIfNeeded();
|
||||||
showConfirmDelete();
|
setOpenConfirmDelete(true);
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
}, [onDelete, showConfirmDelete, handleMoreMenuCloseIfNeeded]);
|
}, [onDelete, handleMoreMenuCloseIfNeeded]);
|
||||||
|
|
||||||
|
const handleConfirmDeleteClose = useCallback(
|
||||||
|
() => setOpenConfirmDelete(false),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
@@ -626,8 +627,27 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
|
|
||||||
const handleShortcuts = useCallback(() => {
|
const handleShortcuts = useCallback(() => {
|
||||||
handleMoreMenuCloseIfNeeded();
|
handleMoreMenuCloseIfNeeded();
|
||||||
showShortcuts();
|
setOpenShortcuts(true);
|
||||||
}, [handleMoreMenuCloseIfNeeded, showShortcuts]);
|
}, [handleMoreMenuCloseIfNeeded]);
|
||||||
|
|
||||||
|
const handleShortcutsClose = useCallback(() => setOpenShortcuts(false), []);
|
||||||
|
|
||||||
|
const shouldIgnoreKeyboardEvent = useCallback(() => {
|
||||||
|
// Don't handle keydowns if any of the modals are open.
|
||||||
|
return (
|
||||||
|
openFileInfo ||
|
||||||
|
moreMenuAnchorEl ||
|
||||||
|
openImageEditor ||
|
||||||
|
openConfirmDelete ||
|
||||||
|
openShortcuts
|
||||||
|
);
|
||||||
|
}, [
|
||||||
|
openFileInfo,
|
||||||
|
moreMenuAnchorEl,
|
||||||
|
openImageEditor,
|
||||||
|
openConfirmDelete,
|
||||||
|
openShortcuts,
|
||||||
|
]);
|
||||||
|
|
||||||
const performKeyAction = useCallback(
|
const performKeyAction = useCallback(
|
||||||
(action): FileViewerPhotoSwipeDelegate["performKeyAction"] => {
|
(action): FileViewerPhotoSwipeDelegate["performKeyAction"] => {
|
||||||
@@ -657,6 +677,7 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
getFiles,
|
getFiles,
|
||||||
isFavorite,
|
isFavorite,
|
||||||
toggleFavorite,
|
toggleFavorite,
|
||||||
|
shouldIgnoreKeyboardEvent,
|
||||||
performKeyAction,
|
performKeyAction,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -667,8 +688,15 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
delegate.getFiles = getFiles;
|
delegate.getFiles = getFiles;
|
||||||
delegate.isFavorite = isFavorite;
|
delegate.isFavorite = isFavorite;
|
||||||
delegate.toggleFavorite = toggleFavorite;
|
delegate.toggleFavorite = toggleFavorite;
|
||||||
|
delegate.shouldIgnoreKeyboardEvent = shouldIgnoreKeyboardEvent;
|
||||||
delegate.performKeyAction = performKeyAction;
|
delegate.performKeyAction = performKeyAction;
|
||||||
}, [getFiles, isFavorite, toggleFavorite, performKeyAction]);
|
}, [
|
||||||
|
getFiles,
|
||||||
|
isFavorite,
|
||||||
|
toggleFavorite,
|
||||||
|
shouldIgnoreKeyboardEvent,
|
||||||
|
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(() => {
|
||||||
@@ -822,7 +850,8 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
</MoreMenu>
|
</MoreMenu>
|
||||||
{/* TODO(PS): Fix imports */}
|
{/* TODO(PS): Fix imports */}
|
||||||
<ConfirmDeleteFileDialog
|
<ConfirmDeleteFileDialog
|
||||||
{...confirmDeleteVisibilityProps}
|
open={openConfirmDelete}
|
||||||
|
onClose={handleConfirmDeleteClose}
|
||||||
onConfirm={handleDelete}
|
onConfirm={handleDelete}
|
||||||
/>
|
/>
|
||||||
<ImageEditorOverlay
|
<ImageEditorOverlay
|
||||||
@@ -831,7 +860,7 @@ const FileViewer: React.FC<FileViewerProps> = ({
|
|||||||
file={activeAnnotatedFile?.file}
|
file={activeAnnotatedFile?.file}
|
||||||
onSaveEditedCopy={handleSaveEditedCopy}
|
onSaveEditedCopy={handleSaveEditedCopy}
|
||||||
/>
|
/>
|
||||||
<Shortcuts {...shortcutsVisibilityProps} />
|
<Shortcuts open={openShortcuts} onClose={handleShortcutsClose} />
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -73,6 +73,14 @@ 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 there is a keydown event, and our PhotoSwipe instance wants
|
||||||
|
* to know if it should ignore it or handle it.
|
||||||
|
*
|
||||||
|
* The delegate should return true when, e.g., the file info dialog is
|
||||||
|
* being displayed.
|
||||||
|
*/
|
||||||
|
shouldIgnoreKeyboardEvent: () => boolean;
|
||||||
/**
|
/**
|
||||||
* Called when the user triggers a potential action using a keyboard
|
* Called when the user triggers a potential action using a keyboard
|
||||||
* shortcut.
|
* shortcut.
|
||||||
@@ -734,22 +742,18 @@ export class FileViewerPhotoSwipe {
|
|||||||
const handleToggleFullscreen = () =>
|
const handleToggleFullscreen = () =>
|
||||||
delegate.performKeyAction("toggle-fullscreen");
|
delegate.performKeyAction("toggle-fullscreen");
|
||||||
|
|
||||||
pswp.on("keydown", (_e) => {
|
pswp.on("keydown", (pswpEvent) => {
|
||||||
const e: KeyboardEvent = _e.originalEvent;
|
// Ignore keyboard events when we do not have "focus".
|
||||||
|
if (delegate.shouldIgnoreKeyboardEvent()) {
|
||||||
|
pswpEvent.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const e: KeyboardEvent = pswpEvent.originalEvent;
|
||||||
|
|
||||||
// Even though we ignore shift, Caps lock might still be on.
|
// Even though we ignore shift, Caps lock might still be on.
|
||||||
const key = e.key.toLowerCase();
|
const key = e.key.toLowerCase();
|
||||||
|
|
||||||
console.log(
|
|
||||||
e,
|
|
||||||
key,
|
|
||||||
e.shiftKey,
|
|
||||||
e.altKey,
|
|
||||||
e.metaKey,
|
|
||||||
e.ctrlKey,
|
|
||||||
e.code,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Keep the keybindings such that they don't use modifiers, because
|
// Keep the keybindings such that they don't use modifiers, because
|
||||||
// these are more likely to interfere with browser shortcuts.
|
// these are more likely to interfere with browser shortcuts.
|
||||||
//
|
//
|
||||||
|
Reference in New Issue
Block a user