From 9117b3cdfacd3bfcfe636116f7f4302d817a9575 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 18 Oct 2021 23:55:58 +0300 Subject: [PATCH] Extracted DeleteMessagesBox to separated file. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/boxes/confirm_box.cpp | 393 --------------- Telegram/SourceFiles/boxes/confirm_box.h | 54 --- .../SourceFiles/boxes/delete_messages_box.cpp | 459 ++++++++++++++++++ .../SourceFiles/boxes/delete_messages_box.h | 74 +++ .../calls/calls_box_controller.cpp | 2 +- .../history/history_inner_widget.cpp | 2 +- .../SourceFiles/history/history_widget.cpp | 1 + .../view/history_view_context_menu.cpp | 1 + .../history/view/history_view_list_widget.cpp | 2 +- .../view/history_view_replies_section.cpp | 1 + .../view/history_view_scheduled_section.cpp | 1 + Telegram/SourceFiles/info/info_top_bar.cpp | 2 +- .../info/media/info_media_list_widget.cpp | 2 +- .../media/view/media_view_overlay_widget.cpp | 2 +- .../SourceFiles/window/window_peer_menu.cpp | 1 + 16 files changed, 546 insertions(+), 453 deletions(-) create mode 100644 Telegram/SourceFiles/boxes/delete_messages_box.cpp create mode 100644 Telegram/SourceFiles/boxes/delete_messages_box.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 5ac048005..0bc675b10 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -201,6 +201,8 @@ PRIVATE boxes/connection_box.h boxes/create_poll_box.cpp boxes/create_poll_box.h + boxes/delete_messages_box.cpp + boxes/delete_messages_box.h boxes/dictionaries_manager.cpp boxes/dictionaries_manager.h boxes/download_path_box.cpp diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index b945d5d23..21782d589 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -441,399 +441,6 @@ void MaxInviteBox::resizeEvent(QResizeEvent *e) { _invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height); } -DeleteMessagesBox::DeleteMessagesBox( - QWidget*, - not_null item, - bool suggestModerateActions) -: _session(&item->history()->session()) -, _ids(1, item->fullId()) { - if (suggestModerateActions) { - _moderateBan = item->suggestBanReport(); - _moderateDeleteAll = item->suggestDeleteAllReport(); - if (_moderateBan || _moderateDeleteAll) { - _moderateFrom = item->from()->asUser(); - _moderateInChannel = item->history()->peer->asChannel(); - } - } -} - -DeleteMessagesBox::DeleteMessagesBox( - QWidget*, - not_null session, - MessageIdsList &&selected) -: _session(session) -, _ids(std::move(selected)) { - Expects(!_ids.empty()); -} - -DeleteMessagesBox::DeleteMessagesBox( - QWidget*, - not_null peer, - bool justClear) -: _session(&peer->session()) -, _wipeHistoryPeer(peer) -, _wipeHistoryJustClear(justClear) { -} - -void DeleteMessagesBox::prepare() { - auto details = TextWithEntities(); - const auto appendDetails = [&](TextWithEntities &&text) { - details.append(qstr("\n\n")).append(std::move(text)); - }; - auto deleteText = lifetime().make_state>(); - *deleteText = tr::lng_box_delete(); - auto deleteStyle = &st::defaultBoxButton; - auto canDelete = true; - if (const auto peer = _wipeHistoryPeer) { - if (_wipeHistoryJustClear) { - const auto isChannel = peer->isBroadcast(); - const auto isPublicGroup = peer->isMegagroup() - && peer->asChannel()->isPublic(); - if (isChannel || isPublicGroup) { - canDelete = false; - } - details.text = isChannel - ? tr::lng_no_clear_history_channel(tr::now) - : isPublicGroup - ? tr::lng_no_clear_history_group(tr::now) - : peer->isSelf() - ? tr::lng_sure_delete_saved_messages(tr::now) - : peer->isUser() - ? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name) - : tr::lng_sure_delete_group_history(tr::now, lt_group, peer->name); - deleteStyle = &st::attentionBoxButton; - } else { - details.text = peer->isSelf() - ? tr::lng_sure_delete_saved_messages(tr::now) - : peer->isUser() - ? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name) - : peer->isChat() - ? tr::lng_sure_delete_and_exit(tr::now, lt_group, peer->name) - : peer->isMegagroup() - ? tr::lng_sure_leave_group(tr::now) - : tr::lng_sure_leave_channel(tr::now); - if (!peer->isUser()) { - *deleteText = tr::lng_box_leave(); - } - deleteStyle = &st::attentionBoxButton; - } - if (auto revoke = revokeText(peer)) { - _revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox); - appendDetails(std::move(revoke->description)); - if (!peer->isUser() && !_wipeHistoryJustClear) { - _revoke->checkedValue( - ) | rpl::start_with_next([=](bool revokeForAll) { - *deleteText = revokeForAll - ? tr::lng_box_delete() - : tr::lng_box_leave(); - }, _revoke->lifetime()); - } - } - } else if (_moderateFrom) { - Assert(_moderateInChannel != nullptr); - - details.text = tr::lng_selected_delete_sure_this(tr::now); - if (_moderateBan) { - _banUser.create(this, tr::lng_ban_user(tr::now), false, st::defaultBoxCheckbox); - } - _reportSpam.create(this, tr::lng_report_spam(tr::now), false, st::defaultBoxCheckbox); - if (_moderateDeleteAll) { - _deleteAll.create(this, tr::lng_delete_all_from(tr::now), false, st::defaultBoxCheckbox); - } - } else { - details.text = (_ids.size() == 1) - ? tr::lng_selected_delete_sure_this(tr::now) - : tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size()); - if (const auto peer = checkFromSinglePeer()) { - auto count = int(_ids.size()); - if (hasScheduledMessages()) { - } else if (auto revoke = revokeText(peer)) { - _revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox); - appendDetails(std::move(revoke->description)); - } else if (peer->isChannel()) { - if (peer->isMegagroup()) { - appendDetails({ tr::lng_delete_for_everyone_hint(tr::now, lt_count, count) }); - } - } else if (peer->isChat()) { - appendDetails({ tr::lng_delete_for_me_chat_hint(tr::now, lt_count, count) }); - } else if (!peer->isSelf()) { - appendDetails({ tr::lng_delete_for_me_hint(tr::now, lt_count, count) }); - } - } - } - _text.create(this, rpl::single(std::move(details)), st::boxLabel); - - if (_wipeHistoryJustClear - && _wipeHistoryPeer - && ((_wipeHistoryPeer->isUser() - && !_wipeHistoryPeer->isSelf() - && !_wipeHistoryPeer->isNotificationsUser()) - || (_wipeHistoryPeer->isChat() - && _wipeHistoryPeer->asChat()->canDeleteMessages()) - || (_wipeHistoryPeer->isChannel() - && _wipeHistoryPeer->asChannel()->canDeleteMessages()))) { - _wipeHistoryPeer->updateFull(); - _autoDeleteSettings.create( - this, - (_wipeHistoryPeer->messagesTTL() - ? tr::lng_edit_auto_delete_settings(tr::now) - : tr::lng_enable_auto_delete(tr::now)), - st::boxLinkButton); - _autoDeleteSettings->setClickedCallback([=] { - getDelegate()->show( - Box( - HistoryView::Controls::AutoDeleteSettingsBox, - _wipeHistoryPeer), - Ui::LayerOption(0)); - }); - } - - if (canDelete) { - addButton( - deleteText->value(), - [=] { deleteAndClear(); }, - *deleteStyle); - addButton(tr::lng_cancel(), [=] { closeBox(); }); - } else { - addButton(tr::lng_about_done(), [=] { closeBox(); }); - } - - auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom(); - if (_moderateFrom) { - fullHeight += st::boxMediumSkip; - if (_banUser) { - fullHeight += _banUser->heightNoMargins() + st::boxLittleSkip; - } - fullHeight += _reportSpam->heightNoMargins(); - if (_deleteAll) { - fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins(); - } - } else if (_revoke) { - fullHeight += st::boxMediumSkip + _revoke->heightNoMargins(); - } - if (_autoDeleteSettings) { - fullHeight += st::boxMediumSkip + _autoDeleteSettings->height() + st::boxLittleSkip; - } - setDimensions(st::boxWidth, fullHeight); -} - -bool DeleteMessagesBox::hasScheduledMessages() const { - for (const auto &fullId : _ids) { - if (const auto item = _session->data().message(fullId)) { - if (item->isScheduled()) { - return true; - } - } - } - return false; -} - -PeerData *DeleteMessagesBox::checkFromSinglePeer() const { - auto result = (PeerData*)nullptr; - for (const auto &fullId : _ids) { - if (const auto item = _session->data().message(fullId)) { - const auto peer = item->history()->peer; - if (!result) { - result = peer; - } else if (result != peer) { - return nullptr; - } - } - } - return result; -} - -auto DeleteMessagesBox::revokeText(not_null peer) const --> std::optional { - auto result = RevokeConfig(); - if (peer == _wipeHistoryPeer) { - if (!peer->canRevokeFullHistory()) { - return std::nullopt; - } else if (const auto user = peer->asUser()) { - result.checkbox = tr::lng_delete_for_other_check( - tr::now, - lt_user, - user->firstName); - } else if (_wipeHistoryJustClear) { - return std::nullopt; - } else { - result.checkbox = tr::lng_delete_for_everyone_check(tr::now); - } - return result; - } - - const auto items = ranges::views::all( - _ids - ) | ranges::views::transform([&](FullMsgId id) { - return peer->owner().message(id); - }) | ranges::views::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; - } - - const auto now = base::unixtime::now(); - const auto canRevoke = [&](HistoryItem * item) { - return item->canDeleteForEveryone(now); - }; - const auto cannotRevoke = [&](HistoryItem *item) { - return !item->canDeleteForEveryone(now); - }; - const auto canRevokeAll = ranges::none_of(items, cannotRevoke); - auto outgoing = items | ranges::views::filter(&HistoryItem::out); - const auto canRevokeOutgoingCount = canRevokeAll - ? -1 - : ranges::count_if(outgoing, canRevoke); - - if (canRevokeAll) { - if (const auto user = peer->asUser()) { - result.checkbox = tr::lng_delete_for_other_check( - tr::now, - lt_user, - user->firstName); - } else { - result.checkbox = tr::lng_delete_for_everyone_check(tr::now); - } - return result; - } else if (canRevokeOutgoingCount > 0) { - result.checkbox = tr::lng_delete_for_other_my(tr::now); - if (const auto user = peer->asUser()) { - if (canRevokeOutgoingCount == 1) { - result.description = tr::lng_selected_unsend_about_user_one( - tr::now, - lt_user, - Ui::Text::Bold(user->shortName()), - Ui::Text::WithEntities); - } else { - result.description = tr::lng_selected_unsend_about_user( - tr::now, - lt_count, - canRevokeOutgoingCount, - lt_user, - Ui::Text::Bold(user->shortName()), - Ui::Text::WithEntities); - } - } else if (canRevokeOutgoingCount == 1) { - result.description = tr::lng_selected_unsend_about_group_one( - tr::now, - Ui::Text::WithEntities); - } else { - result.description = tr::lng_selected_unsend_about_group( - tr::now, - lt_count, - canRevokeOutgoingCount, - Ui::Text::WithEntities); - } - return result; - } - return std::nullopt; -} - -void DeleteMessagesBox::resizeEvent(QResizeEvent *e) { - BoxContent::resizeEvent(e); - - _text->moveToLeft(st::boxPadding.left(), st::boxPadding.top()); - auto top = _text->bottomNoMargins() + st::boxMediumSkip; - if (_moderateFrom) { - if (_banUser) { - _banUser->moveToLeft(st::boxPadding.left(), top); - top += _banUser->heightNoMargins() + st::boxLittleSkip; - } - _reportSpam->moveToLeft(st::boxPadding.left(), top); - top += _reportSpam->heightNoMargins() + st::boxLittleSkip; - if (_deleteAll) { - _deleteAll->moveToLeft(st::boxPadding.left(), top); - top += _deleteAll->heightNoMargins() + st::boxLittleSkip; - } - } else if (_revoke) { - const auto availableWidth = width() - 2 * st::boxPadding.left(); - _revoke->resizeToNaturalWidth(availableWidth); - _revoke->moveToLeft(st::boxPadding.left(), top); - top += _revoke->heightNoMargins() + st::boxLittleSkip; - } - if (_autoDeleteSettings) { - top += st::boxMediumSkip - st::boxLittleSkip; - _autoDeleteSettings->moveToLeft(st::boxPadding.left(), top); - } -} - -void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - // Don't make the clearing history so easy. - if (!_wipeHistoryPeer) { - deleteAndClear(); - } - } else { - BoxContent::keyPressEvent(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 { - for (const auto &controller : peer->session().windows()) { - if (controller->activeChatCurrent().peer() == peer) { - Ui::showChatsList(&peer->session()); - } - } - // 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( - _moderateInChannel, - _moderateFrom, - ChatRestrictionsInfo()); - } - if (_reportSpam->checked()) { - _moderateInChannel->session().api().request( - MTPchannels_ReportSpam( - _moderateInChannel->inputChannel, - _moderateFrom->inputUser, - MTP_vector(1, MTP_int(_ids[0].msg))) - ).send(); - } - if (_deleteAll && _deleteAll->checked()) { - _moderateInChannel->session().api().deleteAllFromUser( - _moderateInChannel, - _moderateFrom); - } - } - - if (_deleteConfirmedCallback) { - _deleteConfirmedCallback(); - } - - // deleteMessages can initiate closing of the current section, - // which will cause this box to be destroyed. - const auto session = _session; - const auto weak = Ui::MakeWeak(this); - - session->data().histories().deleteMessages(_ids, revoke); - - if (const auto strong = weak.data()) { - strong->closeBox(); - } - session->data().sendHistoryChangeNotifications(); -} - ConfirmDontWarnBox::ConfirmDontWarnBox( QWidget*, rpl::producer text, diff --git a/Telegram/SourceFiles/boxes/confirm_box.h b/Telegram/SourceFiles/boxes/confirm_box.h index dbf53901f..ca038a395 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.h +++ b/Telegram/SourceFiles/boxes/confirm_box.h @@ -169,60 +169,6 @@ private: }; -class DeleteMessagesBox final : public Ui::BoxContent { -public: - DeleteMessagesBox( - QWidget*, - not_null item, - bool suggestModerateActions); - DeleteMessagesBox( - QWidget*, - not_null session, - MessageIdsList &&selected); - DeleteMessagesBox(QWidget*, not_null peer, bool justClear); - - void setDeleteConfirmedCallback(Fn callback) { - _deleteConfirmedCallback = std::move(callback); - } - -protected: - void prepare() override; - - void resizeEvent(QResizeEvent *e) override; - void keyPressEvent(QKeyEvent *e) override; - -private: - struct RevokeConfig { - QString checkbox; - TextWithEntities description; - }; - void deleteAndClear(); - [[nodiscard]] PeerData *checkFromSinglePeer() const; - [[nodiscard]] bool hasScheduledMessages() const; - [[nodiscard]] std::optional revokeText( - not_null peer) const; - - const not_null _session; - - PeerData * const _wipeHistoryPeer = nullptr; - const bool _wipeHistoryJustClear = false; - const MessageIdsList _ids; - UserData *_moderateFrom = nullptr; - ChannelData *_moderateInChannel = nullptr; - bool _moderateBan = false; - bool _moderateDeleteAll = false; - - object_ptr _text = { nullptr }; - object_ptr _revoke = { nullptr }; - object_ptr _banUser = { nullptr }; - object_ptr _reportSpam = { nullptr }; - object_ptr _deleteAll = { nullptr }; - object_ptr _autoDeleteSettings = { nullptr }; - - Fn _deleteConfirmedCallback; - -}; - class ConfirmDontWarnBox : public Ui::BoxContent { public: ConfirmDontWarnBox( diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.cpp b/Telegram/SourceFiles/boxes/delete_messages_box.cpp new file mode 100644 index 000000000..b13edac73 --- /dev/null +++ b/Telegram/SourceFiles/boxes/delete_messages_box.cpp @@ -0,0 +1,459 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "boxes/delete_messages_box.h" + +#include "apiwrap.h" +#include "base/unixtime.h" +#include "data/data_channel.h" +#include "data/data_chat.h" +#include "data/data_histories.h" +#include "data/data_session.h" +#include "data/data_user.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/view/controls/history_view_ttl_button.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "ui/layers/generic_box.h" +#include "ui/text/text_utilities.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" +#include "window/window_session_controller.h" +#include "facades.h" // Ui::showChatsList +#include "styles/style_layers.h" +#include "styles/style_boxes.h" + +DeleteMessagesBox::DeleteMessagesBox( + QWidget*, + not_null item, + bool suggestModerateActions) +: _session(&item->history()->session()) +, _ids(1, item->fullId()) { + if (suggestModerateActions) { + _moderateBan = item->suggestBanReport(); + _moderateDeleteAll = item->suggestDeleteAllReport(); + if (_moderateBan || _moderateDeleteAll) { + _moderateFrom = item->from()->asUser(); + _moderateInChannel = item->history()->peer->asChannel(); + } + } +} + +DeleteMessagesBox::DeleteMessagesBox( + QWidget*, + not_null session, + MessageIdsList &&selected) +: _session(session) +, _ids(std::move(selected)) { + Expects(!_ids.empty()); +} + +DeleteMessagesBox::DeleteMessagesBox( + QWidget*, + not_null peer, + bool justClear) +: _session(&peer->session()) +, _wipeHistoryPeer(peer) +, _wipeHistoryJustClear(justClear) { +} + +void DeleteMessagesBox::prepare() { + auto details = TextWithEntities(); + const auto appendDetails = [&](TextWithEntities &&text) { + details.append(qstr("\n\n")).append(std::move(text)); + }; + auto deleteText = lifetime().make_state>(); + *deleteText = tr::lng_box_delete(); + auto deleteStyle = &st::defaultBoxButton; + auto canDelete = true; + if (const auto peer = _wipeHistoryPeer) { + if (_wipeHistoryJustClear) { + const auto isChannel = peer->isBroadcast(); + const auto isPublicGroup = peer->isMegagroup() + && peer->asChannel()->isPublic(); + if (isChannel || isPublicGroup) { + canDelete = false; + } + details.text = isChannel + ? tr::lng_no_clear_history_channel(tr::now) + : isPublicGroup + ? tr::lng_no_clear_history_group(tr::now) + : peer->isSelf() + ? tr::lng_sure_delete_saved_messages(tr::now) + : peer->isUser() + ? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name) + : tr::lng_sure_delete_group_history( + tr::now, + lt_group, + peer->name); + deleteStyle = &st::attentionBoxButton; + } else { + details.text = peer->isSelf() + ? tr::lng_sure_delete_saved_messages(tr::now) + : peer->isUser() + ? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name) + : peer->isChat() + ? tr::lng_sure_delete_and_exit(tr::now, lt_group, peer->name) + : peer->isMegagroup() + ? tr::lng_sure_leave_group(tr::now) + : tr::lng_sure_leave_channel(tr::now); + if (!peer->isUser()) { + *deleteText = tr::lng_box_leave(); + } + deleteStyle = &st::attentionBoxButton; + } + if (auto revoke = revokeText(peer)) { + _revoke.create( + this, + revoke->checkbox, + false, + st::defaultBoxCheckbox); + appendDetails(std::move(revoke->description)); + if (!peer->isUser() && !_wipeHistoryJustClear) { + _revoke->checkedValue( + ) | rpl::start_with_next([=](bool revokeForAll) { + *deleteText = revokeForAll + ? tr::lng_box_delete() + : tr::lng_box_leave(); + }, _revoke->lifetime()); + } + } + } else if (_moderateFrom) { + Assert(_moderateInChannel != nullptr); + + details.text = tr::lng_selected_delete_sure_this(tr::now); + if (_moderateBan) { + _banUser.create( + this, + tr::lng_ban_user(tr::now), + false, + st::defaultBoxCheckbox); + } + _reportSpam.create( + this, + tr::lng_report_spam(tr::now), + false, + st::defaultBoxCheckbox); + if (_moderateDeleteAll) { + _deleteAll.create( + this, + tr::lng_delete_all_from(tr::now), + false, + st::defaultBoxCheckbox); + } + } else { + details.text = (_ids.size() == 1) + ? tr::lng_selected_delete_sure_this(tr::now) + : tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size()); + if (const auto peer = checkFromSinglePeer()) { + auto count = int(_ids.size()); + if (hasScheduledMessages()) { + } else if (auto revoke = revokeText(peer)) { + _revoke.create( + this, + revoke->checkbox, + false, + st::defaultBoxCheckbox); + appendDetails(std::move(revoke->description)); + } else if (peer->isChannel()) { + if (peer->isMegagroup()) { + appendDetails({ + tr::lng_delete_for_everyone_hint( + tr::now, + lt_count, + count) + }); + } + } else if (peer->isChat()) { + appendDetails({ + tr::lng_delete_for_me_chat_hint(tr::now, lt_count, count) + }); + } else if (!peer->isSelf()) { + appendDetails({ + tr::lng_delete_for_me_hint(tr::now, lt_count, count) + }); + } + } + } + _text.create(this, rpl::single(std::move(details)), st::boxLabel); + + if (_wipeHistoryJustClear + && _wipeHistoryPeer + && ((_wipeHistoryPeer->isUser() + && !_wipeHistoryPeer->isSelf() + && !_wipeHistoryPeer->isNotificationsUser()) + || (_wipeHistoryPeer->isChat() + && _wipeHistoryPeer->asChat()->canDeleteMessages()) + || (_wipeHistoryPeer->isChannel() + && _wipeHistoryPeer->asChannel()->canDeleteMessages()))) { + _wipeHistoryPeer->updateFull(); + _autoDeleteSettings.create( + this, + (_wipeHistoryPeer->messagesTTL() + ? tr::lng_edit_auto_delete_settings(tr::now) + : tr::lng_enable_auto_delete(tr::now)), + st::boxLinkButton); + _autoDeleteSettings->setClickedCallback([=] { + getDelegate()->show( + Box( + HistoryView::Controls::AutoDeleteSettingsBox, + _wipeHistoryPeer), + Ui::LayerOption(0)); + }); + } + + if (canDelete) { + addButton( + deleteText->value(), + [=] { deleteAndClear(); }, + *deleteStyle); + addButton(tr::lng_cancel(), [=] { closeBox(); }); + } else { + addButton(tr::lng_about_done(), [=] { closeBox(); }); + } + + auto fullHeight = st::boxPadding.top() + + _text->height() + + st::boxPadding.bottom(); + if (_moderateFrom) { + fullHeight += st::boxMediumSkip; + if (_banUser) { + fullHeight += _banUser->heightNoMargins() + st::boxLittleSkip; + } + fullHeight += _reportSpam->heightNoMargins(); + if (_deleteAll) { + fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins(); + } + } else if (_revoke) { + fullHeight += st::boxMediumSkip + _revoke->heightNoMargins(); + } + if (_autoDeleteSettings) { + fullHeight += st::boxMediumSkip + + _autoDeleteSettings->height() + + st::boxLittleSkip; + } + setDimensions(st::boxWidth, fullHeight); +} + +bool DeleteMessagesBox::hasScheduledMessages() const { + for (const auto &fullId : _ids) { + if (const auto item = _session->data().message(fullId)) { + if (item->isScheduled()) { + return true; + } + } + } + return false; +} + +PeerData *DeleteMessagesBox::checkFromSinglePeer() const { + auto result = (PeerData*)nullptr; + for (const auto &fullId : _ids) { + if (const auto item = _session->data().message(fullId)) { + const auto peer = item->history()->peer; + if (!result) { + result = peer; + } else if (result != peer) { + return nullptr; + } + } + } + return result; +} + +auto DeleteMessagesBox::revokeText(not_null peer) const +-> std::optional { + auto result = RevokeConfig(); + if (peer == _wipeHistoryPeer) { + if (!peer->canRevokeFullHistory()) { + return std::nullopt; + } else if (const auto user = peer->asUser()) { + result.checkbox = tr::lng_delete_for_other_check( + tr::now, + lt_user, + user->firstName); + } else if (_wipeHistoryJustClear) { + return std::nullopt; + } else { + result.checkbox = tr::lng_delete_for_everyone_check(tr::now); + } + return result; + } + + const auto items = ranges::views::all( + _ids + ) | ranges::views::transform([&](FullMsgId id) { + return peer->owner().message(id); + }) | ranges::views::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; + } + + const auto now = base::unixtime::now(); + const auto canRevoke = [&](HistoryItem * item) { + return item->canDeleteForEveryone(now); + }; + const auto cannotRevoke = [&](HistoryItem *item) { + return !item->canDeleteForEveryone(now); + }; + const auto canRevokeAll = ranges::none_of(items, cannotRevoke); + auto outgoing = items | ranges::views::filter(&HistoryItem::out); + const auto canRevokeOutgoingCount = canRevokeAll + ? -1 + : ranges::count_if(outgoing, canRevoke); + + if (canRevokeAll) { + if (const auto user = peer->asUser()) { + result.checkbox = tr::lng_delete_for_other_check( + tr::now, + lt_user, + user->firstName); + } else { + result.checkbox = tr::lng_delete_for_everyone_check(tr::now); + } + return result; + } else if (canRevokeOutgoingCount > 0) { + result.checkbox = tr::lng_delete_for_other_my(tr::now); + if (const auto user = peer->asUser()) { + if (canRevokeOutgoingCount == 1) { + result.description = tr::lng_selected_unsend_about_user_one( + tr::now, + lt_user, + Ui::Text::Bold(user->shortName()), + Ui::Text::WithEntities); + } else { + result.description = tr::lng_selected_unsend_about_user( + tr::now, + lt_count, + canRevokeOutgoingCount, + lt_user, + Ui::Text::Bold(user->shortName()), + Ui::Text::WithEntities); + } + } else if (canRevokeOutgoingCount == 1) { + result.description = tr::lng_selected_unsend_about_group_one( + tr::now, + Ui::Text::WithEntities); + } else { + result.description = tr::lng_selected_unsend_about_group( + tr::now, + lt_count, + canRevokeOutgoingCount, + Ui::Text::WithEntities); + } + return result; + } + return std::nullopt; +} + +void DeleteMessagesBox::resizeEvent(QResizeEvent *e) { + BoxContent::resizeEvent(e); + + _text->moveToLeft(st::boxPadding.left(), st::boxPadding.top()); + auto top = _text->bottomNoMargins() + st::boxMediumSkip; + if (_moderateFrom) { + if (_banUser) { + _banUser->moveToLeft(st::boxPadding.left(), top); + top += _banUser->heightNoMargins() + st::boxLittleSkip; + } + _reportSpam->moveToLeft(st::boxPadding.left(), top); + top += _reportSpam->heightNoMargins() + st::boxLittleSkip; + if (_deleteAll) { + _deleteAll->moveToLeft(st::boxPadding.left(), top); + top += _deleteAll->heightNoMargins() + st::boxLittleSkip; + } + } else if (_revoke) { + const auto availableWidth = width() - 2 * st::boxPadding.left(); + _revoke->resizeToNaturalWidth(availableWidth); + _revoke->moveToLeft(st::boxPadding.left(), top); + top += _revoke->heightNoMargins() + st::boxLittleSkip; + } + if (_autoDeleteSettings) { + top += st::boxMediumSkip - st::boxLittleSkip; + _autoDeleteSettings->moveToLeft(st::boxPadding.left(), top); + } +} + +void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + // Don't make the clearing history so easy. + if (!_wipeHistoryPeer) { + deleteAndClear(); + } + } else { + BoxContent::keyPressEvent(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 { + for (const auto &controller : peer->session().windows()) { + if (controller->activeChatCurrent().peer() == peer) { + Ui::showChatsList(&peer->session()); + } + } + // 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( + _moderateInChannel, + _moderateFrom, + ChatRestrictionsInfo()); + } + if (_reportSpam->checked()) { + _moderateInChannel->session().api().request( + MTPchannels_ReportSpam( + _moderateInChannel->inputChannel, + _moderateFrom->inputUser, + MTP_vector(1, MTP_int(_ids[0].msg))) + ).send(); + } + if (_deleteAll && _deleteAll->checked()) { + _moderateInChannel->session().api().deleteAllFromUser( + _moderateInChannel, + _moderateFrom); + } + } + + if (_deleteConfirmedCallback) { + _deleteConfirmedCallback(); + } + + // deleteMessages can initiate closing of the current section, + // which will cause this box to be destroyed. + const auto session = _session; + const auto weak = Ui::MakeWeak(this); + + session->data().histories().deleteMessages(_ids, revoke); + + if (const auto strong = weak.data()) { + strong->closeBox(); + } + session->data().sendHistoryChangeNotifications(); +} diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.h b/Telegram/SourceFiles/boxes/delete_messages_box.h new file mode 100644 index 000000000..627f433df --- /dev/null +++ b/Telegram/SourceFiles/boxes/delete_messages_box.h @@ -0,0 +1,74 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "boxes/abstract_box.h" + +namespace Main { +class Session; +} // namespace Main + +namespace Ui { +class Checkbox; +class FlatLabel; +class LinkButton; +} // namespace Ui + +class DeleteMessagesBox final : public Ui::BoxContent { +public: + DeleteMessagesBox( + QWidget*, + not_null item, + bool suggestModerateActions); + DeleteMessagesBox( + QWidget*, + not_null session, + MessageIdsList &&selected); + DeleteMessagesBox(QWidget*, not_null peer, bool justClear); + + void setDeleteConfirmedCallback(Fn callback) { + _deleteConfirmedCallback = std::move(callback); + } + +protected: + void prepare() override; + + void resizeEvent(QResizeEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + +private: + struct RevokeConfig { + QString checkbox; + TextWithEntities description; + }; + void deleteAndClear(); + [[nodiscard]] PeerData *checkFromSinglePeer() const; + [[nodiscard]] bool hasScheduledMessages() const; + [[nodiscard]] std::optional revokeText( + not_null peer) const; + + const not_null _session; + + PeerData * const _wipeHistoryPeer = nullptr; + const bool _wipeHistoryJustClear = false; + const MessageIdsList _ids; + UserData *_moderateFrom = nullptr; + ChannelData *_moderateInChannel = nullptr; + bool _moderateBan = false; + bool _moderateDeleteAll = false; + + object_ptr _text = { nullptr }; + object_ptr _revoke = { nullptr }; + object_ptr _banUser = { nullptr }; + object_ptr _reportSpam = { nullptr }; + object_ptr _deleteAll = { nullptr }; + object_ptr _autoDeleteSettings = { nullptr }; + + Fn _deleteConfirmedCallback; + +}; diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index fac2508ce..9f8729012 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_changes.h" #include "data/data_media_types.h" #include "data/data_user.h" -#include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "base/unixtime.h" #include "api/api_updates.h" #include "apiwrap.h" diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 5a3e384bb..12e086937 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -41,7 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_controller.h" #include "window/notifications_manager.h" #include "boxes/about_sponsored_box.h" -#include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/sticker_set_box.h" #include "chat_helpers/message_field.h" #include "chat_helpers/emoji_interactions.h" diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 7d2ec62e8..193d2920c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_text_entities.h" #include "api/api_send_progress.h" #include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/send_files_box.h" #include "boxes/share_box.h" #include "boxes/edit_caption_box.h" diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index a832e4926..6aeb96709 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/ui_utility.h" #include "chat_helpers/send_context_menu.h" #include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/sticker_set_box.h" #include "data/data_photo.h" #include "data/data_photo_media.h" diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 2edc1f44a..a6ea59351 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -28,7 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "window/window_peer_menu.h" #include "main/main_session.h" -#include "boxes/confirm_box.h" #include "ui/widgets/popup_menu.h" #include "ui/toast/toast.h" #include "ui/inactive_press.h" @@ -36,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/chat_theme.h" #include "ui/chat/chat_style.h" #include "lang/lang_keys.h" +#include "boxes/delete_messages_box.h" #include "boxes/peers/edit_participant_box.h" #include "data/data_session.h" #include "data/data_folder.h" diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 4dff37433..135587e9f 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_sending.h" #include "apiwrap.h" #include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/edit_caption_box.h" #include "boxes/send_files_box.h" #include "window/window_adaptive.h" diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 0b040f20a..218aa28a2 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_sending.h" #include "apiwrap.h" #include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/edit_caption_box.h" #include "boxes/send_files_box.h" #include "window/window_adaptive.h" diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp index fb0db3777..4b39c82ef 100644 --- a/Telegram/SourceFiles/info/info_top_bar.cpp +++ b/Telegram/SourceFiles/info/info_top_bar.cpp @@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/info_controller.h" #include "info/profile/info_profile_values.h" #include "storage/storage_shared_media.h" -#include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/peer_list_controllers.h" #include "mainwidget.h" #include "main/main_session.h" diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index d75b088a7..bba57353d 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -38,8 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/platform/base_platform_info.h" #include "base/weak_ptr.h" #include "media/player/media_player_instance.h" +#include "boxes/delete_messages_box.h" #include "boxes/peer_list_controllers.h" -#include "boxes/confirm_box.h" #include "core/file_utilities.h" #include "facades.h" diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index b63df68a2..4a2535a37 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -29,7 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/ui_utility.h" #include "ui/cached_round_corners.h" #include "ui/gl/gl_surface.h" -#include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "media/audio/media_audio.h" #include "media/view/media_view_playback_controls.h" #include "media/view/media_view_group_thumbs.h" diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 236d2179b..53e5c45d2 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "boxes/confirm_box.h" +#include "boxes/delete_messages_box.h" #include "boxes/mute_settings_box.h" #include "boxes/add_contact_box.h" #include "boxes/create_poll_box.h"