From ece315f3c5a14ed43a274e52e7e1c6c1a1cd1a2b Mon Sep 17 00:00:00 2001
From: 23rd <23rd@vivaldi.net>
Date: Thu, 16 May 2019 11:39:45 +0300
Subject: [PATCH] Added ability to move archive in main menu.

 - Added Folder::paintUserpic overload for custom color.
 - Reduced size of _cloudButton.
---
 Telegram/Resources/langs/lang.strings         |  3 +
 Telegram/SourceFiles/auth_session.cpp         | 18 +++++
 Telegram/SourceFiles/auth_session.h           |  5 ++
 Telegram/SourceFiles/data/data_folder.cpp     | 23 ++++++-
 Telegram/SourceFiles/data/data_folder.h       |  8 +++
 .../dialogs/dialogs_inner_widget.cpp          | 13 +++-
 Telegram/SourceFiles/window/window.style      |  4 +-
 .../SourceFiles/window/window_main_menu.cpp   | 69 ++++++++++++++++++-
 .../SourceFiles/window/window_main_menu.h     |  3 +
 .../SourceFiles/window/window_peer_menu.cpp   | 18 ++++-
 10 files changed, 151 insertions(+), 13 deletions(-)

diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index e5462d0e1..8359ea980 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1317,6 +1317,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_context_mark_read" = "Mark as read";
 "lng_context_archive_expand" = "Expand";
 "lng_context_archive_collapse" = "Collapse";
+"lng_context_archive_to_menu" = "Move to main menu";
+"lng_context_archive_to_list" = "Move to chats list";
+"lng_context_archive_to_menu_info" = "Archive moved in the main menu!\nYou can return it with context menu of archive button.";
 
 "lng_context_promote_admin" = "Promote to admin";
 "lng_context_edit_permissions" = "Edit permissions";
diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp
index d62f32d7c..0359ef826 100644
--- a/Telegram/SourceFiles/auth_session.cpp
+++ b/Telegram/SourceFiles/auth_session.cpp
@@ -96,6 +96,7 @@ QByteArray AuthSessionSettings::serialize() const {
 		stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0);
 		stream << qint32(_variables.archiveCollapsed.current() ? 1 : 0);
 		stream << qint32(_variables.notifyAboutPinned.current() ? 1 : 0);
+		stream << qint32(_variables.archiveInMainMenu.current() ? 1 : 0);
 	}
 	return result;
 }
@@ -134,6 +135,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
 	qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0;
 	qint32 archiveCollapsed = _variables.archiveCollapsed.current() ? 1 : 0;
 	qint32 notifyAboutPinned = _variables.notifyAboutPinned.current() ? 1 : 0;
+	qint32 archiveInMainMenu = _variables.archiveInMainMenu.current() ? 1 : 0;
 
 	stream >> selectorTab;
 	stream >> lastSeenWarningSeen;
@@ -219,6 +221,9 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
 	if (!stream.atEnd()) {
 		stream >> notifyAboutPinned;
 	}
