diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index d2aa285480..319399bfb5 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2424,7 +2424,8 @@ int ApiWrap::OnlineTillFromStatus( void ApiWrap::clearHistory(not_null peer, bool revoke) { auto deleteTillId = MsgId(0); - if (const auto history = _session->data().historyLoaded(peer)) { + const auto history = _session->data().historyLoaded(peer); + if (history) { while (history->lastMessageKnown()) { const auto last = history->lastMessage(); if (!last) { @@ -2446,7 +2447,6 @@ void ApiWrap::clearHistory(not_null peer, bool revoke) { return; } deleteTillId = history->lastMessage()->id; - history->clear(History::ClearType::ClearHistory); } if (const auto channel = peer->asChannel()) { if (const auto migrated = peer->migrateFrom()) { @@ -2461,6 +2461,9 @@ void ApiWrap::clearHistory(not_null peer, bool revoke) { } else { deleteHistory(peer, true, revoke); } + if (history) { + history->clear(History::ClearType::ClearHistory); + } } void ApiWrap::deleteConversation(not_null peer, bool revoke) { diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index e72908a015..475c04009c 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -293,8 +293,7 @@ AdminLog::OwnedItem GenerateTextItem( const auto clientFlags = MTPDmessage_ClientFlag::f_fake_history_item; const auto replyTo = 0; const auto viaBotId = 0; - const auto item = history->owner().makeMessage( - history, + const auto item = history->makeMessage( ++id, flags, clientFlags, diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index a7eefdbd35..38c5c5c06b 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -740,6 +740,9 @@ void ApplyChannelUpdate( channel->session().api().applyNotifySettings( MTP_inputNotifyPeer(channel->input), update.vnotify_settings()); + + // For clearUpTill() call. + channel->owner().sendHistoryChangeNotifications(); } void ApplyMegagroupAdmins( diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 36f0540759..dc19add6e7 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1724,18 +1724,15 @@ auto Session::messagesListForInsert(ChannelId channelId) : &_channelMessages[channelId]; } -HistoryItem *Session::registerMessage(std::unique_ptr item) { - Expects(item != nullptr); - - const auto result = item.get(); - const auto list = messagesListForInsert(result->channelId()); - const auto i = list->find(result->id); +void Session::registerMessage(not_null item) { + const auto list = messagesListForInsert(item->channelId()); + const auto itemId = item->id; + const auto i = list->find(itemId); if (i != list->end()) { LOG(("App Error: Trying to re-registerMessage().")); i->second->destroy(); } - list->emplace(result->id, std::move(item)); - return result; + list->emplace(itemId, item); } void Session::processMessagesDeleted( @@ -1754,7 +1751,7 @@ void Session::processMessagesDeleted( const auto i = list ? list->find(messageId.v) : Messages::iterator(); if (list && i != list->end()) { const auto history = i->second->history(); - destroyMessage(i->second.get()); + i->second->destroy(); if (!history->chatListMessageKnown()) { historiesToCheck.emplace(history); } @@ -1780,32 +1777,12 @@ void Session::removeDependencyMessage(not_null item) { } } -void Session::destroyMessage(not_null item) { - Expects(item->isHistoryEntry() || !item->mainView()); - +void Session::unregisterMessage(not_null item) { const auto peerId = item->history()->peer->id; - if (item->isHistoryEntry()) { - // All this must be done for all items manually in History::clear()! - item->eraseFromUnreadMentions(); - if (IsServerMsgId(item->id)) { - if (const auto types = item->sharedMediaTypes()) { - session().storage().remove(Storage::SharedMediaRemoveOne( - peerId, - types, - item->id)); - } - } else { - session().api().cancelLocalItem(item); - } - item->history()->itemRemoved(item); - } _itemRemoved.fire_copy(item); groups().unregisterMessage(item); removeDependencyMessage(item); - session().notifications().clearFromItem(item); - - const auto list = messagesListForInsert(peerToChannel(peerId)); - list->erase(item->id); + messagesListForInsert(peerToChannel(peerId))->erase(item->id); } MsgId Session::nextLocalMessageId() { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index aa2774292b..f7d7a95f7b 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -371,22 +371,8 @@ public: const Dialogs::Key &key1, const Dialogs::Key &key2); - template - not_null makeMessage(Args &&...args) { - return static_cast( - registerMessage( - std::make_unique( - std::forward(args)...))); - } - - template - not_null makeServiceMessage(Args &&...args) { - return static_cast( - registerMessage( - std::make_unique( - std::forward(args)...))); - } - void destroyMessage(not_null item); + void registerMessage(not_null item); + void unregisterMessage(not_null item); // Returns true if item found and it is not detached. bool checkEntitiesAndViewsUpdate(const MTPDmessage &data); @@ -698,7 +684,7 @@ public: void clearLocalStorage(); private: - using Messages = std::unordered_map>; + using Messages = std::unordered_map>; void suggestStartExport(); @@ -719,7 +705,8 @@ private: const Messages *messagesList(ChannelId channelId) const; not_null messagesListForInsert(ChannelId channelId); - HistoryItem *registerMessage(std::unique_ptr item); + not_null registerMessage( + std::unique_ptr item); void changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId); void removeDependencyMessage(not_null item); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index 41615d44ad..04e029f3fa 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -392,10 +392,9 @@ void GenerateItems( auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) { auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); - addPart(history->owner().makeServiceMessage( - history, - MTPDmessage_ClientFlag::f_admin_log_entry, + addPart(history->makeServiceMessage( history->nextNonHistoryEntryId(), + MTPDmessage_ClientFlag::f_admin_log_entry, date, message, MTPDmessage::Flags(0), @@ -433,8 +432,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newDescription = PrepareText(newValue, QString()); - auto body = history->owner().makeMessage( - history, + auto body = history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -469,8 +467,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newLink = newValue.isEmpty() ? TextWithEntities() : PrepareText(Core::App().createInternalLinkFull(newValue), QString()); - auto body = history->owner().makeMessage( - history, + auto body = history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -609,8 +606,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vparticipant()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -628,8 +624,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant(), &action.vprev_participant()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -653,8 +648,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant(), &action.vprev_participant()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -687,10 +681,9 @@ void GenerateItems( auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); message.links.push_back(setLink); - addPart(history->owner().makeServiceMessage( - history, - MTPDmessage_ClientFlag::f_admin_log_entry, + addPart(history->makeServiceMessage( history->nextNonHistoryEntryId(), + MTPDmessage_ClientFlag::f_admin_log_entry, date, message, MTPDmessage::Flags(0), @@ -712,8 +705,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateDefaultBannedRightsChangeText(channel, action.vnew_banned_rights(), action.vprev_banned_rights()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -763,10 +755,9 @@ void GenerateItems( auto message = HistoryService::PreparedText{ text }; message.links.push_back(fromLink); message.links.push_back(chatLink); - addPart(history->owner().makeServiceMessage( - history, - MTPDmessage_ClientFlag::f_admin_log_entry, + addPart(history->makeServiceMessage( history->nextNonHistoryEntryId(), + MTPDmessage_ClientFlag::f_admin_log_entry, date, message, MTPDmessage::Flags(0), diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 66e46c0e78..c225d8cb8e 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -637,6 +637,50 @@ HistoryItem *History::addNewMessage( return addNewItem(item, unread); } +not_null History::insertItem( + std::unique_ptr item) { + Expects(item != nullptr); + + const auto [i, ok] = _messages.insert(std::move(item)); + + const auto result = i->get(); + owner().registerMessage(result); + + Ensures(ok); + return result; +} + +void History::destroyMessage(not_null item) { + Expects(item->isHistoryEntry() || !item->mainView()); + + const auto peerId = peer->id; + if (item->isHistoryEntry()) { + // All this must be done for all items manually in History::clear()! + item->eraseFromUnreadMentions(); + if (IsServerMsgId(item->id)) { + if (const auto types = item->sharedMediaTypes()) { + session().storage().remove(Storage::SharedMediaRemoveOne( + peerId, + types, + item->id)); + } + } else { + session().api().cancelLocalItem(item); + } + itemRemoved(item); + } + + owner().unregisterMessage(item); + session().notifications().clearFromItem(item); + + auto hack = std::unique_ptr(item.get()); + const auto i = _messages.find(hack); + hack.release(); + + Assert(i != end(_messages)); + _messages.erase(i); +} + not_null History::addNewItem( not_null item, bool unread) { @@ -693,8 +737,7 @@ not_null History::addNewLocalMessage( const QString &postAuthor, not_null forwardOriginal) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -718,8 +761,7 @@ not_null History::addNewLocalMessage( const TextWithEntities &caption, const MTPReplyMarkup &markup) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -747,8 +789,7 @@ not_null History::addNewLocalMessage( const TextWithEntities &caption, const MTPReplyMarkup &markup) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -775,8 +816,7 @@ not_null History::addNewLocalMessage( not_null game, const MTPReplyMarkup &markup) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -3097,10 +3137,10 @@ void History::clear(ClearType type) { removeJoinedMessage(); forgetScrollState(); + blocks.clear(); + owner().notifyHistoryUnloaded(this); + lastKeyboardInited = false; if (type == ClearType::Unload) { - blocks.clear(); - owner().notifyHistoryUnloaded(this); - lastKeyboardInited = false; _loadedAtTop = _loadedAtBottom = false; } else { // Leave the 'sending' messages in local messages. @@ -3145,7 +3185,6 @@ void History::clear(ClearType type) { //} } } - owner().notifyHistoryChangeDelayed(this); if (const auto chat = peer->asChat()) { chat->lastAuthors.clear(); @@ -3153,27 +3192,28 @@ void History::clear(ClearType type) { } else if (const auto channel = peer->asMegagroup()) { channel->mgInfo->markupSenders.clear(); } + + owner().notifyHistoryChangeDelayed(this); + owner().sendHistoryChangeNotifications(); } void History::clearUpTill(MsgId availableMinId) { - auto minId = minMsgId(); - if (!minId || minId > availableMinId) { - return; - } - do { - const auto item = blocks.front()->messages.front()->data(); + auto remove = std::vector>(); + remove.reserve(_messages.size()); + for (const auto &item : _messages) { const auto itemId = item->id; - if (IsServerMsgId(itemId) && itemId >= availableMinId) { - if (itemId == availableMinId) { - item->applyEditionToHistoryCleared(); - } - break; + if (!IsServerMsgId(itemId)) { + continue; + } else if (itemId == availableMinId) { + item->applyEditionToHistoryCleared(); + } else if (itemId < availableMinId) { + remove.push_back(item.get()); } + } + for (const auto item : remove) { item->destroy(); - } while (!isEmpty()); - + } requestChatListMessage(); - owner().sendHistoryChangeNotifications(); } void History::applyGroupAdminChanges(const base::flat_set &changes) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index f54cfc1f84..5ea915201f 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -90,6 +90,25 @@ public: void applyGroupAdminChanges(const base::flat_set &changes); + template + not_null makeMessage(Args &&...args) { + return static_cast( + insertItem( + std::make_unique( + this, + std::forward(args)...)).get()); + } + + template + not_null makeServiceMessage(Args &&...args) { + return static_cast( + insertItem( + std::make_unique( + this, + std::forward(args)...)).get()); + } + void destroyMessage(not_null item); + HistoryItem *addNewMessage( const MTPMessage &msg, MTPDmessage_ClientFlags clientFlags, @@ -405,6 +424,7 @@ private: void removeBlock(not_null block); void clearSharedMedia(); + not_null insertItem(std::unique_ptr item); not_null addNewItem( not_null item, bool unread); @@ -512,6 +532,7 @@ private: std::optional _lastMessage; std::optional _lastServerMessage; base::flat_set> _localMessages; + std::unordered_set> _messages; // This almost always is equal to _lastMessage. The only difference is // for a group that migrated to a supergroup. Then _lastMessage can diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 821e53b9c3..ce7883a710 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -75,8 +75,7 @@ not_null CreateUnsupportedMessage( EntityInText(EntityType::Italic, 0, text.text.size())); flags &= ~MTPDmessage::Flag::f_post_author; flags |= MTPDmessage::Flag::f_legacy; - return history->owner().makeMessage( - history, + return history->makeMessage( msgId, flags, clientFlags, @@ -413,7 +412,7 @@ bool HistoryItem::isScheduled() const { } void HistoryItem::destroy() { - _history->owner().destroyMessage(this); + _history->destroyMessage(this); } void HistoryItem::refreshMainView() { @@ -929,37 +928,29 @@ not_null HistoryItem::Create( const auto text = HistoryService::PreparedText { tr::lng_message_empty(tr::now) }; - return history->owner().makeServiceMessage( - history, - clientFlags, + return history->makeServiceMessage( data.vid().v, + clientFlags, data.vdate().v, text, data.vflags().v, data.vfrom_id().value_or_empty()); } else if (checked == MediaCheckResult::HasTimeToLive) { - return history->owner().makeServiceMessage( - history, - data, - clientFlags); + return history->makeServiceMessage(data, clientFlags); } - return history->owner().makeMessage(history, data, clientFlags); + return history->makeMessage(data, clientFlags); }, [&](const MTPDmessageService &data) -> HistoryItem* { if (data.vaction().type() == mtpc_messageActionPhoneCall) { - return history->owner().makeMessage(history, data, clientFlags); + return history->makeMessage(data, clientFlags); } - return history->owner().makeServiceMessage( - history, - data, - clientFlags); + return history->makeServiceMessage(data, clientFlags); }, [&](const MTPDmessageEmpty &data) -> HistoryItem* { const auto text = HistoryService::PreparedText{ tr::lng_message_empty(tr::now) }; - return history->owner().makeServiceMessage( - history, - clientFlags, + return history->makeServiceMessage( data.vid().v, + clientFlags, TimeId(0), text); }); diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 48c905d370..4856847d24 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -525,8 +525,8 @@ HistoryService::HistoryService( HistoryService::HistoryService( not_null history, - MTPDmessage_ClientFlags clientFlags, MsgId id, + MTPDmessage_ClientFlags clientFlags, TimeId date, const PreparedText &message, MTPDmessage::Flags flags, @@ -797,10 +797,9 @@ not_null GenerateJoinedMessage( TimeId inviteDate, not_null inviter, MTPDmessage::Flags flags) { - return new HistoryService( - history, - MTPDmessage_ClientFlag::f_local_history_entry, + return history->makeServiceMessage( history->owner().nextLocalMessageId(), + MTPDmessage_ClientFlag::f_local_history_entry, inviteDate, GenerateJoinedText(history, inviter), flags); diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index e1a50c71a7..fe06d26adc 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -68,8 +68,8 @@ public: MTPDmessage_ClientFlags clientFlags); HistoryService( not_null history, - MTPDmessage_ClientFlags clientFlags, MsgId id, + MTPDmessage_ClientFlags clientFlags, TimeId date, const PreparedText &message, MTPDmessage::Flags flags = 0, diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index 5368c1ece4..9954ca90e6 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -165,8 +165,7 @@ AdminLog::OwnedItem GenerateForwardedItem( //MTPMessageReactions(), MTPVector() ).match([&](const MTPDmessage &data) { - return history->owner().makeMessage( - history, + return history->makeMessage( data, MTPDmessage_ClientFlag::f_fake_history_item); }, [](auto &&) -> not_null { diff --git a/Telegram/SourceFiles/support/support_autocomplete.cpp b/Telegram/SourceFiles/support/support_autocomplete.cpp index ddc65146d4..a8724c3108 100644 --- a/Telegram/SourceFiles/support/support_autocomplete.cpp +++ b/Telegram/SourceFiles/support/support_autocomplete.cpp @@ -275,8 +275,7 @@ AdminLog::OwnedItem GenerateCommentItem( const auto clientFlags = MTPDmessage_ClientFlag::f_fake_history_item; const auto replyTo = 0; const auto viaBotId = 0; - const auto item = history->owner().makeMessage( - history, + const auto item = history->makeMessage( id, flags, clientFlags, @@ -322,8 +321,7 @@ AdminLog::OwnedItem GenerateContactItem( MTP_long(0), //MTPMessageReactions(), MTPVector()); - const auto item = history->owner().makeMessage( - history, + const auto item = history->makeMessage( message.c_message(), MTPDmessage_ClientFlag::f_fake_history_item); return AdminLog::OwnedItem(delegate, item);