Show new dev/dir notifications in usual tray icon and Plasmoid

This commit is contained in:
Martchus 2018-05-01 22:27:03 +02:00
parent aa9f88df94
commit 988765f2ba
11 changed files with 157 additions and 29 deletions

View File

@ -87,11 +87,14 @@ void SyncthingApplet::init()
connect(&m_connection, &SyncthingConnection::error, this, &SyncthingApplet::handleInternalError);
connect(&m_connection, &SyncthingConnection::trafficChanged, this, &SyncthingApplet::trafficChanged);
connect(&m_connection, &SyncthingConnection::newNotification, this, &SyncthingApplet::handleNewNotification);
connect(&m_notifier, &SyncthingNotifier::newDevice, &m_dbusNotifier, &DBusStatusNotifier::showNewDev);
connect(&m_notifier, &SyncthingNotifier::newDir, &m_dbusNotifier, &DBusStatusNotifier::showNewDir);
connect(&m_dbusNotifier, &DBusStatusNotifier::connectRequested, &m_connection,
static_cast<void (SyncthingConnection::*)(void)>(&SyncthingConnection::connect));
connect(&m_dbusNotifier, &DBusStatusNotifier::dismissNotificationsRequested, this, &SyncthingApplet::dismissNotifications);
connect(&m_dbusNotifier, &DBusStatusNotifier::showNotificationsRequested, this, &SyncthingApplet::showNotificationsDialog);
connect(&m_dbusNotifier, &DBusStatusNotifier::errorDetailsRequested, this, &SyncthingApplet::showInternalErrorsDialog);
connect(&m_dbusNotifier, &DBusStatusNotifier::webUiRequested, this, &SyncthingApplet::showWebUI);
// restore settings
Settings::restore();

View File

