Forward: Fix forward to forum topics (#6842)
Co-authored-by: Dmitry Kabanov <153344039+dmitrykabanovdev@users.noreply.github.com> Co-authored-by: Dmitry Kabanov <dmitrykabanovdev@gmail.com>
This commit is contained in:
parent
7b26965b45
commit
d7e3456550
@ -22,6 +22,13 @@ import {
|
|||||||
import { selectCurrentLimit } from '../../global/selectors/limits';
|
import { selectCurrentLimit } from '../../global/selectors/limits';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { unique } from '../../util/iteratees';
|
import { unique } from '../../util/iteratees';
|
||||||
|
import {
|
||||||
|
areChatSelectionKeysEqual,
|
||||||
|
buildChatSelectionKey,
|
||||||
|
type ChatSelectionKey,
|
||||||
|
getChatSelectionKeyHash,
|
||||||
|
includesChatSelectionKey,
|
||||||
|
} from '../../util/keys/chatSelectionKey';
|
||||||
import sortChatIds from './helpers/sortChatIds';
|
import sortChatIds from './helpers/sortChatIds';
|
||||||
|
|
||||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||||
@ -52,7 +59,7 @@ export type OwnProps = {
|
|||||||
viewportFooter?: TeactNode;
|
viewportFooter?: TeactNode;
|
||||||
loadMore?: NoneToVoidFunction;
|
loadMore?: NoneToVoidFunction;
|
||||||
onSelectRecipient: (peerId: string, threadId?: ThreadId) => void;
|
onSelectRecipient: (peerId: string, threadId?: ThreadId) => void;
|
||||||
onSelectedIdsChange?: (ids: string[]) => void;
|
onSelectedIdsChange?: (ids: ChatSelectionKey[]) => void;
|
||||||
onClose: NoneToVoidFunction;
|
onClose: NoneToVoidFunction;
|
||||||
onCloseAnimationEnd?: NoneToVoidFunction;
|
onCloseAnimationEnd?: NoneToVoidFunction;
|
||||||
};
|
};
|
||||||
@ -100,9 +107,9 @@ const RecipientPicker = ({
|
|||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
const [selectedIds, setSelectedIds] = useState<ChatSelectionKey[]>([]);
|
||||||
const [removingIds, setRemovingIds] = useState<string[]>([]);
|
const [removingIds, setRemovingIds] = useState<ChatSelectionKey[]>([]);
|
||||||
const [appearingIds, setAppearingIds] = useState<string[]>([]);
|
const [appearingIds, setAppearingIds] = useState<ChatSelectionKey[]>([]);
|
||||||
const selectedIdsRef = useStateRef(selectedIds);
|
const selectedIdsRef = useStateRef(selectedIds);
|
||||||
const removingIdsRef = useStateRef(removingIds);
|
const removingIdsRef = useStateRef(removingIds);
|
||||||
const appearingIdsRef = useStateRef(appearingIds);
|
const appearingIdsRef = useStateRef(appearingIds);
|
||||||
@ -134,46 +141,46 @@ const RecipientPicker = ({
|
|||||||
setActiveFolderIndex(index);
|
setActiveFolderIndex(index);
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateSelectedIds = useLastCallback((newIds: string[], newlyAddedId?: string) => {
|
const updateSelectedIds = useLastCallback((newIds: ChatSelectionKey[], newlyAddedKey?: ChatSelectionKey) => {
|
||||||
setSelectedIds(newIds);
|
setSelectedIds(newIds);
|
||||||
onSelectedIdsChange?.(newIds);
|
onSelectedIdsChange?.(newIds);
|
||||||
|
|
||||||
if (newlyAddedId && selectCanAnimateInterface(getGlobal())) {
|
if (newlyAddedKey && selectCanAnimateInterface(getGlobal())) {
|
||||||
setAppearingIds([...appearingIdsRef.current, newlyAddedId]);
|
setAppearingIds([...appearingIdsRef.current, newlyAddedKey]);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setAppearingIds(appearingIdsRef.current.filter((id) => id !== newlyAddedId));
|
setAppearingIds(appearingIdsRef.current.filter((key) => !areChatSelectionKeysEqual(key, newlyAddedKey)));
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRemoveSelected = useLastCallback((selectionId: string) => {
|
const handleRemoveSelected = useLastCallback((selectionKey: ChatSelectionKey) => {
|
||||||
if (removingIdsRef.current.includes(selectionId)) return;
|
if (includesChatSelectionKey(removingIdsRef.current, selectionKey)) return;
|
||||||
|
|
||||||
const canAnimate = selectCanAnimateInterface(getGlobal());
|
const canAnimate = selectCanAnimateInterface(getGlobal());
|
||||||
if (!canAnimate) {
|
if (!canAnimate) {
|
||||||
const newIds = selectedIdsRef.current.filter((id) => id !== selectionId);
|
const newIds = selectedIdsRef.current.filter((key) => !areChatSelectionKeysEqual(key, selectionKey));
|
||||||
setSelectedIds(newIds);
|
setSelectedIds(newIds);
|
||||||
onSelectedIdsChange?.(newIds);
|
onSelectedIdsChange?.(newIds);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setRemovingIds([...removingIdsRef.current, selectionId]);
|
setRemovingIds([...removingIdsRef.current, selectionKey]);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setRemovingIds(removingIdsRef.current.filter((id) => id !== selectionId));
|
setRemovingIds(removingIdsRef.current.filter((key) => !areChatSelectionKeysEqual(key, selectionKey)));
|
||||||
const newIds = selectedIdsRef.current.filter((id) => id !== selectionId);
|
const newIds = selectedIdsRef.current.filter((key) => !areChatSelectionKeysEqual(key, selectionKey));
|
||||||
setSelectedIds(newIds);
|
setSelectedIds(newIds);
|
||||||
onSelectedIdsChange?.(newIds);
|
onSelectedIdsChange?.(newIds);
|
||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleToggleSelection = useLastCallback((peerId: string, threadId?: ThreadId) => {
|
const handleToggleSelection = useLastCallback((peerId: string, threadId?: ThreadId) => {
|
||||||
const selectionId = threadId ? `${peerId}:${threadId}` : peerId;
|
const selectionKey = buildChatSelectionKey(peerId, threadId ? Number(threadId) : undefined);
|
||||||
|
|
||||||
if (selectedIds.includes(selectionId)) {
|
if (includesChatSelectionKey(selectedIds, selectionKey)) {
|
||||||
handleRemoveSelected(selectionId);
|
handleRemoveSelected(selectionKey);
|
||||||
} else {
|
} else {
|
||||||
updateSelectedIds([...selectedIds, selectionId], selectionId);
|
updateSelectedIds([...selectedIds, selectionKey], selectionKey);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -262,19 +269,8 @@ const RecipientPicker = ({
|
|||||||
|
|
||||||
const hasSelectedChips = isMultiSelect && selectedIds.length > 0;
|
const hasSelectedChips = isMultiSelect && selectedIds.length > 0;
|
||||||
|
|
||||||
const parseSelectionId = useLastCallback((selectionId: string): { peerId: string; topicId?: number } => {
|
const getChipTitle = useLastCallback((selectionKey: ChatSelectionKey): string | undefined => {
|
||||||
const colonIndex = selectionId.indexOf(':');
|
const { peerId, topicId } = selectionKey;
|
||||||
if (colonIndex === -1) {
|
|
||||||
return { peerId: selectionId };
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
peerId: selectionId.substring(0, colonIndex),
|
|
||||||
topicId: Number(selectionId.substring(colonIndex + 1)),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getChipTitle = useLastCallback((selectionId: string): string | undefined => {
|
|
||||||
const { peerId, topicId } = parseSelectionId(selectionId);
|
|
||||||
if (!topicId) return undefined;
|
if (!topicId) return undefined;
|
||||||
|
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
@ -309,15 +305,16 @@ const RecipientPicker = ({
|
|||||||
return (
|
return (
|
||||||
<div className="search-row-with-chips">
|
<div className="search-row-with-chips">
|
||||||
<div className="chips-and-search-scroll no-scrollbar">
|
<div className="chips-and-search-scroll no-scrollbar">
|
||||||
{selectedIds.map((selectionId) => {
|
{selectedIds.map((selectionKey) => {
|
||||||
const { peerId } = parseSelectionId(selectionId);
|
const { peerId } = selectionKey;
|
||||||
const chipTitle = getChipTitle(selectionId);
|
const chipTitle = getChipTitle(selectionKey);
|
||||||
const isAppearing = appearingIds.includes(selectionId);
|
const isAppearing = includesChatSelectionKey(appearingIds, selectionKey);
|
||||||
const isRemoving = removingIds.includes(selectionId);
|
const isRemoving = includesChatSelectionKey(removingIds, selectionKey);
|
||||||
|
const keyHash = getChatSelectionKeyHash(selectionKey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={selectionId}
|
key={keyHash}
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
'picker-chip-wrapper',
|
'picker-chip-wrapper',
|
||||||
isAppearing && 'picker-chip-appear',
|
isAppearing && 'picker-chip-appear',
|
||||||
@ -332,7 +329,7 @@ const RecipientPicker = ({
|
|||||||
canClose
|
canClose
|
||||||
className="picker-chip"
|
className="picker-chip"
|
||||||
itemClassName="picker-chip-name"
|
itemClassName="picker-chip-name"
|
||||||
clickArg={selectionId}
|
clickArg={selectionKey}
|
||||||
onClick={handleRemoveSelected}
|
onClick={handleRemoveSelected}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -356,6 +353,8 @@ const RecipientPicker = ({
|
|||||||
);
|
);
|
||||||
}, [hasSelectedChips, selectedIds, appearingIds, removingIds]);
|
}, [hasSelectedChips, selectedIds, appearingIds, removingIds]);
|
||||||
|
|
||||||
|
const selectedPeerIds = useMemo(() => selectedIds.map((key) => key.peerId), [selectedIds]);
|
||||||
|
|
||||||
const subheaderContent = useMemo(() => {
|
const subheaderContent = useMemo(() => {
|
||||||
const hasRecentContacts = recentContactIds.length > 0 && !search;
|
const hasRecentContacts = recentContactIds.length > 0 && !search;
|
||||||
const hasFolderTabs = shouldRenderFolders;
|
const hasFolderTabs = shouldRenderFolders;
|
||||||
@ -368,7 +367,7 @@ const RecipientPicker = ({
|
|||||||
<PickerRecentContacts
|
<PickerRecentContacts
|
||||||
contactIds={recentContactIds}
|
contactIds={recentContactIds}
|
||||||
currentUserId={currentUserId}
|
currentUserId={currentUserId}
|
||||||
selectedIds={isMultiSelect ? selectedIds : undefined}
|
selectedIds={isMultiSelect ? selectedPeerIds : undefined}
|
||||||
className={styles.recentContacts}
|
className={styles.recentContacts}
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
/>
|
/>
|
||||||
@ -389,7 +388,7 @@ const RecipientPicker = ({
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
handleSelect,
|
handleSelect,
|
||||||
isMultiSelect,
|
isMultiSelect,
|
||||||
selectedIds,
|
selectedPeerIds,
|
||||||
folderTabs,
|
folderTabs,
|
||||||
activeFolderIndex,
|
activeFolderIndex,
|
||||||
handleSwitchFolderIndex,
|
handleSwitchFolderIndex,
|
||||||
|
|||||||
@ -22,6 +22,11 @@ import {
|
|||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import { selectAnimationLevel } from '../../../global/selectors/sharedState';
|
import { selectAnimationLevel } from '../../../global/selectors/sharedState';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
import {
|
||||||
|
buildChatSelectionKey,
|
||||||
|
type ChatSelectionKey,
|
||||||
|
includesChatSelectionKey,
|
||||||
|
} from '../../../util/keys/chatSelectionKey';
|
||||||
import { resolveTransitionName } from '../../../util/resolveTransitionName';
|
import { resolveTransitionName } from '../../../util/resolveTransitionName';
|
||||||
import { REM } from '../helpers/mediaDimensions';
|
import { REM } from '../helpers/mediaDimensions';
|
||||||
import renderText from '../helpers/renderText';
|
import renderText from '../helpers/renderText';
|
||||||
@ -60,7 +65,7 @@ export type OwnProps = {
|
|||||||
renderSearchRow?: (props: SearchRowRenderProps) => TeactNode;
|
renderSearchRow?: (props: SearchRowRenderProps) => TeactNode;
|
||||||
footer?: TeactNode;
|
footer?: TeactNode;
|
||||||
viewportFooter?: TeactNode;
|
viewportFooter?: TeactNode;
|
||||||
selectedIds?: string[];
|
selectedIds?: ChatSelectionKey[];
|
||||||
loadMore?: NoneToVoidFunction;
|
loadMore?: NoneToVoidFunction;
|
||||||
onSearchChange: (search: string) => void;
|
onSearchChange: (search: string) => void;
|
||||||
onSelectChatOrUser: (chatOrUserId: string, threadId?: ThreadId) => void;
|
onSelectChatOrUser: (chatOrUserId: string, threadId?: ThreadId) => void;
|
||||||
@ -237,10 +242,10 @@ const ChatOrUserPicker = ({
|
|||||||
const isForum = chat?.isForum;
|
const isForum = chat?.isForum;
|
||||||
|
|
||||||
const isSelf = peer && !isApiPeerChat(peer) ? peer.isSelf : undefined;
|
const isSelf = peer && !isApiPeerChat(peer) ? peer.isSelf : undefined;
|
||||||
const isSelected = selectedIds?.includes(id);
|
const isSelected = selectedIds && includesChatSelectionKey(selectedIds, buildChatSelectionKey(id));
|
||||||
|
|
||||||
const selectedTopicsCount = isForum && selectedIds
|
const selectedTopicsCount = isForum && selectedIds
|
||||||
? selectedIds.filter((selId) => selId.startsWith(`${id}:`)).length
|
? selectedIds.filter((key) => key.peerId === id && key.topicId !== undefined).length
|
||||||
: 0;
|
: 0;
|
||||||
const hasSelectedTopics = selectedTopicsCount > 0;
|
const hasSelectedTopics = selectedTopicsCount > 0;
|
||||||
|
|
||||||
@ -342,8 +347,8 @@ const ChatOrUserPicker = ({
|
|||||||
onKeyDown={handleTopicKeyDown}
|
onKeyDown={handleTopicKeyDown}
|
||||||
>
|
>
|
||||||
{topicIds.map((topicId, i) => {
|
{topicIds.map((topicId, i) => {
|
||||||
const selectionId = `${forumId}:${topicId}`;
|
const chatSelectionKey = buildChatSelectionKey(forumId!, topicId);
|
||||||
const isTopicSelected = selectedIds?.includes(selectionId);
|
const isTopicSelected = selectedIds && includesChatSelectionKey(selectedIds, chatSelectionKey);
|
||||||
|
|
||||||
const topicCheckboxElement = isMultiSelect ? (
|
const topicCheckboxElement = isMultiSelect ? (
|
||||||
<div className={buildClassName('picker-checkbox', isTopicSelected && 'selected')}>
|
<div className={buildClassName('picker-checkbox', isTopicSelected && 'selected')}>
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import {
|
|||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { getActions, getGlobal, withGlobal } from '../../global';
|
import { getActions, getGlobal, withGlobal } from '../../global';
|
||||||
|
|
||||||
import type { ThreadId } from '../../types';
|
import type { ForwardTarget, ThreadId } from '../../types';
|
||||||
|
import type { ChatSelectionKey } from '../../util/keys/chatSelectionKey';
|
||||||
|
|
||||||
import { getChatTitle, getUserFirstOrLastName } from '../../global/helpers';
|
import { getChatTitle, getUserFirstOrLastName } from '../../global/helpers';
|
||||||
import {
|
import {
|
||||||
@ -78,7 +79,7 @@ const ForwardRecipientPicker: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const renderingIsStory = usePreviousDeprecated(isStory, true);
|
const renderingIsStory = usePreviousDeprecated(isStory, true);
|
||||||
const [isShown, markIsShown, unmarkIsShown] = useFlag();
|
const [isShown, markIsShown, unmarkIsShown] = useFlag();
|
||||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
const [selectedIds, setSelectedIds] = useState<ChatSelectionKey[]>([]);
|
||||||
const [caption, setCaption] = useState('');
|
const [caption, setCaption] = useState('');
|
||||||
const [isPaymentConfirmOpen, openPaymentConfirm, closePaymentConfirm] = useFlag();
|
const [isPaymentConfirmOpen, openPaymentConfirm, closePaymentConfirm] = useFlag();
|
||||||
const [shouldAutoApprove, setShouldAutoApprove] = useState(shouldPaidMessageAutoApprove);
|
const [shouldAutoApprove, setShouldAutoApprove] = useState(shouldPaidMessageAutoApprove);
|
||||||
@ -90,20 +91,20 @@ const ForwardRecipientPicker: FC<OwnProps & StateProps> = ({
|
|||||||
if (!selectedIds.length) return { paidChatsCount: 0, totalStars: 0, totalMessages: 0 };
|
if (!selectedIds.length) return { paidChatsCount: 0, totalStars: 0, totalMessages: 0 };
|
||||||
|
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
let paidChatsCount = 0;
|
const paidChatIds = new Set<string>();
|
||||||
let totalStars = 0;
|
let totalStars = 0;
|
||||||
const hasCaption = caption.trim().length > 0;
|
const hasCaption = caption.trim().length > 0;
|
||||||
const totalMessages = messageCount + (hasCaption ? 1 : 0);
|
const totalMessages = messageCount + (hasCaption ? 1 : 0);
|
||||||
|
|
||||||
for (const chatId of selectedIds) {
|
for (const { peerId: chatId } of selectedIds) {
|
||||||
const paidStars = selectPeerPaidMessagesStars(global, chatId);
|
const paidStars = selectPeerPaidMessagesStars(global, chatId);
|
||||||
if (paidStars) {
|
if (paidStars) {
|
||||||
paidChatsCount++;
|
paidChatIds.add(chatId);
|
||||||
totalStars += paidStars * totalMessages;
|
totalStars += paidStars * totalMessages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { paidChatsCount, totalStars, totalMessages };
|
return { paidChatsCount: paidChatIds.size, totalStars, totalMessages };
|
||||||
}, [selectedIds, messageCount, caption]);
|
}, [selectedIds, messageCount, caption]);
|
||||||
|
|
||||||
const canCopyLink = useMemo(() => {
|
const canCopyLink = useMemo(() => {
|
||||||
@ -179,7 +180,7 @@ const ForwardRecipientPicker: FC<OwnProps & StateProps> = ({
|
|||||||
exitForwardMode();
|
exitForwardMode();
|
||||||
}, [exitForwardMode]);
|
}, [exitForwardMode]);
|
||||||
|
|
||||||
const handleSelectedIdsChange = useLastCallback((ids: string[]) => {
|
const handleSelectedIdsChange = useLastCallback((ids: ChatSelectionKey[]) => {
|
||||||
setSelectedIds(ids);
|
setSelectedIds(ids);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,7 +197,8 @@ const ForwardRecipientPicker: FC<OwnProps & StateProps> = ({
|
|||||||
if (!selectedIds.length) return;
|
if (!selectedIds.length) return;
|
||||||
|
|
||||||
if (selectedIds.length === 1) {
|
if (selectedIds.length === 1) {
|
||||||
setForwardChatOrTopic({ chatId: selectedIds[0] });
|
const { peerId: chatId, topicId } = selectedIds[0];
|
||||||
|
setForwardChatOrTopic({ chatId, topicId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +223,11 @@ const ForwardRecipientPicker: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const executeForward = useLastCallback(() => {
|
const executeForward = useLastCallback(() => {
|
||||||
forwardToMultipleChats({ toChatIds: selectedIds, comment: caption || undefined });
|
const targets: ForwardTarget[] = selectedIds.map(({ peerId, topicId }) => ({
|
||||||
|
chatId: peerId,
|
||||||
|
topicId,
|
||||||
|
}));
|
||||||
|
forwardToMultipleChats({ targets, comment: caption || undefined });
|
||||||
|
|
||||||
showNotification({
|
showNotification({
|
||||||
message: lang('FwdMessagesToChats', { count: selectedIds.length }, { pluralValue: selectedIds.length }),
|
message: lang('FwdMessagesToChats', { count: selectedIds.length }, { pluralValue: selectedIds.length }),
|
||||||
|
|||||||
@ -2620,6 +2620,7 @@ interface ForwardToChatOptions {
|
|||||||
global: GlobalState;
|
global: GlobalState;
|
||||||
fromChat: ApiChat;
|
fromChat: ApiChat;
|
||||||
toChat: ApiChat;
|
toChat: ApiChat;
|
||||||
|
toThreadId?: ThreadId;
|
||||||
realMessages: ApiMessage[];
|
realMessages: ApiMessage[];
|
||||||
serviceMessages: ApiMessage[];
|
serviceMessages: ApiMessage[];
|
||||||
comment?: string;
|
comment?: string;
|
||||||
@ -2633,6 +2634,7 @@ function forwardMessagesToChat({
|
|||||||
global,
|
global,
|
||||||
fromChat,
|
fromChat,
|
||||||
toChat,
|
toChat,
|
||||||
|
toThreadId = MAIN_THREAD_ID,
|
||||||
realMessages,
|
realMessages,
|
||||||
serviceMessages,
|
serviceMessages,
|
||||||
comment,
|
comment,
|
||||||
@ -2642,12 +2644,21 @@ function forwardMessagesToChat({
|
|||||||
isCurrentUserPremium,
|
isCurrentUserPremium,
|
||||||
}: ForwardToChatOptions) {
|
}: ForwardToChatOptions) {
|
||||||
const sendAs = selectSendAs(global, toChat.id);
|
const sendAs = selectSendAs(global, toChat.id);
|
||||||
const lastMessageId = selectChatLastMessageId(global, toChat.id);
|
const threadInfo = toThreadId !== MAIN_THREAD_ID ? selectThreadInfo(global, toChat.id, toThreadId) : undefined;
|
||||||
|
const lastMessageId = toThreadId === MAIN_THREAD_ID
|
||||||
|
? selectChatLastMessageId(global, toChat.id)
|
||||||
|
: threadInfo?.lastMessageId;
|
||||||
const messagePriceInStars = selectPeerPaidMessagesStars(global, toChat.id);
|
const messagePriceInStars = selectPeerPaidMessagesStars(global, toChat.id);
|
||||||
|
const targetMessageList = {
|
||||||
|
chatId: toChat.id,
|
||||||
|
threadId: toThreadId,
|
||||||
|
type: 'thread',
|
||||||
|
} as const;
|
||||||
|
|
||||||
if (comment) {
|
if (comment) {
|
||||||
sendMessage(global, {
|
sendMessage(global, {
|
||||||
chat: toChat,
|
chat: toChat,
|
||||||
|
messageList: targetMessageList,
|
||||||
text: comment,
|
text: comment,
|
||||||
sendAs,
|
sendAs,
|
||||||
lastMessageId,
|
lastMessageId,
|
||||||
@ -2664,7 +2675,7 @@ function forwardMessagesToChat({
|
|||||||
const forwardParams: ForwardMessagesParams = {
|
const forwardParams: ForwardMessagesParams = {
|
||||||
fromChat,
|
fromChat,
|
||||||
toChat,
|
toChat,
|
||||||
toThreadId: MAIN_THREAD_ID,
|
toThreadId,
|
||||||
messages: slice,
|
messages: slice,
|
||||||
isSilent: true,
|
isSilent: true,
|
||||||
sendAs,
|
sendAs,
|
||||||
@ -2687,6 +2698,7 @@ function forwardMessagesToChat({
|
|||||||
|
|
||||||
sendMessage(global, {
|
sendMessage(global, {
|
||||||
chat: toChat,
|
chat: toChat,
|
||||||
|
messageList: targetMessageList,
|
||||||
text,
|
text,
|
||||||
entities,
|
entities,
|
||||||
sticker,
|
sticker,
|
||||||
@ -2699,7 +2711,7 @@ function forwardMessagesToChat({
|
|||||||
}
|
}
|
||||||
|
|
||||||
addActionHandler('forwardToMultipleChats', (global, actions, payload): ActionReturnType => {
|
addActionHandler('forwardToMultipleChats', (global, actions, payload): ActionReturnType => {
|
||||||
const { toChatIds, comment, tabId = getCurrentTabId() } = payload;
|
const { targets, comment, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
fromChatId, messageIds, withMyScore, noAuthors, noCaptions,
|
fromChatId, messageIds, withMyScore, noAuthors, noCaptions,
|
||||||
@ -2725,14 +2737,15 @@ addActionHandler('forwardToMultipleChats', (global, actions, payload): ActionRet
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const toChatId of toChatIds) {
|
for (const { chatId, topicId } of targets) {
|
||||||
const toChat = selectChat(global, toChatId);
|
const toChat = selectChat(global, chatId);
|
||||||
if (!toChat) continue;
|
if (!toChat) continue;
|
||||||
|
|
||||||
forwardMessagesToChat({
|
forwardMessagesToChat({
|
||||||
global,
|
global,
|
||||||
fromChat,
|
fromChat,
|
||||||
toChat,
|
toChat,
|
||||||
|
toThreadId: topicId || MAIN_THREAD_ID,
|
||||||
realMessages: forwardableRealMessages,
|
realMessages: forwardableRealMessages,
|
||||||
serviceMessages,
|
serviceMessages,
|
||||||
comment,
|
comment,
|
||||||
|
|||||||
@ -78,6 +78,7 @@ import type {
|
|||||||
CallSound,
|
CallSound,
|
||||||
ChatListType,
|
ChatListType,
|
||||||
ConfettiParams,
|
ConfettiParams,
|
||||||
|
ForwardTarget,
|
||||||
GiftProfileFilterOptions,
|
GiftProfileFilterOptions,
|
||||||
GlobalSearchContent,
|
GlobalSearchContent,
|
||||||
IAnchorPosition,
|
IAnchorPosition,
|
||||||
@ -2024,7 +2025,7 @@ export interface ActionPayloads {
|
|||||||
exitForwardMode: WithTabId | undefined;
|
exitForwardMode: WithTabId | undefined;
|
||||||
changeRecipient: WithTabId | undefined;
|
changeRecipient: WithTabId | undefined;
|
||||||
forwardToMultipleChats: {
|
forwardToMultipleChats: {
|
||||||
toChatIds: string[];
|
targets: ForwardTarget[];
|
||||||
comment?: string;
|
comment?: string;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
forwardToSavedMessages: {
|
forwardToSavedMessages: {
|
||||||
|
|||||||
@ -105,6 +105,11 @@ export interface IDocumentGroup {
|
|||||||
|
|
||||||
export type ThreadId = string | number;
|
export type ThreadId = string | number;
|
||||||
|
|
||||||
|
export type ForwardTarget = {
|
||||||
|
chatId: string;
|
||||||
|
topicId?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type ThemeKey = 'light' | 'dark';
|
export type ThemeKey = 'light' | 'dark';
|
||||||
export type AnimationLevel = 0 | 1 | 2;
|
export type AnimationLevel = 0 | 1 | 2;
|
||||||
export type FoldersPosition = 'top' | 'left';
|
export type FoldersPosition = 'top' | 'left';
|
||||||
|
|||||||
24
src/util/keys/chatSelectionKey.ts
Normal file
24
src/util/keys/chatSelectionKey.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export type ChatSelectionKey = {
|
||||||
|
peerId: string;
|
||||||
|
topicId?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildChatSelectionKey(peerId: string, topicId?: number): ChatSelectionKey {
|
||||||
|
return { peerId, topicId };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function areChatSelectionKeysEqual(a: ChatSelectionKey, b: ChatSelectionKey): boolean {
|
||||||
|
return a.peerId === b.peerId && a.topicId === b.topicId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function includesChatSelectionKey(arr: ChatSelectionKey[], key: ChatSelectionKey): boolean {
|
||||||
|
return arr.some((k) => areChatSelectionKeysEqual(k, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findChatSelectionKeyIndex(arr: ChatSelectionKey[], key: ChatSelectionKey): number {
|
||||||
|
return arr.findIndex((k) => areChatSelectionKeysEqual(k, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChatSelectionKeyHash(key: ChatSelectionKey): string {
|
||||||
|
return key.topicId !== undefined ? `${key.peerId}:${key.topicId}` : key.peerId;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user