Message / Contact: Support copying number, support non-registered (#1860)
This commit is contained in:
parent
1f99bd3d49
commit
39cdd8e8e8
@ -60,7 +60,9 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
||||
openForwardMenuForSelectedMessages,
|
||||
downloadSelectedMessages,
|
||||
copySelectedMessages,
|
||||
showNotification,
|
||||
} = getActions();
|
||||
const lang = useLang();
|
||||
|
||||
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();
|
||||
const [isReportModalOpen, openReportModal, closeReportModal] = useFlag();
|
||||
@ -78,8 +80,11 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const handleCopy = useCallback(() => {
|
||||
copySelectedMessages();
|
||||
showNotification({
|
||||
message: lang('Share.Link.Copied'),
|
||||
});
|
||||
exitMessageSelectMode();
|
||||
}, [copySelectedMessages, exitMessageSelectMode]);
|
||||
}, [copySelectedMessages, exitMessageSelectMode, lang, showNotification]);
|
||||
|
||||
const handleDownload = useCallback(() => {
|
||||
downloadSelectedMessages();
|
||||
@ -89,8 +94,6 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
||||
const prevSelectedMessagesCount = usePrevious(selectedMessagesCount || undefined, true);
|
||||
const renderingSelectedMessagesCount = isActive ? selectedMessagesCount : prevSelectedMessagesCount;
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const formattedMessagesCount = lang('VoiceOver.Chat.MessagesSelected', renderingSelectedMessagesCount, 'i');
|
||||
|
||||
const className = buildClassName(
|
||||
|
||||
@ -20,6 +20,8 @@ type StateProps = {
|
||||
phoneCodeList: ApiCountryCode[];
|
||||
};
|
||||
|
||||
const UNREGISTERED_CONTACT_ID = '0';
|
||||
|
||||
const Contact: FC<OwnProps & StateProps> = ({
|
||||
contact, user, phoneCodeList,
|
||||
}) => {
|
||||
@ -31,6 +33,7 @@ const Contact: FC<OwnProps & StateProps> = ({
|
||||
phoneNumber,
|
||||
userId,
|
||||
} = contact;
|
||||
const isRegistered = userId !== UNREGISTERED_CONTACT_ID;
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
openChat({ id: userId });
|
||||
@ -38,8 +41,8 @@ const Contact: FC<OwnProps & StateProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName('Contact', Boolean(userId) && 'interactive')}
|
||||
onClick={userId ? handleClick : undefined}
|
||||
className={buildClassName('Contact', isRegistered && 'interactive')}
|
||||
onClick={isRegistered ? handleClick : undefined}
|
||||
>
|
||||
<Avatar size="large" user={user} text={firstName || lastName} />
|
||||
<div className="contact-info">
|
||||
|
||||
@ -6,6 +6,7 @@ import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
import { MessageListType } from '../../../global/types';
|
||||
import { ApiAvailableReaction, ApiMessage } from '../../../api/types';
|
||||
import { IAlbum, IAnchorPosition } from '../../../types';
|
||||
|
||||
import {
|
||||
selectActiveDownloadIds,
|
||||
selectAllowedMessageActions,
|
||||
@ -19,17 +20,18 @@ import {
|
||||
} from '../../../global/helpers';
|
||||
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||
import { getDayStartAt } from '../../../util/dateFormat';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { REM } from '../../common/helpers/mediaDimensions';
|
||||
|
||||
import { copyTextToClipboard } from '../../../util/clipboard';
|
||||
import useShowTransition from '../../../hooks/useShowTransition';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import { REM } from '../../common/helpers/mediaDimensions';
|
||||
|
||||
import DeleteMessageModal from '../../common/DeleteMessageModal';
|
||||
import ReportModal from '../../common/ReportModal';
|
||||
import PinMessageModal from '../../common/PinMessageModal';
|
||||
import MessageContextMenu from './MessageContextMenu';
|
||||
import CalendarModal from '../../common/CalendarModal';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
|
||||
const START_SIZE = 2 * REM;
|
||||
|
||||
@ -300,7 +302,12 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
const handleCopyLink = useCallback(() => {
|
||||
copyTextToClipboard(`https://t.me/${chatUsername || `c/${message.chatId.replace('-', '')}`}/${message.id}`);
|
||||
closeMenu();
|
||||
}, [chatUsername, closeMenu, message.chatId, message.id]);
|
||||
}, [chatUsername, closeMenu, message]);
|
||||
|
||||
const handleCopyNumber = useCallback(() => {
|
||||
copyTextToClipboard(message.content.contact!.phoneNumber);
|
||||
closeMenu();
|
||||
}, [closeMenu, message]);
|
||||
|
||||
const handleDownloadClick = useCallback(() => {
|
||||
(album?.messages || [message]).forEach((msg) => {
|
||||
@ -383,6 +390,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
onClose={closeMenu}
|
||||
onCopyLink={handleCopyLink}
|
||||
onCopyMessages={handleCopyMessages}
|
||||
onCopyNumber={handleCopyNumber}
|
||||
onDownload={handleDownloadClick}
|
||||
onSaveGif={handleSaveGif}
|
||||
onShowSeenBy={handleOpenSeenByModal}
|
||||
@ -464,6 +472,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
&& !areReactionsEmpty(message.reactions) && message.reactions.canSeeList;
|
||||
const canRemoveReaction = isPrivate && message.reactions?.results?.some((l) => l.isChosen);
|
||||
const isProtected = selectIsMessageProtected(global, message);
|
||||
const canCopyNumber = Boolean(message.content.contact);
|
||||
|
||||
return {
|
||||
availableReactions: global.availableReactions,
|
||||
@ -479,7 +488,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
canForward: !isProtected && !isScheduled && canForward,
|
||||
canFaveSticker: !isScheduled && canFaveSticker,
|
||||
canUnfaveSticker: !isScheduled && canUnfaveSticker,
|
||||
canCopy: !isProtected && canCopy,
|
||||
canCopy: canCopyNumber || (!isProtected && canCopy),
|
||||
canCopyLink: !isProtected && !isScheduled && canCopyLink,
|
||||
canSelect,
|
||||
canDownload: !isProtected && canDownload,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, {
|
||||
FC, memo, useCallback, useEffect, useRef,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import { ApiAvailableReaction, ApiMessage, ApiUser } from '../../../api/types';
|
||||
import { IAnchorPosition } from '../../../types';
|
||||
@ -8,11 +9,12 @@ import { IAnchorPosition } from '../../../types';
|
||||
import { getMessageCopyOptions } from './helpers/copyOptions';
|
||||
import { disableScrolling, enableScrolling } from '../../../util/scrollLock';
|
||||
import { getUserFullName } from '../../../global/helpers';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
||||
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useContextMenuPosition from '../../../hooks/useContextMenuPosition';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
||||
|
||||
import Menu from '../../ui/Menu';
|
||||
import MenuItem from '../../ui/MenuItem';
|
||||
@ -66,6 +68,7 @@ type OwnProps = {
|
||||
onCloseAnimationEnd?: () => void;
|
||||
onCopyLink?: () => void;
|
||||
onCopyMessages?: (messageIds: number[]) => void;
|
||||
onCopyNumber?: () => void;
|
||||
onDownload?: () => void;
|
||||
onSaveGif?: () => void;
|
||||
onShowSeenBy?: () => void;
|
||||
@ -121,6 +124,7 @@ const MessageContextMenu: FC<OwnProps> = ({
|
||||
onClose,
|
||||
onCloseAnimationEnd,
|
||||
onCopyLink,
|
||||
onCopyNumber,
|
||||
onDownload,
|
||||
onSaveGif,
|
||||
onShowSeenBy,
|
||||
@ -128,16 +132,28 @@ const MessageContextMenu: FC<OwnProps> = ({
|
||||
onSendReaction,
|
||||
onCopyMessages,
|
||||
}) => {
|
||||
const { showNotification } = getActions();
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||
const copyOptions = getMessageCopyOptions(message, onClose, canCopyLink ? onCopyLink : undefined, onCopyMessages);
|
||||
const lang = useLang();
|
||||
const noReactions = !isPrivate && !enabledReactions?.length;
|
||||
const withReactions = canShowReactionList && !noReactions;
|
||||
|
||||
const [isReady, markIsReady, unmarkIsReady] = useFlag();
|
||||
|
||||
const handleAfterCopy = useCallback(() => {
|
||||
showNotification({
|
||||
message: lang('Share.Link.Copied'),
|
||||
});
|
||||
onClose();
|
||||
}, [lang, onClose, showNotification]);
|
||||
|
||||
const copyOptions = getMessageCopyOptions(
|
||||
message, handleAfterCopy, canCopyLink ? onCopyLink : undefined, onCopyMessages, onCopyNumber,
|
||||
);
|
||||
|
||||
const getTriggerElement = useCallback(() => {
|
||||
return document.querySelector(`.Transition__slide--active > .MessageList div[data-message-id="${message.id}"]`);
|
||||
}, [message.id]);
|
||||
@ -193,8 +209,6 @@ const MessageContextMenu: FC<OwnProps> = ({
|
||||
return enableScrolling;
|
||||
}, [withScroll]);
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
return (
|
||||
<Menu
|
||||
ref={menuRef}
|
||||
|
||||
@ -2,6 +2,7 @@ import { ApiMediaFormat, ApiMessage } from '../../../../api/types';
|
||||
|
||||
import * as mediaLoader from '../../../../util/mediaLoader';
|
||||
import {
|
||||
getMessageContact,
|
||||
getMessageMediaHash,
|
||||
getMessagePhoto,
|
||||
getMessageText,
|
||||
@ -24,11 +25,13 @@ export function getMessageCopyOptions(
|
||||
afterEffect?: () => void,
|
||||
onCopyLink?: () => void,
|
||||
onCopyMessages?: (messageIds: number[]) => void,
|
||||
onCopyNumber?: () => void,
|
||||
): ICopyOptions {
|
||||
const options: ICopyOptions = [];
|
||||
const text = getMessageText(message);
|
||||
const photo = getMessagePhoto(message)
|
||||
|| (!getMessageWebPageVideo(message) ? getMessageWebPagePhoto(message) : undefined);
|
||||
const contact = getMessageContact(message);
|
||||
const mediaHash = getMessageMediaHash(message, 'inline');
|
||||
const canImageBeCopied = photo && (mediaHash || hasMessageLocalBlobUrl(message)) && CLIPBOARD_ITEM_SUPPORTED;
|
||||
const selection = window.getSelection();
|
||||
@ -41,9 +44,7 @@ export function getMessageCopyOptions(
|
||||
Promise.resolve(mediaHash ? mediaLoader.fetch(mediaHash, ApiMediaFormat.BlobUrl) : photo!.blobUrl)
|
||||
.then(copyImageToClipboard);
|
||||
|
||||
if (afterEffect) {
|
||||
afterEffect();
|
||||
}
|
||||
afterEffect?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -68,9 +69,7 @@ export function getMessageCopyOptions(
|
||||
copyTextToClipboard(clipboardText);
|
||||
}
|
||||
|
||||
if (afterEffect) {
|
||||
afterEffect();
|
||||
}
|
||||
afterEffect?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -82,9 +81,19 @@ export function getMessageCopyOptions(
|
||||
handler: () => {
|
||||
onCopyLink();
|
||||
|
||||
if (afterEffect) {
|
||||
afterEffect();
|
||||
}
|
||||
afterEffect?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (contact && onCopyNumber) {
|
||||
options.push({
|
||||
label: 'lng_profile_copy_phone',
|
||||
icon: 'copy',
|
||||
handler: () => {
|
||||
onCopyNumber();
|
||||
|
||||
afterEffect?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user