Prevent native mobile context menu
This commit is contained in:
@@ -39,6 +39,7 @@ import {
|
|||||||
ChapterReadInfo,
|
ChapterReadInfo,
|
||||||
ChapterScanlatorInfo,
|
ChapterScanlatorInfo,
|
||||||
} from '@/modules/chapter/Chapter.types.ts';
|
} from '@/modules/chapter/Chapter.types.ts';
|
||||||
|
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||||
|
|
||||||
type TChapter = ChapterIdInfo &
|
type TChapter = ChapterIdInfo &
|
||||||
ChapterMangaInfo &
|
ChapterMangaInfo &
|
||||||
@@ -62,6 +63,7 @@ interface IProps {
|
|||||||
export const ChapterCard = memo((props: IProps) => {
|
export const ChapterCard = memo((props: IProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const preventMobileContextMenu = MediaQuery.usePreventMobileContextMenu();
|
||||||
|
|
||||||
const menuButtonRef = useRef<HTMLButtonElement>(null);
|
const menuButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
@@ -120,9 +122,10 @@ export const ChapterCard = memo((props: IProps) => {
|
|||||||
<CardActionArea
|
<CardActionArea
|
||||||
component={Link}
|
component={Link}
|
||||||
to={Chapters.getReaderUrl(chapter)}
|
to={Chapters.getReaderUrl(chapter)}
|
||||||
|
onContextMenu={preventMobileContextMenu}
|
||||||
|
sx={MediaQuery.preventMobileContextMenuSx()}
|
||||||
style={{
|
style={{
|
||||||
color: theme.palette.text[chapter.isRead ? 'disabled' : 'primary'],
|
color: theme.palette.text[chapter.isRead ? 'disabled' : 'primary'],
|
||||||
userSelect: 'none',
|
|
||||||
}}
|
}}
|
||||||
state={Chapters.getReaderOpenChapterLocationState(chapter, true)}
|
state={Chapters.getReaderOpenChapterLocationState(chapter, true)}
|
||||||
replace={mode === 'reader'}
|
replace={mode === 'reader'}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
import { Breakpoint } from '@mui/material/styles';
|
import { Breakpoint, SxProps, Theme } from '@mui/material/styles';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { getCurrentTheme } from '@/modules/theme/services/ThemeCreator.ts';
|
import { getCurrentTheme } from '@/modules/theme/services/ThemeCreator.ts';
|
||||||
import { ThemeMode } from '@/modules/theme/contexts/AppThemeContext.tsx';
|
import { ThemeMode } from '@/modules/theme/contexts/AppThemeContext.tsx';
|
||||||
@@ -112,4 +112,24 @@ export class MediaQuery {
|
|||||||
|
|
||||||
return () => matchSystemThemeMode.removeEventListener('change', handleSystemThemeModeChange);
|
return () => matchSystemThemeMode.removeEventListener('change', handleSystemThemeModeChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static usePreventMobileContextMenu() {
|
||||||
|
const isTouchDevice = MediaQuery.useIsTouchDevice();
|
||||||
|
|
||||||
|
return useCallback(
|
||||||
|
(e: React.MouseEvent<any, MouseEvent>) => {
|
||||||
|
if (isTouchDevice) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isTouchDevice],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static preventMobileContextMenuSx(): SxProps<Theme> {
|
||||||
|
return {
|
||||||
|
userSelect: 'none',
|
||||||
|
'-webkit-touch-callout': 'none',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { SpecificMangaCardProps } from '@/modules/manga/Manga.types.ts';
|
|||||||
import { TypographyMaxLines } from '@/modules/core/components/texts/TypographyMaxLines.tsx';
|
import { TypographyMaxLines } from '@/modules/core/components/texts/TypographyMaxLines.tsx';
|
||||||
import { MANGA_COVER_ASPECT_RATIO } from '@/modules/manga/Manga.constants.ts';
|
import { MANGA_COVER_ASPECT_RATIO } from '@/modules/manga/Manga.constants.ts';
|
||||||
import { GridLayout } from '@/modules/core/Core.types.ts';
|
import { GridLayout } from '@/modules/core/Core.types.ts';
|
||||||
|
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||||
|
|
||||||
const BottomGradient = styled('div')({
|
const BottomGradient = styled('div')({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -55,6 +56,7 @@ export const MangaGridCard = memo(
|
|||||||
mangaBadges,
|
mangaBadges,
|
||||||
mode,
|
mode,
|
||||||
}: SpecificMangaCardProps) => {
|
}: SpecificMangaCardProps) => {
|
||||||
|
const preventMobileContextMenu = MediaQuery.usePreventMobileContextMenu();
|
||||||
const optionButtonRef = useRef<HTMLButtonElement>(null);
|
const optionButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
const { id, title } = manga;
|
const { id, title } = manga;
|
||||||
@@ -66,7 +68,11 @@ export const MangaGridCard = memo(
|
|||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
to={mangaLinkTo}
|
to={mangaLinkTo}
|
||||||
state={Mangas.createLocationState(manga, mode)}
|
state={Mangas.createLocationState(manga, mode)}
|
||||||
sx={{ textDecoration: 'none', userSelect: 'none' }}
|
onContextMenu={preventMobileContextMenu}
|
||||||
|
sx={{
|
||||||
|
...MediaQuery.preventMobileContextMenuSx(),
|
||||||
|
textDecoration: 'none',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { Mangas } from '@/modules/manga/services/Mangas.ts';
|
|||||||
import { MangaOptionButton } from '@/modules/manga/components/MangaOptionButton.tsx';
|
import { MangaOptionButton } from '@/modules/manga/components/MangaOptionButton.tsx';
|
||||||
import { ListCardAvatar } from '@/modules/core/components/lists/cards/ListCardAvatar.tsx';
|
import { ListCardAvatar } from '@/modules/core/components/lists/cards/ListCardAvatar.tsx';
|
||||||
import { ListCardContent } from '@/modules/core/components/lists/cards/ListCardContent';
|
import { ListCardContent } from '@/modules/core/components/lists/cards/ListCardContent';
|
||||||
|
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||||
|
|
||||||
export const MangaListCard = memo(
|
export const MangaListCard = memo(
|
||||||
({
|
({
|
||||||
@@ -35,6 +36,8 @@ export const MangaListCard = memo(
|
|||||||
mangaBadges,
|
mangaBadges,
|
||||||
mode,
|
mode,
|
||||||
}: SpecificMangaCardProps) => {
|
}: SpecificMangaCardProps) => {
|
||||||
|
const preventMobileContextMenu = MediaQuery.usePreventMobileContextMenu();
|
||||||
|
|
||||||
const optionButtonRef = useRef<HTMLButtonElement>(null);
|
const optionButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
const { id, title } = manga;
|
const { id, title } = manga;
|
||||||
@@ -47,8 +50,9 @@ export const MangaListCard = memo(
|
|||||||
state={Mangas.createLocationState(manga, mode)}
|
state={Mangas.createLocationState(manga, mode)}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
{...longPressBind(() => popupState.open(optionButtonRef.current))}
|
{...longPressBind(() => popupState.open(optionButtonRef.current))}
|
||||||
|
onContextMenu={preventMobileContextMenu}
|
||||||
sx={{
|
sx={{
|
||||||
userSelect: 'none',
|
...MediaQuery.preventMobileContextMenuSx(),
|
||||||
'@media (hover: hover) and (pointer: fine)': {
|
'@media (hover: hover) and (pointer: fine)': {
|
||||||
'&:hover .manga-option-button': {
|
'&:hover .manga-option-button': {
|
||||||
visibility: 'visible',
|
visibility: 'visible',
|
||||||
|
|||||||
Reference in New Issue
Block a user