mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-11 08:48:14 +00:00
Added ability to download multiple files from context menu.
This commit is contained in:
parent
8175fd19de
commit
c8ae7c7402
@ -971,6 +971,8 @@ PRIVATE
|
||||
media/view/media_view_playback_progress.cpp
|
||||
media/view/media_view_playback_progress.h
|
||||
media/view/media_view_open_common.h
|
||||
menu/menu_item_download_files.cpp
|
||||
menu/menu_item_download_files.h
|
||||
menu/menu_mute.cpp
|
||||
menu/menu_mute.h
|
||||
menu/menu_send.cpp
|
||||
|
@ -2211,6 +2211,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_send_now_selected" = "Send selected now";
|
||||
"lng_context_reschedule_selected" = "Reschedule Selected";
|
||||
"lng_context_delete_selected" = "Delete Selected";
|
||||
"lng_context_save_images_selected" = "Save Selected";
|
||||
"lng_context_save_documents_selected" = "Download Selected";
|
||||
"lng_context_clear_selection" = "Clear Selection";
|
||||
"lng_context_seen_loading" = "Loading...";
|
||||
"lng_context_seen_text#one" = "{count} Seen";
|
||||
@ -2391,6 +2393,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_mediaview_report_profile_photo" = "Report";
|
||||
|
||||
"lng_mediaview_saved_to" = "Image was saved to your {downloads} folder";
|
||||
"lng_mediaview_saved_images_to" = "Images was saved to your {downloads} folder";
|
||||
"lng_mediaview_downloads" = "Downloads";
|
||||
"lng_mediaview_video_loading" = "Loading - {percent}";
|
||||
"lng_mediaview_playback_speed" = "Playback speed: {speed}";
|
||||
|
@ -63,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "layout/layout_selection.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "menu/menu_item_download_files.h"
|
||||
#include "core/application.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_attached_stickers.h"
|
||||
@ -2236,10 +2237,12 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
&st::menuIconCopy);
|
||||
}
|
||||
addItemActions(item, item);
|
||||
if (lnkPhoto) {
|
||||
addPhotoActions(lnkPhoto, item);
|
||||
} else {
|
||||
addDocumentActions(lnkDocument, item);
|
||||
if (!selectedState.count) {
|
||||
if (lnkPhoto) {
|
||||
addPhotoActions(lnkPhoto, item);
|
||||
} else {
|
||||
addDocumentActions(lnkDocument, item);
|
||||
}
|
||||
}
|
||||
if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) {
|
||||
_menu->addAction(item->history()->peer->isMegagroup() ? tr::lng_context_copy_message_link(tr::now) : tr::lng_context_copy_post_link(tr::now), [=] {
|
||||
@ -2257,6 +2260,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
_widget->confirmDeleteSelected();
|
||||
}, &st::menuIconDelete);
|
||||
}
|
||||
if (selectedState.count > 0) {
|
||||
Menu::AddDownloadFilesAction(_menu, controller, _selected, this);
|
||||
}
|
||||
_menu->addAction(tr::lng_context_clear_selection(tr::now), [=] {
|
||||
_widget->clearSelected();
|
||||
}, &st::menuIconSelect);
|
||||
@ -2402,6 +2408,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
_widget->confirmDeleteSelected();
|
||||
}, &st::menuIconDelete);
|
||||
}
|
||||
if (selectedState.count > 0) {
|
||||
Menu::AddDownloadFilesAction(_menu, controller, _selected, this);
|
||||
}
|
||||
_menu->addAction(tr::lng_context_clear_selection(tr::now), [=] {
|
||||
_widget->clearSelected();
|
||||
}, &st::menuIconSelect);
|
||||
|
@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/controls/who_reacted_context_action.h"
|
||||
#include "ui/boxes/report_box.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "menu/menu_item_download_files.h"
|
||||
#include "menu/menu_send.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
@ -803,6 +804,20 @@ void AddDeleteAction(
|
||||
}
|
||||
}
|
||||
|
||||
void AddDownloadFilesAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request,
|
||||
not_null<ListWidget*> list) {
|
||||
if (!request.overSelection || request.selectedItems.empty()) {
|
||||
return;
|
||||
}
|
||||
Menu::AddDownloadFilesAction(
|
||||
menu,
|
||||
request.navigation->parentController(),
|
||||
request.selectedItems,
|
||||
list);
|
||||
}
|
||||
|
||||
void AddReportAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request,
|
||||
@ -901,6 +916,7 @@ void AddMessageActions(
|
||||
AddForwardAction(menu, request, list);
|
||||
AddSendNowAction(menu, request, list);
|
||||
AddDeleteAction(menu, request, list);
|
||||
AddDownloadFilesAction(menu, request, list);
|
||||
AddReportAction(menu, request, list);
|
||||
AddSelectionAction(menu, request, list);
|
||||
AddRescheduleAction(menu, request, list);
|
||||
@ -969,7 +985,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
||||
}
|
||||
|
||||
AddTopMessageActions(result, request, list);
|
||||
if (lnkPhoto) {
|
||||
if (lnkPhoto && request.selectedItems.empty()) {
|
||||
AddPhotoActions(result, lnkPhoto, item, list);
|
||||
} else if (lnkDocument) {
|
||||
AddDocumentActions(result, lnkDocument, item, list);
|
||||
|
185
Telegram/SourceFiles/menu/menu_item_download_files.cpp
Normal file
185
Telegram/SourceFiles/menu/menu_item_download_files.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "menu/menu_item_download_files.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_click_handler.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history_inner_widget.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/view/history_view_list_widget.h" // HistoryView::SelectedItem.
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Menu {
|
||||
namespace {
|
||||
|
||||
using DocumentViewPtr = std::shared_ptr<Data::DocumentMedia>;
|
||||
using Documents = std::vector<std::pair<DocumentViewPtr, FullMsgId>>;
|
||||
using Photos = std::vector<std::shared_ptr<Data::PhotoMedia>>;
|
||||
|
||||
[[nodiscard]] bool Added(
|
||||
HistoryItem *item,
|
||||
Documents &documents,
|
||||
Photos &photos) {
|
||||
if (item && !item->forbidsForward()) {
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto photo = media->photo()) {
|
||||
if (const auto view = photo->activeMediaView()) {
|
||||
if (view->loaded()) {
|
||||
photos.push_back(view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (const auto document = media->document()) {
|
||||
if (const auto view = document->activeMediaView()) {
|
||||
if (!view->loaded()) {
|
||||
documents.emplace_back(view, item->fullId());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Documents &&documents,
|
||||
Photos &&photos,
|
||||
Fn<void()> callback) {
|
||||
const auto text = documents.empty()
|
||||
? tr::lng_context_save_images_selected(tr::now)
|
||||
: tr::lng_context_save_documents_selected(tr::now);
|
||||
const auto icon = documents.empty()
|
||||
? &st::menuIconSaveImage
|
||||
: &st::menuIconDownload;
|
||||
const auto showToast = documents.empty();
|
||||
|
||||
const auto saveImages = [=] {
|
||||
const auto session = &controller->session();
|
||||
const auto downloadPath = Core::App().settings().downloadPath();
|
||||
const auto path = downloadPath.isEmpty()
|
||||
? File::DefaultDownloadPath(session)
|
||||
: (downloadPath == u"tmp"_q)
|
||||
? session->local().tempDirectory()
|
||||
: downloadPath;
|
||||
|
||||
const auto fullPath = [&](int i) {
|
||||
return filedialogDefaultName(
|
||||
u"photo_"_q + QString::number(i),
|
||||
u".jpg"_q,
|
||||
path);
|
||||
};
|
||||
auto lastPath = QString();
|
||||
for (auto i = 0; i < photos.size(); i++) {
|
||||
lastPath = fullPath(i + 1);
|
||||
photos[i]->saveToFile(lastPath);
|
||||
}
|
||||
|
||||
if (showToast) {
|
||||
const auto filter = [lastPath](const auto ...) {
|
||||
File::ShowInFolder(lastPath);
|
||||
return false;
|
||||
};
|
||||
const auto config = Ui::Toast::Config{
|
||||
.text = (photos.size() > 1
|
||||
? tr::lng_mediaview_saved_images_to
|
||||
: tr::lng_mediaview_saved_to)(
|
||||
tr::now,
|
||||
lt_downloads,
|
||||
Ui::Text::Link(
|
||||
tr::lng_mediaview_downloads(tr::now),
|
||||
"internal:show_saved_message"),
|
||||
Ui::Text::WithEntities),
|
||||
.st = &st::defaultToast,
|
||||
.filter = filter,
|
||||
};
|
||||
Ui::Toast::Show(Window::Show(controller).toastParent(), config);
|
||||
}
|
||||
};
|
||||
const auto saveDocuments = [=] {
|
||||
for (const auto &pair : documents) {
|
||||
DocumentSaveClickHandler::Save(pair.second, pair.first->owner());
|
||||
}
|
||||
};
|
||||
|
||||
menu->addAction(text, [=] {
|
||||
saveImages();
|
||||
saveDocuments();
|
||||
callback();
|
||||
}, icon);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AddDownloadFilesAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<Window::SessionController*> window,
|
||||
const std::vector<HistoryView::SelectedItem> &selectedItems,
|
||||
not_null<HistoryView::ListWidget*> list) {
|
||||
if (selectedItems.empty() || Core::App().settings().askDownloadPath()) {
|
||||
return;
|
||||
}
|
||||
auto docs = Documents();
|
||||
auto photos = Photos();
|
||||
for (const auto &selectedItem : selectedItems) {
|
||||
const auto &id = selectedItem.msgId;
|
||||
const auto item = window->session().data().message(id);
|
||||
|
||||
if (!Added(item, docs, photos)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto done = [weak = Ui::MakeWeak(list)] {
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->cancelSelection();
|
||||
}
|
||||
};
|
||||
AddAction(menu, window, std::move(docs), std::move(photos), done);
|
||||
}
|
||||
|
||||
void AddDownloadFilesAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<Window::SessionController*> window,
|
||||
const std::map<HistoryItem*, TextSelection, std::less<>> &items,
|
||||
not_null<HistoryInner*> list) {
|
||||
if (items.empty() || Core::App().settings().askDownloadPath()) {
|
||||
return;
|
||||
}
|
||||
auto docs = Documents();
|
||||
auto photos = Photos();
|
||||
for (const auto &pair : items) {
|
||||
if (!Added(pair.first, docs, photos)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto done = [weak = Ui::MakeWeak(list)] {
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->clearSelected();
|
||||
}
|
||||
};
|
||||
AddAction(menu, window, std::move(docs), std::move(photos), done);
|
||||
}
|
||||
|
||||
} // namespace Menu
|
41
Telegram/SourceFiles/menu/menu_item_download_files.h
Normal file
41
Telegram/SourceFiles/menu/menu_item_download_files.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class HistoryInner;
|
||||
class HistoryItem;
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView {
|
||||
class ListWidget;
|
||||
struct SelectedItem;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Menu {
|
||||
|
||||
void AddDownloadFilesAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<Window::SessionController*> window,
|
||||
const std::vector<HistoryView::SelectedItem> &selectedItems,
|
||||
not_null<HistoryView::ListWidget*> list);
|
||||
|
||||
void AddDownloadFilesAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<Window::SessionController*> window,
|
||||
// From the legacy history inner widget.
|
||||
const std::map<HistoryItem*, TextSelection, std::less<>> &items,
|
||||
not_null<HistoryInner*> list);
|
||||
|
||||
} // namespace Menu
|
Loading…
Reference in New Issue
Block a user