Added accounts list to tray menu on macOS.

Related commit: 57b22d2ad2.
This commit is contained in:
23rd
2026-02-28 09:44:31 +03:00
committed by John Preston
parent 7899e4943b
commit 7d310e56cc
7 changed files with 202 additions and 0 deletions
+13
View File
@@ -1814,10 +1814,23 @@ PRIVATE
settings.cpp settings.cpp
settings.h settings.h
stdafx.h stdafx.h
tray_accounts_menu.h
tray.cpp tray.cpp
tray.h tray.h
) )
if (APPLE)
nice_target_sources(Telegram ${src_loc}
PRIVATE
tray_accounts_menu.cpp
)
else()
nice_target_sources(Telegram ${src_loc}
PRIVATE
tray_accounts_menu_dummy.cpp
)
endif()
if (NOT build_winstore) if (NOT build_winstore)
remove_target_sources(Telegram ${src_loc} remove_target_sources(Telegram ${src_loc}
platform/win/windows_start_task.cpp platform/win/windows_start_task.cpp
@@ -12,6 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unique_qptr.h" #include "base/unique_qptr.h"
class QMenu; class QMenu;
class QIcon;
namespace Ui {
class DynamicImage;
} // namespace Ui
namespace Platform { namespace Platform {
@@ -38,6 +43,16 @@ public:
void destroyMenu(); void destroyMenu();
void addAction(rpl::producer<QString> text, Fn<void()> &&callback); void addAction(rpl::producer<QString> text, Fn<void()> &&callback);
void addAction(
rpl::producer<QString> text,
Fn<void()> &&callback,
const QIcon &icon);
void addAction(
rpl::producer<QString> text,
Fn<void()> &&callback,
std::shared_ptr<Ui::DynamicImage> icon,
int size);
void addSeparator();
void showTrayMessage() const; void showTrayMessage() const;
[[nodiscard]] bool hasTrayMessageSupport() const; [[nodiscard]] bool hasTrayMessageSupport() const;
@@ -13,9 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_controller.h" #include "window/window_controller.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/dynamic_image.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include <QtWidgets/QMenu> #include <QtWidgets/QMenu>
#include <QtGui/QIcon>
#import <AppKit/NSMenu.h> #import <AppKit/NSMenu.h>
#import <AppKit/NSStatusItem.h> #import <AppKit/NSStatusItem.h>
@@ -387,11 +389,19 @@ void Tray::destroyMenu() {
} }
void Tray::addAction(rpl::producer<QString> text, Fn<void()> &&callback) { void Tray::addAction(rpl::producer<QString> text, Fn<void()> &&callback) {
addAction(std::move(text), std::move(callback), QIcon());
}
void Tray::addAction(
rpl::producer<QString> text,
Fn<void()> &&callback,
const QIcon &icon) {
if (!_menu) { if (!_menu) {
return; return;
} }
const auto action = _menu->addAction(QString(), std::move(callback)); const auto action = _menu->addAction(QString(), std::move(callback));
action->setIcon(icon);
std::move( std::move(
text text
) | rpl::on_next([=](const QString &text) { ) | rpl::on_next([=](const QString &text) {
@@ -399,6 +409,43 @@ void Tray::addAction(rpl::producer<QString> text, Fn<void()> &&callback) {
}, _actionsLifetime); }, _actionsLifetime);
} }
void Tray::addAction(
rpl::producer<QString> text,
Fn<void()> &&callback,
std::shared_ptr<Ui::DynamicImage> icon,
int size) {
if (!_menu) {
return;
}
const auto action = _menu->addAction(QString(), std::move(callback));
if (icon) {
const auto updateIcon = crl::guard(action, [=] {
action->setIcon(QIcon(QPixmap::fromImage(icon->image(size))));
});
icon->subscribeToUpdates([=] {
Core::Sandbox::Instance().customEnterFromEventLoop([=] {
updateIcon();
});
});
updateIcon();
_actionsLifetime.add([icon = std::move(icon)] {
icon->subscribeToUpdates(nullptr);
});
}
std::move(
text
) | rpl::on_next([=](const QString &text) {
action->setText(text);
}, _actionsLifetime);
}
void Tray::addSeparator() {
if (_menu) {
_menu->addSeparator();
}
}
void Tray::showTrayMessage() const { void Tray::showTrayMessage() const {
} }
+7
View File
@@ -6,6 +6,7 @@ For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "tray.h" #include "tray.h"
#include "tray_accounts_menu.h"
#include "core/application.h" #include "core/application.h"
#include "core/core_settings.h" #include "core/core_settings.h"
@@ -51,6 +52,10 @@ void Tray::create() {
rebuildMenu(); rebuildMenu();
}, _tray.lifetime()); }, _tray.lifetime());
TrayAccountsMenu::SetupChangesSubscription(
[=] { rebuildMenu(); },
_tray.lifetime());
_tray.iconClicks( _tray.iconClicks(
) | rpl::on_next([=] { ) | rpl::on_next([=] {
const auto skipTrayClick = (_lastTrayClickTime > 0) const auto skipTrayClick = (_lastTrayClickTime > 0)
@@ -97,6 +102,8 @@ void Tray::rebuildMenu() {
_tray.addAction(tr::lng_quit_from_tray(), [] { Core::Quit(); }); _tray.addAction(tr::lng_quit_from_tray(), [] { Core::Quit(); });
TrayAccountsMenu::Fill(_tray);
updateMenuText(); updateMenuText();
} }
@@ -0,0 +1,81 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "tray_accounts_menu.h"
#include "base/weak_ptr.h"
#include "base/qt/qt_key_modifiers.h"
#include "core/application.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "info/profile/info_profile_values.h"
#include "main/main_account.h"
#include "main/main_domain.h"
#include "main/main_session.h"
#include "styles/style_window.h"
#include "ui/dynamic_thumbnails.h"
namespace Core::TrayAccountsMenu {
void SetupChangesSubscription(Fn<void()> callback, rpl::lifetime &lifetime) {
const auto accountSessionsLifetime = lifetime.make_state<rpl::lifetime>();
const auto watchAccountSessions = [=] {
accountSessionsLifetime->destroy();
for (const auto &[index, account] : Core::App().domain().accounts()) {
account->sessionChanges(
) | rpl::on_next([=](Main::Session*) {
callback();
}, *accountSessionsLifetime);
}
};
Core::App().domain().accountsChanges() | rpl::on_next([=] {
watchAccountSessions();
callback();
}, lifetime);
watchAccountSessions();
}
void Fill(Platform::Tray &tray) {
auto accounts = std::vector<not_null<Main::Account*>>();
for (const auto &account : Core::App().domain().orderedAccounts()) {
if (account->sessionExists()) {
accounts.push_back(account);
}
}
if (accounts.size() <= 1) {
return;
}
tray.addSeparator();
constexpr auto kMaxLength = 30;
for (const auto account : accounts) {
const auto user = account->session().user();
const auto weak = base::make_weak(account);
tray.addAction(
Info::Profile::NameValue(
user
) | rpl::map([=](const QString &name) {
return (name.size() > kMaxLength)
? (name.mid(0, kMaxLength) + Ui::kQEllipsis)
: name;
}),
[weak] {
const auto strong = weak.get();
if (!strong || !strong->sessionExists()) {
return;
}
if (base::IsCtrlPressed()) {
Core::App().ensureSeparateWindowFor({ strong });
} else {
Core::App().domain().maybeActivate(strong);
}
},
Ui::MakeUserpicThumbnail(user, true),
st::notifyMacPhotoSize);
}
}
} // namespace Core::TrayAccountsMenu
+19
View File
@@ -0,0 +1,19 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "platform/platform_tray.h"
namespace Core::TrayAccountsMenu {
void SetupChangesSubscription(
Fn<void()> callback,
rpl::lifetime &lifetime);
void Fill(Platform::Tray &tray);
} // namespace Core::TrayAccountsMenu
@@ -0,0 +1,20 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "tray_accounts_menu.h"
namespace Core::TrayAccountsMenu {
void SetupChangesSubscription(
[[maybe_unused]] Fn<void()> callback,
[[maybe_unused]] rpl::lifetime &lifetime) {
}
void Fill([[maybe_unused]] Platform::Tray &tray) {
}
} // namespace Core::TrayAccountsMenu