Message: Fix downloading scheduled media (#3174)
This commit is contained in:
parent
a71a3bc53b
commit
96670d0454
@ -185,6 +185,7 @@ export function buildApiMessageWithChatId(
|
|||||||
if (action) {
|
if (action) {
|
||||||
content.action = action;
|
content.action = action;
|
||||||
}
|
}
|
||||||
|
const isScheduled = mtpMessage.date > (Math.round(Date.now() / 1000) + getServerTimeOffset());
|
||||||
|
|
||||||
const isInvoiceMedia = mtpMessage.media instanceof GramJs.MessageMediaInvoice
|
const isInvoiceMedia = mtpMessage.media instanceof GramJs.MessageMediaInvoice
|
||||||
&& Boolean(mtpMessage.media.extendedMedia);
|
&& Boolean(mtpMessage.media.extendedMedia);
|
||||||
@ -216,6 +217,7 @@ export function buildApiMessageWithChatId(
|
|||||||
senderId: fromId || (mtpMessage.out && mtpMessage.post && currentUserId) || chatId,
|
senderId: fromId || (mtpMessage.out && mtpMessage.post && currentUserId) || chatId,
|
||||||
views: mtpMessage.views,
|
views: mtpMessage.views,
|
||||||
forwards: mtpMessage.forwards,
|
forwards: mtpMessage.forwards,
|
||||||
|
isScheduled,
|
||||||
isFromScheduled: mtpMessage.fromScheduled,
|
isFromScheduled: mtpMessage.fromScheduled,
|
||||||
isSilent: mtpMessage.silent,
|
isSilent: mtpMessage.silent,
|
||||||
isPinned: mtpMessage.pinned,
|
isPinned: mtpMessage.pinned,
|
||||||
|
|||||||
@ -53,7 +53,7 @@ type OwnProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
isSelectable?: boolean;
|
isSelectable?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
isDownloading: boolean;
|
isDownloading?: boolean;
|
||||||
isTranscribing?: boolean;
|
isTranscribing?: boolean;
|
||||||
isTranscribed?: boolean;
|
isTranscribed?: boolean;
|
||||||
canDownload?: boolean;
|
canDownload?: boolean;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ type OwnProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
sender?: string;
|
sender?: string;
|
||||||
autoLoadFileMaxSizeMb?: number;
|
autoLoadFileMaxSizeMb?: number;
|
||||||
isDownloading: boolean;
|
isDownloading?: boolean;
|
||||||
onCancelUpload?: () => void;
|
onCancelUpload?: () => void;
|
||||||
onMediaClick?: () => void;
|
onMediaClick?: () => void;
|
||||||
onDateClick?: (messageId: number, chatId: string) => void;
|
onDateClick?: (messageId: number, chatId: string) => void;
|
||||||
|
|||||||
@ -103,7 +103,7 @@ const AudioResults: FC<OwnProps & StateProps> = ({
|
|||||||
onPlay={handlePlayAudio}
|
onPlay={handlePlayAudio}
|
||||||
onDateClick={handleMessageFocus}
|
onDateClick={handleMessageFocus}
|
||||||
canDownload={!chatsById[message.chatId]?.isProtected && !message.isProtected}
|
canDownload={!chatsById[message.chatId]?.isProtected && !message.isProtected}
|
||||||
isDownloading={activeDownloads[message.chatId]?.includes(message.id)}
|
isDownloading={activeDownloads[message.chatId]?.ids?.includes(message.id)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -105,7 +105,7 @@ const FileResults: FC<OwnProps & StateProps> = ({
|
|||||||
smaller
|
smaller
|
||||||
sender={getSenderName(lang, message, chatsById, usersById)}
|
sender={getSenderName(lang, message, chatsById, usersById)}
|
||||||
className="scroll-item"
|
className="scroll-item"
|
||||||
isDownloading={activeDownloads[message.chatId]?.includes(message.id)}
|
isDownloading={activeDownloads[message.chatId]?.ids?.includes(message.id)}
|
||||||
observeIntersection={observeIntersectionForMedia}
|
observeIntersection={observeIntersectionForMedia}
|
||||||
onDateClick={handleMessageFocus}
|
onDateClick={handleMessageFocus}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { GlobalState } from '../../../../global/types';
|
import type { GlobalState, TabState } from '../../../../global/types';
|
||||||
import type {
|
import type {
|
||||||
ApiChat, ApiGlobalMessageSearchType, ApiMessage, ApiUser,
|
ApiChat, ApiGlobalMessageSearchType, ApiMessage, ApiUser,
|
||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
@ -15,7 +15,7 @@ export type StateProps = {
|
|||||||
foundIds?: string[];
|
foundIds?: string[];
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
searchChatId?: string;
|
searchChatId?: string;
|
||||||
activeDownloads: Record<string, number[]>;
|
activeDownloads: TabState['activeDownloads']['byChatId'];
|
||||||
isChatProtected?: boolean;
|
isChatProtected?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import { memo, useCallback, useEffect } from '../../lib/teact/teact';
|
import { memo, useCallback, useEffect } from '../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../global';
|
import { getActions, getGlobal, withGlobal } from '../../global';
|
||||||
|
|
||||||
import type { GlobalState, TabState } from '../../global/types';
|
import type { GlobalState, TabState } from '../../global/types';
|
||||||
import type { ApiMessage } from '../../api/types';
|
import type { ApiMessage } from '../../api/types';
|
||||||
@ -13,6 +13,7 @@ import download from '../../util/download';
|
|||||||
import {
|
import {
|
||||||
getMessageContentFilename, getMessageMediaFormat, getMessageMediaHash,
|
getMessageContentFilename, getMessageMediaFormat, getMessageMediaHash,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { compact } from '../../util/iteratees';
|
||||||
|
|
||||||
import useRunDebounced from '../../hooks/useRunDebounced';
|
import useRunDebounced from '../../hooks/useRunDebounced';
|
||||||
|
|
||||||
@ -28,7 +29,6 @@ const downloadedMessages = new Set<ApiMessage>();
|
|||||||
|
|
||||||
const DownloadManager: FC<StateProps> = ({
|
const DownloadManager: FC<StateProps> = ({
|
||||||
activeDownloads,
|
activeDownloads,
|
||||||
messages,
|
|
||||||
}) => {
|
}) => {
|
||||||
const { cancelMessagesMediaDownload, showNotification } = getActions();
|
const { cancelMessagesMediaDownload, showNotification } = getActions();
|
||||||
|
|
||||||
@ -45,9 +45,16 @@ const DownloadManager: FC<StateProps> = ({
|
|||||||
}, [cancelMessagesMediaDownload, runDebounced]);
|
}, [cancelMessagesMediaDownload, runDebounced]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const activeMessages = Object.entries(activeDownloads).map(([chatId, messageIds]) => (
|
// No need for expensive global updates on messages, so we avoid them
|
||||||
messageIds.map((id) => messages![chatId].byId[id])
|
const messages = getGlobal().messages.byChatId;
|
||||||
)).flat();
|
const scheduledMessages = getGlobal().scheduledMessages.byChatId;
|
||||||
|
|
||||||
|
const activeMessages = Object.entries(activeDownloads).map(([chatId, chatActiveDownloads]) => {
|
||||||
|
const chatMessages = chatActiveDownloads.ids?.map((id) => messages[chatId]?.byId[id]);
|
||||||
|
const chatScheduledMessages = chatActiveDownloads.scheduledIds?.map((id) => scheduledMessages[chatId]?.byId[id]);
|
||||||
|
|
||||||
|
return compact([...chatMessages || [], ...chatScheduledMessages || []]);
|
||||||
|
}).flat();
|
||||||
|
|
||||||
if (!activeMessages.length) {
|
if (!activeMessages.length) {
|
||||||
processedMessages.clear();
|
processedMessages.clear();
|
||||||
@ -104,7 +111,7 @@ const DownloadManager: FC<StateProps> = ({
|
|||||||
handleMessageDownloaded(message);
|
handleMessageDownloaded(message);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [messages, activeDownloads, cancelMessagesMediaDownload, handleMessageDownloaded, showNotification]);
|
}, [activeDownloads, cancelMessagesMediaDownload, handleMessageDownloaded, showNotification]);
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
@ -112,11 +119,9 @@ const DownloadManager: FC<StateProps> = ({
|
|||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const activeDownloads = selectTabState(global).activeDownloads.byChatId;
|
const activeDownloads = selectTabState(global).activeDownloads.byChatId;
|
||||||
const hasActiveDownloads = Object.values(activeDownloads).some((messageIds) => messageIds.length);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeDownloads,
|
activeDownloads,
|
||||||
messages: hasActiveDownloads ? global.messages.byChatId : undefined,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(DownloadManager));
|
)(DownloadManager));
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import DeleteProfilePhotoModal from '../common/DeleteProfilePhotoModal';
|
|||||||
import './MediaViewerActions.scss';
|
import './MediaViewerActions.scss';
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
isDownloading: boolean;
|
isDownloading?: boolean;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
isChatProtected?: boolean;
|
isChatProtected?: boolean;
|
||||||
canDelete?: boolean;
|
canDelete?: boolean;
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { getActions, getGlobal, withGlobal } from '../../../global';
|
|||||||
import withSelectControl from './hocs/withSelectControl';
|
import withSelectControl from './hocs/withSelectControl';
|
||||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||||
import {
|
import {
|
||||||
selectActiveDownloadIds,
|
selectActiveDownloads,
|
||||||
selectCanAutoLoadMedia,
|
selectCanAutoLoadMedia,
|
||||||
selectCanAutoPlayMedia,
|
selectCanAutoPlayMedia,
|
||||||
selectTheme,
|
selectTheme,
|
||||||
@ -40,7 +40,7 @@ type OwnProps = {
|
|||||||
type StateProps = {
|
type StateProps = {
|
||||||
theme: ISettings['theme'];
|
theme: ISettings['theme'];
|
||||||
uploadsById: GlobalState['fileUploads']['byMessageLocalId'];
|
uploadsById: GlobalState['fileUploads']['byMessageLocalId'];
|
||||||
activeDownloadIds: number[];
|
activeDownloadIds?: number[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const Album: FC<OwnProps & StateProps> = ({
|
const Album: FC<OwnProps & StateProps> = ({
|
||||||
@ -92,7 +92,7 @@ const Album: FC<OwnProps & StateProps> = ({
|
|||||||
isProtected={isProtected}
|
isProtected={isProtected}
|
||||||
onClick={onMediaClick}
|
onClick={onMediaClick}
|
||||||
onCancelUpload={handleCancelUpload}
|
onCancelUpload={handleCancelUpload}
|
||||||
isDownloading={activeDownloadIds.includes(message.id)}
|
isDownloading={activeDownloadIds?.includes(message.id)}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -110,7 +110,7 @@ const Album: FC<OwnProps & StateProps> = ({
|
|||||||
isProtected={isProtected}
|
isProtected={isProtected}
|
||||||
onClick={onMediaClick}
|
onClick={onMediaClick}
|
||||||
onCancelUpload={handleCancelUpload}
|
onCancelUpload={handleCancelUpload}
|
||||||
isDownloading={activeDownloadIds.includes(message.id)}
|
isDownloading={activeDownloadIds?.includes(message.id)}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -135,11 +135,13 @@ export default withGlobal<OwnProps>(
|
|||||||
(global, { album }): StateProps => {
|
(global, { album }): StateProps => {
|
||||||
const { chatId } = album.mainMessage;
|
const { chatId } = album.mainMessage;
|
||||||
const theme = selectTheme(global);
|
const theme = selectTheme(global);
|
||||||
const activeDownloadIds = selectActiveDownloadIds(global, chatId);
|
const activeDownloads = selectActiveDownloads(global, chatId);
|
||||||
|
const isScheduled = album.mainMessage.isScheduled;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme,
|
theme,
|
||||||
uploadsById: global.fileUploads.byMessageLocalId,
|
uploadsById: global.fileUploads.byMessageLocalId,
|
||||||
activeDownloadIds,
|
activeDownloadIds: isScheduled ? activeDownloads?.scheduledIds : activeDownloads?.ids,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Album);
|
)(Album);
|
||||||
|
|||||||
@ -4,14 +4,14 @@ import React, {
|
|||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { MessageListType } from '../../../global/types';
|
import type { MessageListType, TabState } from '../../../global/types';
|
||||||
import type {
|
import type {
|
||||||
ApiAvailableReaction, ApiStickerSetInfo, ApiMessage, ApiStickerSet, ApiChatReactions, ApiReaction, ApiThreadInfo,
|
ApiAvailableReaction, ApiStickerSetInfo, ApiMessage, ApiStickerSet, ApiChatReactions, ApiReaction, ApiThreadInfo,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { IAlbum, IAnchorPosition } from '../../../types';
|
import type { IAlbum, IAnchorPosition } from '../../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
selectActiveDownloadIds,
|
selectActiveDownloads,
|
||||||
selectAllowedMessageActions,
|
selectAllowedMessageActions,
|
||||||
selectCanPlayAnimatedEmojis,
|
selectCanPlayAnimatedEmojis,
|
||||||
selectCanScheduleUntilOnline,
|
selectCanScheduleUntilOnline,
|
||||||
@ -101,7 +101,7 @@ type StateProps = {
|
|||||||
canSaveGif?: boolean;
|
canSaveGif?: boolean;
|
||||||
canRevote?: boolean;
|
canRevote?: boolean;
|
||||||
canClosePoll?: boolean;
|
canClosePoll?: boolean;
|
||||||
activeDownloads: number[];
|
activeDownloads?: TabState['activeDownloads']['byChatId'][number];
|
||||||
canShowSeenBy?: boolean;
|
canShowSeenBy?: boolean;
|
||||||
enabledReactions?: ApiChatReactions;
|
enabledReactions?: ApiChatReactions;
|
||||||
canScheduleUntilOnline?: boolean;
|
canScheduleUntilOnline?: boolean;
|
||||||
@ -249,8 +249,15 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
return Object.keys(message.seenByDates).slice(0, 3).map((id) => usersById[id]).filter(Boolean);
|
return Object.keys(message.seenByDates).slice(0, 3).map((id) => usersById[id]).filter(Boolean);
|
||||||
}, [message.reactions?.recentReactions, message.seenByDates]);
|
}, [message.reactions?.recentReactions, message.seenByDates]);
|
||||||
|
|
||||||
const isDownloading = album ? album.messages.some((msg) => activeDownloads.includes(msg.id))
|
const isDownloading = useMemo(() => {
|
||||||
: activeDownloads.includes(message.id);
|
if (album) {
|
||||||
|
return album.messages.some((msg) => {
|
||||||
|
return activeDownloads?.[message.isScheduled ? 'scheduledIds' : 'ids']?.includes(msg.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeDownloads?.[message.isScheduled ? 'scheduledIds' : 'ids']?.includes(message.id);
|
||||||
|
}, [activeDownloads, album, message]);
|
||||||
|
|
||||||
const handleDelete = useCallback(() => {
|
const handleDelete = useCallback(() => {
|
||||||
setIsMenuOpen(false);
|
setIsMenuOpen(false);
|
||||||
@ -566,7 +573,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { message, messageListType, detectedLanguage }): StateProps => {
|
(global, { message, messageListType, detectedLanguage }): StateProps => {
|
||||||
const { threadId } = selectCurrentMessageList(global) || {};
|
const { threadId } = selectCurrentMessageList(global) || {};
|
||||||
const activeDownloads = selectActiveDownloadIds(global, message.chatId);
|
const activeDownloads = selectActiveDownloads(global, message.chatId);
|
||||||
const chat = selectChat(global, message.chatId);
|
const chat = selectChat(global, message.chatId);
|
||||||
const { seenByExpiresAt, seenByMaxChatMembers, maxUniqueReactions } = global.appConfig || {};
|
const { seenByExpiresAt, seenByMaxChatMembers, maxUniqueReactions } = global.appConfig || {};
|
||||||
const {
|
const {
|
||||||
|
|||||||
@ -228,7 +228,7 @@ type StateProps = {
|
|||||||
isInSelectMode?: boolean;
|
isInSelectMode?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
isGroupSelected?: boolean;
|
isGroupSelected?: boolean;
|
||||||
isDownloading: boolean;
|
isDownloading?: boolean;
|
||||||
threadId?: number;
|
threadId?: number;
|
||||||
isPinnedList?: boolean;
|
isPinnedList?: boolean;
|
||||||
isPinned?: boolean;
|
isPinned?: boolean;
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export type OwnProps = {
|
|||||||
dimensions?: IMediaDimensions & { isSmall?: boolean };
|
dimensions?: IMediaDimensions & { isSmall?: boolean };
|
||||||
asForwarded?: boolean;
|
asForwarded?: boolean;
|
||||||
nonInteractive?: boolean;
|
nonInteractive?: boolean;
|
||||||
isDownloading: boolean;
|
isDownloading?: boolean;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
theme: ISettings['theme'];
|
theme: ISettings['theme'];
|
||||||
onClick?: (id: number) => void;
|
onClick?: (id: number) => void;
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export type OwnProps = {
|
|||||||
dimensions?: IMediaDimensions;
|
dimensions?: IMediaDimensions;
|
||||||
asForwarded?: boolean;
|
asForwarded?: boolean;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
isDownloading: boolean;
|
isDownloading?: boolean;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
onClick?: (id: number) => void;
|
onClick?: (id: number) => void;
|
||||||
onCancelUpload?: (message: ApiMessage) => void;
|
onCancelUpload?: (message: ApiMessage) => void;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import {
|
|||||||
getHasAdminRight, isChatAdmin, isChatChannel, isChatGroup, isUserBot, isUserId, isUserRightBanned,
|
getHasAdminRight, isChatAdmin, isChatChannel, isChatGroup, isUserBot, isUserId, isUserRightBanned,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
import {
|
import {
|
||||||
selectActiveDownloadIds,
|
selectActiveDownloads,
|
||||||
selectChat,
|
selectChat,
|
||||||
selectChatFullInfo,
|
selectChatFullInfo,
|
||||||
selectChatMessages,
|
selectChatMessages,
|
||||||
@ -97,7 +97,7 @@ type StateProps = {
|
|||||||
isRightColumnShown: boolean;
|
isRightColumnShown: boolean;
|
||||||
isRestricted?: boolean;
|
isRestricted?: boolean;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
activeDownloadIds: number[];
|
activeDownloadIds?: number[];
|
||||||
isChatProtected?: boolean;
|
isChatProtected?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
|||||||
withDate
|
withDate
|
||||||
smaller
|
smaller
|
||||||
className="scroll-item"
|
className="scroll-item"
|
||||||
isDownloading={activeDownloadIds.includes(id)}
|
isDownloading={activeDownloadIds?.includes(id)}
|
||||||
observeIntersection={observeIntersectionForMedia}
|
observeIntersection={observeIntersectionForMedia}
|
||||||
onDateClick={handleMessageFocus}
|
onDateClick={handleMessageFocus}
|
||||||
/>
|
/>
|
||||||
@ -401,7 +401,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
|||||||
onPlay={handlePlayAudio}
|
onPlay={handlePlayAudio}
|
||||||
onDateClick={handleMessageFocus}
|
onDateClick={handleMessageFocus}
|
||||||
canDownload={!isChatProtected && !messagesById[id].isProtected}
|
canDownload={!isChatProtected && !messagesById[id].isProtected}
|
||||||
isDownloading={activeDownloadIds.includes(id)}
|
isDownloading={activeDownloadIds?.includes(id)}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : resultType === 'voice' ? (
|
) : resultType === 'voice' ? (
|
||||||
@ -418,7 +418,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
|||||||
onPlay={handlePlayAudio}
|
onPlay={handlePlayAudio}
|
||||||
onDateClick={handleMessageFocus}
|
onDateClick={handleMessageFocus}
|
||||||
canDownload={!isChatProtected && !messagesById[id].isProtected}
|
canDownload={!isChatProtected && !messagesById[id].isProtected}
|
||||||
isDownloading={activeDownloadIds.includes(id)}
|
isDownloading={activeDownloadIds?.includes(id)}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : resultType === 'members' ? (
|
) : resultType === 'members' ? (
|
||||||
@ -537,7 +537,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const canAddMembers = hasMembersTab && chat
|
const canAddMembers = hasMembersTab && chat
|
||||||
&& (getHasAdminRight(chat, 'inviteUsers') || !isUserRightBanned(chat, 'inviteUsers') || chat.isCreator);
|
&& (getHasAdminRight(chat, 'inviteUsers') || !isUserRightBanned(chat, 'inviteUsers') || chat.isCreator);
|
||||||
const canDeleteMembers = hasMembersTab && chat && (getHasAdminRight(chat, 'banUsers') || chat.isCreator);
|
const canDeleteMembers = hasMembersTab && chat && (getHasAdminRight(chat, 'banUsers') || chat.isCreator);
|
||||||
const activeDownloadIds = selectActiveDownloadIds(global, chatId);
|
const activeDownloads = selectActiveDownloads(global, chatId);
|
||||||
|
|
||||||
let hasCommonChatsTab;
|
let hasCommonChatsTab;
|
||||||
let resolvedUserId;
|
let resolvedUserId;
|
||||||
@ -564,7 +564,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
isRightColumnShown: selectIsRightColumnShown(global, isMobile),
|
isRightColumnShown: selectIsRightColumnShown(global, isMobile),
|
||||||
isRestricted: chat?.isRestricted,
|
isRestricted: chat?.isRestricted,
|
||||||
lastSyncTime: global.lastSyncTime,
|
lastSyncTime: global.lastSyncTime,
|
||||||
activeDownloadIds,
|
activeDownloadIds: activeDownloads?.ids,
|
||||||
usersById,
|
usersById,
|
||||||
userStatusesById,
|
userStatusesById,
|
||||||
chatsById,
|
chatsById,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import type { ApiMessage } from '../../../api/types';
|
|||||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||||
import { FocusDirection } from '../../../types';
|
import { FocusDirection } from '../../../types';
|
||||||
import type {
|
import type {
|
||||||
TabState, GlobalState, ActionReturnType,
|
GlobalState, ActionReturnType,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -23,6 +23,8 @@ import {
|
|||||||
replaceTabThreadParam,
|
replaceTabThreadParam,
|
||||||
updateFocusDirection,
|
updateFocusDirection,
|
||||||
updateFocusedMessage,
|
updateFocusedMessage,
|
||||||
|
cancelMessageMediaDownload,
|
||||||
|
addActiveMessageMediaDownload,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
selectCurrentChat,
|
selectCurrentChat,
|
||||||
@ -557,49 +559,23 @@ addActionHandler('openForwardMenuForSelectedMessages', (global, actions, payload
|
|||||||
addActionHandler('cancelMessageMediaDownload', (global, actions, payload): ActionReturnType => {
|
addActionHandler('cancelMessageMediaDownload', (global, actions, payload): ActionReturnType => {
|
||||||
const { message, tabId = getCurrentTabId() } = payload;
|
const { message, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
const tabState = selectTabState(global, tabId);
|
return cancelMessageMediaDownload(global, message, tabId);
|
||||||
const byChatId = tabState.activeDownloads.byChatId[message.chatId];
|
|
||||||
if (!byChatId || !byChatId.length) return;
|
|
||||||
|
|
||||||
global = updateTabState(global, {
|
|
||||||
activeDownloads: {
|
|
||||||
byChatId: {
|
|
||||||
...tabState.activeDownloads.byChatId,
|
|
||||||
[message.chatId]: byChatId.filter((id) => id !== message.id),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, tabId);
|
|
||||||
setGlobal(global);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('cancelMessagesMediaDownload', (global, actions, payload): ActionReturnType => {
|
addActionHandler('cancelMessagesMediaDownload', (global, actions, payload): ActionReturnType => {
|
||||||
const { messages, tabId = getCurrentTabId() } = payload;
|
const { messages, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
const byChatId = selectTabState(global, tabId).activeDownloads.byChatId;
|
for (const message of messages) {
|
||||||
const newByChatId: TabState['activeDownloads']['byChatId'] = {};
|
global = cancelMessageMediaDownload(global, message, tabId);
|
||||||
Object.keys(byChatId).forEach((chatId) => {
|
}
|
||||||
newByChatId[chatId] = byChatId[chatId].filter((id) => !messages.find((message) => message.id === id));
|
|
||||||
});
|
return global;
|
||||||
return updateTabState(global, {
|
|
||||||
activeDownloads: {
|
|
||||||
byChatId: newByChatId,
|
|
||||||
},
|
|
||||||
}, tabId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('downloadMessageMedia', (global, actions, payload): ActionReturnType => {
|
addActionHandler('downloadMessageMedia', (global, actions, payload): ActionReturnType => {
|
||||||
const { message, tabId = getCurrentTabId() } = payload;
|
const { message, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
const tabState = selectTabState(global, tabId);
|
return addActiveMessageMediaDownload(global, message, tabId);
|
||||||
global = updateTabState(global, {
|
|
||||||
activeDownloads: {
|
|
||||||
byChatId: {
|
|
||||||
...tabState.activeDownloads.byChatId,
|
|
||||||
[message.chatId]: [...(tabState.activeDownloads.byChatId[message.chatId] || []), message.id],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, tabId);
|
|
||||||
setGlobal(global);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('downloadSelectedMessages', (global, actions, payload): ActionReturnType => {
|
addActionHandler('downloadSelectedMessages', (global, actions, payload): ActionReturnType => {
|
||||||
|
|||||||
@ -230,7 +230,7 @@ export function getMessageContentFilename(message: ApiMessage) {
|
|||||||
return content.audio.fileName;
|
return content.audio.fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseFilename = getMessageKey(message);
|
const baseFilename = `${getMessageKey(message)}${message.isScheduled ? '_scheduled' : ''}`;
|
||||||
|
|
||||||
if (photo) {
|
if (photo) {
|
||||||
return `${baseFilename}.jpg`;
|
return `${baseFilename}.jpg`;
|
||||||
|
|||||||
@ -691,3 +691,53 @@ export function updateTopicLastMessageId<T extends GlobalState>(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addActiveMessageMediaDownload<T extends GlobalState>(
|
||||||
|
global: T,
|
||||||
|
message: ApiMessage,
|
||||||
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
|
) {
|
||||||
|
const tabState = selectTabState(global, tabId);
|
||||||
|
const byChatId = tabState.activeDownloads.byChatId[message.chatId] || {};
|
||||||
|
const currentIds = (message.isScheduled ? byChatId?.scheduledIds : byChatId?.ids) || [];
|
||||||
|
|
||||||
|
global = updateTabState(global, {
|
||||||
|
activeDownloads: {
|
||||||
|
byChatId: {
|
||||||
|
...tabState.activeDownloads.byChatId,
|
||||||
|
[message.chatId]: {
|
||||||
|
...byChatId,
|
||||||
|
[message.isScheduled ? 'scheduledIds' : 'ids']: unique([...currentIds, message.id]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cancelMessageMediaDownload<T extends GlobalState>(
|
||||||
|
global: T,
|
||||||
|
message: ApiMessage,
|
||||||
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
|
) {
|
||||||
|
const tabState = selectTabState(global, tabId);
|
||||||
|
const byChatId = tabState.activeDownloads.byChatId[message.chatId];
|
||||||
|
if (!byChatId) return global;
|
||||||
|
|
||||||
|
const currentIds = (message.isScheduled ? byChatId.scheduledIds : byChatId.ids) || [];
|
||||||
|
|
||||||
|
global = updateTabState(global, {
|
||||||
|
activeDownloads: {
|
||||||
|
byChatId: {
|
||||||
|
...tabState.activeDownloads.byChatId,
|
||||||
|
[message.chatId]: {
|
||||||
|
...byChatId,
|
||||||
|
[message.isScheduled ? 'scheduledIds' : 'ids']: currentIds.filter((id) => id !== message.id),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|||||||
@ -725,14 +725,17 @@ export function selectIsDownloading<T extends GlobalState>(
|
|||||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
) {
|
) {
|
||||||
const activeInChat = selectTabState(global, tabId).activeDownloads.byChatId[message.chatId];
|
const activeInChat = selectTabState(global, tabId).activeDownloads.byChatId[message.chatId];
|
||||||
return activeInChat ? activeInChat.includes(message.id) : false;
|
if (!activeInChat) return false;
|
||||||
|
|
||||||
|
return Boolean(message.isScheduled
|
||||||
|
? activeInChat.scheduledIds?.includes(message.id) : activeInChat.ids?.includes(message.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectActiveDownloadIds<T extends GlobalState>(
|
export function selectActiveDownloads<T extends GlobalState>(
|
||||||
global: T, chatId: string,
|
global: T, chatId: string,
|
||||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
) {
|
) {
|
||||||
return selectTabState(global, tabId).activeDownloads.byChatId[chatId] || MEMO_EMPTY_ARRAY;
|
return selectTabState(global, tabId).activeDownloads.byChatId[chatId];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectUploadProgress<T extends GlobalState>(global: T, message: ApiMessage) {
|
export function selectUploadProgress<T extends GlobalState>(global: T, message: ApiMessage) {
|
||||||
|
|||||||
@ -440,7 +440,12 @@ export type TabState = {
|
|||||||
openedCustomEmojiSetIds?: string[];
|
openedCustomEmojiSetIds?: string[];
|
||||||
|
|
||||||
activeDownloads: {
|
activeDownloads: {
|
||||||
byChatId: Record<string, number[]>;
|
byChatId: {
|
||||||
|
[chatId: string]: {
|
||||||
|
ids?: number[];
|
||||||
|
scheduledIds?: number[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
statistics: {
|
statistics: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user