249 lines
6.8 KiB
C++
249 lines
6.8 KiB
C++
#pragma once
|
|
|
|
#include <QDateTime>
|
|
#include <QHash>
|
|
#include <QJSValue>
|
|
#include <QList>
|
|
#include <QObject>
|
|
#include <QPointer>
|
|
#include <qqmlintegration.h>
|
|
#include <QQmlListProperty>
|
|
#include <QSet>
|
|
#include <QString>
|
|
#include <QTimer>
|
|
|
|
namespace ZShell::config {
|
|
class Notifs;
|
|
}
|
|
|
|
namespace ZShell::Services {
|
|
|
|
class NotificationStore;
|
|
class NotifImageProvider;
|
|
|
|
class NotificationActionRow : public QObject {
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
QML_UNCREATABLE(
|
|
"NotificationActionRow instances come from a NotificationStore")
|
|
|
|
Q_PROPERTY(bool invokable READ invokable NOTIFY invokableChanged)
|
|
Q_PROPERTY(QString identifier READ identifier CONSTANT)
|
|
Q_PROPERTY(QString text READ text CONSTANT)
|
|
|
|
public:
|
|
NotificationActionRow(
|
|
QObject* action,
|
|
const QString& identifier,
|
|
const QString& text,
|
|
QObject* parent = nullptr);
|
|
|
|
[[nodiscard]] bool invokable() const;
|
|
[[nodiscard]] QString identifier() const;
|
|
[[nodiscard]] QString text() const;
|
|
|
|
Q_INVOKABLE void invoke();
|
|
|
|
signals:
|
|
void invokableChanged();
|
|
|
|
private:
|
|
QPointer<QObject> m_action;
|
|
QString m_identifier;
|
|
QString m_text;
|
|
};
|
|
|
|
class NotificationRow : public QObject {
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
QML_UNCREATABLE("NotificationRow instances come from a NotificationStore")
|
|
|
|
Q_PROPERTY(QQmlListProperty<NotificationActionRow> actions READ actions NOTIFY actionsChanged)
|
|
Q_PROPERTY(QString appIcon READ appIcon NOTIFY appIconChanged)
|
|
Q_PROPERTY(QString appName READ appName NOTIFY appNameChanged)
|
|
Q_PROPERTY(QString body READ body NOTIFY bodyChanged)
|
|
Q_PROPERTY(bool closed READ closed NOTIFY closedChanged)
|
|
Q_PROPERTY(bool hasActionIcons READ hasActionIcons NOTIFY hasActionIconsChanged)
|
|
Q_PROPERTY(QString image READ image NOTIFY imageChanged)
|
|
Q_PROPERTY(QString imageSource READ imageSource NOTIFY imageSourceChanged)
|
|
Q_PROPERTY(int notificationId READ notificationId CONSTANT)
|
|
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
|
Q_PROPERTY(bool popup READ popup WRITE setPopup NOTIFY popupChanged)
|
|
Q_PROPERTY(bool resident READ resident NOTIFY residentChanged)
|
|
Q_PROPERTY(QString summary READ summary NOTIFY summaryChanged)
|
|
Q_PROPERTY(QDateTime time READ time CONSTANT)
|
|
Q_PROPERTY(QString timeStr READ timeStr NOTIFY timeStrChanged)
|
|
Q_PROPERTY(int urgency READ urgency NOTIFY urgencyChanged)
|
|
|
|
public:
|
|
explicit NotificationRow(QObject* parent = nullptr);
|
|
|
|
[[nodiscard]] QQmlListProperty<NotificationActionRow> actions();
|
|
[[nodiscard]] QString appIcon() const;
|
|
[[nodiscard]] QString appName() const;
|
|
[[nodiscard]] QString body() const;
|
|
[[nodiscard]] bool closed() const;
|
|
[[nodiscard]] bool hasActionIcons() const;
|
|
[[nodiscard]] QString image() const;
|
|
[[nodiscard]] QString imageSource() const;
|
|
[[nodiscard]] int notificationId() const;
|
|
[[nodiscard]] int progress() const;
|
|
[[nodiscard]] bool popup() const;
|
|
void setPopup(bool popup);
|
|
[[nodiscard]] bool resident() const;
|
|
[[nodiscard]] QString summary() const;
|
|
[[nodiscard]] QDateTime time() const;
|
|
[[nodiscard]] QString timeStr() const;
|
|
[[nodiscard]] int urgency() const;
|
|
|
|
Q_INVOKABLE void close();
|
|
Q_INVOKABLE void lock(QObject* item);
|
|
Q_INVOKABLE void pausePopup();
|
|
Q_INVOKABLE void resumePopup();
|
|
Q_INVOKABLE void unlock(QObject* item);
|
|
|
|
signals:
|
|
void actionsChanged();
|
|
void appIconChanged();
|
|
void appNameChanged();
|
|
void bodyChanged();
|
|
void closedChanged();
|
|
void hasActionIconsChanged();
|
|
void imageChanged();
|
|
void imageSourceChanged();
|
|
void popupChanged();
|
|
void progressChanged();
|
|
void residentChanged();
|
|
void summaryChanged();
|
|
void timeStrChanged();
|
|
void urgencyChanged();
|
|
|
|
private:
|
|
friend NotificationStore;
|
|
|
|
[[nodiscard]] bool expired(qint64 now) const;
|
|
void refreshTimeStr();
|
|
|
|
QList<NotificationActionRow*> m_actions;
|
|
NotificationStore* m_store = nullptr;
|
|
|
|
QString m_appIcon;
|
|
QString m_appName;
|
|
QString m_body;
|
|
QString m_digest;
|
|
QString m_image;
|
|
QString m_imageSource;
|
|
QString m_summary;
|
|
QString m_timeStr;
|
|
|
|
qint64 m_deadline = 0;
|
|
qint64 m_rowId = -1;
|
|
qint64 m_timeMs = 0;
|
|
|
|
QPointer<QObject> m_notification;
|
|
QSet<QObject*> m_locks;
|
|
QJSValue m_jsNotification;
|
|
|
|
bool m_closed = false;
|
|
bool m_hasActionIcons = false;
|
|
bool m_liveConnected = false;
|
|
bool m_popup = false;
|
|
bool m_popupPaused = false;
|
|
bool m_resident = false;
|
|
|
|
int m_notificationId = 0;
|
|
int m_progress = 0;
|
|
int m_urgency = 1;
|
|
};
|
|
|
|
class NotificationStore : public QObject {
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
|
|
Q_PROPERTY(bool autoExpire READ autoExpire WRITE setAutoExpire NOTIFY autoExpireChanged)
|
|
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REQUIRED)
|
|
Q_PROPERTY(int popupTimeout READ popupTimeout WRITE setPopupTimeout NOTIFY
|
|
popupTimeoutChanged)
|
|
Q_PROPERTY(QQmlListProperty<NotificationRow> rows READ rows NOTIFY rowsChanged)
|
|
|
|
public:
|
|
explicit NotificationStore(QObject* parent = nullptr);
|
|
~NotificationStore() override;
|
|
|
|
[[nodiscard]] QString path() const;
|
|
void setPath(const QString& path);
|
|
|
|
[[nodiscard]] bool autoExpire() const;
|
|
void setAutoExpire(bool autoExpire);
|
|
|
|
[[nodiscard]] int popupTimeout() const;
|
|
void setPopupTimeout(int timeout);
|
|
|
|
[[nodiscard]] QQmlListProperty<NotificationRow> rows();
|
|
|
|
Q_INVOKABLE NotificationRow* insert(const QJSValue& notification, bool popup);
|
|
Q_INVOKABLE void clear();
|
|
|
|
signals:
|
|
void autoExpireChanged();
|
|
void pathChanged();
|
|
void popupTimeoutChanged();
|
|
void rowsChanged();
|
|
|
|
private slots:
|
|
void handleLiveUpdate();
|
|
|
|
private:
|
|
friend NotificationRow;
|
|
|
|
void attachNotification(
|
|
NotificationRow* row, QObject* notification, const QJSValue& js);
|
|
void applyNotifConfig(const config::Notifs* notifs);
|
|
void closeDb();
|
|
void copyFields(NotificationRow* row, QObject* notification);
|
|
void handleClosed(NotificationRow* row);
|
|
void insertDbRow(NotificationRow* row);
|
|
void loadRows();
|
|
void migrateLegacyJson();
|
|
[[nodiscard]] bool openDb();
|
|
void orphanCleanup();
|
|
void persistPopup(const NotificationRow* row);
|
|
void prune();
|
|
void registerProvider();
|
|
void removeRow(NotificationRow* row);
|
|
// Coalesced rowsChanged: a burst of inserts/removes triggers one QML
|
|
// rebind on the next event loop turn instead of one per notification.
|
|
void scheduleRowsChanged();
|
|
[[nodiscard]] NotificationRow* rowForNotificationId(int id) const;
|
|
void startImageCache(NotificationRow* row);
|
|
void storeImageBlob(
|
|
const QPointer<NotificationRow>& row,
|
|
const QString& digest,
|
|
const QByteArray& png);
|
|
void tick();
|
|
void trimRows();
|
|
void updateDbRow(NotificationRow* row);
|
|
|
|
static QList<NotificationActionRow*> parseActions(
|
|
const QJSValue& actions, NotificationRow* row);
|
|
|
|
int m_popupTimeout = 5000;
|
|
|
|
qint64 m_nextPrune = 0;
|
|
qint64 m_nextTimeStrRefresh = 0;
|
|
bool m_autoExpire = true;
|
|
bool m_clearing = false;
|
|
bool m_rowsSignalPending = false;
|
|
|
|
QString m_uuid;
|
|
QString m_path;
|
|
|
|
QList<NotificationRow*> m_rows;
|
|
QHash<QObject*, NotificationRow*> m_liveRows;
|
|
|
|
NotifImageProvider* m_provider = nullptr;
|
|
QTimer* m_tick = nullptr;
|
|
};
|
|
|
|
} // namespace ZShell::Services
|