Implement deleting own messages from groups

This commit is contained in:
Neurotoxin001 2025-06-25 00:05:56 +03:00
parent 3be793032f
commit 353216cf0a
4 changed files with 167 additions and 3 deletions

View file

@ -1625,6 +1625,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_info_delete_contact" = "Delete contact"; "lng_info_delete_contact" = "Delete contact";
"lng_info_share_contact" = "Share this contact"; "lng_info_share_contact" = "Share this contact";
"lng_profile_clear_history" = "Clear history"; "lng_profile_clear_history" = "Clear history";
"lng_profile_delete_my_messages" = "Delete all my messages";
"lng_profile_delete_conversation" = "Delete chat"; "lng_profile_delete_conversation" = "Delete chat";
"lng_profile_block_user" = "Block user"; "lng_profile_block_user" = "Block user";
"lng_profile_unblock_user" = "Unblock 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_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_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_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_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_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."; "lng_sure_delete_by_date_one" = "Are you sure you want to delete all messages for **{date}**?\n\nThis action cannot be undone.";

View file

@ -38,14 +38,22 @@ DeleteMessagesBox::DeleteMessagesBox(
bool suggestModerateActions) bool suggestModerateActions)
: _session(&item->history()->session()) : _session(&item->history()->session())
, _ids(1, item->fullId()) { , _ids(1, item->fullId()) {
const auto peer = item->history()->peer;
const auto channel = peer->asChannel();
if (suggestModerateActions) { if (suggestModerateActions) {
_moderateBan = item->suggestBanReport(); _moderateBan = item->suggestBanReport();
_moderateDeleteAll = item->suggestDeleteAllReport(); _moderateDeleteAll = item->suggestDeleteAllReport();
if (_moderateBan || _moderateDeleteAll) { } else if (item->out()) {
_moderateFrom = item->from(); const auto chat = peer->asChat();
_moderateInChannel = item->history()->peer->asChannel(); if ((chat && chat->canDeleteMessages()) ||
(channel && !channel->isBroadcast() && channel->canDeleteMessages())) {
_moderateDeleteAll = true;
} }
} }
if ((_moderateBan || _moderateDeleteAll) && channel) {
_moderateFrom = item->from();
_moderateInChannel = channel;
}
} }
DeleteMessagesBox::DeleteMessagesBox( DeleteMessagesBox::DeleteMessagesBox(

View file

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/pin_messages_box.h" #include "boxes/pin_messages_box.h"
#include "boxes/premium_limits_box.h" #include "boxes/premium_limits_box.h"
#include "boxes/report_messages_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_bot_to_chat_box.h"
#include "boxes/peers/add_participants_box.h" #include "boxes/peers/add_participants_box.h"
#include "boxes/peers/edit_forum_topic_box.h" #include "boxes/peers/edit_forum_topic_box.h"
@ -287,6 +288,7 @@ private:
void addToggleUnreadMark(); void addToggleUnreadMark();
void addToggleArchive(); void addToggleArchive();
void addClearHistory(); void addClearHistory();
void addDeleteMyMessages();
void addDeleteChat(); void addDeleteChat();
void addLeaveChat(); void addLeaveChat();
void addJoinChat(); void addJoinChat();
@ -745,6 +747,31 @@ void Filler::addClearHistory() {
&st::menuIconClear); &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() { void Filler::addDeleteChat() {
if (_topic || _peer->isChannel()) { if (_topic || _peer->isChannel()) {
return; return;
@ -1425,6 +1452,7 @@ void Filler::fillContextMenuActions() {
} }
} }
addClearHistory(); addClearHistory();
addDeleteMyMessages();
addDeleteChat(); addDeleteChat();
addLeaveChat(); addLeaveChat();
addDeleteTopic(); addDeleteTopic();
@ -1448,6 +1476,7 @@ void Filler::fillHistoryActions() {
addReport(); addReport();
AyuUi::AddDeletedMessagesActions(_peer, _thread, _controller, _addAction); AyuUi::AddDeletedMessagesActions(_peer, _thread, _controller, _addAction);
addClearHistory(); addClearHistory();
addDeleteMyMessages();
addDeleteChat(); addDeleteChat();
addLeaveChat(); addLeaveChat();
} }
@ -3179,6 +3208,128 @@ Fn<void()> ClearHistoryHandler(
}; };
} }
void DeleteMyMessagesAfterConfirm(not_null<PeerData*> peer) {
const auto session = &peer->session();
auto collected = std::make_shared<std::vector<MsgId>>();
const auto removeNext = std::make_shared<Fn<void(int)>>();
const auto requestNext = std::make_shared<Fn<void(MsgId)>>();
*removeNext = [=](int index) {
if (index >= int(collected->size())) {
DEBUG_LOG(("Deleted all %1 my messages in this chat").arg(collected->size()));
return;
}
QVector<MTPint> ids;
ids.reserve(std::min<int>(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<int>() % 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<MTPint>(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<MTPint>(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<MTPReaction>(),
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<void()> DeleteMyMessagesHandler(not_null<Window::SessionController *> controller, not_null<PeerData *> peer) {
return [=]
{
if (!controller->showFrozenError()) {
controller->show(Ui::MakeConfirmBox({
.text = tr::lng_sure_delete_my_messages(tr::now),
.confirmed =
[=](Fn<void()> &&close)
{
DeleteMyMessagesAfterConfirm(peer);
close();
},
.confirmText = tr::lng_box_delete(),
.cancelText = tr::lng_cancel(),
.confirmStyle = &st::attentionBoxButton,
}));
}
};
}
Fn<void()> DeleteAndLeaveHandler( Fn<void()> DeleteAndLeaveHandler(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<PeerData*> peer) { not_null<PeerData*> peer) {

View file

@ -147,6 +147,9 @@ Fn<void()> DeleteAndLeaveHandler(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<PeerData*> peer); not_null<PeerData*> peer);
Fn<void()> DeleteMyMessagesHandler(
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer);
object_ptr<Ui::BoxContent> PrepareChooseRecipientBox( object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FnMut<bool(not_null<Data::Thread*>)> &&chosen, FnMut<bool(not_null<Data::Thread*>)> &&chosen,