Composer: Support disabling web link (#1020)

This commit is contained in:
Alexander Zinchuk 2021-04-19 18:36:54 +03:00
parent 0b59ebd7b0
commit b7f776593e
7 changed files with 53 additions and 13 deletions

View File

@ -182,6 +182,7 @@ export function sendMessage(
isSilent, isSilent,
scheduledAt, scheduledAt,
groupedId, groupedId,
noWebPage,
}: { }: {
chat: ApiChat; chat: ApiChat;
text?: string; text?: string;
@ -194,6 +195,7 @@ export function sendMessage(
isSilent?: boolean; isSilent?: boolean;
scheduledAt?: number; scheduledAt?: number;
groupedId?: string; groupedId?: string;
noWebPage?: boolean;
}, },
onProgress?: ApiOnProgress, onProgress?: ApiOnProgress,
) { ) {
@ -267,6 +269,7 @@ export function sendMessage(
...(scheduledAt && { scheduleDate: scheduledAt }), ...(scheduledAt && { scheduleDate: scheduledAt }),
...(replyingTo && { replyToMsgId: replyingTo }), ...(replyingTo && { replyToMsgId: replyingTo }),
...(media && { media }), ...(media && { media }),
...(noWebPage && { noWebpage: noWebPage }),
}), true); }), true);
})(); })();

View File

@ -701,7 +701,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
<div className="svg-appendix" ref={appendixRef} /> <div className="svg-appendix" ref={appendixRef} />
<ComposerEmbeddedMessage /> <ComposerEmbeddedMessage />
{allowedAttachmentOptions.canAttachEmbedLinks && ( {allowedAttachmentOptions.canAttachEmbedLinks && (
<WebPagePreview chatId={chatId} messageText={!attachments.length ? html : ''} /> <WebPagePreview chatId={chatId} threadId={threadId} messageText={!attachments.length ? html : ''} />
)} )}
<div className="message-input-wrapper"> <div className="message-input-wrapper">
{IS_MOBILE_SCREEN ? ( {IS_MOBILE_SCREEN ? (

View File

@ -5,9 +5,6 @@
padding-right: 0.625rem; padding-right: 0.625rem;
padding-top: 0.45rem; padding-top: 0.45rem;
// TODO: Remove this when support for disabling webpage preview is added
padding-left: 3.375rem;
--accent-color: var(--color-primary); --accent-color: var(--color-primary);
.ComposerEmbeddedMessage + & { .ComposerEmbeddedMessage + & {

View File

@ -3,33 +3,42 @@ import React, {
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { withGlobal } from '../../../lib/teact/teactn'; import { withGlobal } from '../../../lib/teact/teactn';
import { GlobalActions, GlobalState } from '../../../global/types'; import { GlobalActions } from '../../../global/types';
import { ApiMessage, ApiMessageEntityTypes } from '../../../api/types'; import { ApiMessage, ApiMessageEntityTypes, ApiWebPage } from '../../../api/types';
import { selectNoWebPage } from '../../../modules/selectors';
import { pick } from '../../../util/iteratees'; import { pick } from '../../../util/iteratees';
import parseMessageInput from './helpers/parseMessageInput'; import parseMessageInput from './helpers/parseMessageInput';
import useOnChange from '../../../hooks/useOnChange'; import useOnChange from '../../../hooks/useOnChange';
import WebPage from '../message/WebPage'; import WebPage from '../message/WebPage';
import Button from '../../ui/Button';
import './WebPagePreview.scss'; import './WebPagePreview.scss';
type OwnProps = { type OwnProps = {
chatId: number; chatId: number;
threadId: number;
messageText: string; messageText: string;
}; };
type StateProps = Pick<GlobalState, 'webPagePreview'>; type StateProps = {
type DispatchProps = Pick<GlobalActions, 'loadWebPagePreview' | 'clearWebPagePreview'>; webPagePreview?: ApiWebPage;
noWebPage?: boolean;
};
type DispatchProps = Pick<GlobalActions, 'loadWebPagePreview' | 'clearWebPagePreview' | 'toggleMessageWebPage'>;
const RE_LINK = /https?:\/\/(www.)?([a-zA-Z0-9.-]{2,256})([a-zA-Z/.-]{1,256})([?|#][=&#a-zA-Z0-9]{2,128})?/; const RE_LINK = /https?:\/\/(www.)?([a-zA-Z0-9.-]{2,256})([a-zA-Z/.-]{1,256})([?|#][=&#a-zA-Z0-9]{2,128})?/;
const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({ const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
chatId, chatId,
threadId,
messageText, messageText,
webPagePreview, webPagePreview,
noWebPage,
loadWebPagePreview, loadWebPagePreview,
clearWebPagePreview, clearWebPagePreview,
toggleMessageWebPage,
}) => { }) => {
const link = useMemo(() => { const link = useMemo(() => {
const { text, entities } = parseMessageInput(messageText); const { text, entities } = parseMessageInput(messageText);
@ -52,14 +61,20 @@ const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
loadWebPagePreview({ text: link }); loadWebPagePreview({ text: link });
} else { } else {
clearWebPagePreview(); clearWebPagePreview();
toggleMessageWebPage({ chatId, threadId });
} }
}, [clearWebPagePreview, link, loadWebPagePreview]); }, [chatId, toggleMessageWebPage, clearWebPagePreview, link, loadWebPagePreview, threadId]);
useOnChange(() => { useOnChange(() => {
clearWebPagePreview(); clearWebPagePreview();
toggleMessageWebPage({ chatId, threadId });
}, [chatId]); }, [chatId]);
if (!webPagePreview || !messageText.length) { const handleClearWebpagePreview = () => {
toggleMessageWebPage({ chatId, threadId, noWebPage: true });
};
if (!webPagePreview || !messageText.length || noWebPage) {
return undefined; return undefined;
} }
@ -73,12 +88,23 @@ const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
return ( return (
<div className="WebPagePreview"> <div className="WebPagePreview">
<Button round color="translucent" ariaLabel="Clear Webpage Preview" onClick={handleClearWebpagePreview}>
<i className="icon-close" />
</Button>
<WebPage message={messageStub} inPreview /> <WebPage message={messageStub} inPreview />
</div> </div>
); );
}; };
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global): StateProps => pick(global, ['webPagePreview']), (global, { chatId, threadId }): StateProps => {
(setGlobal, actions): DispatchProps => pick(actions, ['loadWebPagePreview', 'clearWebPagePreview']), const noWebPage = selectNoWebPage(global, chatId, threadId);
return {
webPagePreview: global.webPagePreview,
noWebPage,
};
},
(setGlobal, actions): DispatchProps => pick(actions, [
'loadWebPagePreview', 'clearWebPagePreview', 'toggleMessageWebPage',
]),
)(WebPagePreview)); )(WebPagePreview));

