diff --git a/interfaces/notificationsmodel.h b/interfaces/notificationsmodel.h --- a/interfaces/notificationsmodel.h +++ b/interfaces/notificationsmodel.h @@ -71,6 +71,7 @@ private Q_SLOTS: void notificationAdded(const QString& id); void notificationRemoved(const QString& id); + void notificationUpdated(const QString& id); void refreshNotificationList(); void receivedNotifications(QDBusPendingCallWatcher* watcher); void clearNotifications(); diff --git a/interfaces/notificationsmodel.cpp b/interfaces/notificationsmodel.cpp --- a/interfaces/notificationsmodel.cpp +++ b/interfaces/notificationsmodel.cpp @@ -92,6 +92,8 @@ this, &NotificationsModel::notificationRemoved); connect(m_dbusInterface, &OrgKdeKdeconnectDeviceNotificationsInterface::allNotificationsRemoved, this, &NotificationsModel::clearNotifications); + connect(m_dbusInterface, &OrgKdeKdeconnectDeviceNotificationsInterface::notificationUpdated, + this, &NotificationsModel::notificationUpdated); refreshNotificationList(); @@ -261,3 +263,9 @@ endRemoveRows(); } } + +void NotificationsModel::notificationUpdated(const QString& id) +{ + //TODO only emit the affected indices + Q_EMIT dataChanged(index(0,0), index(m_notificationList.size() - 1, 0)); +} diff --git a/plugins/notifications/notification.h b/plugins/notifications/notification.h --- a/plugins/notifications/notification.h +++ b/plugins/notifications/notification.h @@ -60,17 +60,18 @@ void show(); bool silent() const { return m_silent; } void update(const NetworkPackage& np); + bool isReady() const { return m_ready; } KNotification* createKNotification(bool update, const NetworkPackage& np); public Q_SLOTS: Q_SCRIPTABLE void dismiss(); - Q_SCRIPTABLE void applyIconAndShow(); Q_SCRIPTABLE void reply(); void closed(); Q_SIGNALS: void dismissRequested(const QString& m_internalId); void replyRequested(); + void ready(); private: QString m_internalId; @@ -87,8 +88,12 @@ bool m_silent; bool m_closed; QString m_payloadHash; + bool m_ready; void parseNetworkPackage(const NetworkPackage& np); + void loadIcon(const NetworkPackage& np); + void applyIcon(); + void applyNoIcon(); }; #endif diff --git a/plugins/notifications/notification.cpp b/plugins/notifications/notification.cpp --- a/plugins/notifications/notification.cpp +++ b/plugins/notifications/notification.cpp @@ -19,6 +19,7 @@ */ #include "notification.h" +#include "notification_debug.h" #include #include @@ -36,6 +37,7 @@ m_imagesDir = QDir::temp().absoluteFilePath(QStringLiteral("kdeconnect")); m_imagesDir.mkpath(m_imagesDir.absolutePath()); m_closed = false; + m_ready = false; parseNetworkPackage(np); createKNotification(false, np); @@ -55,21 +57,14 @@ void Notification::show() { + m_ready = true; + Q_EMIT ready(); if (!m_silent) { m_closed = false; m_notification->sendEvent(); } } -void Notification::applyIconAndShow() -{ - if (!m_silent) { - QPixmap icon(m_iconPath, "PNG"); - m_notification->setPixmap(icon); - show(); - } -} - void Notification::update(const NetworkPackage& np) { parseNetworkPackage(np); @@ -101,26 +96,25 @@ m_notification->setText(escapedTitle+": "+escapedText); } + m_hasIcon = m_hasIcon && !m_payloadHash.isEmpty(); + if (!m_hasIcon) { - //HACK The only way to display no icon at all is trying to load a non-existant icon - m_notification->setIconName(QString("not_a_real_icon")); + applyNoIcon(); show(); } else { - QString filename = m_payloadHash; - if (filename.isEmpty()) { - m_hasIcon = false; + m_iconPath = m_imagesDir.absoluteFilePath(m_payloadHash); + + if (!QFile::exists(m_iconPath)) { + loadIcon(np); } else { - m_iconPath = m_imagesDir.absoluteFilePath(filename); - QUrl destinationUrl(m_iconPath); - FileTransferJob* job = np.createPayloadTransferJob(destinationUrl); - job->start(); - connect(job, &FileTransferJob::result, this, &Notification::applyIconAndShow); + applyIcon(); + show(); } } - if(!m_requestReplyId.isEmpty()) { - m_notification->setActions( QStringList(i18n("Reply")) ); + if (!m_requestReplyId.isEmpty()) { + m_notification->setActions(QStringList(i18n("Reply"))); connect(m_notification, &KNotification::action1Activated, this, &Notification::reply); } @@ -129,6 +123,36 @@ return m_notification; } +void Notification::loadIcon(const NetworkPackage& np) +{ + m_ready = false; + FileTransferJob* job = np.createPayloadTransferJob(QUrl::fromLocalFile(m_iconPath)); + job->start(); + + connect(job, &FileTransferJob::result, this, [this, job]{ + + if (job->error()) { + qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Error in FileTransferJob: " << job->errorString(); + applyNoIcon(); + } else { + applyIcon(); + } + show(); + }); +} + +void Notification::applyIcon() +{ + QPixmap icon(m_iconPath, "PNG"); + m_notification->setPixmap(icon); +} + +void Notification::applyNoIcon() +{ + //HACK The only way to display no icon at all is trying to load a non-existant icon + m_notification->setIconName(QString("not_a_real_icon")); +} + void Notification::reply() { Q_EMIT replyRequested(); diff --git a/plugins/notifications/notificationsdbusinterface.h b/plugins/notifications/notificationsdbusinterface.h --- a/plugins/notifications/notificationsdbusinterface.h +++ b/plugins/notifications/notificationsdbusinterface.h @@ -39,6 +39,7 @@ Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.notifications") public: + explicit NotificationsDbusInterface(KdeConnectPlugin* plugin); ~NotificationsDbusInterface() override; @@ -55,6 +56,7 @@ Q_SIGNALS: Q_SCRIPTABLE void notificationPosted(const QString& publicId); Q_SCRIPTABLE void notificationRemoved(const QString& publicId); + Q_SCRIPTABLE void notificationUpdated(const QString& publicId); Q_SCRIPTABLE void allNotificationsRemoved(); private /*methods*/: diff --git a/plugins/notifications/notificationsdbusinterface.cpp b/plugins/notifications/notificationsdbusinterface.cpp --- a/plugins/notifications/notificationsdbusinterface.cpp +++ b/plugins/notifications/notificationsdbusinterface.cpp @@ -82,11 +82,28 @@ if (!m_internalIdToPublicId.contains(id)) { Notification* noti = new Notification(np, this); - addNotification(noti); + + if (noti->isReady()) { + addNotification(noti); + } else { + connect(noti, &Notification::ready, this, [this, noti]{ + addNotification(noti); + }); + } } else { QString pubId = m_internalIdToPublicId[id]; - m_notifications[pubId]->update(np); + Notification* noti = m_notifications[pubId]; + noti->update(np); + + if (noti->isReady()) { + Q_EMIT notificationUpdated(pubId); + } else { + connect(noti, &Notification::ready, this, [this, pubId]{ + Q_EMIT notificationUpdated(pubId); + }); + } } + } } @@ -120,7 +137,7 @@ //qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "removeNotification" << internalId; if (!m_internalIdToPublicId.contains(internalId)) { - qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found noti by internal Id: " << internalId; + //qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found noti by internal Id: " << internalId; return; } @@ -128,12 +145,12 @@ Notification* noti = m_notifications.take(publicId); if (!noti) { - qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found noti by public Id: " << publicId; + //qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found noti by public Id: " << publicId; return; } //Deleting the notification will unregister it automatically - //QDBusConnection::sessionBus().unregisterObject(mDevice->dbusPath()+"/notifications/"+publicId); + //QDBusConnection::sessionBus().unregisterObject(mdevice->dbusPath()+"/notifications/"+publicId); noti->deleteLater(); Q_EMIT notificationRemoved(publicId);