From 1bf376ca2014c844e83a2532ce9a843b11977cce Mon Sep 17 00:00:00 2001 From: Bush2021 <79072750+Bush2021@users.noreply.github.com> Date: Wed, 9 Jul 2025 07:34:03 -0400 Subject: [PATCH 1/2] feat: repeater --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/ayu/ayu_settings.cpp | 5 + Telegram/SourceFiles/ayu/ayu_settings.h | 4 + .../ayu/ui/context_menu/context_menu.cpp | 130 ++++++++++++++++++ .../ayu/ui/context_menu/context_menu.h | 1 + .../ayu/ui/settings/settings_ayu.cpp | 13 ++ .../history/history_inner_widget.cpp | 1 + .../view/history_view_context_menu.cpp | 1 + 8 files changed, 156 insertions(+) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index caac333013..89d71094fc 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -7151,3 +7151,4 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_AboutText1" = "ToS breaking Telegram client based on {api_link}."; "ayu_UpdateAyuGram" = "Update AyuGram"; "ayu_UtilityRestartRequired" = "The app will close in 5 seconds."; +"ayu_Repeater" = "+1 / Repeater"; diff --git a/Telegram/SourceFiles/ayu/ayu_settings.cpp b/Telegram/SourceFiles/ayu/ayu_settings.cpp index f6bb469bd2..f1c1d075fb 100644 --- a/Telegram/SourceFiles/ayu/ayu_settings.cpp +++ b/Telegram/SourceFiles/ayu/ayu_settings.cpp @@ -257,6 +257,7 @@ AyuGramSettings::AyuGramSettings() { showHideMessageInContextMenu = 0; showUserMessagesInContextMenu = 2; showMessageDetailsInContextMenu = 2; + showRepeaterInContextMenu = 2; showAttachButtonInMessageField = true; showCommandsButtonInMessageField = true; @@ -473,6 +474,10 @@ void set_showMessageDetailsInContextMenu(int val) { settings->showMessageDetailsInContextMenu = val; } +void set_showRepeaterInContextMenu(int val) { + settings->showRepeaterInContextMenu = val; +} + void set_showAttachButtonInMessageField(bool val) { settings->showAttachButtonInMessageField = val; triggerHistoryUpdate(); diff --git a/Telegram/SourceFiles/ayu/ayu_settings.h b/Telegram/SourceFiles/ayu/ayu_settings.h index 192e59f2ee..1b4fe3e7a6 100644 --- a/Telegram/SourceFiles/ayu/ayu_settings.h +++ b/Telegram/SourceFiles/ayu/ayu_settings.h @@ -91,6 +91,7 @@ public: int showHideMessageInContextMenu; int showUserMessagesInContextMenu; int showMessageDetailsInContextMenu; + int showRepeaterInContextMenu; bool showAttachButtonInMessageField; bool showCommandsButtonInMessageField; @@ -175,6 +176,7 @@ void set_showViewsPanelInContextMenu(int val); void set_showHideMessageInContextMenu(int val); void set_showUserMessagesInContextMenu(int val); void set_showMessageDetailsInContextMenu(int val); +void set_showRepeaterInContextMenu(int val); void set_showAttachButtonInMessageField(bool val); void set_showCommandsButtonInMessageField(bool val); @@ -245,6 +247,7 @@ inline void to_json(nlohmann::json &nlohmann_json_j, const AyuGramSettings &nloh NLOHMANN_JSON_TO(showHideMessageInContextMenu) NLOHMANN_JSON_TO(showUserMessagesInContextMenu) NLOHMANN_JSON_TO(showMessageDetailsInContextMenu) + NLOHMANN_JSON_TO(showRepeaterInContextMenu) NLOHMANN_JSON_TO(showAttachButtonInMessageField) NLOHMANN_JSON_TO(showCommandsButtonInMessageField) NLOHMANN_JSON_TO(showEmojiButtonInMessageField) @@ -310,6 +313,7 @@ inline void from_json(const nlohmann::json &nlohmann_json_j, AyuGramSettings &nl NLOHMANN_JSON_FROM_WITH_DEFAULT(showHideMessageInContextMenu) NLOHMANN_JSON_FROM_WITH_DEFAULT(showUserMessagesInContextMenu) NLOHMANN_JSON_FROM_WITH_DEFAULT(showMessageDetailsInContextMenu) + NLOHMANN_JSON_FROM_WITH_DEFAULT(showRepeaterInContextMenu) NLOHMANN_JSON_FROM_WITH_DEFAULT(showAttachButtonInMessageField) NLOHMANN_JSON_FROM_WITH_DEFAULT(showCommandsButtonInMessageField) NLOHMANN_JSON_FROM_WITH_DEFAULT(showEmojiButtonInMessageField) diff --git a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp index 1d28a8297b..07cb548cc2 100644 --- a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp +++ b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp @@ -42,6 +42,10 @@ #include "window/window_controller.h" #include "window/window_session_controller.h" +#include "main/session/send_as_peers.h" +#include "api/api_sending.h" +#include "history/history_widget.h" + namespace AyuUi { namespace { @@ -631,6 +635,132 @@ void AddMessageDetailsAction(not_null menu, HistoryItem *item) { }); } +Api::SendAction prepareSendAction(auto _history, Api::SendOptions options) { + auto result = Api::SendAction(_history, options); + return result; +} + +void AddRepeaterAction(not_null menu, HistoryItem *item) { + const auto settings = &AyuSettings::getInstance(); + if (!needToShowItem(settings->showRepeaterInContextMenu)) { + return; + } + + if (!item) { + return; + } + + const auto itemId = item->fullId(); + const auto _history = item->history(); + if ((item->history()->peer->isMegagroup() || item->history()->peer->isChat() || item->history()->peer->isUser())) { + if (item->allowsForward()) { + menu->addAction( + tr::ayu_Repeater(tr::now), + [=] { + if (item->id <= 0) return; + const auto api = &item->history()->peer->session().api(); + auto action = Api::SendAction( + item->history()->peer->owner().history(item->history()->peer), + Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)}); + action.clearDraft = false; + if (item->history()->peer->isUser() || item->history()->peer->isChat()) { + action.options.sendAs = nullptr; + } + + if (item->topic()) { + action.replyTo = FullReplyTo{ + .messageId = item->fullId(), + .topicRootId = item->topicRootId(), + }; + } + + const auto history = item->history()->peer->owner().history(item->history()->peer); + auto resolved = history->resolveForwardDraft(Data::ForwardDraft{.ids = MessageIdsList(1, itemId)}); + + api->forwardMessages( + std::move(resolved), action, [] {}); + }, + &st::menuIconDiscussion); + } else if (!item->isService() && !item->emptyText() && item->media() == nullptr) { + menu->addAction( + tr::ayu_Repeater(tr::now), + [=] { + if (item->id <= 0) return; + const auto api = &item->history()->peer->session().api(); + auto message = ApiWrap::MessageToSend(prepareSendAction( + _history->peer->owner().history(item->history()->peer), + Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)})); + message.textWithTags = {item->originalText().text, + TextUtilities::ConvertEntitiesToTextTags(item->originalText().entities)}; + if (item->history()->peer->isUser() || item->history()->peer->isChat()) { + message.action.options.sendAs = nullptr; + } + if (item->topic()) { + message.action.replyTo = FullReplyTo{ + .messageId = item->fullId(), + .topicRootId = item->topicRootId(), + }; + } + api->sendMessage(std::move(message)); + }, + &st::menuIconDiscussion); + } else if (!item->isService() && item->media()->document() != nullptr && + item->media()->document()->sticker() != nullptr) { + if (item->allowsForward()) { + menu->addAction( + tr::ayu_Repeater(tr::now), + [=] { + if (item->id <= 0) return; + const auto api = &item->history()->peer->session().api(); + auto action = Api::SendAction( + item->history()->peer->owner().history(item->history()->peer), + Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)}); + action.clearDraft = false; + if (item->history()->peer->isUser() || item->history()->peer->isChat()) { + action.options.sendAs = nullptr; + } + if (item->topic()) { + action.replyTo = FullReplyTo{ + .messageId = item->fullId(), + .topicRootId = item->topicRootId(), + }; + } + + const auto history = item->history()->peer->owner().history(item->history()->peer); + auto resolved = history->resolveForwardDraft(Data::ForwardDraft{ + .ids = MessageIdsList(1, itemId), .options = Data::ForwardOptions::NoSenderNames}); + + api->forwardMessages( + std::move(resolved), action, [] {}); + }, + &st::menuIconDiscussion); + } else { + menu->addAction( + tr::ayu_Repeater(tr::now), + [=] { + if (item->id <= 0) return; + const auto document = item->media()->document(); + const auto history = item->history()->peer->owner().history(item->history()->peer); + auto message = ApiWrap::MessageToSend(prepareSendAction( + history, + Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)})); + if (item->history()->peer->isUser() || item->history()->peer->isChat()) { + message.action.options.sendAs = nullptr; + } + if (item->topic()) { + message.action.replyTo = FullReplyTo{ + .messageId = item->fullId(), + .topicRootId = item->topicRootId(), + }; + } + Api::SendExistingDocument(std::move(message), document); + }, + &st::menuIconDiscussion); + } + } + } +} + void AddReadUntilAction(not_null menu, HistoryItem *item) { if (item->isLocal() || item->isService() || item->out() || item->isDeleted()) { return; diff --git a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h index 5fc9346c69..bb51dad7ef 100644 --- a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h +++ b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h @@ -37,6 +37,7 @@ void AddHistoryAction(not_null menu, HistoryItem *item); void AddHideMessageAction(not_null menu, HistoryItem *item); void AddUserMessagesAction(not_null menu, HistoryItem *item); void AddMessageDetailsAction(not_null menu, HistoryItem *item); +void AddRepeaterAction(not_null menu, HistoryItem *item); void AddReadUntilAction(not_null menu, HistoryItem *item); void AddBurnAction(not_null menu, HistoryItem *item); diff --git a/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp b/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp index 298bbb667d..e5c86867cb 100644 --- a/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp +++ b/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp @@ -974,6 +974,19 @@ void SetupContextMenuElements(not_null container, AyuSettings::set_showMessageDetailsInContextMenu(index); AyuSettings::save(); }); + AddChooseButtonWithIconAndRightText( + container, + controller, + settings->showRepeaterInContextMenu, + options, + tr::ayu_Repeater(), + tr::ayu_SettingsContextMenuTitle(), + st::menuIconDiscussion, + [=](int index) + { + AyuSettings::set_showRepeaterInContextMenu(index); + AyuSettings::save(); + }); AddSkip(container); AddDividerText(container, tr::ayu_SettingsContextMenuDescription()); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index afadf42c55..7e4f0d92e5 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2549,6 +2549,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { AyuUi::AddHideMessageAction(_menu, item); AyuUi::AddUserMessagesAction(_menu, item); AyuUi::AddMessageDetailsAction(_menu, item); + AyuUi::AddRepeaterAction(_menu, item); }; const auto addPhotoActions = [&](not_null photo, HistoryItem *item) { const auto media = photo->activeMediaView(); diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 859608d249..670dc512f7 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -1058,6 +1058,7 @@ void AddMessageActions( AyuUi::AddHideMessageAction(menu, request.item); AyuUi::AddUserMessagesAction(menu, request.item); AyuUi::AddMessageDetailsAction(menu, request.item); + AyuUi::AddRepeaterAction(menu, request.item); } AddPostLinkAction(menu, request); From d953730ea0a01db1e43ea362ab718081b22792bd Mon Sep 17 00:00:00 2001 From: Bush2021 <79072750+Bush2021@users.noreply.github.com> Date: Thu, 10 Jul 2025 01:24:21 -0400 Subject: [PATCH 2/2] refactor: refactor repeater using `AyuForward` --- .../ayu/ui/context_menu/context_menu.cpp | 170 ++++++------------ 1 file changed, 58 insertions(+), 112 deletions(-) diff --git a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp index 07cb548cc2..8089c1db37 100644 --- a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp +++ b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp @@ -13,6 +13,7 @@ #include "ayu/ayu_settings.h" #include "ayu/ayu_state.h" #include "ayu/data/messages_storage.h" +#include "ayu/features/forward/ayu_forward.h" #include "ayu/ui/context_menu/menu_item_subtext.h" #include "ayu/utils/qt_key_modifiers_extended.h" #include "history/history_item_components.h" @@ -635,130 +636,75 @@ void AddMessageDetailsAction(not_null menu, HistoryItem *item) { }); } -Api::SendAction prepareSendAction(auto _history, Api::SendOptions options) { - auto result = Api::SendAction(_history, options); - return result; -} - void AddRepeaterAction(not_null menu, HistoryItem *item) { const auto settings = &AyuSettings::getInstance(); if (!needToShowItem(settings->showRepeaterInContextMenu)) { return; } - if (!item) { + if (!item || item->isService() || item->id <= 0) { + return; + } + + const auto peer = item->history()->peer; + if (!peer->isUser() && !peer->isChat() && !peer->isMegagroup()) { + return; + } + + const auto canRepeat = item->allowsForward() || + (!item->emptyText() && !item->isDeleted()) || + (item->media() && (item->media()->document() || item->media()->photo())); + + if (!canRepeat) { return; } const auto itemId = item->fullId(); - const auto _history = item->history(); - if ((item->history()->peer->isMegagroup() || item->history()->peer->isChat() || item->history()->peer->isUser())) { - if (item->allowsForward()) { - menu->addAction( - tr::ayu_Repeater(tr::now), - [=] { - if (item->id <= 0) return; - const auto api = &item->history()->peer->session().api(); - auto action = Api::SendAction( - item->history()->peer->owner().history(item->history()->peer), - Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)}); - action.clearDraft = false; - if (item->history()->peer->isUser() || item->history()->peer->isChat()) { - action.options.sendAs = nullptr; - } + const auto history = item->history(); + const auto session = &history->session(); - if (item->topic()) { - action.replyTo = FullReplyTo{ - .messageId = item->fullId(), - .topicRootId = item->topicRootId(), - }; - } - - const auto history = item->history()->peer->owner().history(item->history()->peer); - auto resolved = history->resolveForwardDraft(Data::ForwardDraft{.ids = MessageIdsList(1, itemId)}); - - api->forwardMessages( - std::move(resolved), action, [] {}); - }, - &st::menuIconDiscussion); - } else if (!item->isService() && !item->emptyText() && item->media() == nullptr) { - menu->addAction( - tr::ayu_Repeater(tr::now), - [=] { - if (item->id <= 0) return; - const auto api = &item->history()->peer->session().api(); - auto message = ApiWrap::MessageToSend(prepareSendAction( - _history->peer->owner().history(item->history()->peer), - Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)})); - message.textWithTags = {item->originalText().text, - TextUtilities::ConvertEntitiesToTextTags(item->originalText().entities)}; - if (item->history()->peer->isUser() || item->history()->peer->isChat()) { - message.action.options.sendAs = nullptr; - } - if (item->topic()) { - message.action.replyTo = FullReplyTo{ - .messageId = item->fullId(), - .topicRootId = item->topicRootId(), - }; - } - api->sendMessage(std::move(message)); - }, - &st::menuIconDiscussion); - } else if (!item->isService() && item->media()->document() != nullptr && - item->media()->document()->sticker() != nullptr) { - if (item->allowsForward()) { - menu->addAction( - tr::ayu_Repeater(tr::now), - [=] { - if (item->id <= 0) return; - const auto api = &item->history()->peer->session().api(); - auto action = Api::SendAction( - item->history()->peer->owner().history(item->history()->peer), - Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)}); - action.clearDraft = false; - if (item->history()->peer->isUser() || item->history()->peer->isChat()) { - action.options.sendAs = nullptr; - } - if (item->topic()) { - action.replyTo = FullReplyTo{ - .messageId = item->fullId(), - .topicRootId = item->topicRootId(), - }; - } - - const auto history = item->history()->peer->owner().history(item->history()->peer); - auto resolved = history->resolveForwardDraft(Data::ForwardDraft{ - .ids = MessageIdsList(1, itemId), .options = Data::ForwardOptions::NoSenderNames}); - - api->forwardMessages( - std::move(resolved), action, [] {}); - }, - &st::menuIconDiscussion); - } else { - menu->addAction( - tr::ayu_Repeater(tr::now), - [=] { - if (item->id <= 0) return; - const auto document = item->media()->document(); - const auto history = item->history()->peer->owner().history(item->history()->peer); - auto message = ApiWrap::MessageToSend(prepareSendAction( - history, - Api::SendOptions{.sendAs = _history->session().sendAsPeers().resolveChosen(_history->peer)})); - if (item->history()->peer->isUser() || item->history()->peer->isChat()) { - message.action.options.sendAs = nullptr; - } - if (item->topic()) { - message.action.replyTo = FullReplyTo{ - .messageId = item->fullId(), - .topicRootId = item->topicRootId(), - }; - } - Api::SendExistingDocument(std::move(message), document); - }, - &st::menuIconDiscussion); + menu->addAction( + tr::ayu_Repeater(tr::now), + [=] { + auto sendOptions = Api::SendOptions{ + .sendAs = session->sendAsPeers().resolveChosen(peer) + }; + + if (peer->isUser() || peer->isChat()) { + sendOptions.sendAs = nullptr; } - } - } + + auto action = Api::SendAction(history, sendOptions); + action.clearDraft = false; + + if (item->topic()) { + action.replyTo = FullReplyTo{ + .messageId = itemId, + .topicRootId = item->topicRootId(), + }; + } + + auto forwardDraft = Data::ForwardDraft{ + .ids = MessageIdsList(1, itemId), + .options = Data::ForwardOptions::PreserveInfo + }; + auto resolved = history->resolveForwardDraft(forwardDraft); + const auto needsFullAyuForward = AyuForward::isFullAyuForwardNeeded(item); + const auto needsAyuForward = AyuForward::isAyuForwardNeeded(item); + + if (needsFullAyuForward) { + crl::async([=] { + AyuForward::forwardMessages(session, action, false, resolved); + }); + } else if (needsAyuForward) { + crl::async([=] { + AyuForward::intelligentForward(session, action, resolved); + }); + } else { + session->api().forwardMessages(std::move(resolved), action, [] {}); + } + }, + &st::menuIconDiscussion); } void AddReadUntilAction(not_null menu, HistoryItem *item) {