Channels: Support reply in another chat (#4798)
This commit is contained in:
parent
23b6e5e66d
commit
8d34fb3c20
@ -113,7 +113,7 @@ const ForwardRecipientPicker: FC<OwnProps & StateProps> = ({
|
|||||||
<RecipientPicker
|
<RecipientPicker
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
className={renderingIsStory ? 'component-theme-dark' : undefined}
|
className={renderingIsStory ? 'component-theme-dark' : undefined}
|
||||||
searchPlaceholder={lang('ForwardTo')}
|
searchPlaceholder={lang(isForwarding ? 'ForwardTo' : 'ReplyToDialog')}
|
||||||
onSelectRecipient={handleSelectRecipient}
|
onSelectRecipient={handleSelectRecipient}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onCloseAnimationEnd={unmarkIsShown}
|
onCloseAnimationEnd={unmarkIsShown}
|
||||||
|
|||||||
@ -201,8 +201,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const { messageIds: selectedMessageIds } = tabState.selectedMessages || {};
|
const { messageIds: selectedMessageIds } = tabState.selectedMessages || {};
|
||||||
const hasProtectedMessage = chatId ? selectHasProtectedMessage(global, chatId, selectedMessageIds) : false;
|
const hasProtectedMessage = chatId ? selectHasProtectedMessage(global, chatId, selectedMessageIds) : false;
|
||||||
const canForward = !isSchedule && chatId ? selectCanForwardMessages(global, chatId, selectedMessageIds) : false;
|
const canForward = !isSchedule && chatId ? selectCanForwardMessages(global, chatId, selectedMessageIds) : false;
|
||||||
const isForwardModalOpen = tabState.forwardMessages.isModalShown;
|
const isShareMessageModalOpen = tabState.isShareMessageModalShown;
|
||||||
const isAnyModalOpen = Boolean(isForwardModalOpen || tabState.requestedDraft
|
const isAnyModalOpen = Boolean(isShareMessageModalOpen || tabState.requestedDraft
|
||||||
|| tabState.requestedAttachBotInChat || tabState.requestedAttachBotInstall);
|
|| tabState.requestedAttachBotInChat || tabState.requestedAttachBotInstall);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -400,8 +400,9 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
}): StateProps => {
|
}): StateProps => {
|
||||||
const {
|
const {
|
||||||
forwardMessages: {
|
forwardMessages: {
|
||||||
fromChatId, toChatId, messageIds: forwardMessageIds, noAuthors, noCaptions, isModalShown,
|
fromChatId, toChatId, messageIds: forwardMessageIds, noAuthors, noCaptions,
|
||||||
},
|
},
|
||||||
|
isShareMessageModalShown: isModalShown,
|
||||||
shouldPreventComposerAnimation,
|
shouldPreventComposerAnimation,
|
||||||
} = selectTabState(global);
|
} = selectTabState(global);
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { MAIN_THREAD_ID } from '../../../api/types';
|
|||||||
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||||
import {
|
import {
|
||||||
areReactionsEmpty,
|
areReactionsEmpty,
|
||||||
|
getHasAdminRight,
|
||||||
getIsDownloading,
|
getIsDownloading,
|
||||||
getMessageDownloadableMedia,
|
getMessageDownloadableMedia,
|
||||||
getMessageVideo,
|
getMessageVideo,
|
||||||
@ -127,6 +128,8 @@ type StateProps = {
|
|||||||
canPlayAnimatedEmojis?: boolean;
|
canPlayAnimatedEmojis?: boolean;
|
||||||
isReactionPickerOpen?: boolean;
|
isReactionPickerOpen?: boolean;
|
||||||
isInSavedMessages?: boolean;
|
isInSavedMessages?: boolean;
|
||||||
|
isChannel?: boolean;
|
||||||
|
canPostMessagesInChannel?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
@ -187,6 +190,8 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
isInSavedMessages,
|
isInSavedMessages,
|
||||||
onClose,
|
onClose,
|
||||||
onCloseAnimationEnd,
|
onCloseAnimationEnd,
|
||||||
|
isChannel,
|
||||||
|
canPostMessagesInChannel,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
openThread,
|
openThread,
|
||||||
@ -194,6 +199,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
setEditingId,
|
setEditingId,
|
||||||
pinMessage,
|
pinMessage,
|
||||||
openForwardMenu,
|
openForwardMenu,
|
||||||
|
openReplyMenu,
|
||||||
faveSticker,
|
faveSticker,
|
||||||
unfaveSticker,
|
unfaveSticker,
|
||||||
toggleMessageSelection,
|
toggleMessageSelection,
|
||||||
@ -357,11 +363,16 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleReply = useLastCallback(() => {
|
const handleReply = useLastCallback(() => {
|
||||||
updateDraftReplyInfo({
|
const quoteText = canQuoteSelection && selectionRange ? getSelectionAsFormattedText(selectionRange) : undefined;
|
||||||
replyToMsgId: message.id,
|
if (isChannel && !canPostMessagesInChannel) {
|
||||||
quoteText: canQuoteSelection && selectionRange ? getSelectionAsFormattedText(selectionRange) : undefined,
|
openReplyMenu({ fromChatId: message.chatId, messageId: message.id, quoteText });
|
||||||
replyToPeerId: undefined,
|
} else {
|
||||||
});
|
updateDraftReplyInfo({
|
||||||
|
replyToMsgId: message.id,
|
||||||
|
quoteText,
|
||||||
|
replyToPeerId: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
closeMenu();
|
closeMenu();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -705,6 +716,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const isPinned = messageListType === 'pinned';
|
const isPinned = messageListType === 'pinned';
|
||||||
const isScheduled = messageListType === 'scheduled';
|
const isScheduled = messageListType === 'scheduled';
|
||||||
const isChannel = chat && isChatChannel(chat);
|
const isChannel = chat && isChatChannel(chat);
|
||||||
|
const canPostMessagesInChannel = isChannel && getHasAdminRight(chat, 'postMessages');
|
||||||
const isLocal = isMessageLocal(message);
|
const isLocal = isMessageLocal(message);
|
||||||
const hasTtl = hasMessageTtl(message);
|
const hasTtl = hasMessageTtl(message);
|
||||||
const canShowSeenBy = Boolean(!isLocal
|
const canShowSeenBy = Boolean(!isLocal
|
||||||
@ -787,6 +799,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
||||||
isReactionPickerOpen: selectIsReactionPickerOpen(global),
|
isReactionPickerOpen: selectIsReactionPickerOpen(global),
|
||||||
isInSavedMessages,
|
isInSavedMessages,
|
||||||
|
isChannel,
|
||||||
|
canPostMessagesInChannel,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(ContextMenuContainer));
|
)(ContextMenuContainer));
|
||||||
|
|||||||
@ -1121,6 +1121,7 @@ addActionHandler('forwardMessages', (global, actions, payload): ActionReturnType
|
|||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
isShareMessageModalShown: false,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
@ -1827,11 +1828,12 @@ addActionHandler('openChatOrTopicWithReplyInDraft', (global, actions, payload):
|
|||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
|
|
||||||
|
const tabState = selectTabState(global, tabId);
|
||||||
|
const replyingInfo = tabState.replyingMessage;
|
||||||
|
|
||||||
global = updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
forwardMessages: {
|
isShareMessageModalShown: false,
|
||||||
...selectTabState(global, tabId).forwardMessages,
|
replyingMessage: {},
|
||||||
isModalShown: false,
|
|
||||||
},
|
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
@ -1843,7 +1845,16 @@ addActionHandler('openChatOrTopicWithReplyInDraft', (global, actions, payload):
|
|||||||
const threadId = topicId || MAIN_THREAD_ID;
|
const threadId = topicId || MAIN_THREAD_ID;
|
||||||
const currentChatId = currentChat.id;
|
const currentChatId = currentChat.id;
|
||||||
|
|
||||||
const currentReplyInfo = selectDraft(global, currentChatId, currentThreadId)?.replyInfo;
|
const newReplyInfo = {
|
||||||
|
type: 'message',
|
||||||
|
replyToMsgId: replyingInfo.messageId,
|
||||||
|
replyToTopId: replyingInfo.toThreadId,
|
||||||
|
replyToPeerId: currentChatId,
|
||||||
|
quoteText: replyingInfo.quoteText,
|
||||||
|
} as ApiInputMessageReplyInfo;
|
||||||
|
|
||||||
|
const currentReplyInfo = replyingInfo.messageId
|
||||||
|
? newReplyInfo : selectDraft(global, currentChatId, currentThreadId)?.replyInfo;
|
||||||
if (!currentReplyInfo) return;
|
if (!currentReplyInfo) return;
|
||||||
|
|
||||||
if (!selectReplyCanBeSentToChat(global, toChatId, currentChatId, currentReplyInfo)) {
|
if (!selectReplyCanBeSentToChat(global, toChatId, currentChatId, currentReplyInfo)) {
|
||||||
@ -1896,8 +1907,8 @@ addActionHandler('setForwardChatOrTopic', async (global, actions, payload): Prom
|
|||||||
...selectTabState(global, tabId).forwardMessages,
|
...selectTabState(global, tabId).forwardMessages,
|
||||||
toChatId: chatId,
|
toChatId: chatId,
|
||||||
toThreadId: topicId,
|
toThreadId: topicId,
|
||||||
isModalShown: false,
|
|
||||||
},
|
},
|
||||||
|
isShareMessageModalShown: false,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
actions.openThread({ chatId, threadId: topicId || MAIN_THREAD_ID, tabId });
|
actions.openThread({ chatId, threadId: topicId || MAIN_THREAD_ID, tabId });
|
||||||
@ -1947,6 +1958,7 @@ addActionHandler('forwardStory', (global, actions, payload): ActionReturnType =>
|
|||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
isShareMessageModalShown: false,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -61,6 +61,7 @@ addActionHandler('processOpenChatOrThread', (global, actions, payload): ActionRe
|
|||||||
contentToBeScheduled: undefined,
|
contentToBeScheduled: undefined,
|
||||||
...(chatId !== selectTabState(global, tabId).forwardMessages.toChatId && {
|
...(chatId !== selectTabState(global, tabId).forwardMessages.toChatId && {
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
isShareMessageModalShown: false,
|
||||||
}),
|
}),
|
||||||
}, tabId);
|
}, tabId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ addActionHandler('openMediaViewer', (global, actions, payload): ActionReturnType
|
|||||||
withDynamicLoading,
|
withDynamicLoading,
|
||||||
},
|
},
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
isShareMessageModalShown: false,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -515,6 +515,20 @@ addActionHandler('setShouldPreventComposerAnimation', (global, actions, payload)
|
|||||||
}, tabId);
|
}, tabId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('openReplyMenu', (global, actions, payload): ActionReturnType => {
|
||||||
|
const {
|
||||||
|
fromChatId, messageId, quoteText, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
return updateTabState(global, {
|
||||||
|
replyingMessage: {
|
||||||
|
fromChatId,
|
||||||
|
messageId,
|
||||||
|
quoteText,
|
||||||
|
},
|
||||||
|
isShareMessageModalShown: true,
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('openForwardMenu', (global, actions, payload): ActionReturnType => {
|
addActionHandler('openForwardMenu', (global, actions, payload): ActionReturnType => {
|
||||||
const {
|
const {
|
||||||
fromChatId, messageIds, storyId, groupedId, withMyScore, tabId = getCurrentTabId(),
|
fromChatId, messageIds, storyId, groupedId, withMyScore, tabId = getCurrentTabId(),
|
||||||
@ -528,9 +542,9 @@ addActionHandler('openForwardMenu', (global, actions, payload): ActionReturnType
|
|||||||
fromChatId,
|
fromChatId,
|
||||||
messageIds: groupedMessageIds || messageIds,
|
messageIds: groupedMessageIds || messageIds,
|
||||||
storyId,
|
storyId,
|
||||||
isModalShown: true,
|
|
||||||
withMyScore,
|
withMyScore,
|
||||||
},
|
},
|
||||||
|
isShareMessageModalShown: true,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -540,10 +554,10 @@ addActionHandler('changeRecipient', (global, actions, payload): ActionReturnType
|
|||||||
forwardMessages: {
|
forwardMessages: {
|
||||||
...selectTabState(global, tabId).forwardMessages,
|
...selectTabState(global, tabId).forwardMessages,
|
||||||
toChatId: undefined,
|
toChatId: undefined,
|
||||||
isModalShown: true,
|
|
||||||
noAuthors: false,
|
noAuthors: false,
|
||||||
noCaptions: false,
|
noCaptions: false,
|
||||||
},
|
},
|
||||||
|
isShareMessageModalShown: true,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -575,7 +589,9 @@ addActionHandler('exitForwardMode', (global, actions, payload): ActionReturnType
|
|||||||
const { tabId = getCurrentTabId() } = payload || {};
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
|
||||||
global = updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
|
isShareMessageModalShown: false,
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
replyingMessage: {},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -349,8 +349,12 @@ export const INITIAL_TAB_STATE: TabState = {
|
|||||||
isMuted: false,
|
isMuted: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isShareMessageModalShown: false,
|
||||||
|
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
|
||||||
|
replyingMessage: {},
|
||||||
|
|
||||||
pollResults: {},
|
pollResults: {},
|
||||||
|
|
||||||
payment: {},
|
payment: {},
|
||||||
|
|||||||
@ -655,9 +655,13 @@ export function selectAllowedMessageActions<T extends GlobalState>(global: T, me
|
|||||||
|
|
||||||
const threadInfo = selectThreadInfo(global, message.chatId, threadId);
|
const threadInfo = selectThreadInfo(global, message.chatId, threadId);
|
||||||
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);
|
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);
|
||||||
const canReply = !isLocal && !isServiceNotification && !chat.isForbidden
|
const canPostInChat = getCanPostInChat(chat, threadId, isMessageThread, chatFullInfo);
|
||||||
&& getCanPostInChat(chat, threadId, isMessageThread, chatFullInfo)
|
const canReply = (() => {
|
||||||
&& (!messageTopic || !messageTopic.isClosed || messageTopic.isOwner || getHasAdminRight(chat, 'manageTopics'));
|
if (isLocal || isServiceNotification) return false;
|
||||||
|
if (isChatChannel(chat)) return true;
|
||||||
|
if (!canPostInChat || chat.isForbidden) return false;
|
||||||
|
return !messageTopic || !messageTopic.isClosed || messageTopic.isOwner || getHasAdminRight(chat, 'manageTopics');
|
||||||
|
})();
|
||||||
|
|
||||||
const hasPinPermission = isPrivate || (
|
const hasPinPermission = isPrivate || (
|
||||||
chat.isCreator
|
chat.isCreator
|
||||||
@ -945,8 +949,8 @@ export function selectIsForwardModalOpen<T extends GlobalState>(
|
|||||||
global: T,
|
global: T,
|
||||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
) {
|
) {
|
||||||
const { forwardMessages } = selectTabState(global, tabId);
|
const { isShareMessageModalShown } = selectTabState(global, tabId);
|
||||||
return Boolean(forwardMessages.isModalShown);
|
return Boolean(isShareMessageModalShown);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectCommonBoxChatId<T extends GlobalState>(global: T, messageId: number) {
|
export function selectCommonBoxChatId<T extends GlobalState>(global: T, messageId: number) {
|
||||||
|
|||||||
@ -491,8 +491,17 @@ export type TabState = {
|
|||||||
loadingMessageId: number;
|
loadingMessageId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
isShareMessageModalShown?: boolean;
|
||||||
|
|
||||||
|
replyingMessage: {
|
||||||
|
fromChatId?: string;
|
||||||
|
messageId?: number;
|
||||||
|
quoteText?: ApiFormattedText;
|
||||||
|
toChatId?: string;
|
||||||
|
toThreadId?: ThreadId;
|
||||||
|
};
|
||||||
|
|
||||||
forwardMessages: {
|
forwardMessages: {
|
||||||
isModalShown?: boolean;
|
|
||||||
fromChatId?: string;
|
fromChatId?: string;
|
||||||
messageIds?: number[];
|
messageIds?: number[];
|
||||||
storyId?: number;
|
storyId?: number;
|
||||||
@ -2625,6 +2634,13 @@ export interface ActionPayloads {
|
|||||||
shouldPreventComposerAnimation: boolean;
|
shouldPreventComposerAnimation: boolean;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
|
||||||
|
// Replies
|
||||||
|
openReplyMenu: {
|
||||||
|
fromChatId: string;
|
||||||
|
messageId?: number;
|
||||||
|
quoteText?: ApiFormattedText;
|
||||||
|
} & WithTabId;
|
||||||
|
|
||||||
// Forwards
|
// Forwards
|
||||||
openForwardMenu: {
|
openForwardMenu: {
|
||||||
fromChatId: string;
|
fromChatId: string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user