#pragma once #include #include #include #include #include #include #include #include #include "../../core/retainable.hpp" #include "../../core/util.hpp" #include "dbusimage.hpp" namespace qs::service::notifications { ///! The urgency level of a Notification. /// See @@Notification.urgency. class NotificationUrgency: public QObject { Q_OBJECT; QML_ELEMENT; QML_SINGLETON; public: enum Enum : quint8 { Low = 0, Normal = 1, Critical = 2, }; Q_ENUM(Enum); Q_INVOKABLE static QString toString(qs::service::notifications::NotificationUrgency::Enum value); }; ///! The reason a Notification was closed. /// See @@Notification.closed(s). class NotificationCloseReason: public QObject { Q_OBJECT; QML_ELEMENT; QML_SINGLETON; public: enum Enum : quint8 { /// The notification expired due to a timeout. Expired = 1, /// The notification was explicitly dismissed by the user. Dismissed = 2, /// The remote application requested the notification be removed. CloseRequested = 3, }; Q_ENUM(Enum); Q_INVOKABLE static QString toString(qs::service::notifications::NotificationCloseReason::Enum value); }; class NotificationAction; ///! A notification emitted by a NotificationServer. /// A notification emitted by a NotificationServer. /// /// > [!INFO] This type is @@Quickshell.Retainable. It /// > can be retained after destruction if necessary. class Notification : public QObject , public Retainable { Q_OBJECT; // clang-format off /// Id of the notification as given to the client. Q_PROPERTY(quint32 id READ id CONSTANT); /// If the notification is tracked by the notification server. /// /// Setting this property to false is equivalent to calling @@dismiss(). Q_PROPERTY(bool tracked READ isTracked WRITE setTracked NOTIFY trackedChanged); /// If this notification was carried over from the last generation /// when quickshell reloaded. /// /// Notifications from the last generation will only be emitted /// if @@NotificationServer.keepOnReload is true. Q_PROPERTY(bool lastGeneration READ isLastGeneration CONSTANT); /// Time in seconds the notification should be valid for Q_PROPERTY(qreal expireTimeout READ expireTimeout NOTIFY expireTimeoutChanged BINDABLE bindableExpireTimeout); /// The sending application's name. Q_PROPERTY(QString appName READ appName NOTIFY appNameChanged BINDABLE bindableAppName); /// The sending application's icon. If none was provided, then the icon from an associated /// desktop entry will be retrieved. If none was found then "". Q_PROPERTY(QString appIcon READ appIcon NOTIFY appIconChanged BINDABLE bindableAppIcon); /// The image associated with this notification, or "" if none. Q_PROPERTY(QString summary READ summary NOTIFY summaryChanged BINDABLE bindableSummary); Q_PROPERTY(QString body READ body NOTIFY bodyChanged BINDABLE bindableBody); Q_PROPERTY(qs::service::notifications::NotificationUrgency::Enum urgency READ urgency NOTIFY urgencyChanged BINDABLE bindableUrgency); /// Actions that can be taken for this notification. Q_PROPERTY(QList actions READ actions NOTIFY actionsChanged); /// If actions associated with this notification have icons available. /// /// See @@NotificationAction.identifier for details. Q_PROPERTY(bool hasActionIcons READ hasActionIcons NOTIFY hasActionIconsChanged); /// If true, the notification will not be destroyed after an action is invoked. Q_PROPERTY(bool resident READ resident NOTIFY residentChanged); /// If true, the notification should skip any kind of persistence function like a notification area. Q_PROPERTY(bool transient READ transient NOTIFY transientChanged); /// The name of the sender's desktop entry or "" if none was supplied. Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged); /// An image associated with the notification. /// /// This image is often something like a profile picture in instant messaging applications. Q_PROPERTY(QString image READ image NOTIFY imageChanged); /// All hints sent by the client application as a javascript object. /// Many common hints are exposed via other properties. Q_PROPERTY(QVariantMap hints READ hints NOTIFY hintsChanged); // clang-format on QML_ELEMENT; QML_UNCREATABLE("Notifications must be acquired from a NotificationServer"); public: explicit Notification(quint32 id, QObject* parent): QObject(parent), mId(id) {} /// Destroy the notification and hint to the remote application that it has /// timed out an expired. Q_INVOKABLE void expire(); /// Destroy the notification and hint to the remote application that it was /// explicitly closed by the user. Q_INVOKABLE void dismiss(); void updateProperties( const QString& appName, QString appIcon, const QString& summary, const QString& body, const QStringList& actions, QVariantMap hints, qint32 expireTimeout ); void close(NotificationCloseReason::Enum reason); [[nodiscard]] quint32 id() const; [[nodiscard]] bool isTracked() const; [[nodiscard]] bool isLastGeneration() const; void setLastGeneration(); QS_BINDABLE_GETTER(qreal, bExpireTimeout, expireTimeout, bindableExpireTimeout); QS_BINDABLE_GETTER(QString, bAppName, appName, bindableAppName); QS_BINDABLE_GETTER(QString, bAppIcon, appIcon, bindableAppIcon); QS_BINDABLE_GETTER(QString, bSummary, summary, bindableSummary); QS_BINDABLE_GETTER(QString, bBody, body, bindableBody); QS_BINDABLE_GETTER(NotificationUrgency::Enum, bUrgency, urgency, bindableUrgency); [[nodiscard]] QList actions() const; QS_BINDABLE_GETTER(bool, bHasActionIcons, hasActionIcons, bindableHasActionIcons); QS_BINDABLE_GETTER(bool, bResident, resident, bindableResident); QS_BINDABLE_GETTER(bool, bTransient, transient, bindableTransient); QS_BINDABLE_GETTER(QString, bDesktopEntry, desktopEntry, bindableDesktopEntry); QS_BINDABLE_GETTER(QString, bImage, image, bindableImage); QS_BINDABLE_GETTER(QVariantMap, bHints, hints, bindableHints); [[nodiscard]] NotificationCloseReason::Enum closeReason() const; void setTracked(bool tracked); signals: /// Sent when a notification has been closed. /// /// The notification object will be destroyed as soon as all signal handlers exit. void closed(qs::service::notifications::NotificationCloseReason::Enum reason); void trackedChanged(); void expireTimeoutChanged(); void appNameChanged(); void appIconChanged(); void summaryChanged(); void bodyChanged(); void urgencyChanged(); void actionsChanged(); void hasActionIconsChanged(); void residentChanged(); void transientChanged(); void desktopEntryChanged(); void imageChanged(); void hintsChanged(); private: quint32 mId; NotificationCloseReason::Enum mCloseReason = NotificationCloseReason::Dismissed; bool mLastGeneration = false; NotificationImage mImagePixmap; QList mActions; // clang-format off Q_OBJECT_BINDABLE_PROPERTY(Notification, qreal, bExpireTimeout, &Notification::expireTimeoutChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bAppName, &Notification::appNameChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bAppIcon, &Notification::appIconChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bSummary, &Notification::summaryChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bBody, &Notification::bodyChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bHasActionIcons, &Notification::hasActionIconsChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bResident, &Notification::residentChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bTransient, &Notification::transientChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bDesktopEntry, &Notification::desktopEntryChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bImage, &Notification::imageChanged); Q_OBJECT_BINDABLE_PROPERTY(Notification, QVariantMap, bHints, &Notification::hintsChanged); // clang-format on Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS( Notification, NotificationUrgency::Enum, bUrgency, NotificationUrgency::Normal, &Notification::urgencyChanged ); }; ///! An action associated with a Notification. /// See @@Notification.actions. class NotificationAction: public QObject { Q_OBJECT; /// The identifier of the action. /// /// When @@Notification.hasActionIcons is true, this property will be an icon name. /// When it is false, this property is irrelevant. Q_PROPERTY(QString identifier READ identifier CONSTANT); /// The localized text that should be displayed on a button. Q_PROPERTY(QString text READ text NOTIFY textChanged); QML_ELEMENT; QML_UNCREATABLE("NotificationActions must be acquired from a Notification"); public: explicit NotificationAction(QString identifier, QString text, Notification* notification) : QObject(notification) , notification(notification) , mIdentifier(std::move(identifier)) , mText(std::move(text)) {} /// Invoke the action. If @@Notification.resident is false it will be dismissed. Q_INVOKABLE void invoke(); [[nodiscard]] QString identifier() const; [[nodiscard]] QString text() const; void setText(const QString& text); signals: void textChanged(); private: Notification* notification; QString mIdentifier; QString mText; }; } // namespace qs::service::notifications