Add revoking of full history.

This commit is contained in:
John Preston 2019-03-21 17:48:40 +04:00
parent 33069739ee
commit eb1825defd
9 changed files with 130 additions and 113 deletions

View File

@ -2446,6 +2446,30 @@ void ApiWrap::applyAffectedMessages(
App::main()->ptsUpdateAndApply(data.vpts.v, data.vpts_count.v);
}
void ApiWrap::deleteMessages(
not_null<PeerData*> peer,
const QVector<MTPint> &ids,
bool revoke) {
const auto done = [=](const MTPmessages_AffectedMessages & result) {
applyAffectedMessages(peer, result);
if (const auto history = peer->owner().historyLoaded(peer)) {
history->requestChatListMessage();
}
};
if (const auto channel = peer->asChannel()) {
request(MTPchannels_DeleteMessages(
channel->inputChannel,
MTP_vector<MTPint>(ids)
)).done(done).send();
} else {
using Flag = MTPmessages_DeleteMessages::Flag;
request(MTPmessages_DeleteMessages(
MTP_flags(revoke ? Flag::f_revoke : Flag(0)),
MTP_vector<MTPint>(ids)
)).done(done).send();
}
}
void ApiWrap::saveDraftsToCloud() {
for (auto i = _draftsSaveRequestIds.begin(), e = _draftsSaveRequestIds.end(); i != e; ++i) {
if (i->second) continue; // sent already

View File

@ -213,6 +213,10 @@ public:
void clearHistory(not_null<PeerData*> peer, bool revoke);
void deleteConversation(not_null<PeerData*> peer, bool revoke);
void deleteMessages(
not_null<PeerData*> peer,
const QVector<MTPint> &ids,
bool revoke);
base::Observable<PeerData*> &fullPeerUpdated() {
return _fullPeerUpdated;

View File

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "ui/empty_userpic.h"
#include "core/click_handler_types.h"
#include "window/window_controller.h"
#include "storage/localstorage.h"
#include "data/data_session.h"
#include "data/data_channel.h"
@ -473,13 +474,52 @@ DeleteMessagesBox::DeleteMessagesBox(
Expects(!_ids.empty());
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
bool justClear)
: _wipeHistoryPeer(peer)
, _wipeHistoryJustClear(justClear) {
}
void DeleteMessagesBox::prepare() {
auto details = TextWithEntities();
const auto appendDetails = [&](TextWithEntities &&text) {
TextUtilities::Append(details, { "\n\n" });
TextUtilities::Append(details, std::move(text));
};
if (_moderateFrom) {
auto deleteKey = lng_box_delete;
auto deleteStyle = &st::defaultBoxButton;
if (const auto peer = _wipeHistoryPeer) {
if (_wipeHistoryJustClear) {
details.text = peer->isSelf()
? lang(lng_sure_delete_saved_messages)
: peer->isUser()
? lng_sure_delete_history(lt_contact, peer->name)
: lng_sure_delete_group_history(lt_group, peer->name);
deleteStyle = &st::attentionBoxButton;
} else {
details.text = peer->isSelf()
? lang(lng_sure_delete_saved_messages)
: peer->isUser()
? lng_sure_delete_history(lt_contact, peer->name)
: peer->isChat()
? lng_sure_delete_and_exit(lt_group, peer->name)
: lang(peer->isMegagroup()
? lng_sure_leave_group
: lng_sure_leave_channel);
deleteKey = _wipeHistoryPeer->isUser()
? lng_box_delete
: lng_box_leave;
deleteStyle = &(peer->isChannel()
? st::defaultBoxButton
: st::attentionBoxButton);
}
if (auto revoke = revokeText(peer)) {
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
}
} else if (_moderateFrom) {
Assert(_moderateInChannel != nullptr);
details.text = lang(lng_selected_delete_sure_this);
if (_moderateBan) {
@ -511,8 +551,11 @@ void DeleteMessagesBox::prepare() {
}
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
addButton(langFactory(lng_box_delete), [this] { deleteAndClear(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
addButton(
langFactory(deleteKey),
[=] { deleteAndClear(); },
*deleteStyle);
addButton(langFactory(lng_cancel), [=] { closeBox(); });
auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
if (_moderateFrom) {
@ -547,6 +590,20 @@ PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
-> std::optional<RevokeConfig> {
auto result = RevokeConfig();
if (peer == _wipeHistoryPeer) {
if (!peer->canRevokeFullHistory()) {
return std::nullopt;
} else if (const auto user = peer->asUser()) {
result.checkbox = lng_delete_for_other_check(
lt_user,
user->firstName);
} else {
result.checkbox = lang(lng_delete_for_everyone_check);
}
return result;
}
const auto items = ranges::view::all(
_ids
) | ranges::view::transform([](FullMsgId id) {
@ -554,6 +611,7 @@ auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
}) | ranges::view::filter([](HistoryItem *item) {
return (item != nullptr);
}) | ranges::to_vector;
if (items.size() != _ids.size()) {
// We don't have information about all messages.
return std::nullopt;
@ -575,13 +633,14 @@ auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
? -1
: ranges::count_if(outgoing, canRevoke);
auto result = RevokeConfig();
if (canRevokeAll) {
result.checkbox = peer->isUser()
? lng_delete_for_other_check(
if (const auto user = peer->asUser()) {
result.checkbox = lng_delete_for_other_check(
lt_user,
peer->asUser()->firstName)
: lang(lng_delete_for_everyone_check);
user->firstName);
} else {
result.checkbox = lang(lng_delete_for_everyone_check);
}
return result;
} else if (canRevokeOutgoingCount > 0) {
result.checkbox = lang(lng_delete_for_other_my);
@ -645,6 +704,28 @@ void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
}
void DeleteMessagesBox::deleteAndClear() {
const auto revoke = _revoke ? _revoke->checked() : false;
if (const auto peer = _wipeHistoryPeer) {
const auto justClear = _wipeHistoryJustClear;
closeBox();
if (justClear) {
peer->session().api().clearHistory(peer, revoke);
} else {
const auto controller = App::wnd()->controller();
if (controller->activeChatCurrent().peer() == peer) {
Ui::showChatsList();
}
// Don't delete old history by default,
// because Android app doesn't.
//
//if (const auto from = peer->migrateFrom()) {
// peer->session().api().deleteConversation(from, false);
//}
peer->session().api().deleteConversation(peer, revoke);
}
return;
}
if (_moderateFrom) {
if (_banUser && _banUser->checked()) {
_moderateInChannel->session().api().kickParticipant(
@ -688,9 +769,8 @@ void DeleteMessagesBox::deleteAndClear() {
}
}
const auto revoke = _revoke ? _revoke->checked() : false;
for (const auto &[peer, ids] : idsByPeer) {
App::main()->deleteMessages(peer, ids, revoke);
peer->session().api().deleteMessages(peer, ids, revoke);
}
Ui::hideLayer();
Auth().data().sendHistoryChangeNotifications();

View File

@ -151,7 +151,7 @@ public:
not_null<HistoryItem*> item,
bool suggestModerateActions);
DeleteMessagesBox(QWidget*, MessageIdsList &&selected);
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool deleteChat);
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
void setDeleteConfirmedCallback(Fn<void()> callback) {
_deleteConfirmedCallback = std::move(callback);
@ -172,6 +172,8 @@ private:
PeerData *checkFromSinglePeer() const;
std::optional<RevokeConfig> revokeText(not_null<PeerData*> peer) const;
PeerData * const _wipeHistoryPeer = nullptr;
const bool _wipeHistoryJustClear = false;
const MessageIdsList _ids;
UserData *_moderateFrom = nullptr;
ChannelData *_moderateInChannel = nullptr;

View File

@ -648,6 +648,12 @@ Data::RestrictionCheckResult PeerData::amRestricted(
return Result::Allowed();
}
bool PeerData::canRevokeFullHistory() const {
return isUser()
&& Global::RevokePrivateInbox()
&& (Global::RevokePrivateTimeLimit() == 0x7FFFFFFF);
}
namespace Data {
std::vector<ChatRestrictions> ListOfRestrictions() {

View File

@ -160,6 +160,7 @@ public:
[[nodiscard]] bool canWrite() const;
[[nodiscard]] Data::RestrictionCheckResult amRestricted(
ChatRestriction right) const;
[[nodiscard]] bool canRevokeFullHistory() const;
[[nodiscard]] UserData *asUser();
[[nodiscard]] const UserData *asUser() const;

View File

@ -899,26 +899,6 @@ void MainWidget::dialogsActivate() {
_dialogs->activate();
}
void MainWidget::deleteMessages(
not_null<PeerData*> peer,
const QVector<MTPint> &ids,
bool revoke) {
if (const auto channel = peer->asChannel()) {
MTP::send(
MTPchannels_DeleteMessages(
channel->inputChannel,
MTP_vector<MTPint>(ids)),
rpcDone(&MainWidget::messagesAffected, peer));
} else {
using Flag = MTPmessages_DeleteMessages::Flag;
MTP::send(
MTPmessages_DeleteMessages(
MTP_flags(revoke ? Flag::f_revoke : Flag(0)),
MTP_vector<MTPint>(ids)),
rpcDone(&MainWidget::messagesAffected, peer));
}
}
void MainWidget::removeDialog(Dialogs::Key key) {
_dialogs->removeDialog(key);
}
@ -1055,21 +1035,6 @@ void MainWidget::checkLastUpdate(bool afterSleep) {
}
}
void MainWidget::messagesAffected(
not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result) {
const auto &data = result.c_messages_affectedMessages();
if (const auto channel = peer->asChannel()) {
channel->ptsUpdateAndApply(data.vpts.v, data.vpts_count.v);
} else {
ptsUpdateAndApply(data.vpts.v, data.vpts_count.v);
}
if (const auto history = session().data().historyLoaded(peer)) {
history->requestChatListMessage();
}
}
void MainWidget::handleAudioUpdate(const Media::Player::TrackState &state) {
using State = Media::Player::State;
const auto document = state.id.audio();

View File

@ -195,11 +195,6 @@ public:
void deletePhotoLayer(PhotoData *photo);
void deleteMessages(
not_null<PeerData*> peer,
const QVector<MTPint> &ids,
bool revoke);
bool sendMessageFail(const RPCError &error);
Dialogs::IndexedList *contactsList();
@ -371,10 +366,6 @@ private:
void destroyExportTopBar();
void exportTopBarHeightUpdated();
void messagesAffected(
not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result);
Window::SectionSlideParams prepareShowAnimation(
bool willHaveTopBarShadow);
void showNewSection(

View File

@ -788,69 +788,13 @@ void PeerMenuAddMuteAction(
Fn<void()> ClearHistoryHandler(not_null<PeerData*> peer) {
return [=] {
const auto weak = std::make_shared<QPointer<BoxContent>>();
const auto text = peer->isSelf()
? lang(lng_sure_delete_saved_messages)
: peer->isUser()
? lng_sure_delete_history(lt_contact, peer->name)
: lng_sure_delete_group_history(lt_group, peer->name);
const auto callback = [=] {
if (const auto strong = *weak) {
strong->closeBox();
}
peer->session().api().clearHistory(peer, false);
};
*weak = Ui::show(
Box<ConfirmBox>(
text,
lang(lng_box_delete),
st::attentionBoxButton,
callback),
LayerOption::KeepOther);
Ui::show(Box<DeleteMessagesBox>(peer, true), LayerOption::KeepOther);
};
}
Fn<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer) {
return [=] {
const auto weak = std::make_shared<QPointer<BoxContent>>();
const auto text = peer->isSelf()
? lang(lng_sure_delete_saved_messages)
: peer->isUser()
? lng_sure_delete_history(lt_contact, peer->name)
: peer->isChat()
? lng_sure_delete_and_exit(lt_group, peer->name)
: lang(peer->isMegagroup()
? lng_sure_leave_group
: lng_sure_leave_channel);
const auto confirm = lang(peer->isUser()
? lng_box_delete
: lng_box_leave);
const auto &confirmStyle = peer->isChannel()
? st::defaultBoxButton
: st::attentionBoxButton;
const auto callback = [=] {
if (const auto strong = *weak) {
strong->closeBox();
}
const auto controller = App::wnd()->controller();
if (controller->activeChatCurrent().peer() == peer) {
Ui::showChatsList();
}
// Don't delete old history by default,
// because Android app doesn't.
//
//if (const auto from = peer->migrateFrom()) {
// peer->session().api().deleteConversation(from, false);
//}
peer->session().api().deleteConversation(peer, false);
};
*weak = Ui::show(
Box<ConfirmBox>(
text,
confirm,
confirmStyle,
callback),
LayerOption::KeepOther);
Ui::show(Box<DeleteMessagesBox>(peer, false), LayerOption::KeepOther);
};
}