mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-20 02:00:55 +07:00
add new icons error & fix logic
This commit is contained in:
@@ -425,7 +425,12 @@ void CoreSignalHandlers::initNotificationHandler()
|
||||
|
||||
auto* trayHandler = qobject_cast<SystemTrayNotificationHandler*>(m_coreController->m_notificationHandler);
|
||||
connect(m_coreController, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl);
|
||||
#endif
|
||||
|
||||
connect(m_coreController->m_connectionUiController, &ConnectionUiController::connectionErrorOccurred, trayHandler,
|
||||
&SystemTrayNotificationHandler::setConnectionError);
|
||||
connect(m_coreController->m_pageController, &PageController::errorMessageClosed, trayHandler,
|
||||
&SystemTrayNotificationHandler::clearConnectionError);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CoreSignalHandlers::initUpdateFoundHandler()
|
||||
|
||||
@@ -69,7 +69,8 @@
|
||||
<file>tray/off-light.svg</file>
|
||||
<file>tray/on-black.svg</file>
|
||||
<file>tray/on-white.svg</file>
|
||||
<file>tray/error.svg</file>
|
||||
<file>tray/error-black.svg</file>
|
||||
<file>tray/error-white.svg</file>
|
||||
<file>controls/monitor.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.4 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.4 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -22,7 +22,7 @@ class MacOSStatusIcon final : public QObject {
|
||||
|
||||
public:
|
||||
void setIcon(const QString& iconUrl);
|
||||
void setIconFromData(const QByteArray& imageData);
|
||||
void setIconFromData(const QByteArray& imageData, bool asTemplate = true);
|
||||
void setMenu(QMenu* menu);
|
||||
void rebuildNativeMenu();
|
||||
void setToolTip(const QString& tooltip);
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
@property(retain) NSMenu* nativeMenu;
|
||||
@property(retain) NSMutableArray* menuActionTargets;
|
||||
|
||||
- (void)setIcon:(NSData*)imageData;
|
||||
- (void)setIcon:(NSData*)imageData asTemplate:(BOOL)asTemplate;
|
||||
- (void)setToolTip:(NSString*)tooltip;
|
||||
- (void)rebuildMenuFromQMenu:(QMenu*)menu;
|
||||
@end
|
||||
@@ -71,11 +71,14 @@
|
||||
/**
|
||||
* Sets the image for the status icon.
|
||||
*
|
||||
* @param iconPath The data for the icon image.
|
||||
* @param imageData The data for the icon image.
|
||||
* @param asTemplate When true the icon is a template image recolored by the
|
||||
* system for the current menu bar appearance. When false the icon is
|
||||
* rendered in its original colors (used for the colored error icon).
|
||||
*/
|
||||
- (void)setIcon:(NSData*)imageData {
|
||||
- (void)setIcon:(NSData*)imageData asTemplate:(BOOL)asTemplate {
|
||||
NSImage* image = [[NSImage alloc] initWithData:imageData];
|
||||
[image setTemplate:true];
|
||||
[image setTemplate:asTemplate];
|
||||
|
||||
[self.statusItem.button setImage:image];
|
||||
[image release];
|
||||
@@ -169,10 +172,10 @@ void MacOSStatusIcon::setIcon(const QString& iconPath) {
|
||||
QResource imageResource = QResource(iconPath);
|
||||
Q_ASSERT(imageResource.isValid());
|
||||
|
||||
[m_statusBarIcon setIcon:imageResource.uncompressedData().toNSData()];
|
||||
[m_statusBarIcon setIcon:imageResource.uncompressedData().toNSData() asTemplate:true];
|
||||
}
|
||||
|
||||
void MacOSStatusIcon::setIconFromData(const QByteArray& imageData) {
|
||||
void MacOSStatusIcon::setIconFromData(const QByteArray& imageData, bool asTemplate) {
|
||||
logger.debug() << "Set icon from rendered data";
|
||||
|
||||
if (imageData.isEmpty()) {
|
||||
@@ -180,7 +183,7 @@ void MacOSStatusIcon::setIconFromData(const QByteArray& imageData) {
|
||||
}
|
||||
|
||||
NSData* data = [NSData dataWithBytes:imageData.constData() length:imageData.size()];
|
||||
[m_statusBarIcon setIcon:data];
|
||||
[m_statusBarIcon setIcon:data asTemplate:asTemplate];
|
||||
}
|
||||
|
||||
void MacOSStatusIcon::setMenu(QMenu* menu) {
|
||||
|
||||
@@ -23,7 +23,13 @@ void MacTrayIconBackend::show()
|
||||
|
||||
void MacTrayIconBackend::applyVisual(const TrayIconVisual &visual)
|
||||
{
|
||||
m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(visual.connectionState));
|
||||
if (TrayIconCommon::isColoredState(visual.connectionState)) {
|
||||
// Error icon carries a red badge: render it in color, not as a template.
|
||||
m_statusIcon.setIconFromData(TrayIconCommon::buildColorPng(visual.connectionState, visual.darkTheme),
|
||||
/*asTemplate*/ false);
|
||||
} else {
|
||||
m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(visual.connectionState), /*asTemplate*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacTrayIconBackend::showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec)
|
||||
|
||||
@@ -248,3 +248,8 @@ void PageController::onShowErrorMessage(ErrorCode errorCode)
|
||||
|
||||
emit showErrorMessage(fullMessage);
|
||||
}
|
||||
|
||||
void PageController::onErrorMessageClosed()
|
||||
{
|
||||
emit errorMessageClosed();
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ public slots:
|
||||
int getDrawerDepth() const;
|
||||
int incrementDrawerDepth();
|
||||
int decrementDrawerDepth();
|
||||
|
||||
void onErrorMessageClosed();
|
||||
bool isEdgeToEdgeEnabled();
|
||||
int getStatusBarHeight();
|
||||
int getNavigationBarHeight();
|
||||
@@ -162,7 +162,7 @@ signals:
|
||||
void showErrorMessage(amnezia::ErrorCode);
|
||||
void showErrorMessage(const QString &errorMessage);
|
||||
void showNotificationMessage(const QString &message);
|
||||
|
||||
void errorMessageClosed();
|
||||
void showBusyIndicator(bool visible);
|
||||
void disableControls(bool disabled);
|
||||
void disableTabBar(bool disabled);
|
||||
|
||||
@@ -203,6 +203,13 @@ Window {
|
||||
PopupType {
|
||||
id: popupErrorMessage
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: popupErrorMessage
|
||||
function onClosed() {
|
||||
PageController.onErrorMessageClosed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
||||
@@ -93,11 +93,27 @@ void SystemTrayNotificationHandler::refreshTheme()
|
||||
TrayIconVisual SystemTrayNotificationHandler::currentTrayVisual() const
|
||||
{
|
||||
TrayIconVisual visual;
|
||||
visual.connectionState = m_trayState;
|
||||
visual.connectionState = m_errorLatched ? Vpn::ConnectionState::Error : m_trayState;
|
||||
visual.darkTheme = m_isDarkTheme;
|
||||
return visual;
|
||||
}
|
||||
|
||||
void SystemTrayNotificationHandler::setConnectionError()
|
||||
{
|
||||
m_errorLatched = true;
|
||||
updateTrayIcon();
|
||||
}
|
||||
|
||||
void SystemTrayNotificationHandler::clearConnectionError()
|
||||
{
|
||||
if (!m_errorLatched) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_errorLatched = false;
|
||||
updateTrayIcon();
|
||||
}
|
||||
|
||||
void SystemTrayNotificationHandler::updateTrayIcon()
|
||||
{
|
||||
if (!m_trayIcon) {
|
||||
@@ -118,6 +134,20 @@ void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationR
|
||||
|
||||
void SystemTrayNotificationHandler::setTrayState(Vpn::ConnectionState state)
|
||||
{
|
||||
if (state == Vpn::ConnectionState::Error || state == Vpn::ConnectionState::Unknown) {
|
||||
// Latch the error icon. Both Error and Unknown surface the error message
|
||||
// in the UI. The connection is torn down to Disconnected right after, so
|
||||
// treat the real state as Disconnected and let the latch keep the error
|
||||
// icon visible until the error is acknowledged.
|
||||
m_errorLatched = true;
|
||||
state = Vpn::ConnectionState::Disconnected;
|
||||
} else if (state != Vpn::ConnectionState::Disconnected) {
|
||||
// A new (re)connecting/connected lifecycle clears a previous error.
|
||||
// Plain Disconnected leaves the latch untouched so the auto-Disconnected
|
||||
// that immediately follows an error does not drop the error icon.
|
||||
m_errorLatched = false;
|
||||
}
|
||||
|
||||
m_trayState = state;
|
||||
|
||||
switch (state) {
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
public slots:
|
||||
void updateWebsiteUrl(const QString &newWebsiteUrl);
|
||||
void setConnectionError();
|
||||
void clearConnectionError();
|
||||
|
||||
protected:
|
||||
void notify(Message type, const QString& title,
|
||||
@@ -51,6 +53,7 @@ private:
|
||||
|
||||
Vpn::ConnectionState m_trayState = Vpn::ConnectionState::Unknown;
|
||||
bool m_isDarkTheme = false;
|
||||
bool m_errorLatched = false;
|
||||
|
||||
QString websiteUrl = "https://amnezia.org";
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme)
|
||||
{
|
||||
switch (state) {
|
||||
case Vpn::ConnectionState::Error:
|
||||
return QString::fromLatin1(kIconError);
|
||||
return QString::fromLatin1(darkTheme ? kIconErrorWhite : kIconErrorBlack);
|
||||
case Vpn::ConnectionState::Connected:
|
||||
return QString::fromLatin1(darkTheme ? kIconOnWhite : kIconOnBlack);
|
||||
case Vpn::ConnectionState::Disconnected:
|
||||
@@ -25,6 +25,11 @@ QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme)
|
||||
}
|
||||
}
|
||||
|
||||
bool isColoredState(Vpn::ConnectionState state)
|
||||
{
|
||||
return state == Vpn::ConnectionState::Error;
|
||||
}
|
||||
|
||||
QPixmap renderIcon(const QString &resourcePath, int size)
|
||||
{
|
||||
QSvgRenderer renderer(resourcePath);
|
||||
@@ -53,10 +58,8 @@ QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme)
|
||||
return icon;
|
||||
}
|
||||
|
||||
QByteArray buildTemplatePng(Vpn::ConnectionState state)
|
||||
QByteArray pixmapToPng(const QPixmap &pixmap)
|
||||
{
|
||||
const QPixmap pixmap = renderIcon(resourcePathForState(state, /*darkTheme*/ true), kDefaultTrayIconSize);
|
||||
|
||||
QByteArray bytes;
|
||||
QBuffer buffer(&bytes);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
@@ -64,4 +67,14 @@ QByteArray buildTemplatePng(Vpn::ConnectionState state)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
QByteArray buildTemplatePng(Vpn::ConnectionState state)
|
||||
{
|
||||
return pixmapToPng(renderIcon(resourcePathForState(state, /*darkTheme*/ true), kDefaultTrayIconSize));
|
||||
}
|
||||
|
||||
QByteArray buildColorPng(Vpn::ConnectionState state, bool darkTheme)
|
||||
{
|
||||
return pixmapToPng(renderIcon(resourcePathForState(state, darkTheme), kDefaultTrayIconSize));
|
||||
}
|
||||
|
||||
} // namespace TrayIconCommon
|
||||
|
||||
@@ -16,15 +16,19 @@ namespace TrayIconCommon
|
||||
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";
|
||||
constexpr char kIconErrorBlack[] = ":/images/tray/error-black.svg";
|
||||
constexpr char kIconErrorWhite[] = ":/images/tray/error-white.svg";
|
||||
|
||||
QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme);
|
||||
|
||||
bool isColoredState(Vpn::ConnectionState state);
|
||||
|
||||
QPixmap renderIcon(const QString &resourcePath, int size);
|
||||
|
||||
QPixmap buildPixmap(int size, Vpn::ConnectionState state, bool darkTheme);
|
||||
QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme);
|
||||
QByteArray buildTemplatePng(Vpn::ConnectionState state);
|
||||
QByteArray buildColorPng(Vpn::ConnectionState state, bool darkTheme);
|
||||
|
||||
} // namespace TrayIconCommon
|
||||
|
||||
|
||||
Reference in New Issue
Block a user