Fix desktop long press action

After the long press action, the set onClick action was triggered as well.
This caused issues like opening the manga page in the source browse page when adding the manga via a long press to the library
This commit is contained in:
schroda
2026-06-06 19:06:44 +02:00
parent 8d95e7c864
commit 024e814254
8 changed files with 505 additions and 478 deletions

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useCallback, useRef } from 'react';
import type {
LongPressCallbackMeta,
LongPressMouseHandlers,
LongPressPointerHandlers,
LongPressReactEvents,
LongPressResult,
LongPressTouchHandlers,
} from 'use-long-press';
// oxlint-disable-next-line no-restricted-imports
import { useLongPress } from 'use-long-press';
export type UsePressResult = LongPressResult<
(LongPressPointerHandlers | LongPressMouseHandlers | LongPressTouchHandlers) & {
onClick: (event: React.MouseEvent | React.TouchEvent) => void;
}
>;
export const usePress = (
options: Omit<Parameters<typeof useLongPress>[1], 'onCancel' | 'onStart'> & {
onLongPress: NonNullable<Parameters<typeof useLongPress>[0]>;
onPress: (event: React.MouseEvent | React.TouchEvent) => void;
},
): UsePressResult => {
const { onLongPress, onPress, ...actualOptions } = options;
const hasLongPressRef = useRef(false);
const onCancel = useCallback(() => {
if (hasLongPressRef.current) {
hasLongPressRef.current = false;
}
}, []);
const bind = useLongPress(
useCallback(
(event: LongPressReactEvents<Element>, meta: LongPressCallbackMeta<unknown>) => {
hasLongPressRef.current = true;
onLongPress(event, meta);
},
[onLongPress],
),
{
...actualOptions,
onCancel,
onStart: onCancel,
},
);
return useCallback(
(context?: unknown) => ({
...bind(context),
onClick: (event: React.MouseEvent | React.TouchEvent) => {
if (!hasLongPressRef.current) {
onPress(event);
} else {
event.preventDefault();
}
},
}),
[bind, onPress],
);
};

View File

