From 97446ae7830b7a9e03c130befb974f292a245df3 Mon Sep 17 00:00:00 2001
From: 23rd <23rd@vivaldi.net>
Date: Mon, 11 May 2020 03:11:32 +0300
Subject: [PATCH] Added ability to reschedule scheduled messages.

---
 Telegram/Resources/langs/lang.strings         |  1 +
 Telegram/SourceFiles/apiwrap.cpp              | 37 +++++++++++++++
 Telegram/SourceFiles/apiwrap.h                |  4 ++
 .../view/history_view_context_menu.cpp        | 45 +++++++++++++++++++
 .../history/view/history_view_schedule_box.h  |  5 ++-
 5 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 4722c2f7d..397d57520 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1454,6 +1454,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_context_edit_msg" = "Edit";
 "lng_context_forward_msg" = "Forward Message";
 "lng_context_send_now_msg" = "Send now";
+"lng_context_reschedule" = "Reschedule";
 "lng_context_delete_msg" = "Delete Message";
 "lng_context_select_msg" = "Select Message";
 "lng_context_report_msg" = "Report Message";
diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 24d30648d..9786062ce 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -5857,6 +5857,43 @@ void ApiWrap::closePoll(not_null<HistoryItem*> item) {
 	_pollCloseRequestIds.emplace(itemId, requestId);
 }
 
+void ApiWrap::rescheduleMessage(
+		not_null<HistoryItem*> item,
+		Api::SendOptions options) {
+	const auto text = item->originalText().text;
+	const auto sentEntities = Api::EntitiesToMTP(
+		item->originalText().entities,
+		Api::ConvertOption::SkipLocal);
+	const auto media = item->media();
+
+	const auto emptyFlag = MTPmessages_EditMessage::Flag(0);
+	const auto flags = MTPmessages_EditMessage::Flag::f_schedule_date
+	| (!text.isEmpty()
+		? MTPmessages_EditMessage::Flag::f_message
+		: emptyFlag)
+	| ((!media || !media->webpage())
+		? MTPmessages_EditMessage::Flag::f_no_webpage
+		: emptyFlag)
+	| (!sentEntities.v.isEmpty()
+		? MTPmessages_EditMessage::Flag::f_entities
+		: emptyFlag);
+
+	const auto id = _session->data().scheduledMessages().lookupId(item);
+	request(MTPmessages_EditMessage(
+		MTP_flags(flags),
+		item->history()->peer->input,
+		MTP_int(id),
+		MTP_string(text),
+		MTPInputMedia(),
+		MTPReplyMarkup(),
+		sentEntities,
+		MTP_int(options.scheduled)
+	)).done([=](const MTPUpdates &result) {
+		applyUpdates(result);
+	}).fail([](const RPCError &error) {
+	}).send();
+}
+
 void ApiWrap::reloadPollResults(not_null<HistoryItem*> item) {
 	const auto itemId = item->fullId();
 	if (!IsServerMsgId(item->id)
diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h
index eb4015625..65a148a81 100644
--- a/Telegram/SourceFiles/apiwrap.h
+++ b/Telegram/SourceFiles/apiwrap.h
@@ -476,6 +476,10 @@ public:
 	void closePoll(not_null<HistoryItem*> item);
 	void reloadPollResults(not_null<HistoryItem*> item);
 
+	void rescheduleMessage(
+		not_null<HistoryItem*> item,
+		Api::SendOptions options);
+
 private:
 	struct MessageDataRequest {
 		using Callbacks = QList<RequestMessageDataCallback>;
diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
index ec3da7b81..c35dd7692 100644
--- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_item.h"
 #include "history/history_message.h"
 #include "history/history_item_text.h"
+#include "history/view/history_view_schedule_box.h"
 #include "history/view/media/history_view_media.h"
 #include "history/view/media/history_view_web_page.h"
 #include "ui/widgets/popup_menu.h"
@@ -385,6 +386,49 @@ bool AddSendNowMessageAction(
 	return true;
 }
 
+bool AddRescheduleMessageAction(
+		not_null<Ui::PopupMenu*> menu,
+		const ContextMenuRequest &request) {
+	const auto item = request.item;
+	if (!item || item->isSending() || !request.selectedItems.empty()) {
+		return false;
+	}
+	const auto peer = item->history()->peer;
+	if (const auto channel = peer->asChannel()) {
+		if (!channel->canEditMessages()) {
+			return false;
+		}
+	}
+	const auto owner = &item->history()->owner();
+	const auto itemId = item->fullId();
+	menu->addAction(tr::lng_context_reschedule(tr::now), [=] {
+		const auto item = owner->message(itemId);
+		if (!item) {
+			return;
+		}
+		const auto callback = [=](Api::SendOptions options) {
+			item->history()->session().api().rescheduleMessage(item, options);
+		};
+
+		const auto sendMenuType = !peer
+			? SendMenuType::Disabled
+			: peer->isSelf()
+			? SendMenuType::Reminder
+			: HistoryView::CanScheduleUntilOnline(peer)
+			? SendMenuType::ScheduledToUser
+			: SendMenuType::Scheduled;
+
+		Ui::show(
+			HistoryView::PrepareScheduleBox(
+				&request.navigation->session(),
+				sendMenuType,
+				callback,
+			item->date() + 600),
+			Ui::LayerOption::KeepOther);
+	});
+	return true;
+}
+
 void AddSendNowAction(
 		not_null<Ui::PopupMenu*> menu,
 		const ContextMenuRequest &request,
@@ -531,6 +575,7 @@ void AddMessageActions(
 	AddSendNowAction(menu, request, list);
 	AddDeleteAction(menu, request, list);
 	AddSelectionAction(menu, request, list);
+	AddRescheduleMessageAction(menu, request);
 }
 
 void AddCopyLinkAction(
diff --git a/Telegram/SourceFiles/history/view/history_view_schedule_box.h b/Telegram/SourceFiles/history/view/history_view_schedule_box.h
index 6e4e9c3c2..d51b2e2b1 100644
--- a/Telegram/SourceFiles/history/view/history_view_schedule_box.h
+++ b/Telegram/SourceFiles/history/view/history_view_schedule_box.h
@@ -29,12 +29,13 @@ template <typename Guard, typename Submit>
 [[nodiscard]] object_ptr<Ui::GenericBox> PrepareScheduleBox(
 		Guard &&guard,
 		SendMenuType type,
-		Submit &&submit) {
+		Submit &&submit,
+		TimeId scheduleTime = DefaultScheduleTime()) {
 	return Box(
 		ScheduleBox,
 		type,
 		crl::guard(std::forward<Guard>(guard), std::forward<Submit>(submit)),
-		DefaultScheduleTime());
+		scheduleTime);
 }
 
 } // namespace HistoryView