diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 779778df3e..715824fd5f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1625,6 +1625,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_info_delete_contact" = "Delete contact"; "lng_info_share_contact" = "Share this contact"; "lng_profile_clear_history" = "Clear history"; +"lng_profile_delete_my_messages" = "Delete all my messages"; "lng_profile_delete_conversation" = "Delete chat"; "lng_profile_block_user" = "Block user"; "lng_profile_unblock_user" = "Unblock user"; @@ -2011,6 +2012,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_sure_leave_group" = "Are you sure you want to leave this group?"; "lng_sure_delete_group" = "Are you sure you want to delete this group? All members will be removed, and all messages will be lost."; "lng_sure_delete_saved_messages" = "Are you sure you want to delete all your saved messages?\n\nThis action cannot be undone."; +"lng_sure_delete_my_messages" = "Are you sure you want to delete all your messages from this group?"; "lng_no_clear_history_channel" = "In channels you can enable auto-delete for messages."; "lng_no_clear_history_group" = "In public groups you can enable auto-delete for messages."; "lng_sure_delete_by_date_one" = "Are you sure you want to delete all messages for **{date}**?\n\nThis action cannot be undone."; 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 da58c91829..a9cc910ad6 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/pin_messages_box.h" #include "boxes/premium_limits_box.h" #include "boxes/report_messages_box.h" +#include "data/data_search_controller.h" #include "boxes/peers/add_bot_to_chat_box.h" #include "boxes/peers/add_participants_box.h" #include "boxes/peers/edit_forum_topic_box.h" @@ -287,6 +288,7 @@ private: void addToggleUnreadMark(); void addToggleArchive(); void addClearHistory(); + void addDeleteMyMessages(); void addDeleteChat(); void addLeaveChat(); void addJoinChat(); @@ -745,6 +747,31 @@ void Filler::addClearHistory() { &st::menuIconClear); } +void Filler::addDeleteMyMessages() { + if (_topic) { + return; + } + const auto isGroup = _peer->isChat() || _peer->isMegagroup(); + if (!isGroup) { + return; + } + if (const auto chat = _peer->asChat()) { + if (!chat->amIn() || chat->amCreator() || chat->hasAdminRights()) { + return; + } + } else if (const auto channel = _peer->asChannel()) { + if (!channel->isMegagroup() || !channel->amIn() || channel->amCreator() || channel->hasAdminRights()) { + return; + } + } else { + return; + } + _addAction( + tr::lng_profile_delete_my_messages(tr::now), + DeleteMyMessagesHandler(_controller, _peer), + &st::menuIconDelete); +} + void Filler::addDeleteChat() { if (_topic || _peer->isChannel()) { return; @@ -1425,6 +1452,7 @@ void Filler::fillContextMenuActions() { } } addClearHistory(); + addDeleteMyMessages(); addDeleteChat(); addLeaveChat(); addDeleteTopic(); @@ -1448,6 +1476,7 @@ void Filler::fillHistoryActions() { addReport(); AyuUi::AddDeletedMessagesActions(_peer, _thread, _controller, _addAction); addClearHistory(); + addDeleteMyMessages(); addDeleteChat(); addLeaveChat(); } @@ -3179,6 +3208,128 @@ Fn ClearHistoryHandler( }; } +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::lng_sure_delete_my_messages(tr::now), + .confirmed = + [=](Fn &&close) + { + DeleteMyMessagesAfterConfirm(peer); + close(); + }, + .confirmText = tr::lng_box_delete(), + .cancelText = tr::lng_cancel(), + .confirmStyle = &st::attentionBoxButton, + })); + } + }; +} Fn DeleteAndLeaveHandler( not_null controller, not_null peer) { diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index a125c3c55d..f9dc2eca58 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -147,6 +147,9 @@ Fn DeleteAndLeaveHandler( not_null controller, not_null peer); +Fn DeleteMyMessagesHandler( + not_null controller, + not_null peer); object_ptr PrepareChooseRecipientBox( not_null session, FnMut)> &&chosen,