From 6c19274eac1b999525e85118cfbe967e360a975e Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 10 Oct 2023 17:51:27 +0400 Subject: [PATCH] Support external reply to channel posts. --- .../history/history_inner_widget.cpp | 20 ++++- .../SourceFiles/history/history_widget.cpp | 20 ++++- .../history_view_compose_controls.cpp | 18 ++++ .../controls/history_view_forward_panel.cpp | 84 +++++++++++-------- .../controls/history_view_forward_panel.h | 18 +++- .../view/history_view_context_menu.cpp | 24 ++++-- .../view/history_view_replies_section.cpp | 14 +++- 7 files changed, 145 insertions(+), 53 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index d4b3aaf46..4d68ab061 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/admin_log/history_admin_log_item.h" #include "history/history_item.h" #include "history/history_item_helpers.h" +#include "history/view/controls/history_view_forward_panel.h" #include "history/view/media/history_view_media.h" #include "history/view/media/history_view_sticker.h" #include "history/view/media/history_view_web_page.h" @@ -2196,7 +2197,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { return; } const auto itemId = item->fullId(); - const auto canReply = [&] { + const auto canSendReply = [&] { const auto peer = item->history()->peer; const auto topic = item->topic(); return topic @@ -2204,9 +2205,24 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { : (Data::CanSendAnything(peer) && (!peer->isChannel() || peer->asChannel()->amIn())); }(); + const auto canReply = canSendReply || [&] { + const auto peer = item->history()->peer; + if (const auto chat = peer->asChat()) { + return !chat->isForbidden(); + } else if (const auto channel = peer->asChannel()) { + return !channel->isForbidden(); + } + return true; + }(); if (canReply) { _menu->addAction(tr::lng_context_reply_msg(tr::now), [=] { - _widget->replyToMessage({ itemId }); + if (canSendReply) { + _widget->replyToMessage({ itemId }); + } else { + HistoryView::Controls::ShowReplyToChatBox( + controller->uiShow(), + { itemId }); + } }, &st::menuIconReply); } const auto repliesCount = item->repliesCount(); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 846be207e..ad1ec6f5e 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6222,10 +6222,19 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { _forwardPanel->editOptions(controller()->uiShow()); } } else if (const auto reply = replyTo()) { - HistoryView::Controls::EditReplyOptions( - controller(), + const auto highlight = [=] { + controller()->showPeerHistory( + reply.messageId.peer, + Window::SectionShow::Way::Forward, + reply.messageId.msg); + }; + const auto history = _history; + using namespace HistoryView::Controls; + EditReplyOptions( + controller()->uiShow(), reply, - _history); + highlight, + [=] { ClearDraftReplyTo(history, reply.messageId); }); } else if (_editMsgId) { controller()->showPeerHistory( _peer, @@ -7611,7 +7620,10 @@ bool HistoryWidget::updateCanSendMessage() { if (!_peer) { return false; } - const auto replyTo = (_replyTo && !_editMsgId) ? _replyEditMsg : 0; + const auto checkTopicFromReplyTo = _replyTo + && !_editMsgId + && (_replyTo.messageId.peer == _peer->id); + const auto replyTo = checkTopicFromReplyTo ? _replyEditMsg : 0; const auto topic = replyTo ? replyTo->topic() : nullptr; const auto allWithoutPolls = Data::AllSendRestrictions() & ~ChatRestriction::SendPolls; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 56f6cf752..0e793b955 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -414,6 +414,7 @@ private: const std::shared_ptr _show; History *_history = nullptr; + MsgId _topicRootId = 0; rpl::variable _title; rpl::variable _description; @@ -468,6 +469,7 @@ FieldHeader::FieldHeader( void FieldHeader::setHistory(const SetHistoryArgs &args) { _history = *args.history; + _topicRootId = args.topicRootId; } void FieldHeader::init() { @@ -619,8 +621,24 @@ void FieldHeader::init() { } else if (isLeftButton && inPhotoEdit) { _editPhotoRequests.fire({}); } else if (isLeftButton && inPreviewRect) { + const auto reply = replyingToMessage(); if (!isEditingMessage() && readyToForward()) { _forwardPanel->editOptions(_show); + } else if (!isEditingMessage() && reply) { + using namespace Controls; + const auto highlight = [=] { + _scrollToItemRequests.fire_copy(reply.messageId); + }; + const auto history = _history; + const auto topicRootId = _topicRootId; + const auto clearOldReplyTo = [=, id = reply.messageId] { + ClearDraftReplyTo(history, topicRootId, id); + }; + EditReplyOptions( + _show, + reply, + highlight, + clearOldReplyTo); } else { auto id = isEditingMessage() ? _editMsgId.current() diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp index dd6fd636d..6e9bb5903 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp @@ -403,10 +403,38 @@ void ForwardPanel::paint( }); } +void ClearDraftReplyTo(not_null thread, FullMsgId equalTo) { + ClearDraftReplyTo( + thread->owningHistory(), + thread->topicRootId(), + equalTo); +} + +void ClearDraftReplyTo( + not_null history, + MsgId topicRootId, + FullMsgId equalTo) { + const auto local = history->localDraft(topicRootId); + if (!local || (equalTo && local->reply.messageId != equalTo)) { + return; + } + auto draft = *local; + draft.reply = { .topicRootId = topicRootId }; + if (Data::DraftIsNull(&draft)) { + history->clearLocalDraft(topicRootId); + } else { + history->setLocalDraft( + std::make_unique(std::move(draft))); + } + if (const auto thread = history->threadFor(topicRootId)) { + history->session().api().saveDraftToCloudDelayed(thread); + } +} + void ShowReplyToChatBox( - not_null window, + std::shared_ptr show, FullReplyTo reply, - base::weak_ptr oldThread) { + Fn clearOldDraft) { class Controller final : public ChooseRecipientBoxController { public: using Chosen = not_null; @@ -426,7 +454,15 @@ void ShowReplyToChatBox( return _singleChosen.events(); } + bool respectSavedMessagesChat() const override { + return false; + } + private: + void prepareViewHook() override { + delegate()->peerListSetTitle(rpl::single(u"Reply in..."_q)); + } + rpl::event_stream _singleChosen; }; @@ -436,13 +472,13 @@ void ShowReplyToChatBox( not_null controller; base::unique_qptr menu; }; - const auto session = &window->session(); + const auto session = &show->session(); const auto state = [&] { auto controller = std::make_unique(session); const auto controllerRaw = controller.get(); auto box = Box(std::move(controller), nullptr); const auto boxRaw = box.data(); - window->uiShow()->show(std::move(box)); + show->show(std::move(box)); auto state = State{ boxRaw, controllerRaw }; return boxRaw->lifetime().make_state(std::move(state)); }(); @@ -466,26 +502,9 @@ void ShowReplyToChatBox( thread, Data::EntryUpdate::Flag::LocalDraftSet); - // Clear old one. - crl::on_main(oldThread, [=] { - const auto old = oldThread.get(); - const auto history = old->owningHistory(); - const auto topicRootId = old->topicRootId(); - if (const auto local = history->localDraft(topicRootId)) { - if (local->reply.messageId == reply.messageId) { - auto draft = *local; - draft.reply = { .topicRootId = topicRootId }; - if (Data::DraftIsNull(&draft)) { - history->clearLocalDraft(topicRootId); - } else { - history->setLocalDraft( - std::make_unique( - std::move(draft))); - } - old->session().api().saveDraftToCloudDelayed(old); - } - } - }); + if (clearOldDraft) { + crl::on_main(&history->session(), clearOldDraft); + } return true; }; auto callback = [=, chosen = std::move(chosen)]( @@ -502,11 +521,11 @@ void ShowReplyToChatBox( } void EditReplyOptions( - not_null controller, + std::shared_ptr show, FullReplyTo reply, - not_null thread) { - const auto weak = base::make_weak(thread); - controller->uiShow()->show(Box([=](not_null box) { + Fn highlight, + Fn clearOldDraft) { + show->show(Box([=](not_null box) { box->setTitle(rpl::single(u"Reply to Message"_q)); Settings::AddButton( @@ -515,7 +534,7 @@ void EditReplyOptions( st::settingsButton, { &st::menuIconReply } )->setClickedCallback([=] { - ShowReplyToChatBox(controller, reply, weak); + ShowReplyToChatBox(show, reply, clearOldDraft); }); Settings::AddButton( @@ -523,12 +542,7 @@ void EditReplyOptions( rpl::single(u"Show message"_q), st::settingsButton, { &st::menuIconShowInChat } - )->setClickedCallback([=] { - controller->showPeerHistory( - reply.messageId.peer, - Window::SectionShow::Way::Forward, - reply.messageId.msg); - }); + )->setClickedCallback(highlight); box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h index 26464e36f..963d780af 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h @@ -71,9 +71,21 @@ private: }; -void EditReplyOptions( - not_null controller, +void ClearDraftReplyTo(not_null thread, FullMsgId equalTo); +void ClearDraftReplyTo( + not_null history, + MsgId topicRootId, + FullMsgId equalTo); + +void ShowReplyToChatBox( + std::shared_ptr show, FullReplyTo reply, - not_null thread); + Fn clearOldDraft = nullptr); + +void EditReplyOptions( + std::shared_ptr show, + FullReplyTo reply, + Fn highlight, + Fn clearOldDraft = nullptr); } // namespace HistoryView::Controls diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 3073d3495..56d9b9b8b 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_stories.h" #include "data/data_groups.h" #include "data/data_channel.h" +#include "data/data_chat.h" #include "data/data_file_click_handler.h" #include "data/data_file_origin.h" #include "data/data_message_reactions.h" @@ -588,20 +589,33 @@ bool AddReplyToMessageAction( const auto peer = item ? item->history()->peer.get() : nullptr; if (!item || !item->isRegular() - || !(topic - ? Data::CanSendAnything(topic) - : Data::CanSendAnything(peer)) || (context != Context::History && context != Context::Replies)) { return false; } + const auto canSendReply = topic + ? Data::CanSendAnything(topic) + : Data::CanSendAnything(peer); + const auto canReply = canSendReply || [&] { + const auto peer = item->history()->peer; + if (const auto chat = peer->asChat()) { + return !chat->isForbidden(); + } else if (const auto channel = peer->asChannel()) { + return !channel->isForbidden(); + } + return true; + }(); + if (!canReply) { + return false; + } + const auto owner = &item->history()->owner(); const auto itemId = item->fullId(); menu->addAction(tr::lng_context_reply_msg(tr::now), [=] { - const auto item = owner->message(itemId); if (!item) { return; + } else { + list->replyToMessageRequestNotify({ itemId }); } - list->replyToMessageRequestNotify({ item->fullId() }); }, &st::menuIconReply); return true; } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 080984847..49fac6d31 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_replies_section.h" #include "history/view/controls/history_view_compose_controls.h" +#include "history/view/controls/history_view_forward_panel.h" #include "history/view/history_view_top_bar_widget.h" #include "history/view/history_view_list_widget.h" #include "history/view/history_view_schedule_box.h" @@ -318,10 +319,15 @@ RepliesWidget::RepliesWidget( }, _inner->lifetime()); _inner->replyToMessageRequested( - ) | rpl::filter([=] { - return !_joinGroup; - }) | rpl::start_with_next([=](auto fullId) { - replyToMessage(fullId); + ) | rpl::start_with_next([=](auto fullId) { + const auto canSendReply = _topic + ? Data::CanSendAnything(_topic) + : Data::CanSendAnything(_history->peer); + if (_joinGroup || !canSendReply) { + Controls::ShowReplyToChatBox(controller->uiShow(), { fullId }); + } else { + replyToMessage(fullId); + } }, _inner->lifetime()); _inner->showMessageRequested(