@ -39,25 +39,32 @@ namespace QtGui {
TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
: QSystemTrayIcon(parent)
, m_trayMenu(connectionConfig, this)
, m_dbusNotificationsEnabled(Settings::values().dbusNotifications)
, m_notifyOnSyncthingErrors(Settings::values().notifyOn.syncthingErrors)
, m_messageClickedAction(TrayIconMessageClickedAction::None)
{
// get widget, connection and notifier
const auto &widget(m_trayMenu.widget());
const auto &connection(widget.connection());
const auto &notifier(widget.notifier());
// set context menu
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("internet-web-browser"),
QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/internet-web-browser.svg"))),
tr("Web UI")),
&QAction::triggered, &m_trayMenu.widget(), &TrayWidget::showWebUi);
&QAction::triggered, &widget, &TrayWidget::showWebUi);
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/preferences-other.svg"))),
tr("Settings")),
&QAction::triggered, &m_trayMenu.widget(), &TrayWidget::showSettingsDialog);
&QAction::triggered, &widget, &TrayWidget::showSettingsDialog);
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("folder-sync"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/folder-sync.svg"))),
tr("Rescan all")),
&QAction::triggered, &m_trayMenu.widget().connection(), &SyncthingConnection::rescanAllDirs);
&QAction::triggered, &widget.connection(), &SyncthingConnection::rescanAllDirs);
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("text-x-generic"), QIcon(QStringLiteral(":/icons/hicolor/scalable/mimetypes/text-x-generic.svg"))),
tr("Log")),
&QAction::triggered, &m_trayMenu.widget(), &TrayWidget::showLog);
&QAction::triggered, &widget, &TrayWidget::showLog);
m_errorsAction = m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("emblem-error"), QIcon(QStringLiteral(":/icons/hicolor/scalable/emblems/8/emblem-error.svg"))),
tr("Show internal errors"));
@ -66,7 +73,7 @@ TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
m_contextMenu.addMenu(m_trayMenu.widget().connectionsMenu());
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("help-about"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/help-about.svg"))), tr("About")),
&QAction::triggered, &m_trayMenu.widget(), &TrayWidget::showAboutDialog);
&QAction::triggered, &widget, &TrayWidget::showAboutDialog);
m_contextMenu.addSeparator();
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("window-close"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/window-close.svg"))),
@ -75,23 +82,24 @@ TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
setContextMenu(&m_contextMenu);
// connect signals and slots
const SyncthingConnection &connection = m_trayMenu.widget().connection();
const SyncthingNotifier &notifier = m_trayMenu.widget().notifier();
connect(this, &TrayIcon::activated, this, &TrayIcon::handleActivated);
connect(this, &TrayIcon::messageClicked, this, &TrayIcon::handleMessageClicked);
connect(&connection, &SyncthingConnection::error, this, &TrayIcon::showInternalError);
connect(&connection, &SyncthingConnection::newNotification, this, &TrayIcon::showSyncthingNotification);
connect(&notifier, &SyncthingNotifier::disconnected, this, &TrayIcon::showDisconnected);
connect(&notifier, &SyncthingNotifier::syncComplete, this, &TrayIcon::showSyncComplete);
connect(&notifier, &SyncthingNotifier::newDevice, this, &TrayIcon::showNewDev);
connect(&notifier, &SyncthingNotifier::newDir, this, &TrayIcon::showNewDir);
connect(&connection, &SyncthingConnection::statusChanged, this, &TrayIcon::updateStatusIconAndText);
connect(&connection, &SyncthingConnection::newDevices, this, &TrayIcon::updateStatusIconAndText);
connect(&connection, &SyncthingConnection::devStatusChanged, this, &TrayIcon::updateStatusIconAndText);
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
connect(&m_dbusNotifier, &DBusStatusNotifier::connectRequested, &connection,
static_cast<void (SyncthingConnection::*)(void)>(&SyncthingConnection::connect));
connect(&m_dbusNotifier, &DBusStatusNotifier::dismissNotificationsRequested, &m_trayMenu.widget(), &TrayWidget::dismissNotifications);
connect(&m_dbusNotifier, &DBusStatusNotifier::showNotificationsRequested, &m_trayMenu.widget(), &TrayWidget::showNotifications);
connect(&m_dbusNotifier, &DBusStatusNotifier::dismissNotificationsRequested, &widget, &TrayWidget::dismissNotifications);
connect(&m_dbusNotifier, &DBusStatusNotifier::showNotificationsRequested, &widget, &TrayWidget::showNotifications);
connect(&m_dbusNotifier, &DBusStatusNotifier::errorDetailsRequested, this, &TrayIcon::showInternalErrorsDialog);
connect(&m_dbusNotifier, &DBusStatusNotifier::webUiRequested, &widget, &TrayWidget::showWebUi);
connect(&notifier, &SyncthingNotifier::connected, &m_dbusNotifier, &DBusStatusNotifier::hideDisconnect);
#endif
}
@ -141,13 +149,16 @@ void TrayIcon::handleMessageClicked()
case TrayIconMessageClickedAction::ShowInternalErrors:
showInternalErrorsDialog();
break;
case TrayIconMessageClickedAction::ShowWebUi:
m_trayMenu.widget().showWebUi();
break;
}
}
void TrayIcon::showDisconnected()
{
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if (Settings::values().dbusNotifications) {
if (m_dbusNotificationsEnabled) {
m_dbusNotifier.showDisconnect();
} else
#endif
@ -160,7 +171,7 @@ void TrayIcon::showDisconnected()
void TrayIcon::showSyncComplete(const QString &message)
{
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if (Settings::values().dbusNotifications) {
if (m_dbusNotificationsEnabled) {
m_dbusNotifier.showSyncComplete(message);
} else
#endif
@ -183,7 +194,7 @@ void TrayIcon::showInternalError(
}
InternalError error(errorMsg, request.url(), response);
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if (Settings::values().dbusNotifications) {
if (m_dbusNotificationsEnabled) {
m_dbusNotifier.showInternalError(error);
} else
#endif
@ -197,10 +208,9 @@ void TrayIcon::showInternalError(
void TrayIcon::showSyncthingNotification(ChronoUtilities::DateTime when, const QString &message)
{
const auto &settings(Settings::values());
if (settings.notifyOn.syncthingErrors) {
if (m_notifyOnSyncthingErrors) {
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if (settings.dbusNotifications) {
if (m_dbusNotificationsEnabled) {
m_dbusNotifier.showSyncthingNotification(when, message);
} else
#else
@ -225,6 +235,37 @@ void TrayIcon::updateStatusIconAndText()
setIcon(statusInfo.statusIcon());
}
void TrayIcon::showNewDev(const QString &devId, const QString &message)
{
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if (m_dbusNotificationsEnabled) {
m_dbusNotifier.showNewDev(devId, message);
} else
#else
Q_UNUSED(devId)
#endif
{
m_messageClickedAction = TrayIconMessageClickedAction::ShowWebUi;
showMessage(tr("Syncthing device wants to connect - click for web UI"), message, QSystemTrayIcon::Information);
}
}
void TrayIcon::showNewDir(const QString &devId, const QString &dirId, const QString &message)
{
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if (m_dbusNotificationsEnabled) {
m_dbusNotifier.showNewDir(devId, dirId, message);
} else
#else
Q_UNUSED(devId)
Q_UNUSED(dirId)
#endif
{
m_messageClickedAction = TrayIconMessageClickedAction::ShowWebUi;
showMessage(tr("New Syncthing directory - click for web UI"), message, QSystemTrayIcon::Information);
}
}
void TrayIcon::showInternalErrorsDialog()
{
auto *const errorViewDlg = ErrorViewDialog::instance();

View File

@ -22,7 +22,7 @@ struct SyncthingDev;
namespace QtGui {
enum class TrayIconMessageClickedAction { None, DismissNotification, ShowInternalErrors };
enum class TrayIconMessageClickedAction { None, DismissNotification, ShowInternalErrors, ShowWebUi };
class TrayIcon : public QSystemTrayIcon {
Q_OBJECT
@ -37,6 +37,8 @@ public slots:
void showSyncthingNotification(ChronoUtilities::DateTime when, const QString &message);
void showInternalErrorsDialog();
void updateStatusIconAndText();
void showNewDev(const QString &devId, const QString &message);
void showNewDir(const QString &devId, const QString &dirId, const QString &message);
private slots:
void handleActivated(QSystemTrayIcon::ActivationReason reason);
@ -51,6 +53,8 @@ private:
QAction *m_errorsAction;
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
DBusStatusNotifier m_dbusNotifier;
bool &m_dbusNotificationsEnabled;
bool &m_notifyOnSyncthingErrors;
#endif
TrayIconMessageClickedAction m_messageClickedAction;
};

View File

@ -16,6 +16,7 @@ public:
QSize sizeHint() const;
TrayWidget &widget();
const TrayWidget &widget() const;
TrayIcon *icon();
public slots:
@ -31,6 +32,11 @@ inline TrayWidget &TrayMenu::widget()
return *m_trayWidget;
}
inline const TrayWidget &TrayMenu::widget() const
{
return *m_trayWidget;
}
inline TrayIcon *TrayMenu::icon()
{
return m_trayIcon;

View File

@ -46,7 +46,9 @@ public:
~TrayWidget();
Data::SyncthingConnection &connection();
const Data::SyncthingConnection &connection() const;
Data::SyncthingNotifier &notifier();
const Data::SyncthingNotifier &notifier() const;
QMenu *connectionsMenu();
static const std::vector<TrayWidget *> &instances();
@ -112,11 +114,21 @@ inline Data::SyncthingConnection &TrayWidget::connection()
return m_connection;
}
inline const Data::SyncthingConnection &TrayWidget::connection() const
{
return m_connection;
}
inline Data::SyncthingNotifier &TrayWidget::notifier()
{
return m_notifier;
}
inline const Data::SyncthingNotifier &TrayWidget::notifier() const
{
return m_notifier;
}
inline QMenu *TrayWidget::connectionsMenu()
{
return m_connectionsMenu;

View File

@ -14,23 +14,43 @@ using namespace MiscUtils;
namespace QtGui {
inline QImage makeImage(const QIcon &icon)
{
return icon.pixmap(QSize(128, 128)).toImage();
}
DBusStatusNotifier::DBusStatusNotifier(QObject *parent)
: QObject(parent)
, m_disconnectedNotification(QStringLiteral(APP_NAME), QStringLiteral("network-disconnect"), 5000)
, m_internalErrorNotification(QStringLiteral(APP_NAME) + tr(" - internal error"), NotificationIcon::Critical, 5000)
, m_syncthingNotification(tr("Syncthing notification"), NotificationIcon::Warning, 10000)
, m_syncCompleteNotification(QStringLiteral(APP_NAME), NotificationIcon::Information, 5000)
, m_newDevNotification(QStringLiteral(APP_NAME) + tr(" - new device"), NotificationIcon::Information, 5000)
, m_newDirNotification(QStringLiteral(APP_NAME) + tr(" - new directory"), NotificationIcon::Information, 5000)
{
const auto icons(statusIcons());
m_disconnectedNotification.setMessage(tr("Disconnected from Syncthing"));
m_disconnectedNotification.setActions(QStringList({ QStringLiteral("reconnect"), tr("Try to reconnect") }));
connect(&m_disconnectedNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::connectRequested);
m_syncthingNotification.setImage(makeImage(icons.error));
m_internalErrorNotification.setActions(QStringList({ QStringLiteral("details"), tr("View details") }));
m_syncthingNotification.setImage(statusIcons().error.pixmap(QSize(128, 128)).toImage());
connect(&m_internalErrorNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::errorDetailsRequested);
m_syncthingNotification.setActions(QStringList({ QStringLiteral("show"), tr("Show"), QStringLiteral("dismiss"), tr("Dismiss") }));
m_syncthingNotification.setImage(statusIcons().notify.pixmap(QSize(128, 128)).toImage());
m_syncCompleteNotification.setImage(statusIcons().syncComplete.pixmap(QSize(128, 128)).toImage());
m_syncthingNotification.setImage(makeImage(icons.notify));
m_syncCompleteNotification.setImage(makeImage(icons.syncComplete));
connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::handleSyncthingNotificationAction);
m_newDevNotification.setImage(makeImage(icons.newItem));
m_newDevNotification.setActions(QStringList({ QStringLiteral("webui"), tr("Open web UI") }));
connect(&m_newDevNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::webUiRequested);
m_newDirNotification.setImage(m_newDevNotification.image());
m_newDirNotification.setActions(m_newDevNotification.actions());
connect(&m_newDirNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::webUiRequested);
}
void DBusStatusNotifier::handleSyncthingNotificationAction(const QString &action)

View File

@ -27,12 +27,15 @@ public Q_SLOTS:
void showInternalError(const InternalError &error);
void showSyncthingNotification(ChronoUtilities::DateTime when, const QString &message);
void showSyncComplete(const QString &message);
void showNewDev(const QString &devId, const QString &message);
void showNewDir(const QString &devId, const QString &dirId, const QString &message);
Q_SIGNALS:
void connectRequested();
void dismissNotificationsRequested();
void showNotificationsRequested();
void errorDetailsRequested();
void webUiRequested();
private Q_SLOTS:
void handleSyncthingNotificationAction(const QString &action);
@ -42,6 +45,8 @@ private:
MiscUtils::DBusNotification m_internalErrorNotification;
MiscUtils::DBusNotification m_syncthingNotification;
MiscUtils::DBusNotification m_syncCompleteNotification;
MiscUtils::DBusNotification m_newDevNotification;
MiscUtils::DBusNotification m_newDirNotification;
};
inline void DBusStatusNotifier::showDisconnect()
@ -69,6 +74,20 @@ inline void DBusStatusNotifier::showSyncComplete(const QString &message)
{
m_syncCompleteNotification.update(message);
}
inline void DBusStatusNotifier::showNewDev(const QString &devId, const QString &message)
{
Q_UNUSED(devId)
m_newDevNotification.update(message);
}
inline void DBusStatusNotifier::showNewDir(const QString &devId, const QString &dirId, const QString &message)
{
Q_UNUSED(devId)
Q_UNUSED(dirId)
m_newDirNotification.update(message);
}
} // namespace QtGui
#endif // !defined(SYNCTHINGWIDGETS_DBUSSTATUSNOTIFIER_H) && defined(QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS)

View File

@ -2,14 +2,6 @@
<ui version="4.0">
<class>QtGui::NotificationsOptionPage</class>
<widget class="QWidget" name="QtGui::NotificationsOptionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>345</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Notifications</string>
</property>
@ -59,6 +51,20 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnNewDevConnectsCheckBox">
<property name="text">
<string>new/unknown device connects</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnNewDirSharedCheckBox">
<property name="text">
<string>remote device shares new/unknown directory</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -165,6 +165,8 @@ void restore()
notifyOn.localSyncComplete = settings.value(QStringLiteral("notifyOnLocalSyncComplete"), notifyOn.localSyncComplete).toBool();
notifyOn.remoteSyncComplete = settings.value(QStringLiteral("notifyOnRemoteSyncComplete"), notifyOn.remoteSyncComplete).toBool();
notifyOn.syncthingErrors = settings.value(QStringLiteral("showSyncthingNotifications"), notifyOn.syncthingErrors).toBool();
notifyOn.newDeviceConnects = settings.value(QStringLiteral("notifyOnNewDeviceConnects"), notifyOn.newDeviceConnects).toBool();
notifyOn.newDirectoryShared = settings.value(QStringLiteral("notifyOnNewDirectoryShared"), notifyOn.newDirectoryShared).toBool();
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
v.dbusNotifications = settings.value(QStringLiteral("dbusNotifications"), DBusNotification::isAvailable()).toBool();
#endif
@ -250,6 +252,8 @@ void save()
settings.setValue(QStringLiteral("notifyOnLocalSyncComplete"), notifyOn.localSyncComplete);
settings.setValue(QStringLiteral("notifyOnRemoteSyncComplete"), notifyOn.remoteSyncComplete);
settings.setValue(QStringLiteral("showSyncthingNotifications"), notifyOn.syncthingErrors);
settings.setValue(QStringLiteral("notifyOnNewDeviceConnects"), notifyOn.newDeviceConnects);
settings.setValue(QStringLiteral("notifyOnNewDirectoryShared"), notifyOn.newDirectoryShared);
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
settings.setValue(QStringLiteral("dbusNotifications"), v.dbusNotifications);
#endif
@ -315,6 +319,12 @@ void Settings::apply(SyncthingNotifier &notifier) const
if (notifyOn.remoteSyncComplete) {
notifications |= SyncthingHighLevelNotification::RemoteSyncComplete;
}
if (notifyOn.newDeviceConnects) {
notifications |= SyncthingHighLevelNotification::NewDevice;
}
if (notifyOn.newDirectoryShared) {
notifications |= SyncthingHighLevelNotification::NewDir;
}
notifier.setEnabledNotifications(notifications);
notifier.setIgnoreInavailabilityAfterStart(ignoreInavailabilityAfterStart);
}

View File

@ -41,6 +41,8 @@ struct SYNCTHINGWIDGETS_EXPORT NotifyOn {
bool localSyncComplete = false;
bool remoteSyncComplete = false;
bool syncthingErrors = true;
bool newDeviceConnects = false;
bool newDirectoryShared = false;
};
struct SYNCTHINGWIDGETS_EXPORT Appearance {

View File

@ -354,14 +354,17 @@ QWidget *NotificationsOptionPage::setupWidget()
bool NotificationsOptionPage::apply()
{
bool ok = true;
auto &notifyOn = values().notifyOn;
auto &settings(values());
auto &notifyOn(settings.notifyOn);
notifyOn.disconnect = ui()->notifyOnDisconnectCheckBox->isChecked();
notifyOn.internalErrors = ui()->notifyOnErrorsCheckBox->isChecked();
notifyOn.localSyncComplete = ui()->notifyOnLocalSyncCompleteCheckBox->isChecked();
notifyOn.remoteSyncComplete = ui()->notifyOnRemoteSyncCompleteCheckBox->isChecked();
notifyOn.syncthingErrors = ui()->showSyncthingNotificationsCheckBox->isChecked();
notifyOn.newDeviceConnects = ui()->notifyOnNewDevConnectsCheckBox->isChecked();
notifyOn.newDirectoryShared = ui()->notifyOnNewDirSharedCheckBox->isChecked();
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
if ((values().dbusNotifications = ui()->dbusRadioButton->isChecked()) && !DBusNotification::isAvailable()) {
if ((settings.dbusNotifications = ui()->dbusRadioButton->isChecked()) && !DBusNotification::isAvailable()) {
errors() << QCoreApplication::translate(
"QtGui::NotificationsOptionPage", "Configured to use D-Bus notifications but D-Bus notification daemon seems unavailabe.");
ok = false;
@ -379,6 +382,8 @@ void NotificationsOptionPage::reset()
ui()->notifyOnLocalSyncCompleteCheckBox->setChecked(notifyOn.localSyncComplete);
ui()->notifyOnRemoteSyncCompleteCheckBox->setChecked(notifyOn.remoteSyncComplete);
ui()->showSyncthingNotificationsCheckBox->setChecked(notifyOn.syncthingErrors);
ui()->notifyOnNewDevConnectsCheckBox->setChecked(notifyOn.newDeviceConnects);
ui()->notifyOnNewDirSharedCheckBox->setChecked(notifyOn.newDirectoryShared);
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
(values().dbusNotifications ? ui()->dbusRadioButton : ui()->qtRadioButton)->setChecked(true);
#else