Allow to distinguish icon colors within UI and system tray

This is useful because sometimes the background color of the system
tray is dark but the overall system UI still uses a light theme.

For the Plasmoid this should never be the case, though. Hence the
extra settings are not available there.
This commit is contained in:
Martchus 2019-07-31 20:16:43 +02:00
parent 59e0f93c1c
commit 353f1e2463
13 changed files with 130 additions and 30 deletions

View File

@ -67,7 +67,7 @@ void SyncthingFileItemActionStaticData::initialize()
} }
// use default icon settings // use default icon settings
IconManager::instance().applySettings(StatusIconSettings()); IconManager::instance().applySettings();
m_initialized = true; m_initialized = true;
} }

View File

@ -278,6 +278,7 @@ FontAwesomeIcons::FontAwesomeIcons(const QColor &color, const QSize &size, int m
IconManager::IconManager() IconManager::IconManager()
: m_statusIcons() : m_statusIcons()
, m_trayIcons(m_statusIcons)
, m_fontAwesomeIconsForLightTheme(QColor(10, 10, 10), QSize(64, 64), 8) , m_fontAwesomeIconsForLightTheme(QColor(10, 10, 10), QSize(64, 64), 8)
, m_fontAwesomeIconsForDarkTheme(Qt::white, QSize(64, 64), 8) , m_fontAwesomeIconsForDarkTheme(Qt::white, QSize(64, 64), 8)
{ {

View File

@ -87,6 +87,8 @@ struct LIB_SYNCTHING_MODEL_EXPORT StatusIconSettings {
struct LIB_SYNCTHING_MODEL_EXPORT StatusIcons { struct LIB_SYNCTHING_MODEL_EXPORT StatusIcons {
StatusIcons(); StatusIcons();
StatusIcons(const StatusIconSettings &settings); StatusIcons(const StatusIconSettings &settings);
StatusIcons(const StatusIcons &other) = default;
StatusIcons &operator=(const StatusIcons &other) = default;
QIcon disconnected; QIcon disconnected;
QIcon idling; QIcon idling;
QIcon scanninig; QIcon scanninig;
@ -133,25 +135,37 @@ class LIB_SYNCTHING_MODEL_EXPORT IconManager : public QObject {
public: public:
static IconManager &instance(); static IconManager &instance();
void applySettings(const StatusIconSettings &settings); void applySettings(const StatusIconSettings *statusIconSettings = nullptr, const StatusIconSettings *trayIconSettings = nullptr);
const StatusIcons &statusIcons() const; const StatusIcons &statusIcons() const;
const StatusIcons &trayIcons() const;
const FontAwesomeIcons &fontAwesomeIconsForLightTheme() const; const FontAwesomeIcons &fontAwesomeIconsForLightTheme() const;
const FontAwesomeIcons &fontAwesomeIconsForDarkTheme() const; const FontAwesomeIcons &fontAwesomeIconsForDarkTheme() const;
Q_SIGNALS: Q_SIGNALS:
void statusIconsChanged(const StatusIcons &newStatusIcons); void statusIconsChanged(const StatusIcons &newStatusIcons, const StatusIcons &newTrayIcons);
private: private:
IconManager(); IconManager();
StatusIcons m_statusIcons; StatusIcons m_statusIcons;
StatusIcons m_trayIcons;
FontAwesomeIcons m_fontAwesomeIconsForLightTheme; FontAwesomeIcons m_fontAwesomeIconsForLightTheme;
FontAwesomeIcons m_fontAwesomeIconsForDarkTheme; FontAwesomeIcons m_fontAwesomeIconsForDarkTheme;
}; };
inline void IconManager::applySettings(const StatusIconSettings &settings) inline void IconManager::applySettings(const StatusIconSettings *statusIconSettings, const StatusIconSettings *trayIconSettings)
{ {
emit statusIconsChanged(m_statusIcons = StatusIcons(settings)); if (statusIconSettings) {
m_statusIcons = StatusIcons(*statusIconSettings);
} else {
m_statusIcons = StatusIcons(StatusIconSettings());
}
if (trayIconSettings) {
m_trayIcons = StatusIcons(*trayIconSettings);
} else {
m_trayIcons = m_statusIcons;
}
emit statusIconsChanged(m_statusIcons, m_trayIcons);
} }
inline const StatusIcons &IconManager::statusIcons() const inline const StatusIcons &IconManager::statusIcons() const
@ -159,6 +173,11 @@ inline const StatusIcons &IconManager::statusIcons() const
return m_statusIcons; return m_statusIcons;
} }
inline const StatusIcons &IconManager::trayIcons() const
{
return m_trayIcons;
}
inline const FontAwesomeIcons &IconManager::fontAwesomeIconsForLightTheme() const inline const FontAwesomeIcons &IconManager::fontAwesomeIconsForLightTheme() const
{ {
return m_fontAwesomeIconsForLightTheme; return m_fontAwesomeIconsForLightTheme;
@ -174,6 +193,11 @@ inline const StatusIcons &statusIcons()
return IconManager::instance().statusIcons(); return IconManager::instance().statusIcons();
} }
inline const StatusIcons &trayIcons()
{
return IconManager::instance().trayIcons();
}
inline const FontAwesomeIcons &fontAwesomeIconsForLightTheme() inline const FontAwesomeIcons &fontAwesomeIconsForLightTheme()
{ {
return IconManager::instance().fontAwesomeIconsForLightTheme(); return IconManager::instance().fontAwesomeIconsForLightTheme();

View File

@ -398,7 +398,7 @@ void SyncthingApplet::handleSettingsChanged()
m_dirModel.setBrightColors(brightColors); m_dirModel.setBrightColors(brightColors);
m_devModel.setBrightColors(brightColors); m_devModel.setBrightColors(brightColors);
m_downloadModel.setBrightColors(brightColors); m_downloadModel.setBrightColors(brightColors);
IconManager::instance().applySettings(settings.statusIcons); IconManager::instance().applySettings(&settings.icons.status);
// restore selected states // restore selected states
// note: The settings dialog writes this to the Plasmoid's config like the other settings. However, it // note: The settings dialog writes this to the Plasmoid's config like the other settings. However, it

View File

@ -465,7 +465,7 @@ void TrayWidget::applySettings(const QString &connectionConfig)
m_dirModel.setBrightColors(settings.appearance.brightTextColors); m_dirModel.setBrightColors(settings.appearance.brightTextColors);
m_devModel.setBrightColors(settings.appearance.brightTextColors); m_devModel.setBrightColors(settings.appearance.brightTextColors);
m_dlModel.setBrightColors(settings.appearance.brightTextColors); m_dlModel.setBrightColors(settings.appearance.brightTextColors);
IconManager::instance().applySettings(settings.statusIcons); IconManager::instance().applySettings(&settings.icons.status, settings.icons.distinguishTrayIcons ? &settings.icons.tray : nullptr);
// show warning when explicitely specified connection configuration was not found // show warning when explicitely specified connection configuration was not found
if (!specifiedConnectionConfigFound && !connectionConfig.isEmpty()) { if (!specifiedConnectionConfigFound && !connectionConfig.isEmpty()) {

View File

@ -58,10 +58,10 @@ DBusStatusNotifier::DBusStatusNotifier(QObject *parent)
const auto &iconManager = IconManager::instance(); const auto &iconManager = IconManager::instance();
connect(&iconManager, &Data::IconManager::statusIconsChanged, this, &DBusStatusNotifier::setIcons); connect(&iconManager, &Data::IconManager::statusIconsChanged, this, &DBusStatusNotifier::setIcons);
setIcons(iconManager.statusIcons()); setIcons(iconManager.statusIcons(), iconManager.trayIcons());
} }
void DBusStatusNotifier::setIcons(const StatusIcons &icons) void DBusStatusNotifier::setIcons(const StatusIcons &, const StatusIcons &icons)
{ {
if (!icons.isValid) { if (!icons.isValid) {
return; return;

View File

@ -32,7 +32,7 @@ public Q_SLOTS:
void showSyncComplete(const QString &message); void showSyncComplete(const QString &message);
void showNewDev(const QString &devId, const QString &message); void showNewDev(const QString &devId, const QString &message);
void showNewDir(const QString &devId, const QString &dirId, const QString &message); void showNewDir(const QString &devId, const QString &dirId, const QString &message);
void setIcons(const Data::StatusIcons &icons); void setIcons(const Data::StatusIcons &statusIcons, const Data::StatusIcons &icons);
Q_SIGNALS: Q_SIGNALS:
void connectRequested(); void connectRequested();

View File

@ -15,7 +15,7 @@ namespace QtGui {
StatusInfo::StatusInfo() StatusInfo::StatusInfo()
: m_statusText(QCoreApplication::translate("QtGui::StatusInfo", "Initializing ...")) : m_statusText(QCoreApplication::translate("QtGui::StatusInfo", "Initializing ..."))
, m_statusIcon(&statusIcons().disconnected) , m_statusIcon(&trayIcons().disconnected)
{ {
} }
@ -36,6 +36,7 @@ void StatusInfo::updateConnectionStatus(const SyncthingConnection &connection)
{ {
m_additionalStatusInfo.clear(); m_additionalStatusInfo.clear();
const auto &icons = trayIcons();
switch (connection.status()) { switch (connection.status()) {
case SyncthingStatus::Disconnected: case SyncthingStatus::Disconnected:
if (connection.autoReconnectInterval() > 0) { if (connection.autoReconnectInterval() > 0) {
@ -45,11 +46,11 @@ void StatusInfo::updateConnectionStatus(const SyncthingConnection &connection)
} else { } else {
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Not connected to Syncthing"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Not connected to Syncthing");
} }
m_statusIcon = &statusIcons().disconnected; m_statusIcon = &icons.disconnected;
break; break;
case SyncthingStatus::Reconnecting: case SyncthingStatus::Reconnecting:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Reconnecting ..."); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Reconnecting ...");
m_statusIcon = &statusIcons().disconnected; m_statusIcon = &icons.disconnected;
break; break;
default: default:
if (connection.hasOutOfSyncDirs()) { if (connection.hasOutOfSyncDirs()) {
@ -57,36 +58,36 @@ void StatusInfo::updateConnectionStatus(const SyncthingConnection &connection)
case SyncthingStatus::Synchronizing: case SyncthingStatus::Synchronizing:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Synchronization is ongoing"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Synchronization is ongoing");
m_additionalStatusInfo = QCoreApplication::translate("QtGui::StatusInfo", "At least one directory is out of sync"); m_additionalStatusInfo = QCoreApplication::translate("QtGui::StatusInfo", "At least one directory is out of sync");
m_statusIcon = &statusIcons().errorSync; m_statusIcon = &icons.errorSync;
break; break;
default: default:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "At least one directory is out of sync"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "At least one directory is out of sync");
m_statusIcon = &statusIcons().error; m_statusIcon = &icons.error;
} }
} else if (connection.hasUnreadNotifications()) { } else if (connection.hasUnreadNotifications()) {
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Notifications available"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Notifications available");
m_statusIcon = &statusIcons().notify; m_statusIcon = &icons.notify;
} else { } else {
switch (connection.status()) { switch (connection.status()) {
case SyncthingStatus::Idle: case SyncthingStatus::Idle:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Syncthing is idling"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Syncthing is idling");
m_statusIcon = &statusIcons().idling; m_statusIcon = &icons.idling;
break; break;
case SyncthingStatus::Scanning: case SyncthingStatus::Scanning:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Syncthing is scanning"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Syncthing is scanning");
m_statusIcon = &statusIcons().scanninig; m_statusIcon = &icons.scanninig;
break; break;
case SyncthingStatus::Paused: case SyncthingStatus::Paused:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "At least one device is paused"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "At least one device is paused");
m_statusIcon = &statusIcons().pause; m_statusIcon = &icons.pause;
break; break;
case SyncthingStatus::Synchronizing: case SyncthingStatus::Synchronizing:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Synchronization is ongoing"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Synchronization is ongoing");
m_statusIcon = &statusIcons().sync; m_statusIcon = &icons.sync;
break; break;
default: default:
m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Status is unknown"); m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Status is unknown");
m_statusIcon = &statusIcons().disconnected; m_statusIcon = &icons.disconnected;
} }
} }
} }

