feat: better notification storage and image caching + blobs
C++ / fmt (pull_request) Failing after 5s
C++ / build (pull_request) Failing after 11s
C++ / clang-tidy (pull_request) Failing after 10s
JS/TS / fmt (pull_request) Successful in 12s
JS/TS / lint (pull_request) Successful in 10s
Python / static (pull_request) Failing after 27s
Rust / build (pull_request) Successful in 54s
Python / verify (pull_request) Failing after 1m26s
Rust / fmt (pull_request) Successful in 46s
Rust / clippy (pull_request) Successful in 1m6s
C++ / fmt (pull_request) Failing after 5s
C++ / build (pull_request) Failing after 11s
C++ / clang-tidy (pull_request) Failing after 10s
JS/TS / fmt (pull_request) Successful in 12s
JS/TS / lint (pull_request) Successful in 10s
Python / static (pull_request) Failing after 27s
Rust / build (pull_request) Successful in 54s
Python / verify (pull_request) Failing after 1m26s
Rust / fmt (pull_request) Successful in 46s
Rust / clippy (pull_request) Successful in 1m6s
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ class Notifs;
|
||||
|
||||
namespace ZShell::Services {
|
||||
|
||||
class NotificationGroup;
|
||||
class NotificationStore;
|
||||
class NotifImageProvider;
|
||||
|
||||
@@ -58,12 +59,15 @@ class NotificationRow : public QObject {
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("NotificationRow instances come from a NotificationStore")
|
||||
|
||||
Q_PROPERTY(QQmlListProperty<NotificationActionRow> actions READ actions NOTIFY actionsChanged)
|
||||
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(
|
||||
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)
|
||||
@@ -97,9 +101,17 @@ class NotificationRow : public QObject {
|
||||
[[nodiscard]] int urgency() const;
|
||||
|
||||
Q_INVOKABLE void close();
|
||||
Q_INVOKABLE void dismiss();
|
||||
Q_INVOKABLE void dismissPopup();
|
||||
Q_INVOKABLE void holdPopup();
|
||||
Q_INVOKABLE bool isSameAppIcon(const QString& path) const;
|
||||
Q_INVOKABLE bool isSameImage(const QString& path) const;
|
||||
Q_INVOKABLE void lock(QObject* item);
|
||||
Q_INVOKABLE void pausePopup();
|
||||
Q_INVOKABLE void ref(QObject* item);
|
||||
Q_INVOKABLE void releasePopup();
|
||||
Q_INVOKABLE void resumePopup();
|
||||
Q_INVOKABLE void unref(QObject* item);
|
||||
Q_INVOKABLE void unlock(QObject* item);
|
||||
|
||||
signals:
|
||||
@@ -119,12 +131,15 @@ class NotificationRow : public QObject {
|
||||
void urgencyChanged();
|
||||
|
||||
private:
|
||||
friend class NotificationGroup;
|
||||
friend NotificationStore;
|
||||
|
||||
[[nodiscard]] bool expired(qint64 now) const;
|
||||
void refreshTimeStr();
|
||||
|
||||
QList<NotificationActionRow*> m_actions;
|
||||
NotificationGroup* m_group = nullptr;
|
||||
NotificationGroup* m_popupGroup = nullptr;
|
||||
NotificationStore* m_store = nullptr;
|
||||
|
||||
QString m_appIcon;
|
||||
@@ -144,6 +159,10 @@ class NotificationRow : public QObject {
|
||||
QSet<QObject*> m_locks;
|
||||
QJSValue m_jsNotification;
|
||||
|
||||
// The store has already dropped this row from its lists, but a delegate is
|
||||
// still animating it out; the delete waits for the last unlock.
|
||||
bool m_deleteAfterUnlock = false;
|
||||
|
||||
bool m_closed = false;
|
||||
bool m_hasActionIcons = false;
|
||||
bool m_liveConnected = false;
|
||||
@@ -156,15 +175,100 @@ class NotificationRow : public QObject {
|
||||
int m_urgency = 1;
|
||||
};
|
||||
|
||||
class NotificationGroup : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("NotificationGroup instances come from a NotificationStore")
|
||||
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<NotificationRow> activeNotifs READ activeNotifs NOTIFY
|
||||
activeNotifsChanged)
|
||||
Q_PROPERTY(QString appIcon READ appIcon NOTIFY appIconChanged)
|
||||
Q_PROPERTY(QString appName READ appName CONSTANT)
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(QString firstSummary READ firstSummary NOTIFY firstSummaryChanged)
|
||||
Q_PROPERTY(QString image READ image NOTIFY imageChanged)
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<NotificationRow> notifs READ notifs NOTIFY
|
||||
notifsChanged)
|
||||
Q_PROPERTY(QString timeStr READ timeStr NOTIFY timeStrChanged)
|
||||
Q_PROPERTY(int urgency READ urgency NOTIFY urgencyChanged)
|
||||
|
||||
public:
|
||||
NotificationGroup(const QString& appName, QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] QQmlListProperty<NotificationRow> activeNotifs();
|
||||
[[nodiscard]] QString appIcon() const;
|
||||
[[nodiscard]] QString appName() const;
|
||||
[[nodiscard]] int count() const;
|
||||
[[nodiscard]] QString firstSummary() const;
|
||||
[[nodiscard]] QString image() const;
|
||||
[[nodiscard]] QQmlListProperty<NotificationRow> notifs();
|
||||
[[nodiscard]] QString timeStr() const;
|
||||
[[nodiscard]] int urgency() const;
|
||||
|
||||
Q_INVOKABLE bool isSameAppIcon(const QString& path) const;
|
||||
Q_INVOKABLE bool isSameImage(const QString& path) const;
|
||||
Q_INVOKABLE void lock(QObject* item);
|
||||
Q_INVOKABLE void unlock(QObject* item);
|
||||
|
||||
signals:
|
||||
void activeNotifsChanged();
|
||||
void appIconChanged();
|
||||
void countChanged();
|
||||
void firstSummaryChanged();
|
||||
void imageChanged();
|
||||
void notifsChanged();
|
||||
void timeStrChanged();
|
||||
void urgencyChanged();
|
||||
|
||||
private:
|
||||
friend NotificationStore;
|
||||
|
||||
void addRow(NotificationRow* row);
|
||||
void refreshActive();
|
||||
void release();
|
||||
void removeRow(NotificationRow* row);
|
||||
void sync();
|
||||
|
||||
QList<NotificationRow*> m_active;
|
||||
QList<NotificationRow*> m_notifs;
|
||||
|
||||
// The group reads image/appIcon through the row it took them from, so a
|
||||
// row swapping between its raw source and the cached blob keeps the card
|
||||
// in sync instead of holding a stale copy.
|
||||
QPointer<NotificationRow> m_iconSource;
|
||||
QPointer<NotificationRow> m_imageSource;
|
||||
QSet<QObject*> m_locks;
|
||||
|
||||
QString m_appName;
|
||||
QString m_firstSummary;
|
||||
QString m_timeStr;
|
||||
|
||||
int m_count = 0;
|
||||
int m_urgency = 1;
|
||||
bool m_releasing = false;
|
||||
};
|
||||
|
||||
class NotificationStore : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(bool autoExpire READ autoExpire WRITE setAutoExpire NOTIFY autoExpireChanged)
|
||||
Q_PROPERTY(
|
||||
bool autoExpire READ autoExpire WRITE setAutoExpire NOTIFY
|
||||
autoExpireChanged)
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<NotificationGroup> groups READ groups NOTIFY
|
||||
groupsChanged)
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<NotificationGroup> popupGroups READ popupGroups NOTIFY
|
||||
popupGroupsChanged)
|
||||
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)
|
||||
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);
|
||||
@@ -176,17 +280,23 @@ class NotificationStore : public QObject {
|
||||
[[nodiscard]] bool autoExpire() const;
|
||||
void setAutoExpire(bool autoExpire);
|
||||
|
||||
[[nodiscard]] QQmlListProperty<NotificationGroup> groups();
|
||||
[[nodiscard]] QQmlListProperty<NotificationGroup> popupGroups();
|
||||
|
||||
[[nodiscard]] int popupTimeout() const;
|
||||
void setPopupTimeout(int timeout);
|
||||
|
||||
[[nodiscard]] QQmlListProperty<NotificationRow> rows();
|
||||
|
||||
Q_INVOKABLE NotificationRow* insert(const QJSValue& notification, bool popup);
|
||||
Q_INVOKABLE NotificationRow* insert(
|
||||
const QJSValue& notification, bool popup);
|
||||
Q_INVOKABLE void clear();
|
||||
|
||||
signals:
|
||||
void autoExpireChanged();
|
||||
void groupsChanged();
|
||||
void pathChanged();
|
||||
void popupGroupsChanged();
|
||||
void popupTimeoutChanged();
|
||||
void rowsChanged();
|
||||
|
||||
@@ -198,18 +308,24 @@ class NotificationStore : public QObject {
|
||||
|
||||
void attachNotification(
|
||||
NotificationRow* row, QObject* notification, const QJSValue& js);
|
||||
void addGroup(NotificationRow* row);
|
||||
void applyNotifConfig(const config::Notifs* notifs);
|
||||
void closeDb();
|
||||
void copyFields(NotificationRow* row, QObject* notification);
|
||||
void flush();
|
||||
void handleClosed(NotificationRow* row);
|
||||
void insertDbRow(NotificationRow* row);
|
||||
void loadRows();
|
||||
void markDirty(NotificationRow* row);
|
||||
void migrateLegacyJson();
|
||||
[[nodiscard]] bool openDb();
|
||||
void orphanCleanup();
|
||||
void persistPopup(const NotificationRow* row);
|
||||
void prune();
|
||||
void addPopupGroup(NotificationRow* row);
|
||||
void removePopupGroupRow(NotificationRow* row);
|
||||
void updatePopupGroup(NotificationRow* row);
|
||||
void registerProvider();
|
||||
void removeGroupRow(NotificationRow* row);
|
||||
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.
|
||||
@@ -238,10 +354,16 @@ class NotificationStore : public QObject {
|
||||
QString m_uuid;
|
||||
QString m_path;
|
||||
|
||||
QList<NotificationGroup*> m_groups;
|
||||
QList<NotificationGroup*> m_popupGroups;
|
||||
QList<NotificationRow*> m_rows;
|
||||
QHash<QObject*, NotificationRow*> m_liveRows;
|
||||
QHash<QString, NotificationGroup*> m_groupsByName;
|
||||
QHash<QString, NotificationGroup*> m_popupGroupsByName;
|
||||
QSet<NotificationRow*> m_dirty;
|
||||
|
||||
NotifImageProvider* m_provider = nullptr;
|
||||
QTimer* m_flush = nullptr;
|
||||
QTimer* m_tick = nullptr;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user