From cd1c7c56d3d6d9b4bd50d1fc09d47628f51a66fa Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Fri, 8 Jun 2018 23:06:26 +0300
Subject: [PATCH] Skip old and currently-sending draft updates.

---
 Telegram/SourceFiles/apiwrap.cpp              | 23 +++++++++++++++----
 Telegram/SourceFiles/config.h                 |  3 ---
 Telegram/SourceFiles/data/data_drafts.cpp     |  3 +++
 Telegram/SourceFiles/history/history.cpp      | 19 +++++++++++++++
 Telegram/SourceFiles/history/history.h        |  5 ++++
 .../SourceFiles/history/history_widget.cpp    | 11 +++++----
 6 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 3c0cf8346..e18265b55 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -2055,10 +2055,21 @@ void ApiWrap::saveDraftsToCloud() {
 		if (!textWithTags.tags.isEmpty()) {
 			flags |= MTPmessages_SaveDraft::Flag::f_entities;
 		}
-		auto entities = TextUtilities::EntitiesToMTP(ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertOption::SkipLocal);
+		auto entities = TextUtilities::EntitiesToMTP(
+			ConvertTextTagsToEntities(textWithTags.tags),
+			TextUtilities::ConvertOption::SkipLocal);
 
-		cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities)).done([this, history](const MTPBool &result, mtpRequestId requestId) {
-			if (auto cloudDraft = history->cloudDraft()) {
+		history->setSentDraftText(textWithTags.text);
+		cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
+			MTP_flags(flags),
+			MTP_int(cloudDraft->msgId),
+			history->peer->input,
+			MTP_string(textWithTags.text),
+			entities
+		)).done([=](const MTPBool &result, mtpRequestId requestId) {
+			history->clearSentDraftText();
+
+			if (const auto cloudDraft = history->cloudDraft()) {
 				if (cloudDraft->saveRequestId == requestId) {
 					cloudDraft->saveRequestId = 0;
 					history->draftSavedToCloud();
@@ -2069,8 +2080,10 @@ void ApiWrap::saveDraftsToCloud() {
 				_draftsSaveRequestIds.erase(history);
 				checkQuitPreventFinished();
 			}
-		}).fail([this, history](const RPCError &error, mtpRequestId requestId) {
-			if (auto cloudDraft = history->cloudDraft()) {
+		}).fail([=](const RPCError &error, mtpRequestId requestId) {
+			history->clearSentDraftText();
+
+			if (const auto cloudDraft = history->cloudDraft()) {
 				if (cloudDraft->saveRequestId == requestId) {
 					history->clearCloudDraft();
 				}
diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h
index a6f12dd39..5bcb92472 100644
--- a/Telegram/SourceFiles/config.h
+++ b/Telegram/SourceFiles/config.h
@@ -82,9 +82,6 @@ enum {
 	MaxMessageSize = 4096,
 
 	WriteMapTimeout = 1000,
-	SaveDraftTimeout = 1000, // save draft after 1 secs of not changing text
-	SaveDraftAnywayTimeout = 5000, // or save anyway each 5 secs
-	SaveCloudDraftIdleTimeout = 14000, // save draft to the cloud after 14 more seconds
 
 	SetOnlineAfterActivity = 30, // user with hidden last seen stays online for such amount of seconds in the interface
 
diff --git a/Telegram/SourceFiles/data/data_drafts.cpp b/Telegram/SourceFiles/data/data_drafts.cpp
index c9f45a5f2..16d7fd5cc 100644
--- a/Telegram/SourceFiles/data/data_drafts.cpp
+++ b/Telegram/SourceFiles/data/data_drafts.cpp
@@ -52,6 +52,9 @@ void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) {
 			? TextUtilities::EntitiesFromMTP(draft.ventities.v)
 			: EntitiesInText())
 	};
+	if (history->skipCloudDraft(textWithTags.text, draft.vdate.v)) {
+		return;
+	}
 	auto replyTo = draft.has_reply_to_msg_id() ? draft.vreply_to_msg_id.v : MsgId(0);
 	auto cloudDraft = std::make_unique<Draft>(textWithTags, replyTo, MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX), draft.is_no_webpage());
 	cloudDraft->date = draft.vdate.v;
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index 6f029193a..e84582876 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -51,6 +51,7 @@ constexpr auto kStatusShowClientsideChooseContact = 6000;
 constexpr auto kStatusShowClientsidePlayGame = 10000;
 constexpr auto kSetMyActionForMs = 10000;
 constexpr auto kNewBlockEachMessage = 50;
+constexpr auto kSkipCloudDraftsFor = TimeId(3);
 
 void checkForSwitchInlineButton(HistoryItem *item) {
 	if (item->out() || !item->hasSwitchInlineButton()) {
@@ -405,6 +406,24 @@ Data::Draft *History::createCloudDraft(Data::Draft *fromDraft) {
 	return cloudDraft();
 }
 
+bool History::skipCloudDraft(const QString &text, TimeId date) const {
+	if (_lastSentDraftText && *_lastSentDraftText == text) {
+		return true;
+	} else if (date <= _lastSentDraftTime + kSkipCloudDraftsFor) {
+		return true;
+	}
+	return false;
+}
+
+void History::setSentDraftText(const QString &text) {
+	_lastSentDraftText = text;
+}
+
+void History::clearSentDraftText() {
+	_lastSentDraftText = base::none;
+	accumulate_max(_lastSentDraftTime, unixtime());
+}
+
 void History::setEditDraft(std::unique_ptr<Data::Draft> &&draft) {
 	_editDraft = std::move(draft);
 }
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index e80d5bce8..13eb35ac3 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -304,6 +304,9 @@ public:
 	void createLocalDraftFromCloud();
 	void setCloudDraft(std::unique_ptr<Data::Draft> &&draft);
 	Data::Draft *createCloudDraft(Data::Draft *fromDraft);
+	bool skipCloudDraft(const QString &text, TimeId date) const;
+	void setSentDraftText(const QString &text);
+	void clearSentDraftText();
 	void setEditDraft(std::unique_ptr<Data::Draft> &&draft);
 	void clearLocalDraft();
 	void clearCloudDraft();
@@ -501,6 +504,8 @@ private:
 
 	std::unique_ptr<Data::Draft> _localDraft, _cloudDraft;
 	std::unique_ptr<Data::Draft> _editDraft;
+	base::optional<QString> _lastSentDraftText;
+	TimeId _lastSentDraftTime = 0;
 	MessageIdsList _forwardDraft;
 
 	using TypingUsers = QMap<UserData*, TimeMs>;
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index ade50f263..0e63f941e 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -91,6 +91,9 @@ constexpr auto kShowMembersDropdownTimeoutMs = 300;
 constexpr auto kDisplayEditTimeWarningMs = 300 * 1000;
 constexpr auto kFullDayInMs = 86400 * 1000;
 constexpr auto kCancelTypingActionTimeout = TimeMs(5000);
+constexpr auto kSaveDraftTimeout = 1000;
+constexpr auto kSaveDraftAnywayTimeout = 5000;
+constexpr auto kSaveCloudDraftIdleTimeout = 14000;
 
 ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
 	return [](ChannelData *channel, MsgId msgId) {
@@ -1192,9 +1195,9 @@ void HistoryWidget::onDraftSave(bool delayed) {
 		auto ms = getms();
 		if (!_saveDraftStart) {
 			_saveDraftStart = ms;
-			return _saveDraftTimer.start(SaveDraftTimeout);
-		} else if (ms - _saveDraftStart < SaveDraftAnywayTimeout) {
-			return _saveDraftTimer.start(SaveDraftTimeout);
+			return _saveDraftTimer.start(kSaveDraftTimeout);
+		} else if (ms - _saveDraftStart < kSaveDraftAnywayTimeout) {
+			return _saveDraftTimer.start(kSaveDraftTimeout);
 		}
 	}
 	writeDrafts(nullptr, nullptr);
@@ -1275,7 +1278,7 @@ void HistoryWidget::writeDrafts(Data::Draft **localDraft, Data::Draft **editDraf
 	}
 
 	if (!_editMsgId && !_inlineBot) {
-		_saveCloudDraftTimer.start(SaveCloudDraftIdleTimeout);
+		_saveCloudDraftTimer.start(kSaveCloudDraftIdleTimeout);
 	}
 }