From a8c3d6c39bca2046ef6f7e9e362c77e0ccc98e2a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 31 Jan 2022 19:06:40 +0300 Subject: [PATCH] Added ability to reorder accounts in MainMenu. --- Telegram/SourceFiles/core/core_settings.cpp | 24 ++++++- Telegram/SourceFiles/core/core_settings.h | 7 ++ .../SourceFiles/window/window_main_menu.cpp | 69 ++++++++++++++++--- .../SourceFiles/window/window_main_menu.h | 4 ++ 4 files changed, 94 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index c47404bce..fcc262f17 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -113,7 +113,8 @@ QByteArray Settings::serialize() const { + sizeof(qint64) + sizeof(qint32) * 2 + Serialize::bytearraySize(windowPosition) - + sizeof(qint32); + + sizeof(qint32) * 2 + + (_accountsOrder.size() * sizeof(quint64)); for (const auto &[id, rating] : recentEmojiPreloadData) { size += Serialize::stringSize(id) + sizeof(quint16); } @@ -229,6 +230,12 @@ QByteArray Settings::serialize() const { << qint32(_playerRepeatMode.current()) << qint32(_playerOrderMode.current()) << qint32(_macWarnBeforeQuit ? 1 : 0); + + stream + << qint32(_accountsOrder.size()); + for (const auto &id : _accountsOrder) { + stream << quint64(id); + } } return result; } @@ -316,6 +323,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) { qint32 playerRepeatMode = static_cast(_playerRepeatMode.current()); qint32 playerOrderMode = static_cast(_playerOrderMode.current()); qint32 macWarnBeforeQuit = _macWarnBeforeQuit ? 1 : 0; + qint32 accountsOrderCount = 0; + std::vector accountsOrder; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -487,6 +496,16 @@ void Settings::addFromSerialized(const QByteArray &serialized) { if (!stream.atEnd()) { stream >> macWarnBeforeQuit; } + if (!stream.atEnd()) { + stream >> accountsOrderCount; + if (stream.status() == QDataStream::Ok) { + for (auto i = 0; i != accountsOrderCount; ++i) { + quint64 sessionUniqueId; + stream >> sessionUniqueId; + accountsOrder.emplace_back(sessionUniqueId); + } + } + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -629,6 +648,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _photoEditorBrush = photoEditorBrush; _closeToTaskbar = (closeToTaskbar == 1); _customDeviceModel = customDeviceModel; + _accountsOrder = accountsOrder; const auto uncheckedPlayerRepeatMode = static_cast(playerRepeatMode); switch (uncheckedPlayerRepeatMode) { case Media::Player::RepeatMode::None: @@ -922,6 +942,8 @@ void Settings::resetOnLastLogout() { _emojiVariants.clear(); _workMode = WorkMode::WindowAndTray; + + _accountsOrder.clear(); } bool Settings::ThirdColumnByDefault() { diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index 414d56da5..f411bd4bf 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -656,6 +656,12 @@ public: [[nodiscard]] rpl::producer playerOrderModeChanges() const { return _playerOrderMode.changes(); } + [[nodiscard]] std::vector accountsOrder() const { + return _accountsOrder; + } + void setAccountsOrder(const std::vector &order) { + _accountsOrder = order; + } void setMacWarnBeforeQuit(bool value) { _macWarnBeforeQuit = value; @@ -768,6 +774,7 @@ private: rpl::variable _playerRepeatMode; rpl::variable _playerOrderMode; bool _macWarnBeforeQuit = true; + std::vector _accountsOrder; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 4a9c8bd98..9c9cd6fbf 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/shadow.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" +#include "ui/wrap/vertical_layout_reorder.h" #include "ui/text/format_values.h" // Ui::FormatPhone #include "ui/text/text_utilities.h" #include "ui/special_buttons.h" @@ -140,6 +141,27 @@ void ShowCallsBox(not_null window) { window->show(Box(std::move(controller), initBox)); } +[[nodiscard]] std::vector> OrderedAccounts() { + const auto order = Core::App().settings().accountsOrder(); + auto accounts = ranges::views::all( + Core::App().domain().accounts() + ) | ranges::views::transform([](const Main::Domain::AccountWithIndex &a) { + return not_null{ a.account.get() }; + }) | ranges::to_vector; + ranges::stable_sort(accounts, [&]( + not_null a, + not_null b) { + const auto aIt = a->sessionExists() + ? ranges::find(order, a->session().uniqueId()) + : end(order); + const auto bIt = b->sessionExists() + ? ranges::find(order, b->session().uniqueId()) + : end(order); + return aIt < bIt; + }); + return accounts; +} + } // namespace namespace Window { @@ -817,11 +839,37 @@ void MainMenu::setupAccounts() { } void MainMenu::rebuildAccounts() { - const auto inner = _accounts->entity(); + const auto inner = _accounts->entity()->insert( + 1, // After skip with the fixed height. + object_ptr(_accounts.get())); - auto count = 0; - for (const auto &[index, pointer] : Core::App().domain().accounts()) { - const auto account = pointer.get(); + _reorder = std::make_unique(inner); + _reorder->updates( + ) | rpl::start_with_next([=](Ui::VerticalLayoutReorder::Single data) { + using State = Ui::VerticalLayoutReorder::State; + if (data.state == State::Started) { + ++_reordering; + } else { + Ui::PostponeCall(inner, [=] { + --_reordering; + }); + if (data.state == State::Applied) { + std::vector order; + order.reserve(inner->count()); + for (auto i = 0; i < inner->count(); i++) { + for (const auto &[account, button] : _watched) { + if (button.get() == inner->widgetAt(i)) { + order.push_back(account->session().uniqueId()); + } + } + } + Core::App().settings().setAccountsOrder(order); + Core::App().saveSettings(); + } + } + }, inner->lifetime()); + + for (const auto &account : OrderedAccounts()) { auto i = _watched.find(account); Assert(i != _watched.end()); @@ -829,16 +877,19 @@ void MainMenu::rebuildAccounts() { if (!account->sessionExists()) { button = nullptr; } else if (!button) { - button.reset(inner->insert( - ++count, + button.reset(inner->add( object_ptr(inner, account))); button->setClickedCallback([=] { + if (_reordering) { + return; + } if (account == &Core::App().domain().active()) { closeLayer(); return; } auto activate = [=, guard = _accountSwitchGuard.make_guard()]{ if (guard) { + _reorder->finishReordering(); Core::App().domain().maybeActivate(account); } }; @@ -847,15 +898,15 @@ void MainMenu::rebuildAccounts() { account, std::move(activate)); }); - } else { - ++count; } } inner->resizeToWidth(_accounts->width()); _addAccount->toggle( - (count < Main::Domain::kMaxAccounts), + (inner->count() < Main::Domain::kMaxAccounts), anim::type::instant); + + _reorder->start(); } not_null*> MainMenu::setupAddAccount( diff --git a/Telegram/SourceFiles/window/window_main_menu.h b/Telegram/SourceFiles/window/window_main_menu.h index 1ea7c1f2b..af64cdcd5 100644 --- a/Telegram/SourceFiles/window/window_main_menu.h +++ b/Telegram/SourceFiles/window/window_main_menu.h @@ -20,6 +20,7 @@ class UserpicButton; class PopupMenu; class ScrollArea; class VerticalLayout; +class VerticalLayoutReorder; class RippleButton; class PlainShadow; template @@ -94,6 +95,9 @@ private: base::Timer _nightThemeSwitch; base::unique_qptr _contextMenu; + std::unique_ptr _reorder; + int _reordering = 0; + base::binary_guard _accountSwitchGuard; QString _phoneText;