+	if (!stream.atEnd()) {
+		stream >> archiveInMainMenu;
+	}
 	if (stream.status() != QDataStream::Ok) {
 		LOG(("App Error: "
 			"Bad data for AuthSessionSettings::constructFromSerialized()"));
@@ -290,6 +295,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
 	_variables.supportAllSearchResults = (supportAllSearchResults == 1);
 	_variables.archiveCollapsed = (archiveCollapsed == 1);
 	_variables.notifyAboutPinned = (notifyAboutPinned == 1);
+	_variables.archiveInMainMenu = (archiveInMainMenu == 1);
 }
 
 void AuthSessionSettings::setSupportChatsTimeSlice(int slice) {
@@ -408,6 +414,18 @@ rpl::producer<bool> AuthSessionSettings::notifyAboutPinnedChanges() const {
 	return _variables.notifyAboutPinned.changes();
 }
 
+void AuthSessionSettings::setArchiveInMainMenu(bool inMainMenu) {
+	_variables.archiveInMainMenu = inMainMenu;
+}
+
+bool AuthSessionSettings::archiveInMainMenu() const {
+	return _variables.archiveInMainMenu.current();
+}
+
+rpl::producer<bool> AuthSessionSettings::archiveInMainMenuChanges() const {
+	return _variables.archiveInMainMenu.changes();
+}
+
 AuthSession &Auth() {
 	return Core::App().activeAccount().session();
 }
diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h
index ee6cd7806..f91bad6d1 100644
--- a/Telegram/SourceFiles/auth_session.h
+++ b/Telegram/SourceFiles/auth_session.h
@@ -200,6 +200,10 @@ public:
 	bool notifyAboutPinned() const;
 	rpl::producer<bool> notifyAboutPinnedChanges() const;
 
+	void setArchiveInMainMenu(bool inMainMenu);
+	bool archiveInMainMenu() const;
+	rpl::producer<bool> archiveInMainMenuChanges() const;
+
 	bool hadLegacyCallsPeerToPeerNobody() const {
 		return _variables.hadLegacyCallsPeerToPeerNobody;
 	}
@@ -254,6 +258,7 @@ private:
 		Data::AutoDownload::Full autoDownload;
 		rpl::variable<bool> archiveCollapsed = false;
 		rpl::variable<bool> notifyAboutPinned = true;
+		rpl::variable<bool> archiveInMainMenu = false;
 
 		static constexpr auto kDefaultSupportChatsLimitSlice
 			= 7 * 24 * 60 * 60;
diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp
index 10645139b..536c82e7c 100644
--- a/Telegram/SourceFiles/data/data_folder.cpp
+++ b/Telegram/SourceFiles/data/data_folder.cpp
@@ -220,14 +220,30 @@ void Folder::paintUserpic(
 		int x,
 		int y,
 		int size) const {
+	paintUserpic(
+		p,
+		x,
+		y,
+		size,
+		st::historyPeerArchiveUserpicBg,
+		st::historyPeerUserpicFg);
+}
+
+void Folder::paintUserpic(
+		Painter &p,
+		int x,
+		int y,
+		int size,
+		const style::color &bg,
+		const style::color &fg) const {
 	p.setPen(Qt::NoPen);
-	p.setBrush(st::historyPeerArchiveUserpicBg);
+	p.setBrush(bg);
 	{
 		PainterHighQualityEnabler hq(p);
 		p.drawEllipse(x, y, size, size);
 	}
 	if (size == st::dialogsPhotoSize) {
-		st::dialogsArchiveUserpic.paintInCenter(p, { x, y, size, size });
+		st::dialogsArchiveUserpic.paintInCenter(p, { x, y, size, size }, fg->c);
 	} else {
 		p.save();
 		const auto ratio = size / float64(st::dialogsPhotoSize);
@@ -236,7 +252,8 @@ void Folder::paintUserpic(
 		const auto skip = st::dialogsPhotoSize;
 		st::dialogsArchiveUserpic.paintInCenter(
 			p,
-			{ -skip, -skip, 2 * skip, 2 * skip });
+			{ -skip, -skip, 2 * skip, 2 * skip },
+			fg->c);
 		p.restore();
 	}
 	//const auto small = (size - st::lineWidth) / 2; // #feed
diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h
index fd5ea6be4..2f71b7429 100644
--- a/Telegram/SourceFiles/data/data_folder.h
+++ b/Telegram/SourceFiles/data/data_folder.h
@@ -75,6 +75,14 @@ public:
 		int y,
 		int size) const override;
 
+	void paintUserpic(
+		Painter &p,
+		int x,
+		int y,
+		int size,
+		const style::color &bg,
+		const style::color &fg) const;
+
 	bool chatsListLoaded() const;
 	void setChatsListLoaded(bool loaded = true);
 	void setCloudChatsListSize(int size);
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index 5b09aa80a..c8fceb444 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -217,6 +217,11 @@ InnerWidget::InnerWidget(
 		refreshWithCollapsedRows();
 	}, lifetime());
 
