Delete history for specific days in private chats.

This commit is contained in:
John Preston 2021-11-16 11:26:35 +04:00
parent aa0a9b2db9
commit 80fcffcc40
18 changed files with 211 additions and 59 deletions

View File

@ -81,6 +81,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_calendar_select_days" = "Select days";
"lng_calendar_start_tip" = "Press and hold to jump to the start.";
"lng_calendar_end_tip" = "Press and hold to jump to the end.";
"lng_calendar_days#one" = "{count} day";
"lng_calendar_days#other" = "{count} days";
"lng_box_ok" = "OK";
"lng_box_done" = "Done";
@ -1134,6 +1136,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sure_delete_saved_messages" = "Are you sure, you want to delete all your saved messages?\n\nThis action cannot be undone.";
"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.";
"lng_sure_delete_by_date_many" = "Are you sure you want to delete all messages for the **{days}**?\n\nThis action cannot be undone.";
"lng_sure_delete_selected_days#one" = "{count} selected day";
"lng_sure_delete_selected_days#other" = "{count} selected days";
"lng_message_empty" = "Empty Message";
"lng_message_unsupported" = "This message is not supported by your version of Telegram Desktop. Please update to the latest version in Settings, or install it from {link}";

View File

@ -54,6 +54,18 @@ DeleteMessagesBox::DeleteMessagesBox(
Expects(!_ids.empty());
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
QDate firstDayToDelete,
QDate lastDayToDelete)
: _session(&peer->session())
, _wipeHistoryPeer(peer)
, _wipeHistoryJustClear(true)
, _wipeHistoryFirstToDelete(firstDayToDelete)
, _wipeHistoryLastToDelete(lastDayToDelete) {
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
@ -73,7 +85,27 @@ void DeleteMessagesBox::prepare() {
auto deleteStyle = &st::defaultBoxButton;
auto canDelete = true;
if (const auto peer = _wipeHistoryPeer) {
if (_wipeHistoryJustClear) {
if (!_wipeHistoryFirstToDelete.isNull()) {
details = (_wipeHistoryFirstToDelete
== _wipeHistoryLastToDelete)
? tr::lng_sure_delete_by_date_one(
tr::now,
lt_date,
TextWithEntities{
langDayOfMonthFull(_wipeHistoryFirstToDelete) },
Ui::Text::RichLangValue)
: tr::lng_sure_delete_by_date_many(
tr::now,
lt_days,
tr::lng_sure_delete_selected_days(
tr::now,
lt_count,
_wipeHistoryFirstToDelete.daysTo(
_wipeHistoryLastToDelete) + 1,
Ui::Text::WithEntities),
Ui::Text::RichLangValue);
deleteStyle = &st::attentionBoxButton;
} else if (_wipeHistoryJustClear) {
const auto isChannel = peer->isBroadcast();
const auto isPublicGroup = peer->isMegagroup()
&& peer->asChannel()->isPublic();
@ -397,16 +429,41 @@ void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
void DeleteMessagesBox::deleteAndClear() {
const auto revoke = _revoke ? _revoke->checked() : false;
if (const auto peer = _wipeHistoryPeer) {
const auto session = _session;
const auto invokeCallbackAndClose = [&] {
// deleteMessages can initiate closing of the current section,
// which will cause this box to be destroyed.
const auto weak = Ui::MakeWeak(this);
if (const auto callback = _deleteConfirmedCallback) {
callback();
}
if (const auto strong = weak.data()) {
strong->closeBox();
}
};
if (!_wipeHistoryFirstToDelete.isNull()) {
const auto peer = _wipeHistoryPeer;
const auto firstDayToDelete = _wipeHistoryFirstToDelete;
const auto lastDayToDelete = _wipeHistoryLastToDelete;
invokeCallbackAndClose();
session->data().histories().deleteMessagesByDates(
session->data().history(peer),
firstDayToDelete,
lastDayToDelete,
revoke);
session->data().sendHistoryChangeNotifications();
return;
} else if (const auto peer = _wipeHistoryPeer) {
const auto justClear = _wipeHistoryJustClear;
closeBox();
invokeCallbackAndClose();
if (justClear) {
peer->session().api().clearHistory(peer, revoke);
session->api().clearHistory(peer, revoke);
} else {
for (const auto &controller : peer->session().windows()) {
for (const auto &controller : session->windows()) {
if (controller->activeChatCurrent().peer() == peer) {
Ui::showChatsList(&peer->session());
Ui::showChatsList(session);
}
}
// Don't delete old history by default,
@ -415,7 +472,7 @@ void DeleteMessagesBox::deleteAndClear() {
//if (const auto from = peer->migrateFrom()) {
// peer->session().api().deleteConversation(from, false);
//}
peer->session().api().deleteConversation(peer, revoke);
session->api().deleteConversation(peer, revoke);
}
return;
}
@ -441,19 +498,8 @@ void DeleteMessagesBox::deleteAndClear() {
}
}
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();
}
const auto ids = _ids;
invokeCallbackAndClose();
session->data().histories().deleteMessages(ids, revoke);
session->data().sendHistoryChangeNotifications();
}

View File

@ -29,6 +29,11 @@ public:
QWidget*,
not_null<Main::Session*> session,
MessageIdsList &&selected);
DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
QDate firstDayToDelete,
QDate lastDayToDelete);
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
void setDeleteConfirmedCallback(Fn<void()> callback) {
@ -56,6 +61,8 @@ private:
PeerData * const _wipeHistoryPeer = nullptr;
const bool _wipeHistoryJustClear = false;
const QDate _wipeHistoryFirstToDelete;
const QDate _wipeHistoryLastToDelete;
const MessageIdsList _ids;
UserData *_moderateFrom = nullptr;
ChannelData *_moderateInChannel = nullptr;

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h"
#include "data/data_folder.h"
#include "data/data_scheduled_messages.h"
#include "base/unixtime.h"
#include "main/main_session.h"
#include "window/notifications_manager.h"
#include "history/history.h"
@ -708,6 +709,58 @@ void Histories::deleteAllMessages(
});
}
void Histories::deleteMessagesByDates(
not_null<History*> history,
QDate firstDayToDelete,
QDate lastDayToDelete,
bool revoke) {
const auto firstSecondToDelete = base::unixtime::serialize(
{ firstDayToDelete, QTime(0, 0) }
);
const auto lastSecondToDelete = base::unixtime::serialize(
{ lastDayToDelete, QTime(23, 59, 59) }
);
deleteMessagesByDates(
history,
firstSecondToDelete - 1,
lastSecondToDelete + 1,
revoke);
}
void Histories::deleteMessagesByDates(
not_null<History*> history,
TimeId minDate,
TimeId maxDate,
bool revoke) {
sendRequest(history, RequestType::Delete, [=](Fn<void()> finish) {
const auto peer = history->peer;
const auto fail = [=](const MTP::Error &error) {
finish();
};
using Flag = MTPmessages_DeleteHistory::Flag;
const auto flags = Flag::f_just_clear
| Flag::f_min_date
| Flag::f_max_date
| (revoke ? Flag::f_revoke : Flag(0));
return session().api().request(MTPmessages_DeleteHistory(
MTP_flags(flags),
peer->input,
MTP_int(0),
MTP_int(minDate),
MTP_int(maxDate)
)).done([=](const MTPmessages_AffectedHistory &result) {
const auto offset = session().api().applyAffectedHistory(
peer,
result);
if (offset > 0) {
deleteMessagesByDates(history, minDate, maxDate, revoke);
}
finish();
}).fail(fail).send();
});
history->destroyMessagesByDates(minDate, maxDate);
}
void Histories::deleteMessages(const MessageIdsList &ids, bool revoke) {
auto remove = std::vector<not_null<HistoryItem*>>();
remove.reserve(ids.size());

View File

@ -71,6 +71,17 @@ public:
bool justClear,
bool revoke);
void deleteMessagesByDates(
not_null<History*> history,
QDate firstDayToDelete,
QDate lastDayToDelete,
bool revoke);
void deleteMessagesByDates(
not_null<History*> history,
TimeId minDate,
TimeId maxDate,
bool revoke);
void deleteMessages(const MessageIdsList &ids, bool revoke);
int sendRequest(

View File

@ -284,7 +284,7 @@ Widget::Widget(
}, lifetime());
_cancelSearch->setClickedCallback([this] { onCancelSearch(); });
_jumpToDate->entity()->setClickedCallback([this] { showJumpToDate(); });
_jumpToDate->entity()->setClickedCallback([this] { showCalendar(); });
_chooseFromUser->entity()->setClickedCallback([this] { showSearchFrom(); });
rpl::single(
rpl::empty_value()
@ -1453,9 +1453,9 @@ void Widget::clearSearchCache() {
cancelSearchRequest();
}
void Widget::showJumpToDate() {
void Widget::showCalendar() {
if (_searchInChat) {
controller()->showJumpToDate(_searchInChat, QDate());
controller()->showCalendar(_searchInChat, QDate());
}
}

View File

@ -150,7 +150,7 @@ private:
void setupMainMenuToggle();
bool searchForPeersRequired(const QString &query) const;
void setSearchInChat(Key chat, PeerData *from = nullptr);
void showJumpToDate();
void showCalendar();
void showSearchFrom();
void showMainMenu();
void clearSearchCache();

View File

@ -462,6 +462,20 @@ void History::destroyMessage(not_null<HistoryItem*> item) {
}
}
void History::destroyMessagesByDates(TimeId minDate, TimeId maxDate) {
auto toDestroy = std::vector<not_null<HistoryItem*>>();
for (const auto &message : _messages) {
if (message->isRegular()
&& message->date() > minDate
&& message->date() < maxDate) {
toDestroy.push_back(message.get());
}
}
for (const auto item : toDestroy) {
item->destroy();
}
}
void History::unpinAllMessages() {
session().storage().remove(
Storage::SharedMediaRemoveAll(

View File

@ -132,6 +132,7 @@ public:
std::forward<Args>(args)...)).get());
}
void destroyMessage(not_null<HistoryItem*> item);
void destroyMessagesByDates(TimeId minDate, TimeId maxDate);
void unpinAllMessages();

View File

@ -6782,13 +6782,10 @@ void HistoryWidget::confirmDeleteSelected() {
if (items.empty()) {
return;
}
const auto weak = Ui::MakeWeak(this);
auto box = Box<DeleteMessagesBox>(&session(), std::move(items));
box->setDeleteConfirmedCallback([=] {
if (const auto strong = weak.data()) {
strong->clearSelected();
}
});
box->setDeleteConfirmedCallback(crl::guard(this, [=] {
clearSelected();
}));
controller()->show(std::move(box));
}

View File

@ -689,16 +689,13 @@ bool AddDeleteSelectedAction(
}
menu->addAction(tr::lng_context_delete_selected(tr::now), [=] {
const auto weak = Ui::MakeWeak(list);
auto items = ExtractIdsList(request.selectedItems);
auto box = Box<DeleteMessagesBox>(
&request.navigation->session(),
std::move(items));
box->setDeleteConfirmedCallback([=] {
if (const auto strong = weak.data()) {
strong->cancelSelection();
}
});
box->setDeleteConfirmedCallback(crl::guard(list, [=] {
list->cancelSelection();
}));
request.navigation->parentController()->show(std::move(box));
});
return true;

View File

@ -3027,15 +3027,12 @@ void ConfirmDeleteSelectedItems(not_null<ListWidget*> widget) {
return;
}
}
const auto weak = Ui::MakeWeak(widget);
auto box = Box<DeleteMessagesBox>(
&widget->controller()->session(),
widget->getSelectedIds());
box->setDeleteConfirmedCallback([=] {
if (const auto strong = weak.data()) {
strong->cancelSelection();
}
});
box->setDeleteConfirmedCallback(crl::guard(widget, [=] {
widget->cancelSelection();
}));
widget->controller()->show(std::move(box));
}

View File

@ -544,11 +544,9 @@ void TopBar::performDelete() {
auto box = Box<DeleteMessagesBox>(
&_navigation->session(),
std::move(items));
box->setDeleteConfirmedCallback([weak = Ui::MakeWeak(this)] {
if (weak) {
weak->_cancelSelectionClicks.fire({});
}
});
box->setDeleteConfirmedCallback(crl::guard(this, [=] {
_cancelSelectionClicks.fire({});
}));
_navigation->parentController()->show(std::move(box));
}
}

