From e61b1dfa115823de8289479e6a561a3c4fce2730 Mon Sep 17 00:00:00 2001 From: dranik Date: Fri, 5 Jun 2026 09:00:14 +0300 Subject: [PATCH] update icons --- client/images/images.qrc | 9 +-- client/images/tray/active.png | Bin 2677 -> 0 bytes client/images/tray/default.png | Bin 2466 -> 0 bytes client/images/tray/error.png | Bin 2462 -> 0 bytes client/images/tray/error.svg | 3 + client/images/tray/icon.svg | 3 - client/images/tray/off-black.svg | 10 +++ client/images/tray/off-light.svg | 3 + client/images/tray/on-black.svg | 11 +++ client/images/tray/on-white.svg | 11 +++ .../platforms/linux/linuxtrayiconbackend.cpp | 11 ++- client/platforms/linux/linuxtrayiconbackend.h | 2 +- client/platforms/macos/macosstatusicon.h | 1 - client/platforms/macos/macosstatusicon.mm | 57 ++------------- client/platforms/macos/mactrayiconbackend.mm | 4 +- client/platforms/windows/wintrayicon.cpp | 11 ++- client/platforms/windows/wintrayicon.h | 2 +- client/ui/utils/trayIconCommon.cpp | 66 ++++-------------- client/ui/utils/trayIconCommon.h | 24 +++---- 19 files changed, 83 insertions(+), 145 deletions(-) delete mode 100644 client/images/tray/active.png delete mode 100644 client/images/tray/default.png delete mode 100644 client/images/tray/error.png create mode 100644 client/images/tray/error.svg delete mode 100644 client/images/tray/icon.svg create mode 100644 client/images/tray/off-black.svg create mode 100644 client/images/tray/off-light.svg create mode 100644 client/images/tray/on-black.svg create mode 100644 client/images/tray/on-white.svg diff --git a/client/images/images.qrc b/client/images/images.qrc index 51574688d..c00cebd59 100644 --- a/client/images/images.qrc +++ b/client/images/images.qrc @@ -65,10 +65,11 @@ controls/text-cursor.svg controls/trash.svg controls/x-circle.svg - tray/active.png - tray/default.png - tray/error.png - tray/icon.svg + tray/off-black.svg + tray/off-light.svg + tray/on-black.svg + tray/on-white.svg + tray/error.svg controls/monitor.svg diff --git a/client/images/tray/active.png b/client/images/tray/active.png deleted file mode 100644 index 7ceac4b4ec1ed837fe4db8d9c123e773b3923da8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2677 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 diff --git a/client/images/tray/error.png b/client/images/tray/error.png deleted file mode 100644 index a24a32df9c6b63494e70cdb011a6e4b64cbb2137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2462 zcmV;P31Rk$P) zL2lbj425;393YD#OBY@D5QUd*Hr{pBBLzs%0s(w0|BF8R@O=Qc7Wv3$ z$?|BlECR-9Sx)DH&PfOwWDp^)uz$Jx#~d<=5N}*FhYTXbB7+FA%9=rB5>Xx*M2Hn+ z5Fu8OL4;W0mO*3^Q5qRUh!tcIAy(L85Sc`j8mj9twp_LJN8r6fy}l=s{4(B($IhKp~URf^NJ*CZPr0aD@y*i*D)86X;n=&!yKP zqnpYWmvlqtv^Bo{`Y4n1^8N_ym!BVgi->M0W2|Y2&TS-jaRYSot~Jr>^CAcB>+2`D zjxvWK48Jq3<;G;To?%1lDuWon+BoaaMh=?{k{H&ejePdCEp#mM?p<#F?bk=BNq%UV zd^?QBu*mJ&XEMC#6KRss+{?k*9M9vh44F(qPGmz`@4xEjRw=?HYnrmn%@F&SyXnn=GDu{TQ6^!Y856P;I+Dkq&#^=w-=g*{Fs!;B z4Z1%kJ)cdm&J~?Y@3AA_Er=d)bdSu*QtarTWL9~gkMEhIjB$Z11+(OYKE8LJkwL$V zC5t&mbG6K4z$EvK7ym8(ThB`IR@vve=5po~u`0Bj3ahGeO#Fv#E=`>1TqIu0QMY57I}`|*gzWqJsU1$6CgvLk@>ORnUXm!M3#kj8FD-= zw^y%bFhzQEEQ_5%vgDg3&zT}hb93I`?U6}a})kWGLrxuS=1G|o4%$e_77+00>) zbA}udajT}0XZ|BJccGd=F1^Ry66Egc-o0bXCxmQ8vFu!O&f&O&5BruFxtmnZAQ=l{ z%NITHk#%Ru(~OJ-G31IKc2s{d783qlVcb42VwSjHU7lFuNX8)#>b$ESyoUdSK~G4g^HN`ULStD}~qH=E{TVdz{WRDEnE1_qoiEPE82QWiq>qA7o-DD~d zJ$P9nTQ4H=?ZTqCtf%zo*gxOj)XHkho=p9S$hDg+1)_(0YgjIyA2p*@9v=D0AVm3j zhG*@g^)u%tgAnB95s2M5nEGOoR~mCH3ty3F128tSH)rq7D6;Fi36>(!24HUGKLo0K%!=OW%o}dR;=4gjO zk1~Bh53kJ84ud9TdV?NdnWG&BUCQ(aJ;X9cJ7|3}JrX?3m!BWt!)zV&3*Zbu4ri$^ zG4wEd1X|MwMl~8)wOpo8=s}h_`ax<{qF0QAJo=f4XT_1oAWk3*vE`ILt>8`|hSYK< zJTw`G(HIuFRrq0k2^qwYXmdp7=A{`skzZgI$D{2TvpGidt9tf$C#qNI8F7Q%9HTi} z>y-@|q!X)uJiQAa*;$2o7m`T4d-nMBFqb(H#^^0Pwa_GZ_l;pr%s`n#2EpRlJM@g0 zfiy?204aqgWOR?SYoBX58?Zlf(WdAf+(;u;tK?@x#0?sPcrPS(4ud*|=1ZDvN#BJaNwqUXUB&jh1(d`~5KGAxHXojJA$ z;Qjeq;?^CDbfPB$Z3=jw&J*!ikK`>-O5qbx)*Q?7|7B3baV&(olxu47lTg+ik$8!w z2E>3cN4fQJ$ZsNKnBT!`T+uEkjJM7HKhTW1BlKd{HPCLWDs7|2NGlwKD_lWx1?kgnS_HV?W^x- z*@aAkMY<rFO#;_K_D>2-Do-Nf0`P{<&zSP6|Dh8bf2a`%tcBe&x1r==j4A~P(r z$P`vRl0h8t5LrgC)ie5d;*DD?PA!gs9!Q2j>S%H7vP6oD9@6OWTw5lC1c4A2J-FWC zq1ibtm#`7}Obd&!=%LPFiV@8a`Aq?{sK_VsG7Md&T+@m~=GLpRS&>1Ukf3w0$@~|Vu!tMTAoHNJh%sx|?daS@J2Hqd z5^_Fd5JRqssHf0!BZC+r5$EK`%CjTr+)^>qZBFqw*B-D!=amWxI6vy|01~eT>TxIf cQ7%yY2MSST3T(??rvLx|07*qoM6N<$f-I+fvj6}9 diff --git a/client/images/tray/error.svg b/client/images/tray/error.svg new file mode 100644 index 000000000..ffa1e7dd4 --- /dev/null +++ b/client/images/tray/error.svg @@ -0,0 +1,3 @@ + + + diff --git a/client/images/tray/icon.svg b/client/images/tray/icon.svg deleted file mode 100644 index c96c97d98..000000000 --- a/client/images/tray/icon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/images/tray/off-black.svg b/client/images/tray/off-black.svg new file mode 100644 index 000000000..fe9cfbb33 --- /dev/null +++ b/client/images/tray/off-black.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/client/images/tray/off-light.svg b/client/images/tray/off-light.svg new file mode 100644 index 000000000..7aa8194ef --- /dev/null +++ b/client/images/tray/off-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/client/images/tray/on-black.svg b/client/images/tray/on-black.svg new file mode 100644 index 000000000..f84defbe9 --- /dev/null +++ b/client/images/tray/on-black.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/client/images/tray/on-white.svg b/client/images/tray/on-white.svg new file mode 100644 index 000000000..79d876650 --- /dev/null +++ b/client/images/tray/on-white.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/client/platforms/linux/linuxtrayiconbackend.cpp b/client/platforms/linux/linuxtrayiconbackend.cpp index 7bf326d02..ec9e3b104 100644 --- a/client/platforms/linux/linuxtrayiconbackend.cpp +++ b/client/platforms/linux/linuxtrayiconbackend.cpp @@ -32,9 +32,7 @@ void LinuxTrayIconBackend::show() void LinuxTrayIconBackend::applyVisual(const TrayIconVisual &visual) { - const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState); - const QColor indicatorColor = TrayIconCommon::indicatorColorForState(visual.connectionState); - const QIcon icon = buildTrayIcon(opacity, visual.darkTheme, indicatorColor); + const QIcon icon = buildTrayIcon(visual.connectionState, visual.darkTheme); // Some tray implementations cache the first icon; clear before applying an update. if (m_trayIcon.isVisible()) { @@ -47,8 +45,7 @@ void LinuxTrayIconBackend::showMessage(const QString &title, const QString &mess int timerMsec) { m_trayIcon.showMessage(title, message, - buildTrayIcon(TrayIconCommon::kConnectedOpacity, visual.darkTheme, - TrayIconCommon::indicatorColorForState(Vpn::ConnectionState::Connected)), + buildTrayIcon(Vpn::ConnectionState::Connected, visual.darkTheme), timerMsec); } @@ -66,11 +63,11 @@ void LinuxTrayIconBackend::setActivatedHandler(std::function handler) override; private: - QIcon buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const; + QIcon buildTrayIcon(Vpn::ConnectionState state, bool darkTheme) const; QSystemTrayIcon m_trayIcon; }; diff --git a/client/platforms/macos/macosstatusicon.h b/client/platforms/macos/macosstatusicon.h index e67c3d98b..d77dda037 100644 --- a/client/platforms/macos/macosstatusicon.h +++ b/client/platforms/macos/macosstatusicon.h @@ -23,7 +23,6 @@ class MacOSStatusIcon final : public QObject { public: void setIcon(const QString& iconUrl); void setIconFromData(const QByteArray& imageData); - void setIndicatorColor(const QColor& indicatorColor); void setMenu(QMenu* menu); void rebuildNativeMenu(); void setToolTip(const QString& tooltip); diff --git a/client/platforms/macos/macosstatusicon.mm b/client/platforms/macos/macosstatusicon.mm index 0edb13b44..483db3c7a 100644 --- a/client/platforms/macos/macosstatusicon.mm +++ b/client/platforms/macos/macosstatusicon.mm @@ -29,21 +29,17 @@ @end /** - * Creates a NSStatusItem with that can hold an icon. Additionally a NSView is - * set as a subview to the button item of the status item. The view serves as - * an indicator that can be displayed in color eventhough the icon is set as a - * template. In that way we give the system control over it’s effective - * appearance. + * Creates a NSStatusItem that holds the tray icon. The icon is set as a + * template image, so the system controls its effective appearance for the + * current menu bar theme. The connection status is baked into the artwork, so + * no separate colored indicator is drawn. */ @interface MacOSStatusIconDelegate : NSObject @property(assign) NSStatusItem* statusItem; -@property(assign) NSView* statusIndicator; @property(retain) NSMenu* nativeMenu; @property(retain) NSMutableArray* menuActionTargets; - (void)setIcon:(NSData*)imageData; -- (void)setIndicator; -- (void)setIndicatorColor:(NSColor*)color; - (void)setToolTip:(NSString*)tooltip; - (void)rebuildMenuFromQMenu:(QMenu*)menu; @end @@ -62,8 +58,6 @@ self.statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain]; self.statusItem.visible = true; - // Add the indicator as a subview - [self setIndicator]; return self; } @@ -87,34 +81,6 @@ [image release]; } -/** - * Adds status indicator as a subview to the status item button. - */ -- (void)setIndicator { - float viewHeight = NSHeight([self.statusItem.button bounds]); - float dotSize = viewHeight * 0.35; - float dotOrigin = (viewHeight - dotSize) * 0.8; - - NSView* dot = [[NSView alloc] initWithFrame:NSMakeRect(dotOrigin, dotOrigin, dotSize, dotSize)]; - self.statusIndicator = dot; - self.statusIndicator.wantsLayer = true; - self.statusIndicator.layer.cornerRadius = dotSize * 0.5; - - [self.statusItem.button addSubview:self.statusIndicator]; - [dot release]; -} - -/** - * Sets the color if the indicator. - * - * @param color The indicator background color. - */ -- (void)setIndicatorColor:(NSColor*)color { - if (self.statusIndicator) { - self.statusIndicator.layer.backgroundColor = color.CGColor; - } -} - /** * Sets the status bar menu to the status item. * @@ -217,21 +183,6 @@ void MacOSStatusIcon::setIconFromData(const QByteArray& imageData) { [m_statusBarIcon setIcon:data]; } -void MacOSStatusIcon::setIndicatorColor(const QColor& indicatorColor) { - logger.debug() << "Set indicator color"; - - if (!indicatorColor.isValid()) { - [m_statusBarIcon setIndicatorColor:[NSColor clearColor]]; - return; - } - - NSColor* color = [NSColor colorWithCalibratedRed:indicatorColor.red() / 255.0f - green:indicatorColor.green() / 255.0f - blue:indicatorColor.blue() / 255.0f - alpha:indicatorColor.alpha() / 255.0f]; - [m_statusBarIcon setIndicatorColor:color]; -} - void MacOSStatusIcon::setMenu(QMenu* menu) { m_qtMenu = menu; rebuildNativeMenu(); diff --git a/client/platforms/macos/mactrayiconbackend.mm b/client/platforms/macos/mactrayiconbackend.mm index 17d5b23d4..6a8e8663a 100644 --- a/client/platforms/macos/mactrayiconbackend.mm +++ b/client/platforms/macos/mactrayiconbackend.mm @@ -23,9 +23,7 @@ void MacTrayIconBackend::show() void MacTrayIconBackend::applyVisual(const TrayIconVisual &visual) { - const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState); - m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(opacity)); - m_statusIcon.setIndicatorColor(TrayIconCommon::indicatorColorForState(visual.connectionState)); + m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(visual.connectionState)); } void MacTrayIconBackend::showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec) diff --git a/client/platforms/windows/wintrayicon.cpp b/client/platforms/windows/wintrayicon.cpp index 1e1121aec..0562d7bb9 100644 --- a/client/platforms/windows/wintrayicon.cpp +++ b/client/platforms/windows/wintrayicon.cpp @@ -6,22 +6,19 @@ namespace WinTrayIcon { -QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) +QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme) { - return TrayIconCommon::buildIcon(opacity, darkTheme, indicatorColor); + return TrayIconCommon::buildIcon(state, darkTheme); } void applyTo(QSystemTrayIcon &trayIcon, Vpn::ConnectionState state, bool darkTheme) { - const qreal opacity = TrayIconCommon::opacityForState(state); - const QColor indicatorColor = TrayIconCommon::indicatorColorForState(state); - trayIcon.setIcon(buildIcon(opacity, darkTheme, indicatorColor)); + trayIcon.setIcon(buildIcon(state, darkTheme)); } QIcon buildNotifyIcon(bool darkTheme) { - return buildIcon(TrayIconCommon::kConnectedOpacity, darkTheme, - TrayIconCommon::indicatorColorForState(Vpn::ConnectionState::Connected)); + return buildIcon(Vpn::ConnectionState::Connected, darkTheme); } void configure(QSystemTrayIcon &trayIcon, QMenu *menu, const QString &tooltip) diff --git a/client/platforms/windows/wintrayicon.h b/client/platforms/windows/wintrayicon.h index 5d734025c..39225149e 100644 --- a/client/platforms/windows/wintrayicon.h +++ b/client/platforms/windows/wintrayicon.h @@ -12,7 +12,7 @@ class QString; namespace WinTrayIcon { -QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor); +QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme); void applyTo(QSystemTrayIcon &trayIcon, Vpn::ConnectionState state, bool darkTheme); QIcon buildNotifyIcon(bool darkTheme); diff --git a/client/ui/utils/trayIconCommon.cpp b/client/ui/utils/trayIconCommon.cpp index 91458a36c..2ab098855 100644 --- a/client/ui/utils/trayIconCommon.cpp +++ b/client/ui/utils/trayIconCommon.cpp @@ -7,93 +7,55 @@ namespace TrayIconCommon { -qreal opacityForState(Vpn::ConnectionState state) +QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme) { switch (state) { + case Vpn::ConnectionState::Error: + return QString::fromLatin1(kIconError); case Vpn::ConnectionState::Connected: - case Vpn::ConnectionState::Error: return kConnectedOpacity; + return QString::fromLatin1(darkTheme ? kIconOnWhite : kIconOnBlack); case Vpn::ConnectionState::Disconnected: case Vpn::ConnectionState::Preparing: case Vpn::ConnectionState::Connecting: case Vpn::ConnectionState::Disconnecting: case Vpn::ConnectionState::Reconnecting: case Vpn::ConnectionState::Unknown: - default: return kDisconnectedOpacity; + default: + return QString::fromLatin1(darkTheme ? kIconOffLight : kIconOffBlack); } } -QColor indicatorColorForState(Vpn::ConnectionState state) -{ - switch (state) { - case Vpn::ConnectionState::Connected: return QColor(52, 199, 89); - case Vpn::ConnectionState::Error: return QColor(235, 87, 87); - default: return QColor(); - } -} - -QPixmap renderTemplate(const QString &resourcePath, qreal opacity, int size) +QPixmap renderIcon(const QString &resourcePath, int size) { QSvgRenderer renderer(resourcePath); QPixmap pixmap(size, size); pixmap.fill(Qt::transparent); if (!renderer.isValid()) { - qWarning() << "Failed to load tray icon template:" << resourcePath; + qWarning() << "Failed to load tray icon:" << resourcePath; return pixmap; } QPainter painter(&pixmap); - painter.setOpacity(opacity); renderer.render(&painter, QRectF(0, 0, size, size)); return pixmap; } -QPixmap colorizeTemplate(const QPixmap &mask, const QColor &foreground, int size) +QPixmap buildPixmap(int size, Vpn::ConnectionState state, bool darkTheme) { - QPixmap result(size, size); - result.fill(Qt::transparent); - - QPainter painter(&result); - painter.fillRect(result.rect(), foreground); - painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); - painter.drawPixmap(0, 0, mask); - return result; + return renderIcon(resourcePathForState(state, darkTheme), size); } -void drawStatusIndicator(QPainter &painter, const QColor &color, int size) -{ - const qreal dotSize = size * 0.35; - const qreal dotOrigin = (size - dotSize) * 0.8; - - painter.setPen(Qt::NoPen); - painter.setBrush(color); - painter.drawEllipse(QRectF(dotOrigin, dotOrigin, dotSize, dotSize)); -} - -QPixmap buildPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor) -{ - const QPixmap mask = renderTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, size); - const QColor foreground = darkTheme ? Qt::white : Qt::black; - QPixmap pixmap = colorizeTemplate(mask, foreground, size); - - if (indicatorColor.isValid()) { - QPainter painter(&pixmap); - drawStatusIndicator(painter, indicatorColor, size); - } - - return pixmap; -} - -QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) +QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme) { QIcon icon; - icon.addPixmap(buildPixmap(kDefaultTrayIconSize, opacity, darkTheme, indicatorColor)); + icon.addPixmap(buildPixmap(kDefaultTrayIconSize, state, darkTheme)); return icon; } -QByteArray buildTemplatePng(qreal opacity) +QByteArray buildTemplatePng(Vpn::ConnectionState state) { - const QPixmap pixmap = renderTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, kDefaultTrayIconSize); + const QPixmap pixmap = renderIcon(resourcePathForState(state, /*darkTheme*/ true), kDefaultTrayIconSize); QByteArray bytes; QBuffer buffer(&bytes); diff --git a/client/ui/utils/trayIconCommon.h b/client/ui/utils/trayIconCommon.h index a47d24a7d..27657d8b8 100644 --- a/client/ui/utils/trayIconCommon.h +++ b/client/ui/utils/trayIconCommon.h @@ -2,31 +2,29 @@ #define TRAYICONCOMMON_H #include -#include #include -#include #include +#include #include "core/protocols/vpnProtocol.h" namespace TrayIconCommon { constexpr int kDefaultTrayIconSize = 128; - constexpr char kTrayTemplateIconPath[] = ":/images/tray/icon.svg"; - constexpr qreal kDisconnectedOpacity = 0.5; - constexpr qreal kConnectedOpacity = 1.0; + constexpr char kIconOffBlack[] = ":/images/tray/off-black.svg"; + constexpr char kIconOffLight[] = ":/images/tray/off-light.svg"; + constexpr char kIconOnBlack[] = ":/images/tray/on-black.svg"; + constexpr char kIconOnWhite[] = ":/images/tray/on-white.svg"; + constexpr char kIconError[] = ":/images/tray/error.svg"; - qreal opacityForState(Vpn::ConnectionState state); - QColor indicatorColorForState(Vpn::ConnectionState state); + QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme); - QPixmap renderTemplate(const QString &resourcePath, qreal opacity, int size); - QPixmap colorizeTemplate(const QPixmap &mask, const QColor &foreground, int size); - void drawStatusIndicator(QPainter &painter, const QColor &color, int size); + QPixmap renderIcon(const QString &resourcePath, int size); - QPixmap buildPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor); - QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor); - QByteArray buildTemplatePng(qreal opacity); + QPixmap buildPixmap(int size, Vpn::ConnectionState state, bool darkTheme); + QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme); + QByteArray buildTemplatePng(Vpn::ConnectionState state); } // namespace TrayIconCommon