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