diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 141ec5e91b..a1fae40a00 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1849,6 +1849,7 @@ PRIVATE window/window_section_common.h window/window_separate_id.cpp window/window_separate_id.h + window/session/window_session_media.cpp window/window_session_controller.cpp window/window_session_controller.h window/window_session_controller_link_info.h diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 30f12037d0..fe7a9944a6 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -677,11 +677,6 @@ HistoryWidget::HistoryWidget( item->mainView()->itemDataChanged(); }, lifetime()); - session().data().drawToReplyRequests( - ) | rpl::on_next([=](Data::DrawToReplyRequest request) { - handleDrawToReplyRequest(std::move(request)); - }, lifetime()); - Core::App().settings().largeEmojiChanges( ) | rpl::on_next([=] { crl::on_main(this, [=] { @@ -3969,16 +3964,16 @@ void HistoryWidget::maybeMarkReactionsRead(not_null item) { session().api().markContentsRead(item); } -void HistoryWidget::handleDrawToReplyRequest( +bool HistoryWidget::handleDrawToReplyRequest( Data::DrawToReplyRequest request) { if (!_peer || request.messageId.peer != _peer->id) { - return; + return false; } auto image = HistoryView::ResolveDrawToReplyImage( &session().data(), request); if (image.isNull()) { - return; + return false; } const auto replyTo = request.messageId; HistoryView::OpenDrawToReplyEditor( @@ -3997,6 +3992,7 @@ void HistoryWidget::handleDrawToReplyRequest( st::sendMediaPreviewSize); confirmSendingFiles(std::move(list)); })); + return true; } void HistoryWidget::unreadCountUpdated() { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index ae56e2bbae..3f79a66915 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -169,6 +169,7 @@ public: bool isItemCompletelyHidden(HistoryItem *item) const; void updateTopBarSelection(); void updateTopBarChooseForReport(); + bool handleDrawToReplyRequest(Data::DrawToReplyRequest request); void loadMessages(); void loadMessagesDown(); @@ -484,7 +485,6 @@ private: void sendButtonClicked(); void newItemAdded(not_null item); void maybeMarkReactionsRead(not_null item); - void handleDrawToReplyRequest(Data::DrawToReplyRequest request); bool canSendFiles(not_null data) const; bool confirmSendingFiles( diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp index af5b4adee0..8d09db7458 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp @@ -458,36 +458,6 @@ ChatWidget::ChatWidget( }, lifetime()); } - session().data().drawToReplyRequests( - ) | rpl::on_next([=](Data::DrawToReplyRequest request) { - if (request.messageId.peer != _peer->id) { - return; - } - auto image = ResolveDrawToReplyImage( - &session().data(), - request); - if (image.isNull()) { - return; - } - const auto replyTo = request.messageId; - OpenDrawToReplyEditor( - controller, - std::move(image), - crl::guard(this, [=](QImage &&result) { - if (result.isNull()) { - return; - } - if (replyTo) { - replyToMessage({ .messageId = replyTo }); - } - auto list = Storage::PrepareMediaFromImage( - std::move(result), - QByteArray(), - st::sendMediaPreviewSize); - confirmSendingFiles(std::move(list)); - })); - }, lifetime()); - _selfForwardsTagger = std::make_unique( controller, this, @@ -3301,6 +3271,34 @@ void ChatWidget::listShowPremiumToast(not_null document) { _stickerToast->showFor(document); } +bool ChatWidget::handleDrawToReplyRequest(Data::DrawToReplyRequest request) { + if (request.messageId.peer != _peer->id) { + return false; + } + auto image = ResolveDrawToReplyImage(&session().data(), request); + if (image.isNull()) { + return false; + } + const auto replyTo = request.messageId; + OpenDrawToReplyEditor( + controller(), + std::move(image), + crl::guard(this, [=](QImage &&result) { + if (result.isNull()) { + return; + } + if (replyTo) { + replyToMessage({ .messageId = replyTo }); + } + auto list = Storage::PrepareMediaFromImage( + std::move(result), + QByteArray(), + st::sendMediaPreviewSize); + confirmSendingFiles(std::move(list)); + })); + return true; +} + void ChatWidget::listOpenPhoto( not_null photo, FullMsgId context) { diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.h b/Telegram/SourceFiles/history/view/history_view_chat_section.h index 1abbd70664..997e4f09d9 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.h +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.h @@ -54,6 +54,7 @@ class Result; namespace Data { class RepliesList; class ForumTopic; +struct DrawToReplyRequest; } // namespace Data namespace HistoryView { @@ -187,6 +188,7 @@ public: auto listAllowedReactionsValue() ->rpl::producer override; void listShowPremiumToast(not_null document) override; + bool handleDrawToReplyRequest(Data::DrawToReplyRequest request); void listOpenPhoto( not_null photo, FullMsgId context) override; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 21645e860a..d2a9441128 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_photo.h" #include "data/data_chat.h" #include "data/data_channel.h" +#include "data/data_chat_participant_status.h" #include "data/data_peer_values.h" #include "data/data_document.h" #include "data/data_session.h" @@ -620,7 +621,7 @@ void ListWidget::openPhoto(not_null photo, FullMsgId id) { }; _controller->parentController()->openPhoto( photo, - { id, topicRootId(), monoforumPeerId() }, + { id, topicRootId(), monoforumPeerId(), showDrawButton() }, _controller->storiesPeer() ? &context : nullptr); } @@ -635,10 +636,21 @@ void ListWidget::openDocument( _controller->parentController()->openDocument( document, showInMediaView, - { id, topicRootId(), monoforumPeerId() }, + { id, topicRootId(), monoforumPeerId(), showDrawButton() }, _controller->storiesPeer() ? &context : nullptr); } +bool ListWidget::showDrawButton() const { + if (const auto topic = _controller->key().topic()) { + return Data::CanSendAnyOf(topic, Data::FilesSendRestrictions()); + } else if (const auto sublist = _controller->key().sublist()) { + return Data::CanSendAnyOf(sublist, Data::FilesSendRestrictions()); + } else if (const auto peer = _controller->key().peer()) { + return Data::CanSendAnyOf(peer, Data::FilesSendRestrictions()); + } + return false; +} + void ListWidget::trackSession(not_null session) { if (_trackedSessions.contains(session)) { return; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index fbc25875ec..eaf3ec57b7 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -185,6 +185,7 @@ private: rpl::lifetime &lifetime); void setupSelectRestriction(); + [[nodiscard]] bool showDrawButton() const; [[nodiscard]] MsgId topicRootId() const; [[nodiscard]] PeerId monoforumPeerId() const; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 38cd8a033d..beac8028dd 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1563,6 +1563,17 @@ void MainWidget::showHistory( controller()->dropSubsectionTabs(); } +bool MainWidget::handleDrawToReplyRequest(Data::DrawToReplyRequest request) { + if (_mainSection) { + using namespace HistoryView; + if (const auto с = dynamic_cast(_mainSection.data())) { + return с->handleDrawToReplyRequest(std::move(request)); + } + return false; + } + return _history->handleDrawToReplyRequest(std::move(request)); +} + void MainWidget::showMessage( not_null item, const SectionShow ¶ms) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 526c60b709..0a200c4a1d 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -31,6 +31,7 @@ namespace Data { class Thread; class WallPaper; struct ForwardDraft; +struct DrawToReplyRequest; class Forum; class SavedMessages; struct ReportInput; @@ -198,6 +199,7 @@ public: PeerId peer, const SectionShow ¶ms, MsgId msgId); + bool handleDrawToReplyRequest(Data::DrawToReplyRequest request); void showMessage( not_null item, const SectionShow ¶ms); diff --git a/Telegram/SourceFiles/window/session/window_session_media.cpp b/Telegram/SourceFiles/window/session/window_session_media.cpp new file mode 100644 index 0000000000..3e9f54c99a --- /dev/null +++ b/Telegram/SourceFiles/window/session/window_session_media.cpp @@ -0,0 +1,147 @@ +/* +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 "window/window_session_controller.h" + +#include "apiwrap.h" +#include "boxes/send_files_box.h" +#include "data/data_forum_topic.h" +#include "data/data_peer.h" +#include "data/data_saved_sublist.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/view/history_view_draw_to_reply.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "mainwidget.h" +#include "data/data_session.h" +#include "data/data_thread.h" +#include "storage/localimageloader.h" +#include "storage/storage_media_prepare.h" +#include "styles/style_boxes.h" +#include "window/window_separate_id.h" + +namespace Window { + +void SessionController::handleDrawToReplyRequest( + Data::DrawToReplyRequest request) { + if (content()->handleDrawToReplyRequest(request)) { + return; + } + auto image = HistoryView::ResolveDrawToReplyImage( + &session().data(), + request); + if (image.isNull()) { + return; + } + HistoryView::OpenDrawToReplyEditor( + this, + std::move(image), + crl::guard(this, [=](QImage &&result) { + if (result.isNull()) { + return; + } + const auto thread = resolveDrawToReplyThread(request); + if (!thread) { + return; + } + auto list = Storage::PrepareMediaFromImage( + std::move(result), + QByteArray(), + st::sendMediaPreviewSize); + showDrawToReplyFilesBox( + thread, + request.messageId, + std::move(list)); + })); +} + +Data::Thread *SessionController::resolveDrawToReplyThread( + const Data::DrawToReplyRequest &request) const { + if (const auto item = session().data().message(request.messageId)) { + if (const auto topic = item->topic()) { + return topic; + } else if (const auto sublist = item->savedSublist()) { + return sublist; + } + return item->history(); + } + if (const auto thread = activeChatCurrent().thread()) { + if (thread->peer()->id == request.messageId.peer) { + return thread; + } + } + if (const auto thread = windowId().thread) { + if (thread->peer()->id == request.messageId.peer) { + return thread; + } + } + return session().data().historyLoaded(request.messageId.peer); +} + +void SessionController::showDrawToReplyFilesBox( + not_null thread, + FullMsgId replyTo, + Ui::PreparedList &&list) { + const auto weak = base::make_weak(thread); + const auto peer = thread->peer(); + const auto show = uiShow(); + show->show(Box(SendFilesBoxDescriptor{ + .show = show, + .list = std::move(list), + .caption = TextWithTags(), + .toPeer = peer, + .limits = DefaultLimitsForPeer(peer), + .check = DefaultCheckForPeer(show, peer), + .sendType = Api::SendType::Normal, + .confirmed = crl::guard(this, [=]( + std::shared_ptr bundle, + Api::SendOptions options) { + if (const auto thread = weak.get()) { + sendDrawToReplyFiles( + thread, + replyTo, + std::move(bundle), + options); + } + }), + })); +} + +void SessionController::sendDrawToReplyFiles( + not_null thread, + FullMsgId replyTo, + std::shared_ptr bundle, + Api::SendOptions options) { + if (!bundle) { + return; + } + const auto type = bundle->way.sendImagesAsPhotos() + ? SendMediaType::Photo + : SendMediaType::File; + auto action = Api::SendAction(thread, options); + action.clearDraft = false; + action.replyTo = { + .messageId = replyTo, + .topicRootId = thread->topicRootId(), + .monoforumPeerId = thread->monoforumPeerId(), + }; + auto &api = session().api(); + auto sent = false; + for (auto &group : bundle->groups) { + const auto album = (group.type != Ui::AlbumType::None) + ? std::make_shared() + : nullptr; + api.sendFiles(std::move(group.list), type, album, action); + sent = true; + } + if (sent) { + showToast(tr::lng_stories_reply_sent(tr::now)); + } +} + +} // namespace Window diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index aa383de0ce..9f1fa45258 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_saved_messages.h" #include "data/data_saved_sublist.h" #include "data/data_session.h" +#include "data/data_thread.h" #include "data/data_file_origin.h" #include "data/data_flags.h" #include "data/data_folder.h" @@ -118,6 +119,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/cloud_password/settings_cloud_password_start.h" #include "settings/cloud_password/settings_cloud_password_email_confirm.h" #include "settings/sections/settings_main.h" +#include "styles/style_chat.h" #include "settings/sections/settings_premium.h" #include "settings/sections/settings_privacy_security.h" #include "styles/style_window.h" @@ -1875,6 +1877,10 @@ void SessionController::init() { if (session().supportMode()) { session().supportHelper().registerWindow(this); } + session().data().drawToReplyRequests( + ) | rpl::on_next([=](Data::DrawToReplyRequest request) { + handleDrawToReplyRequest(std::move(request)); + }, lifetime()); setupShortcuts(); } diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index b218c99627..bead50cbe1 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -26,6 +26,7 @@ enum class WindowLayout; namespace Data { struct StoriesContext; +struct DrawToReplyRequest; class SavedMessages; enum class StorySourcesList : uchar; } // namespace Data @@ -70,8 +71,14 @@ struct ChatThemeBackgroundData; class MessageSendingAnimationController; struct BoostCounters; struct ChatPaintContextArgs; +struct PreparedList; +struct PreparedBundle; } // namespace Ui +namespace Api { +struct SendOptions; +} // namespace Api + namespace Data { struct CloudTheme; enum class CloudThemeType; @@ -783,6 +790,18 @@ private: [[nodiscard]] bool openPhotoExternal( not_null photo, Data::FileOrigin origin); + void handleDrawToReplyRequest(Data::DrawToReplyRequest request); + [[nodiscard]] Data::Thread *resolveDrawToReplyThread( + const Data::DrawToReplyRequest &request) const; + void showDrawToReplyFilesBox( + not_null thread, + FullMsgId replyTo, + Ui::PreparedList &&list); + void sendDrawToReplyFiles( + not_null thread, + FullMsgId replyTo, + std::shared_ptr bundle, + Api::SendOptions options); const not_null _window; const std::unique_ptr _emojiInteractions;