diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index d3fa27af19..836f4d786b 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_menu_update" = "Update"; "lng_menu_back" = "Back"; "lng_menu_night_mode" = "Night Mode"; +"lng_menu_add_account" = "Add Account"; "lng_disable_notifications_from_tray" = "Disable notifications"; "lng_enable_notifications_from_tray" = "Enable notifications"; diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index 9a4cbd243e..a7fea72c00 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -145,6 +145,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { qint32 dictionariesEnabledCount = 0; std::vector dictionariesEnabled; qint32 autoDownloadDictionaries = _autoDownloadDictionaries.current() ? 1 : 0; + qint32 mainMenuAccountsShown = _mainMenuAccountsShown.current() ? 1 : 0; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -203,7 +204,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) { } } stream - >> autoDownloadDictionaries; + >> autoDownloadDictionaries + >> mainMenuAccountsShown; } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " @@ -274,6 +276,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _videoPipGeometry = (videoPipGeometry); _dictionariesEnabled = std::move(dictionariesEnabled); _autoDownloadDictionaries = (autoDownloadDictionaries == 1); + _mainMenuAccountsShown = (mainMenuAccountsShown == 1); } bool Settings::chatWide() const { @@ -337,7 +340,7 @@ void Settings::resetOnLastLogout() { //_videoPipGeometry = QByteArray(); _dictionariesEnabled = std::vector(); _autoDownloadDictionaries = true; - + _mainMenuAccountsShown = false; } } // namespace Core diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index a1351280f6..7bfcc1d179 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -349,6 +349,15 @@ public: void setRememberedFlashBounceNotifyFromTray(bool value) { _rememberedFlashBounceNotifyFromTray = value; } + [[nodiscard]] bool mainMenuAccountsShown() const { + return _mainMenuAccountsShown.current(); + } + [[nodiscard]] rpl::producer mainMenuAccountsShownValue() const { + return _mainMenuAccountsShown.value(); + } + void setMainMenuAccountsShown(bool value) { + _mainMenuAccountsShown = value; + } [[nodiscard]] static qint32 SerializePlaybackSpeed(float64 speed) { return int(std::round(std::clamp(speed * 4., 2., 8.))) - 2; @@ -407,6 +416,7 @@ private: QByteArray _videoPipGeometry; rpl::variable> _dictionariesEnabled; rpl::variable _autoDownloadDictionaries = true; + rpl::variable _mainMenuAccountsShown = false; float64 _rememberedSongVolume = kDefaultVolume; bool _rememberedSoundNotifyFromTray = false; diff --git a/Telegram/SourceFiles/main/main_domain.cpp b/Telegram/SourceFiles/main/main_domain.cpp index 536a33164e..93796d3e80 100644 --- a/Telegram/SourceFiles/main/main_domain.cpp +++ b/Telegram/SourceFiles/main/main_domain.cpp @@ -100,6 +100,10 @@ const std::vector &Domain::accounts() const { return _accounts; } +rpl::producer<> Domain::accountsChanges() const { + return _accountsChanges.events(); +} + rpl::producer Domain::activeValue() const { return _active.value(); } @@ -176,6 +180,7 @@ void Domain::scheduleUpdateUnreadBadge() { not_null Domain::add(MTP::Environment environment) { Expects(started()); + Expects(_accounts.size() < kMaxAccounts); static const auto cloneConfig = [](const MTP::Config &config) { return std::make_unique(config); @@ -207,6 +212,7 @@ not_null Domain::add(MTP::Environment environment) { const auto account = _accounts.back().account.get(); _local->startAdded(account, std::move(config)); watchSession(account); + _accountsChanges.fire({}); return account; } @@ -280,6 +286,7 @@ void Domain::removeRedundantAccounts() { if (!removePasscodeIfEmpty() && _accounts.size() != was) { scheduleWriteAccounts(); + _accountsChanges.fire({}); } } diff --git a/Telegram/SourceFiles/main/main_domain.h b/Telegram/SourceFiles/main/main_domain.h index 96b9e681b0..aa7a9e0e4a 100644 --- a/Telegram/SourceFiles/main/main_domain.h +++ b/Telegram/SourceFiles/main/main_domain.h @@ -47,6 +47,7 @@ public: [[nodiscard]] auto accounts() const -> const std::vector &; [[nodiscard]] rpl::producer activeValue() const; + [[nodiscard]] rpl::producer<> accountsChanges() const; // Expects(started()); [[nodiscard]] Account &active() const; @@ -83,6 +84,7 @@ private: const std::unique_ptr _local; std::vector _accounts; + rpl::event_stream<> _accountsChanges; rpl::variable _active = nullptr; int _accountToActivate = -1; bool _writeAccountsScheduled = false; diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 8afbd5a7c2..f8082f6d6c 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -113,7 +113,7 @@ mainMenuResetScaleIconLeft: 5px; mainMenuCoverTextLeft: 30px; mainMenuCoverNameTop: 84px; mainMenuCoverStatusTop: 102px; -mainMenuSkip: 13px; +mainMenuSkip: 10px; mainMenu: Menu(defaultMenu) { itemFg: windowBoldFg; itemFgOver: windowBoldFgOver; @@ -145,6 +145,8 @@ mainMenuReload: icon {{ "menu_reload", menuIconFg }}; mainMenuReloadOver: icon {{ "menu_reload", menuIconFgOver }}; mainMenuFixOrder: icon {{ "menu_fix_order", menuIconFg }}; mainMenuFixOrderOver: icon {{ "menu_fix_order", menuIconFgOver }}; +mainMenuAddAccount: icon {{ "menu_fix_order", menuIconFg }}; +mainMenuAddAccountOver: icon {{ "menu_fix_order", menuIconFgOver }}; mainMenuFooterLeft: 30px; mainMenuTelegramLabel: FlatLabel(defaultFlatLabel) { align: align(left); diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 28c88eab9d..00ec473949 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -13,9 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/widgets/menu.h" #include "ui/widgets/popup_menu.h" +#include "ui/widgets/scroll_area.h" +#include "ui/widgets/shadow.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" #include "ui/text/text_utilities.h" #include "ui/special_buttons.h" #include "ui/empty_userpic.h" +#include "base/call_delayed.h" #include "mainwindow.h" #include "storage/localstorage.h" #include "storage/storage_account.h" @@ -27,8 +32,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_box_controller.h" #include "lang/lang_keys.h" #include "core/click_handler_types.h" +#include "core/core_settings.h" +#include "core/application.h" #include "main/main_session.h" #include "main/main_session_settings.h" +#include "main/main_account.h" +#include "main/main_domain.h" +#include "mtproto/mtp_instance.h" #include "mtproto/mtproto_config.h" #include "data/data_folder.h" #include "data/data_session.h" @@ -37,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "app.h" #include "styles/style_window.h" +#include "styles/style_widgets.h" #include "styles/style_dialogs.h" #include "styles/style_settings.h" #include "styles/style_boxes.h" @@ -70,7 +81,22 @@ bool IsShadowShown(const QImage &img, const QRect r, float64 intensityText) { namespace Window { -class MainMenu::ResetScaleButton : public Ui::AbstractButton { +class MainMenu::AccountButton final : public Ui::RippleButton { +public: + AccountButton(QWidget *parent, not_null account); + +private: + void paintEvent(QPaintEvent *e) override; + + const not_null _account; + const style::Menu &_st; + std::shared_ptr _userpicView; + int _unreadBadge = 0; + bool _unreadBadgeMuted = true; + +}; + +class MainMenu::ResetScaleButton final : public Ui::AbstractButton { public: ResetScaleButton(QWidget *parent); @@ -81,6 +107,61 @@ protected: }; +MainMenu::AccountButton::AccountButton( + QWidget *parent, + not_null account) +: RippleButton(parent, st::defaultRippleAnimation) +, _account(account) +, _st(st::mainMenu){ + const auto height = _st.itemPadding.top() + + _st.itemStyle.font->height + + _st.itemPadding.bottom(); + resize(width(), height); + + _account->sessionValue( + ) | rpl::filter([=](Main::Session *session) { + return (session != nullptr); + }) | rpl::start_with_next([=](not_null session) { + rpl::single( + rpl::empty_value() + ) | rpl::then( + session->data().unreadBadgeChanges() + ) | rpl::start_with_next([=] { + _unreadBadge = session->data().unreadBadge(); + _unreadBadgeMuted = session->data().unreadBadgeMuted(); + update(); + }, lifetime()); + }, lifetime()); +} + +void MainMenu::AccountButton::paintEvent(QPaintEvent *e) { + Expects(_account->sessionExists()); + + const auto &session = _account->session(); + + auto p = Painter(this); + const auto over = isOver(); + p.fillRect(rect(), over ? _st.itemBgOver : _st.itemBg); + paintRipple(p, 0, 0); + + const auto available = width() - 2 * _st.itemPadding.left(); + + session.user()->paintUserpicLeft( + p, + _userpicView, + _st.itemIconPosition.x(), + _st.itemIconPosition.y(), + width(), + height() - 2 * _st.itemIconPosition.y()); + + p.setPen(over ? _st.itemFgOver : _st.itemFg); + session.user()->nameText().drawElided( + p, + _st.itemPadding.left(), + _st.itemPadding.top(), + available); +} + MainMenu::ResetScaleButton::ResetScaleButton(QWidget *parent) : AbstractButton(parent) { const auto margin = st::mainMenuCloudButton.height @@ -130,63 +211,38 @@ MainMenu::MainMenu( not_null controller) : LayerWidget(parent) , _controller(controller) -, _menu(this, st::mainMenu) -, _telegram(this, st::mainMenuTelegramLabel) -, _version(this, st::mainMenuVersionLabel) { +, _userpicButton( + this, + _controller, + _controller->session().user(), + Ui::UserpicButton::Role::Custom, + st::mainMenuUserpic) +, _toggleAccounts(this) +, _archiveButton(this, st::mainMenuCloudButton) +, _scroll(this, st::defaultSolidScroll) +, _inner(_scroll->setOwnedWidget( + object_ptr(_scroll.data()))) +, _accounts(_inner->add(object_ptr>( + _inner.get(), + object_ptr(_inner.get())))) +, _shadow(_inner->add(object_ptr>( + _inner.get(), + object_ptr(_inner.get())))) +, _menu(_inner->add( + object_ptr(_inner.get(), st::mainMenu), + { 0, st::mainMenuSkip, 0, 0 })) +, _footer(_inner->add(object_ptr(_inner.get()))) +, _telegram( + Ui::CreateChild(_footer.get(), st::mainMenuTelegramLabel)) +, _version( + Ui::CreateChild( + _footer.get(), + st::mainMenuVersionLabel)) { setAttribute(Qt::WA_OpaquePaintEvent); - const auto showSelfChat = [=] { - controller->content()->choosePeer( - _controller->session().userPeerId(), - ShowAtUnreadMsgId); - }; - const auto showArchive = [=] { - const auto folder = _controller->session().data().folderLoaded( - Data::Folder::kId); - if (folder) { - controller->openFolder(folder); - Ui::hideSettingsAndLayer(); - } - }; - const auto checkArchive = [=] { - const auto folder = _controller->session().data().folderLoaded( - Data::Folder::kId); - return folder - && !folder->chatsList()->empty() - && _controller->session().settings().archiveInMainMenu(); - }; - _userpicButton.create( - this, - _controller, - _controller->session().user(), - Ui::UserpicButton::Role::Custom, - st::mainMenuUserpic); - _userpicButton->setClickedCallback(showSelfChat); - _userpicButton->show(); - _cloudButton.create(this, st::mainMenuCloudButton); - _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(this); - _contextMenu->addAction( - tr::lng_context_archive_to_list(tr::now), [=] { - _controller->session().settings().setArchiveInMainMenu(false); - _controller->session().saveSettingsDelayed(); - Ui::hideSettingsAndLayer(); - }); - _contextMenu->popup(QCursor::pos()); - }, _archiveButton->lifetime()); + setupArchiveButton(); + setupUserpicButton(); + setupAccounts(); _nightThemeSwitch.setCallback([this] { if (const auto action = *_nightThemeAction) { @@ -198,6 +254,19 @@ MainMenu::MainMenu( } }); + _footer->heightValue( + ) | rpl::start_with_next([=] { + _telegram->moveToLeft(st::mainMenuFooterLeft, _footer->height() - st::mainMenuTelegramBottom - _telegram->height()); + _version->moveToLeft(st::mainMenuFooterLeft, _footer->height() - st::mainMenuVersionBottom - _version->height()); + }, _footer->lifetime()); + + rpl::combine( + heightValue(), + _inner->heightValue() + ) | rpl::start_with_next([=] { + updateInnerControlsGeometry(); + }, _inner->lifetime()); + parentResized(); _menu->setTriggeredCallback([](QAction *action, int actionTop, Ui::Menu::TriggeredSource source) { emit action->triggered(); @@ -235,15 +304,219 @@ MainMenu::MainMenu( refreshBackground(); } }); + updatePhone(); + initResetScaleButton(); +} + +void MainMenu::setupArchiveButton() { + const auto showArchive = [=] { + const auto folder = _controller->session().data().folderLoaded( + Data::Folder::kId); + if (folder) { + _controller->openFolder(folder); + Ui::hideSettingsAndLayer(); + } + }; + const auto checkArchive = [=] { + const auto folder = _controller->session().data().folderLoaded( + Data::Folder::kId); + return folder + && !folder->chatsList()->empty() + && _controller->session().settings().archiveInMainMenu(); + }; + _archiveButton->setVisible(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(this); + _contextMenu->addAction( + tr::lng_context_archive_to_list(tr::now), [=] { + _controller->session().settings().setArchiveInMainMenu(false); + _controller->session().saveSettingsDelayed(); + Ui::hideSettingsAndLayer(); + }); + _contextMenu->popup(QCursor::pos()); + }, _archiveButton->lifetime()); + _controller->session().data().chatsListChanges( ) | rpl::filter([](Data::Folder *folder) { return folder && (folder->id() == Data::Folder::kId); }) | rpl::start_with_next([=](Data::Folder *folder) { - _archiveButton->setHidden(!checkArchive()); + _archiveButton->setVisible(checkArchive()); update(); }, lifetime()); - updatePhone(); - initResetScaleButton(); +} + +void MainMenu::setupUserpicButton() { + _userpicButton->setClickedCallback([=] { + _controller->content()->choosePeer( + _controller->session().userPeerId(), + ShowAtUnreadMsgId); + }); + _userpicButton->show(); +} + +void MainMenu::setupAccounts() { + const auto inner = _accounts->entity(); + + inner->add(object_ptr(inner, st::mainMenuSkip)); + _addAccount = setupAddAccount(inner); + inner->add(object_ptr(inner, st::mainMenuSkip)); + + rpl::single( + rpl::empty_value() + ) | rpl::then(Core::App().domain().accountsChanges( + )) | rpl::start_with_next([=] { + const auto &list = Core::App().domain().accounts(); + const auto exists = [&](not_null account) { + for (const auto &[index, existing] : list) { + if (account == existing.get()) { + return true; + } + } + return false; + }; + for (auto i = _watched.begin(); i != _watched.end();) { + if (!exists(i->first)) { + i = _watched.erase(i); + } else { + ++i; + } + } + for (const auto &[index, account] : list) { + if (_watched.emplace(account.get()).second) { + account->sessionChanges( + ) | rpl::start_with_next([=](Main::Session *session) { + rebuildAccounts(); + }, lifetime()); + } + } + rebuildAccounts(); + }, lifetime()); + + _accounts->toggleOn(Core::App().settings().mainMenuAccountsShownValue()); + _accounts->finishAnimating(); + + _shadow->setDuration(0)->toggleOn(_accounts->shownValue()); + + _toggleAccounts->show(); + _toggleAccounts->setClickedCallback([=] { + auto &settings = Core::App().settings(); + const auto shown = !settings.mainMenuAccountsShown(); + settings.setMainMenuAccountsShown(shown); + }); +} + +void MainMenu::rebuildAccounts() { + const auto inner = _accounts->entity(); + + auto count = 0; + for (auto &[account, button] : _watched) { + if (!account->sessionExists()) { + button = nullptr; + } else if (!button) { + button.reset(inner->insert( + ++count, + object_ptr(inner, account))); + button->setClickedCallback([=] { + auto activate = [=, guard = _accountSwitchGuard.make_guard()]{ + if (guard) { + Core::App().domain().activate(account); + } + }; + base::call_delayed( + st::defaultRippleAnimation.hideDuration, + account, + std::move(activate)); + }); + } else { + ++count; + } + } + inner->resizeToWidth(_accounts->width()); + + _addAccount->toggle( + (count < Main::Domain::kMaxAccounts), + anim::type::instant); +} + +not_null*> MainMenu::setupAddAccount( + not_null container) { + const auto result = container->add( + object_ptr>( + container.get(), + object_ptr( + container.get(), + st::defaultRippleAnimation)))->setDuration(0); + const auto st = &st::mainMenu; + const auto height = st->itemPadding.top() + + st->itemStyle.font->height + + st->itemPadding.bottom(); + const auto button = result->entity(); + button->resize(button->width(), height); + + button->paintRequest( + ) | rpl::start_with_next([=] { + auto p = Painter(button); + const auto over = button->isOver(); + p.fillRect(button->rect(), over ? st->itemBgOver : st->itemBg); + button->paintRipple(p, 0, 0); + const auto &icon = over + ? st::mainMenuAddAccountOver + : st::mainMenuAddAccount; + icon.paint(p, st->itemIconPosition, width()); + p.setPen(over ? st->itemFgOver : st->itemFg); + p.setFont(st->itemStyle.font); + p.drawTextLeft( + st->itemPadding.left(), + st->itemPadding.top(), + width(), + tr::lng_menu_add_account(tr::now)); + }, button->lifetime()); + + const auto add = [=](MTP::Environment environment) { + auto &domain = Core::App().domain(); + if (domain.accounts().size() < Main::Domain::kMaxAccounts) { + domain.activate(domain.add(environment)); + } else { + for (auto &[index, account] : domain.accounts()) { + if (!account->sessionExists() + && account->mtp().environment() == environment) { + domain.activate(account.get()); + break; + } + } + } + }; + + button->setAcceptBoth(true); + button->clicks( + ) | rpl::start_with_next([=](Qt::MouseButton which) { + if (which == Qt::LeftButton) { + add(MTP::Environment::Production); + return; + } else if (which != Qt::RightButton + || !(button->clickModifiers() & Qt::ShiftModifier) + || !(button->clickModifiers() & Qt::AltModifier)) { + return; + } + _contextMenu = base::make_unique_q(this); + _contextMenu->addAction("Production Server", [=] { + add(MTP::Environment::Production); + }); + _contextMenu->addAction("Test Server", [=] { + add(MTP::Environment::Test); + }); + _contextMenu->popup(QCursor::pos()); + }, _archiveButton->lifetime()); + + return result; } void MainMenu::parentResized() { @@ -374,31 +647,41 @@ void MainMenu::refreshBackground() { void MainMenu::resizeEvent(QResizeEvent *e) { _menu->setForceWidth(width()); + _inner->resizeToWidth(width()); updateControlsGeometry(); } void MainMenu::updateControlsGeometry() { - if (_userpicButton) { - _userpicButton->moveToLeft(st::mainMenuUserpicLeft, st::mainMenuUserpicTop); - } - if (_cloudButton) { - 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()); - } - } + _userpicButton->moveToLeft(st::mainMenuUserpicLeft, st::mainMenuUserpicTop); if (_resetScaleButton) { _resetScaleButton->moveToRight(0, 0); + _archiveButton->moveToRight(_resetScaleButton->width(), 0); + } else { + const auto offset = st::mainMenuCloudSize / 4; + _archiveButton->moveToRight(offset, offset); + } + _toggleAccounts->setGeometry( + 0, + st::mainMenuCoverNameTop, + width(), + st::mainMenuCoverHeight - st::mainMenuCoverNameTop); + const auto top = st::mainMenuCoverHeight; + _scroll->setGeometry(0, top, width(), height() - top); + updateInnerControlsGeometry(); +} + +void MainMenu::updateInnerControlsGeometry() { + const auto contentHeight = _accounts->height() + + _shadow->height() + + st::mainMenuSkip + + _menu->height(); + const auto available = height() - st::mainMenuCoverHeight - contentHeight; + const auto footerHeight = std::max( + available, + st::mainMenuTelegramBottom + _telegram->height() + st::mainMenuSkip); + if (_footer->height() != footerHeight) { + _footer->resize(_footer->width(), footerHeight); } - _menu->moveToLeft(0, st::mainMenuCoverHeight + st::mainMenuSkip); - _telegram->moveToLeft(st::mainMenuFooterLeft, height() - st::mainMenuTelegramBottom - _telegram->height()); - _version->moveToLeft(st::mainMenuFooterLeft, height() - st::mainMenuVersionBottom - _version->height()); } void MainMenu::updatePhone() { @@ -425,9 +708,7 @@ void MainMenu::paintEvent(QPaintEvent *e) { } if (!cover.isEmpty()) { - const auto widthText = _cloudButton - ? _cloudButton->x() - st::mainMenuCloudSize - : width() - 2 * st::mainMenuCoverTextLeft; + const auto widthText = width() - 2 * st::mainMenuCoverTextLeft; if (isFill) { p.fillRect(cover, st::mainMenuCoverBg); @@ -442,16 +723,6 @@ void MainMenu::paintEvent(QPaintEvent *e) { width()); p.setFont(st::normalFont); p.drawTextLeft(st::mainMenuCoverTextLeft, st::mainMenuCoverStatusTop, width(), _phoneText); - if (_cloudButton) { - Ui::EmptyUserpic::PaintSavedMessages( - p, - _cloudButton->x() + (_cloudButton->width() - st::mainMenuCloudSize) / 2, - _cloudButton->y() + (_cloudButton->height() - st::mainMenuCloudSize) / 2, - width(), - st::mainMenuCloudSize, - isFill ? st::mainMenuCloudBg : st::msgServiceBg, - isFill ? st::mainMenuCloudFg : st::msgServiceFg); - } // Draw Archive button. if (!_archiveButton->isHidden()) { diff --git a/Telegram/SourceFiles/window/window_main_menu.h b/Telegram/SourceFiles/window/window_main_menu.h index cd6406ed7a..bac4e18578 100644 --- a/Telegram/SourceFiles/window/window_main_menu.h +++ b/Telegram/SourceFiles/window/window_main_menu.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" #include "base/object_ptr.h" +#include "base/binary_guard.h" #include "ui/rp_widget.h" #include "ui/layers/layer_widget.h" @@ -18,8 +19,19 @@ class FlatLabel; class Menu; class UserpicButton; class PopupMenu; +class AbstractButton; +class ScrollArea; +class VerticalLayout; +class RippleButton; +class PlainShadow; +template +class SlideWrap; } // namespace Ui +namespace Main { +class Account; +} // namespace Main + namespace Window { class SessionController; @@ -39,25 +51,45 @@ protected: } private: + class AccountButton; + class ResetScaleButton; + + void setupArchiveButton(); + void setupUserpicButton(); + void setupAccounts(); + [[nodiscard]] not_null*> setupAddAccount( + not_null container); + void rebuildAccounts(); void updateControlsGeometry(); + void updateInnerControlsGeometry(); void updatePhone(); void initResetScaleButton(); void refreshMenu(); void refreshBackground(); - class ResetScaleButton; - not_null _controller; - object_ptr _userpicButton = { nullptr }; - object_ptr _cloudButton = { nullptr }; - object_ptr _archiveButton = { nullptr }; + const not_null _controller; + object_ptr _userpicButton; + object_ptr _toggleAccounts; + object_ptr _archiveButton; object_ptr _resetScaleButton = { nullptr }; - object_ptr _menu; - object_ptr _telegram; - object_ptr _version; + object_ptr _scroll; + not_null _inner; + base::flat_map< + not_null, + base::unique_qptr> _watched; + not_null*> _accounts; + Ui::SlideWrap *_addAccount = nullptr; + not_null*> _shadow; + not_null _menu; + not_null _footer; + not_null _telegram; + not_null _version; std::shared_ptr> _nightThemeAction; base::Timer _nightThemeSwitch; base::unique_qptr _contextMenu; + base::binary_guard _accountSwitchGuard; + QString _phoneText; QImage _background; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 4e6763d176..d31d94e8fb 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 4e6763d1769e6305a3da158e1a332ccd6a30398a +Subproject commit d31d94e8fb47b8492fbf341b93c19ddfbcb42fa2