From 53ac4c00ad347eb53bb58faf8e87549b0a5c51f6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 23 Oct 2020 16:35:43 +0300 Subject: [PATCH] Track deleted messages carefully. Fixes #8855. --- .../SourceFiles/data/data_replies_list.cpp | 87 ++++++++++++------- Telegram/SourceFiles/data/data_replies_list.h | 4 +- .../history/view/history_view_list_widget.cpp | 7 +- .../view/history_view_replies_section.cpp | 3 +- 4 files changed, 66 insertions(+), 35 deletions(-) diff --git a/Telegram/SourceFiles/data/data_replies_list.cpp b/Telegram/SourceFiles/data/data_replies_list.cpp index ce90f4ddd4..b2004fa79e 100644 --- a/Telegram/SourceFiles/data/data_replies_list.cpp +++ b/Telegram/SourceFiles/data/data_replies_list.cpp @@ -42,7 +42,10 @@ struct RepliesList::Viewer { MsgId around = 0; int limitBefore = 0; int limitAfter = 0; + int injectedForRoot = 0; base::has_weak_ptr guard; + bool stale = true; + bool scheduled = false; }; RepliesList::RepliesList(not_null history, MsgId rootId) @@ -67,7 +70,9 @@ rpl::producer RepliesList::source( _history->session().changes().historyFlagsValue( _history, Data::HistoryUpdate::Flag::LocalMessages) - ) | rpl::map([=](MessagesSlice &&server, const auto &) { + ) | rpl::filter([=](const MessagesSlice &data, const auto &) { + return (data.fullCount.value_or(0) >= 0); + }) | rpl::map([=](MessagesSlice &&server, const auto &) { appendLocalMessages(server); return std::move(server); }); @@ -82,10 +87,22 @@ rpl::producer RepliesList::sourceFromServer( auto lifetime = rpl::lifetime(); const auto viewer = lifetime.make_state(); const auto push = [=] { + viewer->scheduled = false; if (buildFromData(viewer)) { + viewer->stale = false; consumer.put_next_copy(viewer->slice); } }; + const auto pushDelayed = [=] { + if (!viewer->stale) { + viewer->stale = true; + consumer.put_next_copy(MessagesSlice{ .fullCount = -1 }); + } + if (!viewer->scheduled) { + viewer->scheduled = true; + crl::on_main(&viewer->guard, push); + } + }; viewer->around = around; viewer->limitBefore = limitBefore; viewer->limitAfter = limitAfter; @@ -96,14 +113,10 @@ rpl::producer RepliesList::sourceFromServer( | MessageUpdate::Flag::Destroyed ) | rpl::filter([=](const MessageUpdate &update) { return applyUpdate(viewer, update); - }) | rpl::start_with_next([=] { - crl::on_main(&viewer->guard, push); - }, lifetime); + }) | rpl::start_with_next(pushDelayed, lifetime); _partLoaded.events( - ) | rpl::start_with_next([=] { - crl::on_main(&viewer->guard, push); - }, lifetime); + ) | rpl::start_with_next(pushDelayed, lifetime); push(); return lifetime; @@ -173,32 +186,37 @@ rpl::producer RepliesList::fullCount() const { return _fullCount.value() | rpl::filter_optional(); } -void RepliesList::injectRootMessageAndReverse( - not_null slice) { - injectRootMessage(slice); - ranges::reverse(slice->ids); +void RepliesList::injectRootMessageAndReverse(not_null viewer) { + injectRootMessage(viewer); + ranges::reverse(viewer->slice.ids); } -void RepliesList::injectRootMessage(not_null slice) { +void RepliesList::injectRootMessage(not_null viewer) { + const auto slice = &viewer->slice; + viewer->injectedForRoot = 0; if (slice->skippedBefore != 0) { return; } - if (const auto root = lookupRoot()) { - injectRootDivider(root, slice); + const auto root = lookupRoot(); + if (!root) { + return; + } + injectRootDivider(root, slice); - if (const auto group = _history->owner().groups().find(root)) { - for (const auto item : ranges::view::reverse(group->items)) { - slice->ids.push_back(item->fullId()); - } - if (slice->fullCount) { - *slice->fullCount += group->items.size(); - } - } else { - slice->ids.push_back(root->fullId()); - if (slice->fullCount) { - ++*slice->fullCount; - } + if (const auto group = _history->owner().groups().find(root)) { + for (const auto item : ranges::view::reverse(group->items)) { + slice->ids.push_back(item->fullId()); } + viewer->injectedForRoot = group->items.size(); + if (slice->fullCount) { + *slice->fullCount += group->items.size(); + } + } else { + slice->ids.push_back(root->fullId()); + viewer->injectedForRoot = 1; + } + if (slice->fullCount) { + *slice->fullCount += viewer->injectedForRoot; } } @@ -232,7 +250,8 @@ bool RepliesList::buildFromData(not_null viewer) { = viewer->slice.skippedBefore = viewer->slice.skippedAfter = 0; - injectRootMessageAndReverse(&viewer->slice); + viewer->injectedForRoot = 0; + injectRootMessageAndReverse(viewer); return true; } const auto around = [&] { @@ -285,7 +304,7 @@ bool RepliesList::buildFromData(not_null viewer) { slice->ids.empty() ? 0 : slice->ids.back().msg)); slice->fullCount = _fullCount.current(); - injectRootMessageAndReverse(slice); + injectRootMessageAndReverse(viewer); if (_skippedBefore != 0 && useBefore < viewer->limitBefore + 1) { loadBefore(); @@ -301,10 +320,20 @@ bool RepliesList::applyUpdate( not_null viewer, const MessageUpdate &update) { if (update.item->history() != _history - || update.item->replyToTop() != _rootId || !IsServerMsgId(update.item->id)) { return false; } + if (update.flags & MessageUpdate::Flag::Destroyed) { + const auto id = update.item->fullId(); + for (auto i = 0; i != viewer->injectedForRoot; ++i) { + if (viewer->slice.ids[i] == id) { + return true; + } + } + } + if (update.item->replyToTop() != _rootId) { + return false; + } const auto id = update.item->id; const auto i = ranges::lower_bound(_list, id, std::greater<>()); if (update.flags & MessageUpdate::Flag::Destroyed) { diff --git a/Telegram/SourceFiles/data/data_replies_list.h b/Telegram/SourceFiles/data/data_replies_list.h index 2de7e2b7f2..36932b82b1 100644 --- a/Telegram/SourceFiles/data/data_replies_list.h +++ b/Telegram/SourceFiles/data/data_replies_list.h @@ -47,8 +47,8 @@ private: [[nodiscard]] bool applyUpdate( not_null viewer, const MessageUpdate &update); - void injectRootMessageAndReverse(not_null slice); - void injectRootMessage(not_null slice); + void injectRootMessageAndReverse(not_null viewer); + void injectRootMessage(not_null viewer); void injectRootDivider( not_null root, not_null slice); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index b841a248d9..15aeb735e6 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -292,9 +292,10 @@ ListWidget::ListWidget( }, lifetime()); session().data().itemRemoved( - ) | rpl::start_with_next( - [this](auto item) { itemRemoved(item); }, - lifetime()); + ) | rpl::start_with_next([=](not_null item) { + itemRemoved(item); + }, lifetime()); + subscribe(session().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { if (const auto view = viewForItem(query.item)) { const auto top = itemTop(view); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index af0a9acaeb..26d9b0c4fa 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -216,6 +216,7 @@ RepliesWidget::RepliesWidget( if (update.item == _root) { _root = nullptr; updatePinnedVisibility(); + controller->showBackFromStack(); } while (update.item == _replyReturn) { calculateNextReplyReturn(); @@ -1758,7 +1759,7 @@ MessagesBarData RepliesWidget::listMessagesBar( for (auto i = 0, count = int(elements.size()); i != count; ++i) { const auto item = elements[i]->data(); if (IsServerMsgId(item->id) && item->id > till) { - if (item->out()) { + if (item->out() || !item->replyToId()) { readTill(item); } else { return MessagesBarData{