View File

@ -10,6 +10,12 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="contextLabel"/>
</item>
<item>
<widget class="QCheckBox" name="contextCheckBox"/>
</item>
<item> <item>
<widget class="QGroupBox" name="statusIconsGroupBox"> <widget class="QGroupBox" name="statusIconsGroupBox">
<property name="title"> <property name="title">
@ -128,5 +134,22 @@
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections>
<connection>
<sender>contextCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>statusIconsGroupBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>224</x>
<y>39</y>
</hint>
<hint type="destinationlabel">
<x>224</x>
<y>115</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

View File

@ -257,7 +257,9 @@ void restore()
appearance.frameStyle = settings.value(QStringLiteral("frameStyle"), appearance.frameStyle).toInt(); appearance.frameStyle = settings.value(QStringLiteral("frameStyle"), appearance.frameStyle).toInt();
appearance.tabPosition = settings.value(QStringLiteral("tabPos"), appearance.tabPosition).toInt(); appearance.tabPosition = settings.value(QStringLiteral("tabPos"), appearance.tabPosition).toInt();
appearance.brightTextColors = settings.value(QStringLiteral("brightTextColors"), appearance.brightTextColors).toBool(); appearance.brightTextColors = settings.value(QStringLiteral("brightTextColors"), appearance.brightTextColors).toBool();
v.statusIcons = StatusIconSettings(settings.value(QStringLiteral("statusIcons")).toString()); v.icons.status = StatusIconSettings(settings.value(QStringLiteral("statusIcons")).toString());
v.icons.tray = StatusIconSettings(settings.value(QStringLiteral("trayIcons")).toString());
v.icons.distinguishTrayIcons = settings.value(QStringLiteral("distinguishTrayIcons")).toBool();
settings.beginGroup(QStringLiteral("positioning")); settings.beginGroup(QStringLiteral("positioning"));
auto &positioning = appearance.positioning; auto &positioning = appearance.positioning;
positioning.useCursorPosition = settings.value(QStringLiteral("useCursorPos"), positioning.useCursorPosition).toBool(); positioning.useCursorPosition = settings.value(QStringLiteral("useCursorPos"), positioning.useCursorPosition).toBool();
@ -353,7 +355,9 @@ void save()
settings.setValue(QStringLiteral("frameStyle"), appearance.frameStyle); settings.setValue(QStringLiteral("frameStyle"), appearance.frameStyle);
settings.setValue(QStringLiteral("tabPos"), appearance.tabPosition); settings.setValue(QStringLiteral("tabPos"), appearance.tabPosition);
settings.setValue(QStringLiteral("brightTextColors"), appearance.brightTextColors); settings.setValue(QStringLiteral("brightTextColors"), appearance.brightTextColors);
settings.setValue(QStringLiteral("statusIcons"), v.statusIcons.toString()); settings.setValue(QStringLiteral("statusIcons"), v.icons.status.toString());
settings.setValue(QStringLiteral("trayIcons"), v.icons.tray.toString());
settings.setValue(QStringLiteral("distinguishTrayIcons"), v.icons.distinguishTrayIcons);
settings.beginGroup(QStringLiteral("positioning")); settings.beginGroup(QStringLiteral("positioning"));
settings.setValue(QStringLiteral("useCursorPos"), appearance.positioning.useCursorPosition); settings.setValue(QStringLiteral("useCursorPos"), appearance.positioning.useCursorPosition);
settings.setValue(QStringLiteral("assumedIconPos"), appearance.positioning.assumedIconPosition); settings.setValue(QStringLiteral("assumedIconPos"), appearance.positioning.assumedIconPosition);

