Message: Various fixes for context menu on mobile (#1311)

This commit is contained in:
Alexander Zinchuk 2021-07-23 17:01:45 +03:00
parent 3e5564717c
commit cf96a04364
5 changed files with 46 additions and 15 deletions

View File

@ -12,10 +12,13 @@
} }
@media (pointer: coarse) { @media (pointer: coarse) {
-webkit-user-select: none;
-webkit-touch-callout: none;
user-select: none; user-select: none;
touch-callout: none; touch-callout: none;
&.select-mode-active {
user-select: auto;
touch-callout: default;
}
} }
&.no-avatars .Message > .Avatar { &.no-avatars .Message > .Avatar {

View File

@ -56,6 +56,17 @@
border: 1px var(--select-background-color) solid; border: 1px var(--select-background-color) solid;
background-color: var(--select-background-color); background-color: var(--select-background-color);
} }
body.is-android & {
.can-select-text {
z-index: var(--z-message-select-control);
}
// Prevent media viewer from opening
.media-inner {
pointer-events: none;
}
}
} }
&.has-inline-buttons { &.has-inline-buttons {
@ -126,7 +137,10 @@
.select-mode-active & { .select-mode-active & {
cursor: pointer; cursor: pointer;
user-select: none;
@media (min-width: 600px) {
user-select: none;
}
&:not(.own) { &:not(.own) {
> .Avatar, > .Avatar,

View File

@ -22,7 +22,7 @@ import {
FocusDirection, IAlbum, ISettings, MediaViewerOrigin, FocusDirection, IAlbum, ISettings, MediaViewerOrigin,
} from '../../../types'; } from '../../../types';
import { IS_ANDROID } from '../../../util/environment'; import { IS_ANDROID, IS_TOUCH_ENV } from '../../../util/environment';
import { pick } from '../../../util/iteratees'; import { pick } from '../../../util/iteratees';
import { import {
selectChat, selectChat,
@ -59,6 +59,7 @@ import {
getUserColorKey, getUserColorKey,
} from '../../../modules/helpers'; } from '../../../modules/helpers';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import windowSize from '../../../util/windowSize';
import useEnsureMessage from '../../../hooks/useEnsureMessage'; import useEnsureMessage from '../../../hooks/useEnsureMessage';
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers'; import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
import { renderMessageText } from '../../common/helpers/renderMessageText'; import { renderMessageText } from '../../common/helpers/renderMessageText';
@ -168,7 +169,7 @@ const APPENDIX_OWN = '<svg width="9" height="20" xmlns="http://www.w3.org/2000/s
const APPENDIX_NOT_OWN = '<svg width="9" height="20" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-50%" y="-14.7%" width="200%" height="141.2%" filterUnits="objectBoundingBox" id="a"><feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0" in="shadowBlurOuter1"/></filter></defs><g fill="none" fill-rule="evenodd"><path d="M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z" fill="#000" filter="url(#a)"/><path d="M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z" fill="#FFF" class="corner"/></g></svg>'; const APPENDIX_NOT_OWN = '<svg width="9" height="20" xmlns="http://www.w3.org/2000/svg"><defs><filter x="-50%" y="-14.7%" width="200%" height="141.2%" filterUnits="objectBoundingBox" id="a"><feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0" in="shadowBlurOuter1"/></filter></defs><g fill="none" fill-rule="evenodd"><path d="M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z" fill="#000" filter="url(#a)"/><path d="M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z" fill="#FFF" class="corner"/></g></svg>';
const APPEARANCE_DELAY = 10; const APPEARANCE_DELAY = 10;
const NO_MEDIA_CORNERS_THRESHOLD = 18; const NO_MEDIA_CORNERS_THRESHOLD = 18;
const ANDROID_KEYBOARD_HIDE_DELAY_MS = 150; const ANDROID_KEYBOARD_HIDE_DELAY_MS = 350;
const Message: FC<OwnProps & StateProps & DispatchProps> = ({ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
message, message,
@ -243,9 +244,9 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
const { const {
isContextMenuOpen, contextMenuPosition, isContextMenuOpen, contextMenuPosition,
handleBeforeContextMenu, handleContextMenu, handleBeforeContextMenu, handleContextMenu: onContextMenu,
handleContextMenuClose, handleContextMenuHide, handleContextMenuClose, handleContextMenuHide,
} = useContextMenuHandlers(ref, false, true); } = useContextMenuHandlers(ref, IS_TOUCH_ENV && isInSelectMode, true, IS_ANDROID);
useEffect(() => { useEffect(() => {
if (isContextMenuOpen) { if (isContextMenuOpen) {
@ -452,13 +453,23 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
} }
if (IS_ANDROID) { if (IS_ANDROID) {
setTimeout(() => { if (windowSize.getIsKeyboardVisible()) {
handleContextMenu(e); setTimeout(() => { onContextMenu(e); }, ANDROID_KEYBOARD_HIDE_DELAY_MS);
}, ANDROID_KEYBOARD_HIDE_DELAY_MS); } else {
onContextMenu(e);
}
} else { } else {
handleContextMenu(e); onContextMenu(e);
} }
}, [handleContextMenu]); }, [onContextMenu]);
const handleContextMenu = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (IS_ANDROID) {
handleMessageSelect(e);
} else {
onContextMenu(e);
}
}, [onContextMenu, handleMessageSelect]);
const handleReadMedia = useCallback((): void => { const handleReadMedia = useCallback((): void => {
markMessagesRead({ messageIds: [messageId] }); markMessagesRead({ messageIds: [messageId] });
@ -801,7 +812,7 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
)} )}
{withAvatar && renderAvatar()} {withAvatar && renderAvatar()}
<div <div
className="message-content-wrapper" className={buildClassName('message-content-wrapper', contentClassName.includes('text') && 'can-select-text')}
onClick={isInSelectMode && isInDocumentGroup ? handleMessageSelect : undefined} onClick={isInSelectMode && isInDocumentGroup ? handleMessageSelect : undefined}
> >
<div <div

View File

@ -18,6 +18,7 @@ export default (
elementRef: RefObject<HTMLElement>, elementRef: RefObject<HTMLElement>,
isMenuDisabled?: boolean, isMenuDisabled?: boolean,
shouldDisableOnLink?: boolean, shouldDisableOnLink?: boolean,
shouldDisableOnLongTap?: boolean,
) => { ) => {
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false); const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
const [contextMenuPosition, setContextMenuPosition] = useState<IAnchorPosition | undefined>(undefined); const [contextMenuPosition, setContextMenuPosition] = useState<IAnchorPosition | undefined>(undefined);
@ -67,7 +68,7 @@ export default (
// Support context menu on touch-devices // Support context menu on touch-devices
useEffect(() => { useEffect(() => {
if (isMenuDisabled || !IS_TOUCH_ENV) { if (isMenuDisabled || !IS_TOUCH_ENV || shouldDisableOnLongTap) {
return undefined; return undefined;
} }
@ -129,7 +130,7 @@ export default (
element.removeEventListener('touchend', clearLongPressTimer, true); element.removeEventListener('touchend', clearLongPressTimer, true);
element.removeEventListener('touchmove', clearLongPressTimer); element.removeEventListener('touchmove', clearLongPressTimer);
}; };
}, [contextMenuPosition, isMenuDisabled, elementRef]); }, [contextMenuPosition, isMenuDisabled, shouldDisableOnLongTap, elementRef]);
return { return {
isContextMenuOpen, isContextMenuOpen,

View File

@ -13,6 +13,7 @@ type IDimensions = {
const IS_LANDSCAPE = IS_SINGLE_COLUMN_LAYOUT && isLandscape(); const IS_LANDSCAPE = IS_SINGLE_COLUMN_LAYOUT && isLandscape();
const initialHeight = window.innerHeight;
let windowSize = updateSizes(); let windowSize = updateSizes();
let isRefreshDisabled = false; let isRefreshDisabled = false;
@ -69,6 +70,7 @@ function isLandscape() {
export default { export default {
get: () => windowSize, get: () => windowSize,
getIsKeyboardVisible: () => initialHeight > windowSize.height,
disableRefresh, disableRefresh,
enableRefresh, enableRefresh,
}; };