2026-09-18 09:17:14 -04:00
|
|
|
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
|
2026-09-18 09:52:38 -04:00
|
|
|
// 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: ""
|
2026-09-18 09:17:14 -04:00
|
|
|
|
|
|
|
|
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()
|
2026-09-18 09:52:38 -04:00
|
|
|
onJurisdictionChanged: root.refresh()
|
|
|
|
|
onForDateChanged: root.refresh()
|
2026-09-18 09:17:14 -04:00
|
|
|
Component.onCompleted: root.refresh()
|
|
|
|
|
|
|
|
|
|
Process {
|
|
|
|
|
id: proc
|
|
|
|
|
command: {
|
|
|
|
|
const c = ["typikon", "--json", "--days", String(root.days)];
|
|
|
|
|
if (root.jurisdiction !== "")
|
|
|
|
|
c.push("--jurisdiction", root.jurisdiction);
|
2026-09-18 09:52:38 -04:00
|
|
|
if (root.forDate !== "")
|
|
|
|
|
c.push("--date", root.forDate);
|
2026-09-18 09:17:14 -04:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|