@@ -18,7 +18,6 @@ import type { MouseEvent, TouchEvent } from 'react';
import React, { memo, useRef } from 'react';
import { Link } from 'react-router-dom';
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
import { useLongPress } from 'use-long-press';
import { useLingui } from '@lingui/react/macro';
import { CustomTooltip } from '@/base/components/CustomTooltip.tsx';
import { getDateString } from '@/base/utils/DateHelper.ts';
@@ -43,6 +42,7 @@ import type {
} from '@/features/chapter/Chapter.types.ts';
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
import type { ChapterType } from '@/lib/graphql/generated/graphql-base.types.ts';
import { usePress } from '@/base/hooks/usePress.ts';
type TChapter = ChapterIdInfo &
ChapterMangaInfo &
@@ -104,15 +104,18 @@ export const ChapterCard = memo((props: IProps) => {
onSelect(chapter.id, !selected, event.shiftKey);
};
const longPressBind = useLongPress((event, { context: openMenu }) => {
if (!isSelecting && !!menuButtonRef.current) {
handleClickOpenMenu(event, () => (openMenu as (event: Element) => void)?.(menuButtonRef.current!));
return;
}
const longPressBind = usePress({
onLongPress: (event, { context: openMenu }) => {
if (!isSelecting && !!menuButtonRef.current) {
handleClickOpenMenu(event, () => (openMenu as (event: Element) => void)?.(menuButtonRef.current!));
return;
}
// oxlint-disable-next-line no-param-reassign
event.shiftKey = true;
handleClick(event);
// oxlint-disable-next-line no-param-reassign
event.shiftKey = true;
handleClick(event);
},
onPress: handleClick,
});
return (
@@ -136,7 +139,6 @@ export const ChapterCard = memo((props: IProps) => {
}}
state={Chapters.getReaderOpenChapterLocationState(chapter, true)}
replace={mode === 'reader'}
onClick={(e) => handleClick(e)}
{...longPressBind(popupState.open)}
>
<ListCardContent>

View File

@@ -6,7 +6,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import type { LongPressPointerHandlers, LongPressResult } from 'use-long-press';
import type { PopupState } from 'material-ui-popup-state/hooks';
import type { JSX } from 'react';
import type { SelectableCollectionReturnType } from '@/base/collection/hooks/useSelectableCollection.ts';
@@ -29,6 +28,7 @@ import type {
SourceType,
TrackRecordType,
} from '@/lib/graphql/generated/graphql-base.types.ts';
import type { UsePressResult } from '@/base/hooks/usePress.ts';
export type MangaCardMode = 'default' | 'source' | 'migrate.select.bulk' | 'migrate.select.single' | 'duplicate';
@@ -75,9 +75,8 @@ export interface MangaCardProps {
export type SpecificMangaCardProps = Omit<MangaCardProps, 'manga'> &
Pick<ReturnType<typeof useManageMangaLibraryState>, 'isInLibrary'> & {
manga: MangaCardSpecificProps;
longPressBind: LongPressResult<LongPressPointerHandlers>;
longPressBind: UsePressResult;
popupState: PopupState;
handleClick: (event: React.MouseEvent | React.TouchEvent) => void;
mangaLinkTo: string;
continueReadingButton: JSX.Element;
mangaBadges: JSX.Element;

View File

@@ -8,7 +8,6 @@
import PopupState, { bindMenu } from 'material-ui-popup-state';
import { memo, useCallback, useMemo } from 'react';
import { useLongPress } from 'use-long-press';
import type { SingleModeProps } from '@/features/manga/components/MangaActionMenuItems.tsx';
import { MangaActionMenuItems } from '@/features/manga/components/MangaActionMenuItems.tsx';
import { Menu } from '@/base/components/menu/Menu.tsx';
@@ -32,6 +31,7 @@ import { MangaMigration } from '@/features/migration/MangaMigration.ts';
import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { assertIsDefined } from '@/base/Asserts.ts';
import { usePress } from '@/base/hooks/usePress.ts';
const getMangaLinkTo = (mode: MangaCardMode, mangaId: number): string => {
switch (mode) {
@@ -149,8 +149,8 @@ export const MangaCard = memo((props: MangaCardProps) => {
[mode, selected, updateLibraryState, handleSelection, migrationSourceMangaId],
);
const longPressBind = useLongPress(
useCallback(
const longPressBind = usePress({
onLongPress: useCallback(
(e: any, { context }: any) => {
// oxlint-disable-next-line no-param-reassign
e.shiftKey = true;
@@ -158,7 +158,8 @@ export const MangaCard = memo((props: MangaCardProps) => {
},
[handleClick],
),
);
onPress: handleClick,
});
const MangaCardComponent = useMemo(
() => (gridLayout === GridLayout.List ? MangaListCard : MangaGridCard),
@@ -173,7 +174,6 @@ export const MangaCard = memo((props: MangaCardProps) => {
{...props}
longPressBind={longPressBind}
popupState={popupState}
handleClick={handleClick}
mangaLinkTo={mangaLinkTo}
isInLibrary={isInLibrary}
inLibraryIndicator={inLibraryIndicator}

View File

@@ -45,7 +45,6 @@ export const MangaGridCard = memo(
manga,
longPressBind,
popupState,
handleClick,
mangaLinkTo,
selected,
inLibraryIndicator,
@@ -65,7 +64,6 @@ export const MangaGridCard = memo(
<Link
component={RouterLink}
{...longPressBind(() => popupState.open(optionButtonRef.current))}
onClick={handleClick}
to={mangaLinkTo}
state={Mangas.createLocationState(manga, mode)}
onContextMenu={preventMobileContextMenu}

View File

@@ -26,7 +26,6 @@ export const MangaListCard = memo(
manga,
longPressBind,
popupState,
handleClick,
mangaLinkTo,
selected,
inLibraryIndicator,
@@ -48,7 +47,6 @@ export const MangaListCard = memo(
component={RouterLink}
to={mangaLinkTo}
state={Mangas.createLocationState(manga, mode)}
onClick={handleClick}
{...longPressBind(() => popupState.open(optionButtonRef.current))}
onContextMenu={preventMobileContextMenu}
sx={{