#pragma once #include #include #include #include #include #include #include "../../core/retainable.hpp" #include "../../core/util.hpp" namespace qs::service::notifications { class NotificationImage; ///! The urgency level of a Notification. /// See @@Notification.urgency. class NotificationUrgency: public QObject { Q_OBJECT; QML_ELEMENT; QML_SINGLETON; public: enum Enum { Low = 0, Normal = 1, Critical = 2, }; Q_ENUM(Enum); Q_INVOKABLE static QString toString(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 { /// 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(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; /// 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); /// The sending application's name. Q_PROPERTY(QString appName READ appName NOTIFY appNameChanged); /// 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); /// The image associated with this notification, or "" if none. Q_PROPERTY(QString summary READ summary NOTIFY summaryChanged); Q_PROPERTY(QString body READ body NOTIFY bodyChanged); Q_PROPERTY(NotificationUrgency::Enum urgency READ urgency NOTIFY urgencyChanged); /// Actions that can be taken for this notification. Q_PROPERTY(QVector 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); 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]] NotificationCloseReason::Enum closeReason() const; void setTracked(bool tracked); [[nodiscard]] bool isLastGeneration() const; void setLastGeneration(); [[nodiscard]] QString image() const; signals: /// Sent when a notification has been closed. /// /// The notification object will be destroyed as soon as all signal handlers exit. void closed(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; qreal mExpireTimeout = 0; QString mAppName; QString mAppIcon; QString mSummary; QString mBody; NotificationUrgency::Enum mUrgency = NotificationUrgency::Normal; QVector mActions; bool mHasActionIcons = false; bool mResident = false; bool mTransient = false; QString mImagePath; NotificationImage* mImagePixmap = nullptr; QString mDesktopEntry; QVariantMap mHints; // clang-format off DECLARE_PRIVATE_MEMBER(Notification, expireTimeout, setExpireTimeout, mExpireTimeout, expireTimeoutChanged); DECLARE_PRIVATE_MEMBER(Notification, appName, setAppName, mAppName, appNameChanged); DECLARE_PRIVATE_MEMBER(Notification, appIcon, setAppIcon, mAppIcon, appIconChanged); DECLARE_PRIVATE_MEMBER(Notification, summary, setSummary, mSummary, summaryChanged); DECLARE_PRIVATE_MEMBER(Notification, body, setBody, mBody, bodyChanged); DECLARE_PRIVATE_MEMBER(Notification, urgency, setUrgency, mUrgency, urgencyChanged); DECLARE_MEMBER_WITH_GET(Notification, actions, mActions, actionsChanged); DECLARE_PRIVATE_MEMBER(Notification, hasActionIcons, setHasActionIcons, mHasActionIcons, hasActionIconsChanged); DECLARE_PRIVATE_MEMBER(Notification, resident, setResident, mResident, residentChanged); DECLARE_PRIVATE_MEMBER(Notification, transient, setTransient, mTransient, transientChanged); DECLARE_PRIVATE_MEMBER(Notification, desktopEntry, setDesktopEntry, mDesktopEntry, desktopEntryChanged); DECLARE_PRIVATE_MEMBER(Notification, hints, setHints, mHints, hintsChanged); // clang-format on }; ///! 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