mirror of
https://github.com/danog/telegram-tt.git
synced 2024-12-11 16:49:44 +01:00
Message: Various fixes for context menu on mobile (#1311)
This commit is contained in:
parent
3e5564717c
commit
cf96a04364
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user