diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 970e6d91ec..9adfa372ef 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -6846,6 +6846,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_ClearDeletedMessagesTitle" = "Clear deleted messages"; "ayu_ClearDeletedMessagesText" = "Are you sure you want to clear all deleted messages in this chat?"; "ayu_ClearDeletedMessagesActionText" = "Clear"; +"ayu_DeleteOwnMessages" = "Delete own messages"; +"ayu_DeleteOwnMessagesConfirmation" = "Are you sure you want to delete all your messages from this group?"; "ayu_SuggestGhostModeTitle" = "Ghost Mode"; "ayu_SuggestGhostModeStoryText" = "Do you want to enable **Ghost Mode** before viewing the story?"; "ayu_SuggestGhostModeStoryActionTextYes" = "Yes"; diff --git a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp index 3e585903f1..1d28a8297b 100644 --- a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp +++ b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.cpp @@ -20,25 +20,168 @@ #include "core/mime_type.h" #include "styles/style_ayu_icons.h" #include "styles/style_menu_icons.h" +#include "styles/style_layers.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "window/window_peer_menu.h" #include "ayu/ui/message_history/history_section.h" #include "ayu/utils/telegram_helpers.h" +#include "base/call_delayed.h" +#include "base/random.h" #include "base/unixtime.h" #include "data/data_channel.h" #include "data/data_user.h" #include "data/data_chat.h" #include "data/data_forum_topic.h" +#include "data/data_search_controller.h" #include "data/data_session.h" #include "history/view/history_view_context_menu.h" #include "history/view/history_view_element.h" +#include "ui/boxes/confirm_box.h" #include "window/window_controller.h" #include "window/window_session_controller.h" namespace AyuUi { +namespace { + +void DeleteMyMessagesAfterConfirm(not_null peer) { + const auto session = &peer->session(); + + auto collected = std::make_shared>(); + + const auto removeNext = std::make_shared>(); + const auto requestNext = std::make_shared>(); + + *removeNext = [=](int index) + { + if (index >= int(collected->size())) { + DEBUG_LOG(("Deleted all %1 my messages in this chat").arg(collected->size())); + return; + } + + QVector ids; + ids.reserve(std::min(100, collected->size() - index)); + for (auto i = 0; i < 100 && (index + i) < int(collected->size()); ++i) { + ids.push_back(MTP_int((*collected)[index + i].bare)); + } + + const auto batch = index / 100 + 1; + const auto done = [=](const MTPmessages_AffectedMessages &result) + { + session->api().applyAffectedMessages(peer, result); + if (peer->isChannel()) { + session->data().processMessagesDeleted(peer->id, ids); + } else { + session->data().processNonChannelMessagesDeleted(ids); + } + const auto deleted = index + ids.size(); + DEBUG_LOG(("Deleted batch %1, total deleted %2/%3").arg(batch).arg(deleted).arg(collected->size())); + const auto delay = crl::time(500 + base::RandomValue() % 500); + base::call_delayed(delay, [=] { (*removeNext)(deleted); }); + }; + const auto fail = [=](const MTP::Error &error) + { + DEBUG_LOG(("Delete batch failed: %1").arg(error.type())); + const auto delay = crl::time(1000); + base::call_delayed(delay, [=] { (*removeNext)(index); }); + }; + + if (const auto channel = peer->asChannel()) { + session->api() + .request(MTPchannels_DeleteMessages(channel->inputChannel, MTP_vector(ids))) + .done(done) + .fail(fail) + .handleFloodErrors() + .send(); + } else { + using Flag = MTPmessages_DeleteMessages::Flag; + session->api() + .request(MTPmessages_DeleteMessages(MTP_flags(Flag::f_revoke), MTP_vector(ids))) + .done(done) + .fail(fail) + .handleFloodErrors() + .send(); + } + }; + + *requestNext = [=](MsgId from) + { + using Flag = MTPmessages_Search::Flag; + auto request = MTPmessages_Search( + MTP_flags(Flag::f_from_id), + peer->input, + MTP_string(), + MTP_inputPeerSelf(), + MTPInputPeer(), + MTPVector(), + MTP_int(0), + // top_msg_id + MTP_inputMessagesFilterEmpty(), + MTP_int(0), + // min_date + MTP_int(0), + // max_date + MTP_int(from.bare), + MTP_int(0), + // add_offset + MTP_int(100), + MTP_int(0), + // max_id + MTP_int(0), + // min_id + MTP_long(0)); // hash + + session->api() + .request(std::move(request)) + .done([=](const Api::HistoryRequestResult &result) + { + auto parsed = Api::ParseHistoryResult(peer, from, Data::LoadDirection::Before, result); + MsgId minId; + int batchCount = 0; + for (const auto &id : parsed.messageIds) { + if (!minId || id < minId) minId = id; + collected->push_back(id); + ++batchCount; + } + DEBUG_LOG(("Batch found %1 my messages, total %2").arg(batchCount).arg(collected->size())); + if (parsed.messageIds.size() == 100 && minId) { + (*requestNext)(minId - MsgId(1)); + } else { + DEBUG_LOG(("Found %1 my messages in this chat (SEARCH)").arg(collected->size())); + (*removeNext)(0); + } + }) + .fail([=](const MTP::Error &error) { DEBUG_LOG(("History fetch failed: %1").arg(error.type())); }) + .send(); + }; + + (*requestNext)(MsgId(0)); +} + +Fn DeleteMyMessagesHandler(not_null controller, not_null peer) { + return [=] + { + if (!controller->showFrozenError()) { + controller->show(Ui::MakeConfirmBox({ + .text = tr::ayu_DeleteOwnMessagesConfirmation(tr::now), + .confirmed = + [=](Fn &&close) + { + DeleteMyMessagesAfterConfirm(peer); + close(); + }, + .confirmText = tr::lng_box_delete(), + .cancelText = tr::lng_cancel(), + .confirmStyle = &st::attentionBoxButton, + })); + } + }; +} + +} + bool needToShowItem(int state) { return state == 1 || (state == 2 && base::IsExtendedContextMenuModifierPressed()); } @@ -170,6 +313,34 @@ void AddOpenChannelAction(PeerData *peerData, &st::menuIconChannel); } +void AddDeleteOwnMessagesAction(PeerData *peerData, + Data::ForumTopic *topic, + not_null sessionController, + const Window::PeerMenuCallback &addCallback) { + if (topic) { + return; + } + const auto isGroup = peerData->isChat() || peerData->isMegagroup(); + if (!isGroup) { + return; + } + if (const auto chat = peerData->asChat()) { + if (!chat->amIn() || chat->amCreator() || chat->hasAdminRights()) { + return; + } + } else if (const auto channel = peerData->asChannel()) { + if (!channel->isMegagroup() || !channel->amIn() || channel->amCreator() || channel->hasAdminRights()) { + return; + } + } else { + return; + } + addCallback( + tr::ayu_DeleteOwnMessages(tr::now), + DeleteMyMessagesHandler(sessionController, peerData), + &st::menuIconTTL); +} + void AddHistoryAction(not_null menu, HistoryItem *item) { if (item->hideEditedBadge()) { return; diff --git a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h index 1a422aad05..5fc9346c69 100644 --- a/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h +++ b/Telegram/SourceFiles/ayu/ui/context_menu/context_menu.h @@ -28,6 +28,10 @@ void AddJumpToBeginningAction(PeerData *peerData, void AddOpenChannelAction(PeerData *peerData, not_null sessionController, const Window::PeerMenuCallback &addCallback); +void AddDeleteOwnMessagesAction(PeerData *peerData, + Data::ForumTopic* topic, + not_null sessionController, + const Window::PeerMenuCallback &addCallback); void AddHistoryAction(not_null menu, HistoryItem *item); void AddHideMessageAction(not_null menu, HistoryItem *item); diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.cpp b/Telegram/SourceFiles/boxes/delete_messages_box.cpp index d880ab5860..7ff851209c 100644 --- a/Telegram/SourceFiles/boxes/delete_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/delete_messages_box.cpp @@ -38,14 +38,22 @@ DeleteMessagesBox::DeleteMessagesBox( bool suggestModerateActions) : _session(&item->history()->session()) , _ids(1, item->fullId()) { + const auto peer = item->history()->peer; + const auto channel = peer->asChannel(); if (suggestModerateActions) { _moderateBan = item->suggestBanReport(); _moderateDeleteAll = item->suggestDeleteAllReport(); - if (_moderateBan || _moderateDeleteAll) { - _moderateFrom = item->from(); - _moderateInChannel = item->history()->peer->asChannel(); + } else if (item->out()) { + const auto chat = peer->asChat(); + if ((chat && chat->canDeleteMessages()) || + (channel && !channel->isBroadcast() && channel->canDeleteMessages())) { + _moderateDeleteAll = true; } } + if ((_moderateBan || _moderateDeleteAll) && channel) { + _moderateFrom = item->from(); + _moderateInChannel = channel; + } } DeleteMessagesBox::DeleteMessagesBox( diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index a1c6300699..232060df57 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1425,6 +1425,7 @@ void Filler::fillContextMenuActions() { } } addClearHistory(); + AyuUi::AddDeleteOwnMessagesAction(_peer, _topic, _controller, _addAction); addDeleteChat(); addLeaveChat(); addDeleteTopic(); @@ -1448,6 +1449,7 @@ void Filler::fillHistoryActions() { addReport(); AyuUi::AddDeletedMessagesActions(_peer, _thread, _controller, _addAction); addClearHistory(); + AyuUi::AddDeleteOwnMessagesAction(_peer, _topic, _controller, _addAction); addDeleteChat(); addLeaveChat(); }