From fb244c00b9898086a063e0d01c54ba3e0b1f7aeb Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 8 Apr 2019 13:16:45 +0400
Subject: [PATCH] Fix local history clearing.

---
 Telegram/SourceFiles/apiwrap.cpp              |   3 +-
 Telegram/SourceFiles/data/data_session.cpp    |   8 +-
 Telegram/SourceFiles/history/history.cpp      | 111 +++++++-----------
 Telegram/SourceFiles/history/history.h        |  12 +-
 Telegram/SourceFiles/history/history_item.cpp |  15 +++
 Telegram/SourceFiles/history/history_item.h   |   1 +
 .../SourceFiles/history/history_message.cpp   |  16 +--
 .../SourceFiles/history/history_message.h     |   2 -
 .../SourceFiles/history/history_widget.cpp    |  12 +-
 9 files changed, 84 insertions(+), 96 deletions(-)

diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 32e2e08e3..2f649fc42 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -2383,8 +2383,7 @@ void ApiWrap::clearHistory(not_null<PeerData*> peer, bool revoke) {
 		if (const auto last = history->chatListMessage()) {
 			Local::addSavedPeer(history->peer, ItemDateTime(last));
 		}
-		history->clear();
-		history->markFullyLoaded();
+		history->clear(History::ClearType::ClearHistory);
 	}
 	if (const auto channel = peer->asChannel()) {
 		if (const auto migrated = peer->migrateFrom()) {
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 4029440a0..aedb0f35b 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -167,7 +167,7 @@ void Session::clear() {
 	_sendActions.clear();
 
 	for (const auto &[peerId, history] : _histories) {
-		history->unloadBlocks();
+		history->clear(History::ClearType::Unload);
 	}
 	App::historyClearMsgs();
 	_histories.clear();
@@ -727,7 +727,9 @@ void Session::deleteConversationLocally(not_null<PeerData*> peer) {
 	if (history) {
 		setPinnedDialog(history, false);
 		App::main()->removeDialog(history);
-		history->clear();
+		history->clear(peer->isChannel()
+			? History::ClearType::Unload
+			: History::ClearType::DeleteChat);
 	}
 	if (const auto channel = peer->asMegagroup()) {
 		channel->addFlags(MTPDchannel::Flag::f_left);
@@ -736,8 +738,6 @@ void Session::deleteConversationLocally(not_null<PeerData*> peer) {
 				migrated->updateChatListExistence();
 			}
 		}
-	} else if (history) {
-		history->markFullyLoaded();
 	}
 }
 
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index ddec634d4..6fbfb14d5 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -2102,7 +2102,7 @@ void History::getReadyFor(MsgId msgId) {
 		const auto migrated = owner().history(peer->migrateFrom()->id);
 		migrated->getReadyFor(-msgId);
 		if (migrated->isEmpty()) {
-			unloadBlocks();
+			clear(ClearType::Unload);
 		}
 		return;
 	}
@@ -2110,7 +2110,7 @@ void History::getReadyFor(MsgId msgId) {
 		if (const auto migratePeer = peer->migrateFrom()) {
 			if (const auto migrated = owner().historyLoaded(migratePeer)) {
 				if (migrated->unreadCount()) {
-					unloadBlocks();
+					clear(ClearType::Unload);
 					migrated->getReadyFor(msgId);
 					return;
 				}
@@ -2118,10 +2118,10 @@ void History::getReadyFor(MsgId msgId) {
 		}
 	}
 	if (!isReadyFor(msgId)) {
-		unloadBlocks();
+		clear(ClearType::Unload);
 		if (const auto migratePeer = peer->migrateFrom()) {
 			if (const auto migrated = owner().historyLoaded(migratePeer)) {
-				migrated->unloadBlocks();
+				migrated->clear(ClearType::Unload);
 			}
 		}
 		if (msgId == ShowAtTheEndMsgId) {
@@ -2144,18 +2144,15 @@ void History::setNotLoadedAtBottom() {
 	}
 }
 
-void History::markFullyLoaded() {
-	_loadedAtTop = _loadedAtBottom = true;
-	if (isEmpty()) {
-		session().storage().remove(
-			Storage::SharedMediaRemoveAll(peer->id));
-		if (const auto channel = peer->asChannel()) {
-			if (const auto feed = channel->feed()) {
-				session().storage().remove(
-					Storage::FeedMessagesRemoveAll(
-						feed->id(),
-						channel->bareId()));
-			}
+void History::clearSharedMedia() {
+	session().storage().remove(
+		Storage::SharedMediaRemoveAll(peer->id));
+	if (const auto channel = peer->asChannel()) {
+		if (const auto feed = channel->feed()) {
+			session().storage().remove(
+				Storage::FeedMessagesRemoveAll(
+					feed->id(),
+					channel->bareId()));
 		}
 	}
 }
@@ -2455,23 +2452,17 @@ void History::dialogEntryApplied() {
 		return;
 	}
 	if (!chatListMessage()) {
-		if (const auto chat = peer->asChat()) {
-			if (!chat->haveLeft()) {
-				Local::addSavedPeer(
-					peer,
-					ParseDateTime(chatListTimeId()));
-			}
-		} else if (const auto channel = peer->asChannel()) {
+		if (const auto channel = peer->asChannel()) {
 			const auto inviter = channel->inviter;
 			if (inviter != 0 && channel->amIn()) {
 				if (const auto from = owner().userLoaded(inviter)) {
-					unloadBlocks();
+					clear(ClearType::Unload);
 					addNewerSlice(QVector<MTPMessage>());
 					insertJoinedMessage(true);
 				}
 			}
 		} else {
-			clear();
+			clear(ClearType::DeleteChat);
 		}
 		return;
 	}
@@ -2921,7 +2912,7 @@ bool History::hasOrphanMediaGroupPart() const {
 
 bool History::removeOrphanMediaGroupPart() {
 	if (hasOrphanMediaGroupPart()) {
-		unloadBlocks();
+		clear(ClearType::Unload);
 		return true;
 	}
 	return false;
@@ -2941,54 +2932,50 @@ QVector<MsgId> History::collectMessagesFromUserToDelete(
 	return result;
 }
 
-void History::clear() {
-	clearBlocks(false);
-}
-
-void History::unloadBlocks() {
-	clearBlocks(true);
-}
-
-void History::clearBlocks(bool leaveItems) {
+void History::clear(ClearType type) {
 	_unreadBarView = nullptr;
 	_firstUnreadView = nullptr;
 	_joinedMessage = nullptr;
 
-	if (scrollTopItem) {
-		forgetScrollState();
-	}
-	if (leaveItems) {
+	forgetScrollState();
+	if (type == ClearType::Unload) {
+		blocks.clear();
 		_owner->notifyHistoryUnloaded(this);
+		lastKeyboardInited = false;
+		_loadedAtTop = _loadedAtBottom = false;
 	} else {
-		if (peer->isChannel()) {
-			// We left the channel.
-			_lastMessage = std::nullopt;
-		} else {
-			// History was deleted.
-			setLastMessage(nullptr);
-		}
 		notifies.clear();
 		_owner->notifyHistoryCleared(this);
-	}
-	blocks.clear();
-	if (leaveItems) {
-		lastKeyboardInited = false;
-	} else {
 		changeUnreadCount(-unreadCount());
-		if (auto channel = peer->asChannel()) {
+		if (type == ClearType::DeleteChat) {
+			setLastMessage(nullptr);
+		} else {
+			if (_lastMessage && IsServerMsgId((*_lastMessage)->id)) {
+				(*_lastMessage)->applyEditionToHistoryCleared();
+			} else {
+				_lastMessage = std::nullopt;
+			}
+		}
+		const auto tillId = (_lastMessage && *_lastMessage)
+			? (*_lastMessage)->id
+			: std::numeric_limits<MsgId>::max();
+		clearUpTill(tillId);
+		if (blocks.empty() && _lastMessage && *_lastMessage) {
+			addItemToBlock(*_lastMessage);
+		}
+		_loadedAtTop = _loadedAtBottom = _lastMessage.has_value();
+		clearSharedMedia();
+		clearLastKeyboard();
+		if (const auto channel = peer->asChannel()) {
 			channel->clearPinnedMessage();
 			if (const auto feed = channel->feed()) {
 				// Should be after resetting the _lastMessage.
 				feed->historyCleared(this);
 			}
 		}
-		clearLastKeyboard();
 	}
 	_owner->notifyHistoryChangeDelayed(this);
 
-	_loadedAtTop = false;
-	_loadedAtBottom = !leaveItems;
-	forgetScrollState();
 	if (const auto chat = peer->asChat()) {
 		chat->lastAuthors.clear();
 		chat->markupSenders.clear();
@@ -3007,17 +2994,7 @@ void History::clearUpTill(MsgId availableMinId) {
 		const auto itemId = item->id;
 		if (IsServerMsgId(itemId) && itemId >= availableMinId) {
 			if (itemId == availableMinId) {
-				auto fromId = 0;
-				auto replyToId = 0;
-				item->applyEdition(MTP_messageService(
-					MTP_flags(0),
-					MTP_int(itemId),
-					MTP_int(fromId),
-					peerToMTP(peer->id),
-					MTP_int(replyToId),
-					MTP_int(item->date()),
-					MTP_messageActionHistoryClear()
-				).c_messageService());
+				item->applyEditionToHistoryCleared();
 			}
 			break;
 		}
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index bd588f172..e722b552a 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -84,9 +84,12 @@ public:
 	QVector<MsgId> collectMessagesFromUserToDelete(
 		not_null<UserData*> user) const;
 
-	void clear();
-	void markFullyLoaded();
-	void unloadBlocks();
+	enum class ClearType {
+		Unload,
+		DeleteChat,
+		ClearHistory,
+	};
+	void clear(ClearType type);
 	void clearUpTill(MsgId availableMinId);
 
 	void applyGroupAdminChanges(
@@ -377,8 +380,7 @@ private:
 	// when the last item from this block was detached and
 	// calls the required previousItemChanged()
 	void removeBlock(not_null<HistoryBlock*> block);
-
-	void clearBlocks(bool leaveItems);
+	void clearSharedMedia();
 
 	not_null<HistoryItem*> addNewItem(
 		not_null<HistoryItem*> item,
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index a58e52fae..b8225cf83 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -374,6 +374,21 @@ void HistoryItem::clearMainView() {
 void HistoryItem::addToUnreadMentions(UnreadMentionType type) {
 }
 
+void HistoryItem::applyEditionToHistoryCleared() {
+	const auto fromId = 0;
+	const auto replyToId = 0;
+	applyEdition(
+		MTP_messageService(
+			MTP_flags(0),
+			MTP_int(id),
+			MTP_int(fromId),
+			peerToMTP(history()->peer->id),
+			MTP_int(replyToId),
+			MTP_int(date()),
+			MTP_messageActionHistoryClear()
+		).c_messageService());
+}
+
 void HistoryItem::indexAsNewItem() {
 	if (IsServerMsgId(id)) {
 		CrashReports::SetAnnotation("addToUnreadMentions", QString::number(id));
diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h
index 3566382ac..2b60c32c7 100644
--- a/Telegram/SourceFiles/history/history_item.h
+++ b/Telegram/SourceFiles/history/history_item.h
@@ -188,6 +188,7 @@ public:
 	}
 	virtual void applyEdition(const MTPDmessageService &message) {
 	}
+	void applyEditionToHistoryCleared();
 	virtual void updateSentMedia(const MTPMessageMedia *media) {
 	}
 	virtual void updateReplyMarkup(const MTPReplyMarkup *markup) {
diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp
index 0e2a1bf3e..ea78985bc 100644
--- a/Telegram/SourceFiles/history/history_message.cpp
+++ b/Telegram/SourceFiles/history/history_message.cpp
@@ -937,19 +937,15 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
 
 void HistoryMessage::applyEdition(const MTPDmessageService &message) {
 	if (message.vaction.type() == mtpc_messageActionHistoryClear) {
-		applyEditionToEmpty();
+		setReplyMarkup(nullptr);
+		refreshMedia(nullptr);
+		setEmptyText();
+		setViewsCount(-1);
+
+		finishEditionToEmpty();
 	}
 }
 
-void HistoryMessage::applyEditionToEmpty() {
-	setReplyMarkup(nullptr);
-	refreshMedia(nullptr);
-	setEmptyText();
-	setViewsCount(-1);
-
-	finishEditionToEmpty();
-}
-
 void HistoryMessage::updateSentMedia(const MTPMessageMedia *media) {
 	if (_flags & MTPDmessage_ClientFlag::f_from_inline_bot) {
 		if (!media || !_media || !_media->updateInlineResultMedia(*media)) {
diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h
index 036ad4bff..174e41698 100644
--- a/Telegram/SourceFiles/history/history_message.h
+++ b/Telegram/SourceFiles/history/history_message.h
@@ -159,8 +159,6 @@ private:
 	// It should show the receipt for the payed invoice. Still let mobile apps do that.
 	void replaceBuyWithReceiptInMarkup();
 
-	void applyEditionToEmpty();
-
 	void setReplyMarkup(const MTPReplyMarkup *markup);
 
 	struct CreateConfig;
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 84eaf52eb..14dec140e 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -1653,7 +1653,7 @@ void HistoryWidget::showHistory(
 		if (_migrated
 			&& !_migrated->isEmpty()
 			&& (!_history->loadedAtTop() || !_migrated->loadedAtBottom())) {
-			_migrated->unloadBlocks();
+			_migrated->clear(History::ClearType::Unload);
 		}
 
 		_topBar->setActiveChat(_history);
@@ -2306,9 +2306,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
 		if (_history->loadedAtBottom() && App::wnd()) App::wnd()->checkHistoryActivation();
 	} else if (_firstLoadRequest == requestId) {
 		if (toMigrated) {
-			_history->unloadBlocks();
+			_history->clear(History::ClearType::Unload);
 		} else if (_migrated) {
-			_migrated->unloadBlocks();
+			_migrated->clear(History::ClearType::Unload);
 		}
 		addMessagesToFront(peer, *histList);
 		_firstLoadRequest = 0;
@@ -2320,9 +2320,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
 		historyLoaded();
 	} else if (_delayedShowAtRequest == requestId) {
 		if (toMigrated) {
-			_history->unloadBlocks();
+			_history->clear(History::ClearType::Unload);
 		} else if (_migrated) {
-			_migrated->unloadBlocks();
+			_migrated->clear(History::ClearType::Unload);
 		}
 
 		_delayedShowAtRequest = 0;
@@ -5250,7 +5250,7 @@ void HistoryWidget::handlePeerMigration() {
 		&& to
 		&& !from->isEmpty()
 		&& (!from->loadedAtBottom() || !to->loadedAtTop())) {
-		from->unloadBlocks();
+		from->clear(History::ClearType::Unload);
 	}
 }