summaryrefslogtreecommitdiff
path: root/mobile/mobile.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-03 23:30:12 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-03 23:30:12 +0200
commitd45d0b4e4534253d782cc6312d7edda43cca196d (patch)
tree79a8e1c554d0a4960f9217b28986e3f6df2b2864 /mobile/mobile.go
parentd7da4b09f7775276231d0241cfe2700d247728ee (diff)
downloadlectio-d45d0b4e4534253d782cc6312d7edda43cca196d.tar.gz
lectio-d45d0b4e4534253d782cc6312d7edda43cca196d.zip
baseline: track the gomobile engine facade as-is
mobile/mobile.go and its go.mod/go.sum additions were sitting untracked in the working tree. Recorded here unchanged so the work that follows has a diff baseline; no lines of it are modified by this commit. Also ignore the cmd/dlectio-gen build product and the SDD scratch dir.
Diffstat (limited to 'mobile/mobile.go')
-rw-r--r--mobile/mobile.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/mobile/mobile.go b/mobile/mobile.go
new file mode 100644
index 0000000..c2c6347
--- /dev/null
+++ b/mobile/mobile.go
@@ -0,0 +1,112 @@
+// Package mobile is lectio's engine facade for the dlectio Android app. It is
+// bound to a native Android library with gomobile:
+//
+// gomobile bind -target=android/arm64 -tags fullbible \
+// -o dlectio-engine.aar github.com/lukaszkasprzak/lectio/mobile
+//
+// The app calls Day() with a plain date/form/version and receives one JSON
+// document with the day's identity and rendered Mass readings. All liturgical
+// computation and text resolution happens here, in the exact validated lectio
+// engine — the app does none of it. Keep every exported signature to types
+// gomobile can marshal (string in, string out): that is why the payload is JSON.
+package mobile
+
+import (
+ "encoding/json"
+ "strings"
+
+ "github.com/lukaszkasprzak/lectio/internal/config"
+ "github.com/lukaszkasprzak/lectio/internal/readings"
+ "github.com/lukaszkasprzak/lectio/internal/render"
+)
+
+// reading is one Mass reading, rendered in the requested corpus.
+type reading struct {
+ Ord int `json:"ord"`
+ Part string `json:"part"` // machine key, e.g. "ewangelium" / "psalm"
+ Heading string `json:"heading"` // human label in the interface language, e.g. "Gospel"
+ Citation string `json:"citation"`
+ Text string `json:"text"`
+}
+
+// dayDoc is the JSON returned by Day.
+type dayDoc struct {
+ Date string `json:"date"`
+ Form string `json:"form"`
+ Lang string `json:"lang"`
+ Version string `json:"version"`
+ Name string `json:"name"`
+ Season string `json:"season"`
+ Colour string `json:"colour"`
+ Readings []reading `json:"readings"`
+ Error string `json:"error,omitempty"`
+}
+
+// lectByForm maps the app's form code to lectio's lectionary value.
+func lectByForm(form string) string {
+ if form == "ef" {
+ return "traditional"
+ }
+ return "new"
+}
+
+// Day computes one day's identity and Mass readings and returns them as JSON.
+//
+// date - "YYYY-MM-DD"
+// form - "of" (Ordinary) or "ef" (1962)
+// version - corpus: "drb" | "wuj" | "vul" | "grb"
+// lang - interface language for the celebration name: "en" | "pl"
+//
+// It never panics: any engine error is reported in the JSON "error" field so the
+// JNI boundary always returns a well-formed string.
+func Day(date, form, version, lang string) string {
+ lect := lectByForm(form)
+ out := dayDoc{Date: date, Form: form, Lang: lang, Version: version}
+
+ // Day identity (name/season/colour) in the interface language.
+ cfgID := config.Config{UILanguage: lang, Lectionary: lect, All: true}
+ if _, info, err := readings.Load(cfgID, readings.Options{Date: date, All: true}); err == nil {
+ out.Name = info.Name
+ out.Season = info.Season
+ out.Colour = info.Colour
+ } else {
+ out.Error = err.Error()
+ }
+
+ // Readings, resolved and rendered in the requested corpus. The interface
+ // language localizes the structural labels (Heading) and citation dialect;
+ // the corpus (version) alone decides the scripture text.
+ cfgR := config.Config{UILanguage: lang, Lectionary: lect, ReadingVersion: version, All: true}
+ secs, _, err := readings.Load(cfgR, readings.Options{Date: date, All: true})
+ if err != nil {
+ if out.Error == "" {
+ out.Error = err.Error()
+ }
+ } else {
+ for i, sec := range secs {
+ // GatherVersion's lang localizes only the label/error wording, never
+ // the verse text (which the corpus alone decides), so the interface
+ // language is correct here. HeadingWithRef gives the same localized
+ // "label (citation)" heading lectio shows in its cli/tui/web.
+ _, blocks := render.GatherVersion(version, sec, lect, lang)
+ out.Readings = append(out.Readings, reading{
+ Ord: i,
+ Part: sec.PartID,
+ Heading: render.HeadingWithRef(sec, lang),
+ Citation: sec.Citation,
+ Text: strings.Join(blocks, "\n"),
+ })
+ }
+ }
+
+ b, err := json.Marshal(out)
+ if err != nil {
+ // Should be impossible with these types; degrade gracefully.
+ return `{"error":"marshal failed"}`
+ }
+ return string(b)
+}
+
+// Ping is a trivial JNI smoke test: it returns "pong" so the app can confirm the
+// native engine loaded before issuing a real query.
+func Ping() string { return "pong" }