diff options
Diffstat (limited to 'mail-overview/MailPanel.qml')
| -rw-r--r-- | mail-overview/MailPanel.qml | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/mail-overview/MailPanel.qml b/mail-overview/MailPanel.qml index 7457fb2..0a7f36a 100644 --- a/mail-overview/MailPanel.qml +++ b/mail-overview/MailPanel.qml @@ -10,6 +10,7 @@ // GNU General Public License for more details. import Quickshell +import Quickshell.Io import Quickshell.Wayland import QtQuick @@ -20,6 +21,45 @@ Scope { property string monitor: "DP-1" property bool open: false + // mail-watcher's heartbeat, written every 60s. Read once per open: the + // drawer is a LazyLoader, so closing and reopening rebuilds the FileView + // and reads the current file. Watch is deliberately not used, because the + // heartbeat is written by atomic replace (tmpfile + rename) and an inotify + // watch held on the old inode dies with it. + property bool watcherAlive: false + property int watcherDead: 0 + property int watcherExpected: 0 + + // The same staleness rule as mail-watcher's heartbeat_is_healthy: dead + // threads or a heartbeat older than 300s mean the watcher needs a look. + // Backoff is healthy, so it never turns the dot. + function readHeartbeat(payload) { + root.watcherAlive = false; + root.watcherDead = 0; + root.watcherExpected = 0; + + let data = null; + try { data = JSON.parse(payload); } catch (e) { return; } + if (!data || typeof data.ts !== "string") return; + + const ts = Date.parse(data.ts); + if (isNaN(ts) || (Date.now() - ts) / 1000 > 300) return; + + root.watcherAlive = true; + root.watcherDead = Number(data.dead) || 0; + root.watcherExpected = Number(data.expected) || 0; + } + + readonly property color watcherColor: + !watcherAlive ? Theme.red + : watcherDead > 0 ? Theme.yellow + : Theme.green + + readonly property string watcherText: + !watcherAlive ? "watcher not running" + : watcherDead > 0 ? `${watcherDead} folder(s) dead, check the log` + : `watcher ok · ${watcherExpected} folders` + readonly property var screenObj: Quickshell.screens.find(s => s.name === root.monitor) ?? Quickshell.screens[0] @@ -95,6 +135,13 @@ Scope { // the drawer. MouseArea { anchors.fill: parent } + FileView { + id: heartbeat + path: `${Quickshell.env("HOME")}/.local/state/mail-watcher.heartbeat` + onLoaded: root.readHeartbeat(text()) + onLoadFailed: root.readHeartbeat("") + } + Column { id: content anchors { left: parent.left; right: parent.right; top: parent.top; margins: 16 } @@ -230,17 +277,36 @@ Scope { Rectangle { width: parent.width; height: 1; color: Qt.alpha(Theme.text, 0.12) } + // Watcher health, above the button. Green when idling, + // yellow when a folder gave up, red when there is no fresh + // heartbeat at all. + Item { + width: parent.width + implicitHeight: 22 + + Rectangle { + id: watcherDot + anchors.verticalCenter: parent.verticalCenter + width: 8; height: 8; radius: 4 + color: root.watcherColor + } + + Text { + anchors { left: watcherDot.right; leftMargin: 10; verticalCenter: parent.verticalCenter } + text: root.watcherText + color: Theme.subtext + font.family: Theme.fontFamily + font.pixelSize: Theme.fontSize - 2 + } + } + + Rectangle { width: parent.width; height: 1; color: Qt.alpha(Theme.text, 0.12) } + Row { anchors.right: parent.right spacing: 10 Button { - text: Accounts.syncing ? "Syncing..." : "Sync now" - enabled: !Accounts.syncing - onClicked: Accounts.sync() - } - - Button { text: "Open qtmaildir" onClicked: { Accounts.openClient(); root.close(); } } |