View File

@ -49,6 +49,7 @@ export interface Thread {
editingId?: number; editingId?: number;
editingScheduledId?: number; editingScheduledId?: number;
draft?: ApiFormattedText; draft?: ApiFormattedText;
noWebPage?: boolean;
threadInfo?: ApiThreadInfo; threadInfo?: ApiThreadInfo;
firstMessageId?: number; firstMessageId?: number;
} }
@ -397,7 +398,7 @@ export type ActionTypes = (
'editMessage' | 'deleteHistory' | 'enterMessageSelectMode' | 'toggleMessageSelection' | 'exitMessageSelectMode' | 'editMessage' | 'deleteHistory' | 'enterMessageSelectMode' | 'toggleMessageSelection' | 'exitMessageSelectMode' |
'openTelegramLink' | 'openChatByUsername' | 'requestThreadInfoUpdate' | 'setScrollOffset' | 'unpinAllMessages' | 'openTelegramLink' | 'openChatByUsername' | 'requestThreadInfoUpdate' | 'setScrollOffset' | 'unpinAllMessages' |
'setReplyingToId' | 'setEditingId' | 'editLastMessage' | 'saveDraft' | 'clearDraft' | 'loadPinnedMessages' | 'setReplyingToId' | 'setEditingId' | 'editLastMessage' | 'saveDraft' | 'clearDraft' | 'loadPinnedMessages' |
'loadMessageLink' | 'loadMessageLink' | 'toggleMessageWebPage' |
// scheduled messages // scheduled messages
'loadScheduledHistory' | 'sendScheduledMessages' | 'rescheduleMessage' | 'deleteScheduledMessages' | 'loadScheduledHistory' | 'sendScheduledMessages' | 'rescheduleMessage' | 'deleteScheduledMessages' |
// poll result // poll result

View File

@ -48,6 +48,7 @@ import {
selectEditingScheduledId, selectEditingScheduledId,
selectEditingMessage, selectEditingMessage,
selectScheduledMessage, selectScheduledMessage,
selectNoWebPage,
} from '../../selectors'; } from '../../selectors';
import { rafPromise } from '../../../util/schedulers'; import { rafPromise } from '../../../util/schedulers';
import { copyTextToClipboard } from '../../../util/clipboard'; import { copyTextToClipboard } from '../../../util/clipboard';
@ -171,11 +172,13 @@ addReducer('sendMessage', (global, actions, payload) => {
const chat = selectChat(global, chatId)!; const chat = selectChat(global, chatId)!;
actions.setReplyingToId({ messageId: undefined }); actions.setReplyingToId({ messageId: undefined });
actions.clearWebPagePreview({ chatId, threadId, value: false });
const params = { const params = {
...payload, ...payload,
chat, chat,
replyingTo: selectReplyingToId(global, chatId, threadId), replyingTo: selectReplyingToId(global, chatId, threadId),
noWebPage: selectNoWebPage(global, chatId, threadId),
}; };
const isSingle = !payload.attachments || payload.attachments.length <= 1; const isSingle = !payload.attachments || payload.attachments.length <= 1;
@ -310,6 +313,12 @@ addReducer('clearDraft', (global, actions, payload) => {
return replaceThreadParam(global, chatId, threadId, 'draft', undefined); return replaceThreadParam(global, chatId, threadId, 'draft', undefined);
}); });
addReducer('toggleMessageWebPage', (global, actions, payload) => {
const { chatId, threadId, noWebPage } = payload!;
return replaceThreadParam(global, chatId, threadId, 'noWebPage', noWebPage);
});
addReducer('pinMessage', (global, actions, payload) => { addReducer('pinMessage', (global, actions, payload) => {
const chat = selectCurrentChat(global); const chat = selectCurrentChat(global);
if (!chat) { if (!chat) {

View File

@ -137,6 +137,10 @@ export function selectDraft(global: GlobalState, chatId: number, threadId: numbe
return selectThreadParam(global, chatId, threadId, 'draft'); return selectThreadParam(global, chatId, threadId, 'draft');
} }
export function selectNoWebPage(global: GlobalState, chatId: number, threadId: number) {
return selectThreadParam(global, chatId, threadId, 'noWebPage');
}
export function selectThreadInfo(global: GlobalState, chatId: number, threadId: number) { export function selectThreadInfo(global: GlobalState, chatId: number, threadId: number) {
return selectThreadParam(global, chatId, threadId, 'threadInfo'); return selectThreadParam(global, chatId, threadId, 'threadInfo');
} }