+	session().settings().archiveInMainMenuChanges(
+	) | rpl::start_with_next([=] {
+		refreshWithCollapsedRows();
+	}, lifetime());
+
 	subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &data) {
 		if (data.paletteChanged()) {
 			Layout::clearUnreadBadgesCache();
@@ -302,7 +307,8 @@ void InnerWidget::refreshWithCollapsedRows(bool toTop) {
 	const auto archive = !list->empty()
 		? (*list->begin())->folder()
 		: nullptr;
-	if (archive && session().settings().archiveCollapsed()) {
+	if (archive && session().settings().archiveCollapsed()
+		&& !session().settings().archiveInMainMenu()) {
 		if (_selected && _selected->folder() == archive) {
 			_selected = nullptr;
 		}
@@ -2105,8 +2111,9 @@ Data::Folder *InnerWidget::shownFolder() const {
 }
 
 bool InnerWidget::needCollapsedRowsRefresh() const {
-	const auto archive = !shownDialogs()->empty()
-		? (*shownDialogs()->begin())->folder()
+	const auto list = shownDialogs();
+	const auto archive = !list->empty()
+		? (*list->begin())->folder()
 		: nullptr;
 	const auto collapsedHasArchive = !_collapsedRows.empty()
 		&& (_collapsedRows.back()->folder != nullptr);
diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style
index f1f55265b..06dfdf4be 100644
--- a/Telegram/SourceFiles/window/window.style
+++ b/Telegram/SourceFiles/window/window.style
@@ -96,8 +96,8 @@ mainMenuUserpic: UserpicButton(defaultUserpicButton) {
 	photoSize: 48px;
 }
 mainMenuCloudButton: IconButton {
-	width: 64px;
-	height: 64px;
+	width: 48px;
+	height: 48px;
 
 	icon: icon {
 //		{ "menu_cloud", mainMenuCloudFg },
diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp
index 657cfd2fd..32b3d6f3b 100644
--- a/Telegram/SourceFiles/window/window_main_menu.cpp
+++ b/Telegram/SourceFiles/window/window_main_menu.cpp
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/widgets/buttons.h"
 #include "ui/widgets/labels.h"
 #include "ui/widgets/menu.h"
+#include "ui/widgets/popup_menu.h"
 #include "ui/special_buttons.h"
 #include "ui/empty_userpic.h"
 #include "mainwindow.h"
@@ -26,6 +27,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "core/click_handler_types.h"
 #include "observer_peer.h"
 #include "auth_session.h"
+#include "data/data_folder.h"
+#include "data/data_session.h"
 #include "data/data_user.h"
 #include "mainwidget.h"
 #include "styles/style_window.h"
@@ -124,9 +127,21 @@ MainMenu::MainMenu(
 , _version(this, st::mainMenuVersionLabel) {
 	setAttribute(Qt::WA_OpaquePaintEvent);
 
-	auto showSelfChat = [] {
+	const auto showSelfChat = [] {
 		App::main()->choosePeer(Auth().userPeerId(), ShowAtUnreadMsgId);
 	};
+	const auto showArchive = [=] {
+		if (const auto folder = Auth().data().folderLoaded(Data::Folder::kId)) {
+			App::wnd()->sessionController()->openFolder(folder);
+			Ui::hideSettingsAndLayer();
+		}
+	};
+	const auto checkArchive = [=] {
+		const auto folder = Auth().data().folderLoaded(Data::Folder::kId);
+		return folder
+			&& !folder->chatsList()->empty()
+			&& _controller->session().settings().archiveInMainMenu();
+	};
 	_userpicButton.create(
 		this,
 		_controller,
@@ -139,6 +154,27 @@ MainMenu::MainMenu(
 	_cloudButton->setClickedCallback(showSelfChat);
 	_cloudButton->show();
 
+	_archiveButton.create(this, st::mainMenuCloudButton);
+	_archiveButton->setHidden(!checkArchive());
+	_archiveButton->setAcceptBoth(true);
+	_archiveButton->clicks(
+	) | rpl::start_with_next([=](Qt::MouseButton which) {
+		if (which == Qt::LeftButton) {
+			showArchive();
+			return;
+		} else if (which != Qt::RightButton) {
+			return;
+		}
+		_contextMenu = base::make_unique_q<Ui::PopupMenu>(this);
+		_contextMenu->addAction(
+			lang(lng_context_archive_to_list), [=] {
+			_controller->session().settings().setArchiveInMainMenu(false);
+			_controller->session().saveSettingsDelayed();
+			Ui::hideSettingsAndLayer();
+		});
+		_contextMenu->popup(QCursor::pos());
+	}, _archiveButton->lifetime());
+
 	_nightThemeSwitch.setCallback([this] {
 		if (const auto action = *_nightThemeAction) {
 			const auto nightMode = Window::Theme::IsNightMode();
@@ -178,6 +214,13 @@ MainMenu::MainMenu(
 			refreshBackground();
 		}
 	});
+	Auth().data().chatsListChanges(
+	) | rpl::filter([](Data::Folder *folder) {
+		return folder && (folder->id() == Data::Folder::kId);
+	}) | rpl::start_with_next([=](Data::Folder *folder) {
+		_archiveButton->setHidden(!checkArchive());
+		update();
+	}, lifetime());
 	updatePhone();
 	initResetScaleButton();
 }
@@ -310,7 +353,16 @@ void MainMenu::updateControlsGeometry() {
 		_userpicButton->moveToLeft(st::mainMenuUserpicLeft, st::mainMenuUserpicTop);
 	}
 	if (_cloudButton) {
-		_cloudButton->moveToRight(0, st::mainMenuCoverHeight - _cloudButton->height());
+		const auto offset = st::mainMenuCloudSize / 4;
+		const auto y = st::mainMenuCoverHeight
+			- _cloudButton->height()
+			- offset;
+		_cloudButton->moveToRight(offset, y);
+		if (_archiveButton) {
+			_archiveButton->moveToRight(
+				offset,
+				y - _cloudButton->height());
+		}
 	}
 	if (_resetScaleButton) {
 		_resetScaleButton->moveToRight(0, 0);
@@ -371,6 +423,19 @@ void MainMenu::paintEvent(QPaintEvent *e) {
 				isFill ? st::mainMenuCloudBg : st::msgServiceBg,
 				isFill ? st::mainMenuCloudFg : st::msgServiceFg);
 		}
+
+		// Draw Archive button.
+		if (!_archiveButton->isHidden()) {
+			if (const auto folder = Auth().data().folderLoaded(Data::Folder::kId)) {
+				folder->paintUserpic(
+					p,
+					_archiveButton->x() + (_archiveButton->width() - st::mainMenuCloudSize) / 2,
+					_archiveButton->y() + (_archiveButton->height() - st::mainMenuCloudSize) / 2,
+					st::mainMenuCloudSize,
+					isFill ? st::mainMenuCloudBg : st::msgServiceBg,
+					isFill ? st::mainMenuCloudFg : st::msgServiceFg);
+			}
+		}
 	}
 	auto other = QRect(0, st::mainMenuCoverHeight, width(), height() - st::mainMenuCoverHeight).intersected(clip);
 	if (!other.isEmpty()) {
diff --git a/Telegram/SourceFiles/window/window_main_menu.h b/Telegram/SourceFiles/window/window_main_menu.h
index 41bebca36..081a92270 100644
--- a/Telegram/SourceFiles/window/window_main_menu.h
+++ b/Telegram/SourceFiles/window/window_main_menu.h
@@ -15,6 +15,7 @@ class IconButton;
 class FlatLabel;
 class Menu;
 class UserpicButton;
+class PopupMenu;
 } // namespace Ui
 
 namespace Window {
@@ -44,12 +45,14 @@ private:
 	not_null<SessionController*> _controller;
 	object_ptr<Ui::UserpicButton> _userpicButton = { nullptr };
 	object_ptr<Ui::IconButton> _cloudButton = { nullptr };
+	object_ptr<Ui::IconButton> _archiveButton = { nullptr };
 	object_ptr<ResetScaleButton> _resetScaleButton = { nullptr };
 	object_ptr<Ui::Menu> _menu;
 	object_ptr<Ui::FlatLabel> _telegram;
 	object_ptr<Ui::FlatLabel> _version;
 	std::shared_ptr<QPointer<QAction>> _nightThemeAction;
 	base::Timer _nightThemeSwitch;
+	base::unique_qptr<Ui::PopupMenu> _contextMenu;
 
 	QString _phoneText;
 	QImage _background;
diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp
index d5f781a88..344154728 100644
--- a/Telegram/SourceFiles/window/window_peer_menu.cpp
+++ b/Telegram/SourceFiles/window/window_peer_menu.cpp
@@ -84,7 +84,7 @@ public:
 	void fill();
 
 private:
-	void addToggleCollapse();
+	void addTogglesForArchive();
 	//bool showInfo();
 	//void addTogglePin();
 	//void addInfo();
@@ -544,11 +544,11 @@ FolderFiller::FolderFiller(
 
 void FolderFiller::fill() {
 	if (_source == PeerMenuSource::ChatsList) {
-		addToggleCollapse();
+		addTogglesForArchive();
 	}
 }
 
-void FolderFiller::addToggleCollapse() {
+void FolderFiller::addTogglesForArchive() {
 	if (_folder->id() != Data::Folder::kId) {
 		return;
 	}
@@ -561,6 +561,18 @@ void FolderFiller::addToggleCollapse() {
 		controller->session().settings().setArchiveCollapsed(!hidden);
 		controller->session().saveSettingsDelayed();
 	});
+
+	_addAction(lang(lng_context_archive_to_menu), [=] {
+		Ui::Toast::Config toast;
+		toast.text = lang(lng_context_archive_to_menu_info);
+		toast.maxWidth = st::boxWideWidth;
+		toast.durationMs = kArchivedToastDuration;
+		Ui::Toast::Show(toast);
+
+		controller->session().settings().setArchiveInMainMenu(
+			!controller->session().settings().archiveInMainMenu());
+		controller->session().saveSettingsDelayed();
+	});
 }
 //
 //void FolderFiller::addInfo() {