View File

@ -134,7 +134,11 @@ struct SYNCTHINGWIDGETS_EXPORT Settings {
#endif #endif
unsigned int ignoreInavailabilityAfterStart = 15; unsigned int ignoreInavailabilityAfterStart = 15;
Appearance appearance; Appearance appearance;
Data::StatusIconSettings statusIcons; struct SYNCTHINGWIDGETS_EXPORT Icons {
Data::StatusIconSettings status;
Data::StatusIconSettings tray;
bool distinguishTrayIcons = false;
} icons;
Launcher launcher; Launcher launcher;
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
Systemd systemd; Systemd systemd;

View File

@ -505,8 +505,9 @@ void AppearanceOptionPage::reset()
} }
// IconsOptionPage // IconsOptionPage
IconsOptionPage::IconsOptionPage(QWidget *parentWidget) IconsOptionPage::IconsOptionPage(Context context, QWidget *parentWidget)
: IconsOptionPageBase(parentWidget) : IconsOptionPageBase(parentWidget)
, m_context(context)
{ {
} }
@ -518,6 +519,24 @@ QWidget *IconsOptionPage::setupWidget()
{ {
auto *const widget = IconsOptionPageBase::setupWidget(); auto *const widget = IconsOptionPageBase::setupWidget();
// set context-specific elements
switch (m_context) {
case Context::Combined:
ui()->contextLabel->hide();
ui()->contextCheckBox->hide();
break;
case Context::UI:
widget->setWindowTitle(QCoreApplication::translate("QtGui::IconsOptionPageBase", "UI icons"));
ui()->contextLabel->setText(QCoreApplication::translate("QtGui::IconsOptionPageBase", "These icon colors are used within Syncthing Tray's UI."));
ui()->contextCheckBox->hide();
break;
case Context::System:
widget->setWindowTitle(QCoreApplication::translate("QtGui::IconsOptionPageBase", "System icons"));
ui()->contextLabel->setText(QCoreApplication::translate("QtGui::IconsOptionPageBase", "These icon colors are used for the system tray icon and the notifications."));
ui()->contextCheckBox->setText(QCoreApplication::translate("QtGui::IconsOptionPageBase", "Use same colors as for UI icons"));
break;
}
// populate form for status icon colors // populate form for status icon colors
auto *const gridLayout = ui()->gridLayout; auto *const gridLayout = ui()->gridLayout;
auto *const statusIconsGroupBox = ui()->statusIconsGroupBox; auto *const statusIconsGroupBox = ui()->statusIconsGroupBox;
@ -586,7 +605,17 @@ bool IconsOptionPage::apply()
widgetsForColor.colorButtons[2]->color(), widgetsForColor.colorButtons[2]->color(),
}; };
} }
values().statusIcons = m_settings; auto &iconSettings = values().icons;
switch (m_context) {
case Context::Combined:
case Context::UI:
iconSettings.status = m_settings;
break;
case Context::System:
iconSettings.tray = m_settings;
iconSettings.distinguishTrayIcons = !ui()->contextCheckBox->isChecked();
break;
}
return true; return true;
} }
@ -601,7 +630,17 @@ void IconsOptionPage::update()
void IconsOptionPage::reset() void IconsOptionPage::reset()
{ {
m_settings = values().statusIcons; const auto &iconSettings = values().icons;
switch (m_context) {
case Context::Combined:
case Context::UI:
m_settings = iconSettings.status;
break;
case Context::System:
m_settings = iconSettings.tray;
ui()->contextCheckBox->setChecked(!iconSettings.distinguishTrayIcons);
break;
}
update(); update();
} }
@ -1237,7 +1276,7 @@ SettingsDialog::SettingsDialog(Data::SyncthingConnection *connection, QWidget *p
category = new OptionCategory(this); category = new OptionCategory(this);
category->setDisplayName(tr("Tray")); category->setDisplayName(tr("Tray"));
category->assignPages(QList<OptionPage *>() << new ConnectionOptionPage(connection) << new NotificationsOptionPage << new AppearanceOptionPage category->assignPages(QList<OptionPage *>() << new ConnectionOptionPage(connection) << new NotificationsOptionPage << new AppearanceOptionPage
<< new IconsOptionPage); << new IconsOptionPage(IconsOptionPage::Context::UI) << new IconsOptionPage(IconsOptionPage::Context::System));
category->setIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg"))); category->setIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
categories << category; categories << category;

View File

@ -79,10 +79,14 @@ END_DECLARE_OPTION_PAGE
DECLARE_UI_FILE_BASED_OPTION_PAGE(AppearanceOptionPage) DECLARE_UI_FILE_BASED_OPTION_PAGE(AppearanceOptionPage)
BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE(IconsOptionPage) BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE_CUSTOM_CTOR(IconsOptionPage)
public:
enum class Context { Combined, UI, System };
explicit IconsOptionPage(Context context = Context::Combined, QWidget *parentWidget = nullptr);
DECLARE_SETUP_WIDGETS DECLARE_SETUP_WIDGETS
private: private:
void update(); void update();
Context m_context;
Data::StatusIconSettings m_settings; Data::StatusIconSettings m_settings;
struct { struct {
QtUtilities::ColorButton *colorButtons[3] = {}; QtUtilities::ColorButton *colorButtons[3] = {};