2013-08-20 13:05:22 +01:00
/**
2020-08-17 10:48:10 +01:00
* SPDX - FileCopyrightText : 2013 Albert Vaca < albertvaka @ gmail . com >
2013-08-20 12:55:03 +01:00
*
2020-08-17 10:48:10 +01:00
* SPDX - License - Identifier : GPL - 2.0 - only OR GPL - 3.0 - only OR LicenseRef - KDE - Accepted - GPL
2013-08-20 12:55:03 +01:00
*/
# include "notification.h"
2020-05-26 17:55:47 +01:00
# include "plugin_notification_debug.h"
2013-08-20 12:55:03 +01:00
2017-04-13 20:31:46 +01:00
# include <KNotification>
2021-03-08 20:25:47 +00:00
# include "knotifications_version.h"
# if KNOTIFICATIONS_VERSION >= QT_VERSION_CHECK(5, 81, 0)
# include <KNotificationReplyAction>
# endif
2019-02-08 22:47:41 +00:00
# include <QtGlobal>
2017-04-13 20:31:46 +01:00
# include <QIcon>
# include <QString>
# include <QUrl>
# include <QPixmap>
2017-05-31 14:33:21 +01:00
# include <KLocalizedString>
2017-12-29 17:38:09 +00:00
# include <QFile>
2019-06-02 15:03:11 +01:00
# include <knotifications_version.h>
2019-02-08 22:47:41 +00:00
# include <QJsonArray>
2017-04-13 20:31:46 +01:00
# include <core/filetransferjob.h>
2019-06-02 15:03:11 +01:00
# include <core/notificationserverinfo.h>
2017-04-13 20:31:46 +01:00
2018-03-24 19:39:39 +00:00
QMap < QString , FileTransferJob * > Notification : : s_downloadsInProgress ;
2017-04-13 20:31:46 +01:00
2019-06-02 15:03:11 +01:00
Notification : : Notification ( const NetworkPacket & np , const Device * device , QObject * parent )
2013-08-20 12:55:03 +01:00
: QObject ( parent )
2019-07-19 22:52:24 +01:00
, m_imagesDir ( )
2019-06-02 15:03:11 +01:00
, m_device ( device )
2013-08-20 12:55:03 +01:00
{
2019-12-22 07:49:55 +00:00
//Make a own directory for each user so no one can see each others icons
2017-12-29 17:38:09 +00:00
QString username ;
# ifdef Q_OS_WIN
2019-06-10 15:40:28 +01:00
username = QString : : fromLatin1 ( qgetenv ( " USERNAME " ) ) ;
2017-12-29 17:38:09 +00:00
# else
2019-06-10 15:40:28 +01:00
username = QString : : fromLatin1 ( qgetenv ( " USER " ) ) ;
2017-12-29 17:38:09 +00:00
# endif
2019-07-19 22:52:24 +01:00
m_imagesDir . setPath ( QDir : : temp ( ) . absoluteFilePath ( QStringLiteral ( " kdeconnect_ " ) + username ) ) ;
2017-09-03 20:39:44 +01:00
m_imagesDir . mkpath ( m_imagesDir . absolutePath ( ) ) ;
2017-12-29 17:38:09 +00:00
QFile ( m_imagesDir . absolutePath ( ) ) . setPermissions ( QFileDevice : : ReadOwner | QFileDevice : : WriteOwner | QFileDevice : : ExeOwner ) ;
2017-11-06 03:12:16 +00:00
m_ready = false ;
2017-04-13 20:31:46 +01:00
2018-03-04 19:48:51 +00:00
parseNetworkPacket ( np ) ;
2019-01-24 08:11:24 +00:00
createKNotification ( np ) ;
2019-04-14 18:20:25 +01:00
connect ( m_notification , QOverload < unsigned int > : : of ( & KNotification : : activated ) , this , [ this ] ( unsigned int actionIndex ) {
2021-03-08 20:25:47 +00:00
// Since 5.81 we use KNotification's inline reply instead of our own action
# if KNOTIFICATIONS_VERSION < QT_VERSION_CHECK(5, 81, 0)
2019-04-14 18:20:25 +01:00
// Do nothing for our own reply action
if ( ! m_requestReplyId . isEmpty ( ) & & actionIndex = = 1 ) {
return ;
}
2021-03-08 20:25:47 +00:00
# endif
2019-12-22 07:49:55 +00:00
// Notification action indices start at 1
2019-04-14 18:20:25 +01:00
Q_EMIT actionTriggered ( m_internalId , m_actions [ actionIndex - 1 ] ) ;
} ) ;
2013-08-20 12:55:03 +01:00
}
Notification : : ~ Notification ( )
{
}
void Notification : : dismiss ( )
{
2017-09-03 20:39:44 +01:00
if ( m_dismissable ) {
Q_EMIT dismissRequested ( m_internalId ) ;
2013-08-20 12:55:03 +01:00
}
}
2015-01-21 06:22:14 +00:00
2017-04-13 20:31:46 +01:00
void Notification : : show ( )
{
2017-11-06 03:12:16 +00:00
m_ready = true ;
Q_EMIT ready ( ) ;
2017-09-03 20:39:44 +01:00
if ( ! m_silent ) {
m_notification - > sendEvent ( ) ;
2017-04-13 20:31:46 +01:00
}
}
2018-03-04 19:48:51 +00:00
void Notification : : update ( const NetworkPacket & np )
2017-04-13 20:31:46 +01:00
{
2018-03-04 19:48:51 +00:00
parseNetworkPacket ( np ) ;
2019-01-24 08:11:24 +00:00
createKNotification ( np ) ;
2017-04-13 20:31:46 +01:00
}
2019-03-21 19:53:11 +00:00
void Notification : : createKNotification ( const NetworkPacket & np )
2017-04-13 20:31:46 +01:00
{
2019-01-24 08:11:24 +00:00
if ( ! m_notification ) {
2017-09-03 20:39:44 +01:00
m_notification = new KNotification ( QStringLiteral ( " notification " ) , KNotification : : CloseOnTimeout , this ) ;
m_notification - > setComponentName ( QStringLiteral ( " kdeconnect " ) ) ;
2021-03-17 22:42:50 +00:00
m_notification - > setHint ( QStringLiteral ( " resident " ) , true ) ; // This means the notification won't be deleted automatically, but only with KNotifications 5.81
2017-04-13 20:31:46 +01:00
}
2017-09-03 20:39:44 +01:00
QString escapedTitle = m_title . toHtmlEscaped ( ) ;
2021-02-02 12:54:16 +00:00
// notification title text does not have markup, but in some cases below it is used in body text so we escape it
2017-09-03 20:39:44 +01:00
QString escapedText = m_text . toHtmlEscaped ( ) ;
QString escapedTicker = m_ticker . toHtmlEscaped ( ) ;
2017-05-07 19:22:57 +01:00
2019-06-02 15:03:11 +01:00
if ( NotificationServerInfo : : instance ( ) . supportedHints ( ) . testFlag ( NotificationServerInfo : : X_KDE_DISPLAY_APPNAME ) ) {
2021-02-02 12:54:16 +00:00
m_notification - > setTitle ( m_title ) ;
2017-09-03 20:39:44 +01:00
m_notification - > setText ( escapedText ) ;
2019-06-02 15:03:11 +01:00
m_notification - > setHint ( QStringLiteral ( " x-kde-display-appname " ) , m_appName . toHtmlEscaped ( ) ) ;
2017-04-13 20:31:46 +01:00
} else {
2021-02-02 12:54:16 +00:00
m_notification - > setTitle ( m_appName ) ;
2019-06-02 15:03:11 +01:00
if ( m_title . isEmpty ( ) & & m_text . isEmpty ( ) ) {
m_notification - > setText ( escapedTicker ) ;
} else if ( m_appName = = m_title ) {
m_notification - > setText ( escapedText ) ;
} else if ( m_title . isEmpty ( ) ) {
m_notification - > setText ( escapedText ) ;
} else if ( m_text . isEmpty ( ) ) {
m_notification - > setText ( escapedTitle ) ;
} else {
2019-06-10 15:40:28 +01:00
m_notification - > setText ( escapedTitle + QStringLiteral ( " : " ) + escapedText ) ;
2019-06-02 15:03:11 +01:00
}
2017-04-13 20:31:46 +01:00
}
2019-06-02 15:03:11 +01:00
m_notification - > setHint ( QStringLiteral ( " x-kde-origin-name " ) , m_device - > name ( ) ) ;
2020-04-13 13:24:14 +01:00
if ( ! m_requestReplyId . isEmpty ( ) ) {
2021-03-08 20:25:47 +00:00
# if KNOTIFICATIONS_VERSION >= QT_VERSION_CHECK(5, 81, 0)
auto replyAction = std : : make_unique < KNotificationReplyAction > ( i18nc ( " @action:button " , " Reply " ) ) ;
replyAction - > setPlaceholderText ( i18nc ( " @info:placeholder " , " Reply to %1... " , m_appName ) ) ;
replyAction - > setFallbackBehavior ( KNotificationReplyAction : : FallbackBehavior : : UseRegularAction ) ;
QObject : : connect ( replyAction . get ( ) , & KNotificationReplyAction : : replied , this , & Notification : : replied ) ;
QObject : : connect ( replyAction . get ( ) , & KNotificationReplyAction : : activated , this , & Notification : : reply ) ;
m_notification - > setReplyAction ( std : : move ( replyAction ) ) ;
# else
2020-04-13 13:24:14 +01:00
m_actions . prepend ( i18n ( " Reply " ) ) ;
connect ( m_notification , & KNotification : : action1Activated , this , & Notification : : reply , Qt : : UniqueConnection ) ;
2021-03-08 20:25:47 +00:00
# endif
2020-04-13 13:24:14 +01:00
}
m_notification - > setActions ( m_actions ) ;
2017-11-06 03:12:16 +00:00
m_hasIcon = m_hasIcon & & ! m_payloadHash . isEmpty ( ) ;
2017-09-03 20:39:44 +01:00
if ( ! m_hasIcon ) {
2017-04-13 20:31:46 +01:00
show ( ) ;
} else {
2017-11-06 03:12:16 +00:00
m_iconPath = m_imagesDir . absoluteFilePath ( m_payloadHash ) ;
2018-03-24 19:39:39 +00:00
loadIcon ( np ) ;
2017-04-13 20:31:46 +01:00
}
}
2018-03-04 19:48:51 +00:00
void Notification : : loadIcon ( const NetworkPacket & np )
2017-11-06 03:12:16 +00:00
{
m_ready = false ;
2018-03-24 19:39:39 +00:00
if ( QFileInfo : : exists ( m_iconPath ) ) {
applyIcon ( ) ;
2017-11-06 03:12:16 +00:00
show ( ) ;
2018-03-24 19:39:39 +00:00
} else {
FileTransferJob * fileTransferJob = s_downloadsInProgress . value ( m_iconPath ) ;
if ( ! fileTransferJob ) {
fileTransferJob = np . createPayloadTransferJob ( QUrl : : fromLocalFile ( m_iconPath ) ) ;
fileTransferJob - > start ( ) ;
s_downloadsInProgress [ m_iconPath ] = fileTransferJob ;
}
connect ( fileTransferJob , & FileTransferJob : : result , this , [ this , fileTransferJob ] {
s_downloadsInProgress . remove ( m_iconPath ) ;
if ( fileTransferJob - > error ( ) ) {
qCDebug ( KDECONNECT_PLUGIN_NOTIFICATION ) < < " Error in FileTransferJob: " < < fileTransferJob - > errorString ( ) ;
} else {
applyIcon ( ) ;
}
show ( ) ;
} ) ;
}
2017-11-06 03:12:16 +00:00
}
void Notification : : applyIcon ( )
{
QPixmap icon ( m_iconPath , " PNG " ) ;
m_notification - > setPixmap ( icon ) ;
}
2017-06-01 15:17:37 +01:00
void Notification : : reply ( )
{
Q_EMIT replyRequested ( ) ;
}
2018-03-04 19:48:51 +00:00
void Notification : : parseNetworkPacket ( const NetworkPacket & np )
2017-04-13 20:31:46 +01:00
{
2017-09-03 20:39:44 +01:00
m_internalId = np . get < QString > ( QStringLiteral ( " id " ) ) ;
m_appName = np . get < QString > ( QStringLiteral ( " appName " ) ) ;
m_ticker = np . get < QString > ( QStringLiteral ( " ticker " ) ) ;
m_title = np . get < QString > ( QStringLiteral ( " title " ) ) ;
m_text = np . get < QString > ( QStringLiteral ( " text " ) ) ;
m_dismissable = np . get < bool > ( QStringLiteral ( " isClearable " ) ) ;
m_hasIcon = np . hasPayload ( ) ;
m_silent = np . get < bool > ( QStringLiteral ( " silent " ) ) ;
m_payloadHash = np . get < QString > ( QStringLiteral ( " payloadHash " ) ) ;
m_requestReplyId = np . get < QString > ( QStringLiteral ( " requestReplyId " ) , QString ( ) ) ;
2019-02-08 22:47:41 +00:00
m_actions . clear ( ) ;
2019-02-28 13:04:15 +00:00
const auto actions = np . get < QJsonArray > ( QStringLiteral ( " actions " ) ) ;
for ( const QJsonValue & value : actions ) {
2019-02-08 22:47:41 +00:00
m_actions . append ( value . toString ( ) ) ;
}
2017-04-13 20:31:46 +01:00
}