From 2f7563767dc7214ec3c9a4d0c4d4b50e62c5927f Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 30 Mar 2020 21:04:49 +0400
Subject: [PATCH 1/3] Fix crash in archive / pinned in folder management.

---
 Telegram/SourceFiles/history/history.cpp | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index d1d0bcb43c..fa69e0a9de 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -1948,12 +1948,6 @@ void History::setFolderPointer(Data::Folder *folder) {
 	const auto wasInList = inChatList();
 	if (wasInList) {
 		removeFromChatList(0, owner().chatsList(this->folder()));
-		for (const auto &filter : filters.list()) {
-			const auto id = filter.id();
-			if (inChatList(id)) {
-				removeFromChatList(id, filters.chatsList(id));
-			}
-		}
 	}
 	const auto was = _folder.value_or(nullptr);
 	_folder = folder;
@@ -1962,12 +1956,10 @@ void History::setFolderPointer(Data::Folder *folder) {
 	}
 	if (wasInList) {
 		addToChatList(0, owner().chatsList(folder));
-		for (const auto &filter : filters.list()) {
-			if (filter.contains(this)) {
-				const auto id = filter.id();
-				addToChatList(id, filters.chatsList(id));
-			}
-		}
+
+		owner().chatsFilters().refreshHistory(this);
+		updateChatListEntry();
+
 		owner().chatsListChanged(was);
 		owner().chatsListChanged(folder);
 	} else if (!wasKnown) {

From c2ff27793a56241135fde194256a2ebf7bc5ec90 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 30 Mar 2020 23:34:07 +0400
Subject: [PATCH 2/3] Try to use Ctrl+1..Ctrl+8 for folders.

---
 Telegram/SourceFiles/core/shortcuts.cpp       | 78 ++++++++++++-------
 Telegram/SourceFiles/core/shortcuts.h         | 18 ++---
 .../dialogs/dialogs_inner_widget.cpp          | 60 +++++++-------
 3 files changed, 86 insertions(+), 70 deletions(-)

diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp
index 76bc4bd0d3..f8c10e4ee8 100644
--- a/Telegram/SourceFiles/core/shortcuts.cpp
+++ b/Telegram/SourceFiles/core/shortcuts.cpp
@@ -113,7 +113,7 @@ class Manager {
 	void fill();
 	void clear();
 
-	std::optional<Command> lookup(int shortcutId) const;
+	[[nodiscard]] std::vector<Command> lookup(int shortcutId) const;
 	void toggleMedia(bool toggled);
 	void toggleSupport(bool toggled);
 
@@ -124,14 +124,14 @@ class Manager {
 	void writeDefaultFile();
 	bool readCustomFile();
 
-	void set(const QString &keys, Command command);
+	void set(const QString &keys, Command command, bool replace = false);
 	void remove(const QString &keys);
 	void unregister(base::unique_qptr<QShortcut> shortcut);
 
 	QStringList _errors;
 
 	base::flat_map<QKeySequence, base::unique_qptr<QShortcut>> _shortcuts;
-	base::flat_map<int, Command> _commandByShortcutId;
+	base::flat_multi_map<int, Command> _commandByShortcutId;
 
 	base::flat_set<QShortcut*> _mediaShortcuts;
 	base::flat_set<QShortcut*> _supportShortcuts;
@@ -206,11 +206,14 @@ const QStringList &Manager::errors() const {
 	return _errors;
 }
 
-std::optional<Command> Manager::lookup(int shortcutId) const {
-	const auto i = _commandByShortcutId.find(shortcutId);
-	return (i != end(_commandByShortcutId))
-		? base::make_optional(i->second)
-		: std::nullopt;
+std::vector<Command> Manager::lookup(int shortcutId) const {
+	auto result = std::vector<Command>();
+	auto i = _commandByShortcutId.findFirst(shortcutId);
+	const auto end = _commandByShortcutId.end();
+	for (; i != end && (i->first == shortcutId); ++i) {
+		result.push_back(i->second);
+	}
+	return result;
 }
 
 void Manager::toggleMedia(bool toggled) {
@@ -278,7 +281,7 @@ bool Manager::readCustomFile() {
 			const auto name = (*command).toString();
 			const auto i = CommandByName.find(name);
 			if (i != end(CommandByName)) {
-				set((*keys).toString(), i->second);
+				set((*keys).toString(), i->second, true);
 			} else {
 				LOG(("Shortcut Warning: "
 					"could not find shortcut command handler '%1'"
@@ -343,7 +346,7 @@ void Manager::fillDefaults() {
 		ranges::view::ints(1, ranges::unreachable));
 
 	for (const auto [command, index] : folders) {
-		set(qsl("%1+shift+%2").arg(ctrl).arg(index > 9 ? 0 : index), command);
+		set(qsl("%1+%2").arg(ctrl).arg(index), command);
 	}
 
 	set(qsl("%1+shift+down").arg(ctrl), Command::FolderNext);
@@ -373,10 +376,12 @@ void Manager::writeDefaultFile() {
 	shortcuts.push_back(version);
 
 	for (const auto &[sequence, shortcut] : _shortcuts) {
-		const auto i = _commandByShortcutId.find(shortcut->id());
-		if (i != end(_commandByShortcutId)) {
+		const auto shortcutId = shortcut->id();
+		auto i = _commandByShortcutId.findFirst(shortcutId);
+		const auto end = _commandByShortcutId.end();
+		for (; i != end && i->first == shortcutId; ++i) {
 			const auto j = CommandNames.find(i->second);
-			if (j != end(CommandNames)) {
+			if (j != CommandNames.end()) {
 				QJsonObject entry;
 				entry.insert(qsl("keys"), sequence.toString().toLower());
 				entry.insert(qsl("command"), j->second);
@@ -390,7 +395,7 @@ void Manager::writeDefaultFile() {
 	file.write(document.toJson(QJsonDocument::Indented));
 }
 
-void Manager::set(const QString &keys, Command command) {
+void Manager::set(const QString &keys, Command command, bool replace) {
 	if (keys.isEmpty()) {
 		return;
 	}
@@ -415,22 +420,25 @@ void Manager::set(const QString &keys, Command command) {
 	if (isMediaShortcut || isSupportShortcut) {
 		shortcut->setEnabled(false);
 	}
-	const auto id = shortcut->id();
-	if (!id) {
-		_errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys));
-		return;
-	}
+	auto id = shortcut->id();
 	auto i = _shortcuts.find(result);
 	if (i == end(_shortcuts)) {
 		i = _shortcuts.emplace(result, std::move(shortcut)).first;
-	} else {
+	} else if (replace) {
 		unregister(std::exchange(i->second, std::move(shortcut)));
+	} else {
+		shortcut = nullptr;
+		id = i->second->id();
+	}
+	if (!id) {
+		_errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys));
+		return;
 	}
 	_commandByShortcutId.emplace(id, command);
-	if (isMediaShortcut) {
+	if (shortcut && isMediaShortcut) {
 		_mediaShortcuts.emplace(i->second.get());
 	}
-	if (isSupportShortcut) {
+	if (shortcut && isSupportShortcut) {
 		_supportShortcuts.emplace(i->second.get());
 	}
 }
@@ -465,11 +473,13 @@ Manager Data;
 
 } // namespace
 
-Request::Request(Command command) : _command(command) {
+Request::Request(std::vector<Command> commands)
+: _commands(std::move(commands)) {
 }
 
 bool Request::check(Command command, int priority) {
-	if (_command == command && priority > _handlerPriority) {
+	if (ranges::contains(_commands, command)
+		&& priority > _handlerPriority) {
 		_handlerPriority = priority;
 		return true;
 	}
@@ -481,12 +491,16 @@ bool Request::handle(FnMut<bool()> handler) {
 	return true;
 }
 
-FnMut<bool()> RequestHandler(Command command) {
-	auto request = Request(command);
+FnMut<bool()> RequestHandler(std::vector<Command> commands) {
+	auto request = Request(std::move(commands));
 	RequestsStream.fire(&request);
 	return std::move(request._handler);
 }
 
+FnMut<bool()> RequestHandler(Command command) {
+	return RequestHandler(std::vector<Command>{ command });
+}
+
 bool Launch(Command command) {
 	if (auto handler = RequestHandler(command)) {
 		return handler();
@@ -494,6 +508,13 @@ bool Launch(Command command) {
 	return false;
 }
 
+bool Launch(std::vector<Command> commands) {
+	if (auto handler = RequestHandler(std::move(commands))) {
+		return handler();
+	}
+	return false;
+}
+
 rpl::producer<not_null<Request*>> Requests() {
 	return RequestsStream.events();
 }
@@ -509,10 +530,7 @@ const QStringList &Errors() {
 }
 
 bool HandleEvent(not_null<QShortcutEvent*> event) {
-	if (const auto command = Data.lookup(event->shortcutId())) {
-		return Launch(*command);
-	}
-	return false;
+	return Launch(Data.lookup(event->shortcutId()));
 }
 
 void ToggleMediaShortcuts(bool toggled) {
diff --git a/Telegram/SourceFiles/core/shortcuts.h b/Telegram/SourceFiles/core/shortcuts.h
index fbce7c9ced..4bdf9bca44 100644
--- a/Telegram/SourceFiles/core/shortcuts.h
+++ b/Telegram/SourceFiles/core/shortcuts.h
@@ -35,16 +35,14 @@ enum class Command {
 	ChatPinned4,
 	ChatPinned5,
 
+	ShowAllChats,
 	ShowFolder1,
 	ShowFolder2,
 	ShowFolder3,
 	ShowFolder4,
 	ShowFolder5,
 	ShowFolder6,
-	ShowFolder7,
-	ShowFolder8,
-	ShowFolder9,
-	ShowFolder10,
+	ShowFolderLast,
 
 	FolderNext,
 	FolderPrevious,
@@ -63,16 +61,14 @@ enum class Command {
 };
 
 constexpr auto kShowFolder = {
+	Command::ShowAllChats,
 	Command::ShowFolder1,
 	Command::ShowFolder2,
 	Command::ShowFolder3,
 	Command::ShowFolder4,
 	Command::ShowFolder5,
 	Command::ShowFolder6,
-	Command::ShowFolder7,
-	Command::ShowFolder8,
-	Command::ShowFolder9,
-	Command::ShowFolder10,
+	Command::ShowFolderLast,
 };
 
 [[nodiscard]] FnMut<bool()> RequestHandler(Command command);
@@ -83,13 +79,13 @@ class Request {
 	bool handle(FnMut<bool()> handler);
 
 private:
-	explicit Request(Command command);
+	explicit Request(std::vector<Command> commands);
 
-	Command _command;
+	std::vector<Command> _commands;
 	int _handlerPriority = -1;
 	FnMut<bool()> _handler;
 
-	friend FnMut<bool()> RequestHandler(Command command);
+	friend FnMut<bool()> RequestHandler(std::vector<Command> commands);
 
 };
 
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index 6ad29fc53f..c1e30d385d 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -3008,6 +3008,27 @@ void InnerWidget::setupShortcuts() {
 			return false;
 		});
 
+		const auto filters = &session().data().chatsFilters().list();
+		if (const auto filtersCount = int(filters->size())) {
+			auto &&folders = ranges::view::zip(
+				Shortcuts::kShowFolder,
+				ranges::view::ints(0, ranges::unreachable));
+
+			for (const auto [command, index] : folders) {
+				const auto select = (command == Command::ShowFolderLast)
+					? filtersCount
+					: std::clamp(index, 0, filtersCount);
+				request->check(command) && request->handle([=] {
+					if (select <= filtersCount) {
+						_controller->setActiveChatsFilter((select > 0)
+							? (*filters)[select - 1].id()
+							: 0);
+					}
+					return true;
+				});
+			}
+		}
+
 		static const auto kPinned = {
 			Command::ChatPinned1,
 			Command::ChatPinned2,
@@ -3036,42 +3057,23 @@ void InnerWidget::setupShortcuts() {
 			});
 		}
 
-		auto &&folders = ranges::view::zip(
-			Shortcuts::kShowFolder,
-			ranges::view::ints(0, ranges::unreachable));
-
-		for (const auto [command, index] : folders) {
-			request->check(command) && request->handle([=, index = index] {
-				const auto list = &session().data().chatsFilters().list();
-				if (index >= list->size()) {
-					return false;
-				}
-				const auto filterId = list->at(index).id();
-				_controller->setActiveChatsFilter((filterId == _filterId)
-					? 0
-					: filterId);
-				return true;
-			});
-		}
-
 		const auto nearFolder = [=](bool isNext) {
 			const auto id = _controller->activeChatsFilterCurrent();
 			const auto list = &session().data().chatsFilters().list();
-			const auto it = (id == 0)
-				? begin(*list) - 1
-				: ranges::find(*list, id, &Data::ChatFilter::id);
-			if (it == end(*list) && id != 0) {
+			const auto index = (id != 0)
+				? int(ranges::find(*list, id, &Data::ChatFilter::id)
+					- begin(*list))
+				: -1;
+			if (index == list->size() && id != 0) {
 				return false;
 			}
-			const auto i = isNext ? 1 : -1;
-			const auto index = it - begin(*list) + i;
-			if (index >= (int)list->size() || index < -1) {
+			const auto changed = index + (isNext ? 1 : -1);
+			if (changed >= int(list->size()) || changed < -1) {
 				return false;
 			}
-			const auto filterId = (index == -1)
-				? 0
-				: list->at(index).id();
-			_controller->setActiveChatsFilter(filterId);
+			_controller->setActiveChatsFilter((changed >= 0)
+				? (*list)[changed].id()
+				: 0);
 			return true;
 		};
 

From 9ef41062d316be092fbd07a4aef05eb076622556 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 30 Mar 2020 23:53:10 +0400
Subject: [PATCH 3/3] Ignore whitespaces in dice sending.

---
 Telegram/SourceFiles/api/api_sending.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp
index d0c5315ac0..eaac3957e7 100644
--- a/Telegram/SourceFiles/api/api_sending.cpp
+++ b/Telegram/SourceFiles/api/api_sending.cpp
@@ -200,7 +200,7 @@ void SendExistingPhoto(
 
 bool SendDice(Api::MessageToSend &message) {
 	static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
-	if (message.textWithTags.text != kDiceString) {
+	if (message.textWithTags.text.midRef(0).trimmed() != kDiceString) {
 		return false;
 	}
 	const auto history = message.action.history;
