diff --git a/src/components/appSearchSuper..ts b/src/components/appSearchSuper..ts index 35823088..c5de3257 100644 --- a/src/components/appSearchSuper..ts +++ b/src/components/appSearchSuper..ts @@ -76,6 +76,7 @@ import wrapVideo from './wrappers/video'; import noop from '../helpers/noop'; import wrapMediaSpoiler, {onMediaSpoilerClick} from './wrappers/mediaSpoiler'; import filterAsync from '../helpers/array/filterAsync'; +import ChatContextMenu from './chat/contextMenu'; // const testScroll = false; @@ -111,6 +112,9 @@ class SearchContextMenu { private mid: number; private isSelected: boolean; private managers: AppManagers; + private noForwards: boolean; + private message: MyMessage; + private selectedMessages: MyMessage[]; constructor( private attachTo: HTMLElement, @@ -143,14 +147,19 @@ class SearchContextMenu { this.peerId = item.dataset.peerId.toPeerId(); this.mid = +item.dataset.mid; this.isSelected = searchSuper.selection.isMidSelected(this.peerId, this.mid); + this.message = await this.managers.appMessagesManager.getMessageByPeer(this.peerId, this.mid); + this.noForwards = searchSuper.selection.isSelecting ? + this.searchSuper.selection.selectionForwardBtn.classList.contains('hide') : + !(await this.managers.appMessagesManager.canForward(this.message)); + this.selectedMessages = searchSuper.selection.isSelecting ? await searchSuper.selection.getSelectedMessages() : undefined; await Promise.all(this.buttons.map(async(button) => { let good: boolean; - if(this.isSelected && !button.withSelection) { + if(this.searchSuper.selection.isSelecting && !button.withSelection) { good = false; } else { - good = button.verify ? await button.verify() : true; + good = button.verify ? !!(await button.verify()) : true; } button.element.classList.toggle('hide', !good); @@ -183,13 +192,23 @@ class SearchContextMenu { icon: 'forward', text: 'Forward', onClick: this.onForwardClick, - verify: async() => this.managers.appMessagesManager.canForward(await this.managers.appMessagesManager.getMessageByPeer(this.peerId, this.mid)) + verify: () => !this.noForwards }, { icon: 'forward', text: 'Message.Context.Selection.Forward', onClick: this.onForwardClick, - verify: () => this.isSelected && - !this.searchSuper.selection.selectionForwardBtn.classList.contains('hide'), + verify: () => this.searchSuper.selection.isSelecting && !this.noForwards, + withSelection: true + }, { + icon: 'download', + text: 'MediaViewer.Context.Download', + onClick: () => ChatContextMenu.onDownloadClick(this.message, this.noForwards), + verify: () => !this.searchSuper.selection.isSelecting && ChatContextMenu.canDownload(this.message, undefined, this.noForwards) + }, { + icon: 'download', + text: 'Message.Context.Selection.Download', + onClick: () => ChatContextMenu.onDownloadClick(this.selectedMessages, this.noForwards), + verify: () => this.searchSuper.selection.isSelecting && ChatContextMenu.canDownload(this.selectedMessages, undefined, this.noForwards), withSelection: true }, { icon: 'message', @@ -199,7 +218,9 @@ class SearchContextMenu { }, { icon: 'select', text: 'Message.Context.Select', - onClick: this.onSelectClick + onClick: this.onSelectClick, + verify: () => !this.isSelected, + withSelection: true }, { icon: 'select', text: 'Message.Context.Selection.Clear', @@ -210,12 +231,12 @@ class SearchContextMenu { icon: 'delete danger', text: 'Delete', onClick: this.onDeleteClick, - verify: async() => this.managers.appMessagesManager.canDeleteMessage(await this.managers.appMessagesManager.getMessageByPeer(this.peerId, this.mid)) + verify: () => !this.searchSuper.selection.isSelecting && this.managers.appMessagesManager.canDeleteMessage(this.message) }, { icon: 'delete danger', text: 'Message.Context.Selection.Delete', onClick: this.onDeleteClick, - verify: () => this.isSelected && !this.searchSuper.selection.selectionDeleteBtn.classList.contains('hide'), + verify: () => this.searchSuper.selection.isSelecting && !this.searchSuper.selection.selectionDeleteBtn.classList.contains('hide'), withSelection: true }]; diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index 7f9d74c5..d07c427d 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -37,7 +37,7 @@ import positionMenu, {MenuPositionPadding} from '../../helpers/positionMenu'; import contextMenuController from '../../helpers/contextMenuController'; import {attachContextMenuListener} from '../../helpers/dom/attachContextMenuListener'; import filterAsync from '../../helpers/array/filterAsync'; -import appDownloadManager from '../../lib/appManagers/appDownloadManager'; +import appDownloadManager, {DownloadBlob} from '../../lib/appManagers/appDownloadManager'; import {SERVICE_PEER_ID} from '../../lib/mtproto/mtproto_config'; import {MessagesStorageKey, MyMessage} from '../../lib/appManagers/appMessagesManager'; import filterUnique from '../../helpers/array/filterUnique'; @@ -446,10 +446,8 @@ export default class ChatContextMenu { }, { icon: 'download', text: 'MediaViewer.Context.Download', - onClick: () => { - appDownloadManager.downloadToDisc({media: getMediaFromMessage(this.message, true)}); - }, - verify: () => this.canDownload(this.message, true) + onClick: () => ChatContextMenu.onDownloadClick(this.message, this.noForwards), + verify: () => ChatContextMenu.canDownload(this.message, this.target, this.noForwards) }, { icon: 'checkretract', text: 'Chat.Poll.Unvote', @@ -485,12 +483,8 @@ export default class ChatContextMenu { }, { icon: 'download', text: 'Message.Context.Selection.Download', - onClick: () => { - this.selectedMessages.forEach((message) => { - appDownloadManager.downloadToDisc({media: getMediaFromMessage(message, true)}); - }); - }, - verify: () => this.selectedMessages ? this.selectedMessages.some((message) => this.canDownload(message, false)) : false, + onClick: () => ChatContextMenu.onDownloadClick(this.selectedMessages, this.noForwards), + verify: () => this.selectedMessages && ChatContextMenu.canDownload(this.selectedMessages, undefined, this.noForwards), withSelection: true }, { icon: 'flag', @@ -564,8 +558,12 @@ export default class ChatContextMenu { }]; } - private canDownload(message: MyMessage, withTarget?: boolean) { - if(!canSaveMessageMedia(message) || this.noForwards) { + public static canDownload(message: MyMessage | MyMessage[], withTarget?: HTMLElement, noForwards?: boolean): boolean { + if(Array.isArray(message)) { + return message.some((message) => ChatContextMenu.canDownload(message, withTarget, noForwards)); + } + + if(!canSaveMessageMedia(message) || noForwards) { return false; } @@ -583,7 +581,13 @@ export default class ChatContextMenu { let hasTarget = !withTarget || !!IS_TOUCH_SUPPORTED; - if(isGoodType) hasTarget ||= !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio') || !!findUpClassName(this.target, 'media-sticker-wrapper') || !!findUpClassName(this.target, 'media-photo') || !!findUpClassName(this.target, 'media-video'); + if(isGoodType && withTarget) { + hasTarget ||= !!(findUpClassName(withTarget, 'document') || + findUpClassName(withTarget, 'audio') || + findUpClassName(withTarget, 'media-sticker-wrapper') || + findUpClassName(withTarget, 'media-photo') || + findUpClassName(withTarget, 'media-video')); + } return isGoodType && hasTarget; } @@ -967,4 +971,18 @@ export default class ChatContextMenu { new PopupDeleteMessages(this.peerId, this.isTargetAGroupedItem ? [this.mid] : await this.chat.getMidsByMid(this.mid), this.chat.type); } }; + + public static onDownloadClick(messages: MyMessage | MyMessage[], noForwards?: boolean): DownloadBlob | DownloadBlob[] { + if(Array.isArray(messages)) { + return messages.map((message) => { + return this.onDownloadClick(message) as any; + }); + } + + if(!this.canDownload(messages, undefined, noForwards)) { + return; + } + + return appDownloadManager.downloadToDisc({media: getMediaFromMessage(messages, true)}); + }; } diff --git a/src/components/chat/selection.ts b/src/components/chat/selection.ts index 4bad33b7..d53d129c 100644 --- a/src/components/chat/selection.ts +++ b/src/components/chat/selection.ts @@ -481,7 +481,7 @@ class AppSelection extends EventListenerBase<{ public isMidSelected(peerId: PeerId, mid: number) { const set = this.selectedMids.get(peerId); - return set?.has(mid); + return !!set?.has(mid); } public length() {