View File

@ -1715,12 +1715,9 @@ void ListWidget::forwardItems(MessageIdsList &&items) {
void ListWidget::deleteSelected() {
if (const auto box = deleteItems(collectSelectedIds())) {
const auto weak = Ui::MakeWeak(this);
box->setDeleteConfirmedCallback([=]{
if (const auto strong = weak.data()) {
strong->clearSelected();
}
});
box->setDeleteConfirmedCallback(crl::guard(this, [=]{
clearSelected();
}));
}
}

View File

@ -693,7 +693,10 @@ CalendarBox::Title::Title(
} else if (!_context->selectedMin()) {
setText(tr::lng_calendar_select_days(tr::now));
} else {
setText(QString::number(1 + *_context->selectedMax() - *_context->selectedMin())); // #TODO calendar
setText(tr::lng_calendar_days(
tr::now,
lt_count,
(1 + *_context->selectedMax() - *_context->selectedMin())));
}
}, lifetime());
}
@ -803,6 +806,16 @@ void CalendarBox::toggleSelectionMode(bool enabled) {
_context->toggleSelectionMode(enabled);
}
QDate CalendarBox::selectedFirstDate() const {
const auto min = _context->selectedMin();
return min.has_value() ? _context->dateFromIndex(*min) : QDate();
}
QDate CalendarBox::selectedLastDate() const {
const auto max = _context->selectedMax();
return max.has_value() ? _context->dateFromIndex(*max) : QDate();
}
void CalendarBox::showJumpTooltip(not_null<IconButton*> button) {
_tooltipButton = button;
Ui::Tooltip::Show(kTooltipDelay, this);

View File

@ -50,6 +50,9 @@ public:
void toggleSelectionMode(bool enabled);
[[nodiscard]] QDate selectedFirstDate() const;
[[nodiscard]] QDate selectedLastDate() const;
protected:
void prepare() override;

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/add_contact_box.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/delete_messages_box.h"
#include "window/window_adaptive.h"
#include "window/window_controller.h"
#include "window/main_window.h"
@ -151,7 +152,7 @@ void DateClickHandler::setDate(QDate date) {
void DateClickHandler::onClick(ClickContext context) const {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto window = my.sessionWindow.get()) {
window->showJumpToDate(_chat, _date);
window->showCalendar(_chat, _date);
}
}
@ -1146,7 +1147,7 @@ void SessionController::startOrJoinGroupCall(
}
}
void SessionController::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
void SessionController::showCalendar(Dialogs::Key chat, QDate requestedDate) {
const auto history = chat.history();
if (!history) {
return;
@ -1248,7 +1249,18 @@ void SessionController::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
});
auto text = tr::lng_profile_clear_history();
const auto button = box->addLeftButton(std::move(text), [=] {
const auto firstDate = box->selectedFirstDate();
const auto lastDate = box->selectedLastDate();
if (!firstDate.isNull()) {
auto confirm = Box<DeleteMessagesBox>(
history->peer,
firstDate,
lastDate);
confirm->setDeleteConfirmedCallback(crl::guard(box, [=] {
box->closeBox();
}));
box->getDelegate()->show(std::move(confirm));
}
}, (*selected > 0) ? st::attentionBoxButton : buttonState->disabled);
if (!*selected) {
button->setPointerCursor(false);

View File

@ -363,7 +363,7 @@ public:
}
void removeLayerBlackout();
void showJumpToDate(
void showCalendar(
Dialogs::Key chat,
QDate requestedDate);