mirror of
https://git.pumpin.online/funkpower/menologion.git
synced 2026-10-22 18:57:14 +00:00
Nobody installs a desktop widget they have not seen. Three shots go in the README -- the Nativity Fast, where the week runs through three fasting levels; ROCOR on 7 January, where the corner reads 25 December and makes the old-calendar point in one glance; and Great Week, which uses nearly every level there is. shot.qml renders the real widget on a plain backdrop at a fixed position on the overlay layer, so a screen grab of that rectangle is the widget and never whatever was behind it. Typikon gains a forDate property, which is what lets a screenshot show Great Week in September, and is worth having anyway for looking ahead. The header note now always carries the church date instead of repeating the season the line below it already gives.
95 lines
3.6 KiB
QML
95 lines
3.6 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
|
|
// The liturgical day, from the `typikon` command.
|
|
//
|
|
// Computed locally, so this needs no network and cannot go stale. It only has
|
|
// to be re-read when the date changes, which a clock at minute precision
|
|
// notices without polling a subprocess every few seconds.
|
|
Singleton {
|
|
id: root
|
|
|
|
// Set this to a jurisdiction key — "rocor", "antiochian", "oca" — or leave
|
|
// it empty to use whatever `typikon --set-default` wrote.
|
|
property string jurisdiction: ""
|
|
// Today plus the next six, so the week ahead is visible at a glance.
|
|
property int days: 7
|
|
// Empty means today. Set it to an ISO date to look at a different one --
|
|
// useful for seeing what Great Week will ask of you before it arrives.
|
|
property string forDate: ""
|
|
|
|
property bool available: false
|
|
property string error: ""
|
|
|
|
property var week: []
|
|
property var today: ({})
|
|
|
|
readonly property string date: today.date ?? ""
|
|
readonly property string weekday: today.weekday ?? ""
|
|
readonly property string churchDate: today.churchDate ?? ""
|
|
readonly property string season: today.season ?? ""
|
|
readonly property string cycle: today.cycle ?? ""
|
|
readonly property string feast: today.feast ?? ""
|
|
readonly property string title: today.title ?? ""
|
|
readonly property string rank: today.rank ?? ""
|
|
readonly property string fast: today.fast ?? "none"
|
|
readonly property string fastLabel: today.fastLabel ?? ""
|
|
readonly property string emoji: today.emoji ?? ""
|
|
readonly property string reason: today.reason ?? ""
|
|
readonly property string obligation: today.obligation ?? ""
|
|
readonly property string pascha: today.pascha ?? ""
|
|
readonly property int daysToPascha: today.daysToPascha ?? 0
|
|
readonly property var commemorations: today.commemorations ?? []
|
|
|
|
readonly property bool obligatory: obligation === "obligatory"
|
|
|
|
function refresh() { if (!proc.running) proc.running = true; }
|
|
|
|
SystemClock { id: clock; precision: SystemClock.Minutes }
|
|
|
|
// Re-read when the day rolls over, not on a timer. The answer changes at
|
|
// midnight and at no other moment.
|
|
readonly property string _day: Qt.formatDateTime(clock.date, "yyyy-MM-dd")
|
|
on_DayChanged: root.refresh()
|
|
onJurisdictionChanged: root.refresh()
|
|
onForDateChanged: root.refresh()
|
|
Component.onCompleted: root.refresh()
|
|
|
|
Process {
|
|
id: proc
|
|
command: {
|
|
const c = ["typikon", "--json", "--days", String(root.days)];
|
|
if (root.jurisdiction !== "")
|
|
c.push("--jurisdiction", root.jurisdiction);
|
|
if (root.forDate !== "")
|
|
c.push("--date", root.forDate);
|
|
return c;
|
|
}
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
try {
|
|
const parsed = JSON.parse(this.text);
|
|
root.week = parsed.days ?? [parsed];
|
|
root.today = root.week.length ? root.week[0] : {};
|
|
root.available = true;
|
|
root.error = "";
|
|
} catch (e) {
|
|
root.available = false;
|
|
root.error = "could not read typikon";
|
|
}
|
|
}
|
|
}
|
|
stderr: StdioCollector {
|
|
onStreamFinished: {
|
|
if (this.text.trim() !== "") {
|
|
root.available = false;
|
|
root.error = this.text.trim();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|