Secretary Journal (Android) - Changelog
Every released version of the Secretary Journal app, newest first.
App documentation: Apps/journal
Status
Status 2026-10-01 (143)
Secretary Journal 143 (versionCode 143): die Sync-Aktion ist ohne Konto weg, Passwortfelder zeigen Klartext. Beides sitzt im gemeinsamen Code und trifft damit alle acht Clients.
(1) Keine Sync-Aktion ohne Konto. AppHeader (Kit.kt) blendet die Sync-Aktion bereits aus, wenn onSync null ist - das war die vorhandene Konvention, nur wurde sie an keiner Stelle benutzt. OfflineBanner (StatusBanners.kt) verlangte dagegen einen nicht-nullbaren onSync und zeichnete den Refresh-Button bedingungslos; der Parameter ist jetzt (() -> Unit)?, und ohne Konto fehlt der Knopf (die Meldung "offline" bleibt stehen). Alle Aufrufstellen reichen den Callback nur noch durch, wenn wirklich ein Konto existiert: loggedIn der jeweiligen ViewModel, im Kalender der collected isLoggedIn-StateFlow. Das Journal ist der einzige Client, bei dem das sichtbar war - es hat keine Login-Sperre und laeuft im lokalen Modus (localMode = !repo.isConfigured()) ohne Konto weiter, zeigte den Sync-Knopf aber trotzdem. Beim Secrets-Tresor war der Knopf vorhanden und nur deaktiviert (enabled = state.connected); er wird jetzt gar nicht erst gezeichnet, der Spinner waehrend state.syncing bleibt. Am Launcher aendert sich nichts: die Server-Sync-Sektion im Settings-Screen war schon an account != null gehaengt.
(2) Passwortfelder zeigen Klartext. Alle Eingabefelder fuer Passwoerter nehmen VisualTransformation.None; die Tastatur bleibt KeyboardType.Password. Betroffen sind der gemeinsame Login-Screen (SecretaryLoginScreen), die Journal-Passwortdialoge (PasswordDialogs: Setzen, Aendern, Abfragen) und das Entschperren (UnlockScreen) sowie im Tresor die Felder fuer Recovery-Passphrase, Entschperr-Passphrase, KDBX-Import und KDBX-Export (SecretsApp) und das Passwortfeld im Eintrags-Editor (Browse). Anlass war die Darstellung, nicht die Sicherheit: die Maske besteht aus U+25CF (●), und die gebundelte Typewriter-Schrift Special Elite deckt dieses Zeichen nicht ab - die Felder zeigten unlesbare Ersatzglyphen. In den Tresor-Dialogen ist der Sichtbarkeits-Umschalter damit ueberfluessig und mit ihm die Felder passwordVisible/visible, der Eye-Button bzw. der Textbutton Anzeigen/Verbergen und die Visibility/VisibilityOff-Imports weg. Der Reveal-Pfad fuer gespeicherte Secrets in Browse (FieldRow) bleibt unberuehrt: das ist eine Anzeige, keine Eingabe.
Tests: keine neuen, kein JVM-Verhalten geaendert. 662 Tests gruen (Kalender 55, common 100, Kontakte 44, Launcher 12, Secrets 405, Tasks 46), verifiziert ueber gradle test; alle neun Module kompilieren (compileDebugKotlin, offline), und die Neuuebersetzung meldet in keiner der geaenderten Dateien eine Warnung. Das Journal ist der Client, bei dem (1) ohne Konto wirklich sichtbar war - kein Login-Gate, lokaler Modus.
versionCode 142 -> 143.
Status 2026-09-30 (142)
Secretary Journal 142 (versionCode 142): Gewohnheiten-Typ fehlte im Tutorial (SRS 1.9.0, FR-J-120).
Der Einstiegstyp EntryType.HABIT kam in v130 mit allem drum und dran
(Editor, FAB, Kalender, Klartext-Bericht, Vorlagen, gesammelte Texte) — die
pages-Liste in TutorialScreen.kt wurde dabei aber nicht mitgezogen und
endete beim Skill. Das Tutorial war damit unvollstaendig, obwohl
tutorial_types_body "alle Eintragstypen" verspricht und
tutorial_gathered_body die Gewohnheiten schon nennt. Neu ist eine
Gewohnheiten-Seite hinter der Skill-Seite, damit die Reihenfolge der
EntryType.entries (HABIT steht dort am Ende) erhalten bleibt:
Icons.Filled.Checklist (derselbe Icon wie in JournalTypeUi),
tutorial_habit_title/tutorial_habit_body DE+EN, und TutorialTry.HABIT
als neue Enum-Konstante. Der "Ausprobieren"-Knopf darauf braucht die
when-Verzweigung im NavGraph, sonst waere die Seite nur Text — sie
verdrahtet vm.openHabitEntryForDate(LocalDate.now()), also den
vorausgefuellten Gewohnheiten-Editor, wie die anderen Typen.
tutorial_types_body sagt jetzt "Gewohnheiten und Skills" statt nur
"Skills". Das Tutorial hat damit 16 Seiten (vorher 15), der
Seitenzaehler (tutorial_page_cd) und die Punkteanzeiige zaehlen die
Liste automatisch mit. Der KDoc am Screen vermerkt nun ausdruecklich,
dass ein neuer Einstiegstyp hier eine Seite braucht — genau die Luecke,
die v130 aufgerissen hat. SRS 1.9.0.
versionCode 141 -> 142. CONTEXT.md updated.
Status 2026-09-30 (141)
Secretary Journal 141 (versionCode 141): Gesammelte Medikamenten als Kombination + alle Felder gleich behandelt (SRS 1.8.0, FR-J-112/113/114).
(1) Medikamenten-Kombination wird gesammelt. Bisher standen im
Gathered-Screen zwei getrennte Zeilen fuer Wirkstoff und Staerke — die
Kombination, also was tatsaechlich eingenommen wurde, gar nicht. Neu ist das
abgeleitete GatherField.MEDICINE_COMBINATION: medicineCombination
verknuepft den Wirkstoff mit der Dosis ("Ibuprofen 400 mg", ohne Dosis
degeneriert es zum reinen Wirkstoff, ohne Stoff greift es auf einen Legacy-
Namen zurueck). Das ist die einzige abgeleitete GatherField – sie hat
kein Editor-Feld, gatheredTextOf liest sie, und withGatheredText
verweigert sie mit error("MEDICINE_COMBINATION is derived - split it with
withRenamedGatheredText"), statt still eine der beiden Haelften zu
treffen. Ein Umbenennen oder Zusammenfuehren dieser Zeile schreibt
deshalb beide Felder zurueck: das neue JournalViewModel
.withRenamedMedicineCombination schneidet am ersten Leerzeichen
(substringBefore/substringAfter), ein Eintrag ohne Dosis behaelt eine
leere Dosis, und ein medicineName, der den Wirkstoff spiegelt, wandert
mit (medicineName == medicineSubstance || == old vor dem Leerzeichen),
ein abweichender Legacy-Name bleibt stehen. gatheredTexts() fuehrt nun
statt der Sonderregel pro-medizin ein emitted-Set: der Name wird
weiterhin zugunsten des Wirkstoffs verworfen (v57-Spiegelung), und
sonst wird kein Text zweimal fuer denselben Eintrag gelistet — ohne
Dose also kein zweites "Ibuprofen" aus der Kombination.
gatherFields fuehrt die Kombination zwischen Wirkstoff und Staerke.
ProposalEngine.scanRecurringPatterns sieht sie automatisch mit, der
Ausloeser-/Skill-Editor filtert weiterhin auf field == TEXT.
(2) Die Feld-Labels sind weg. Die Meta-Zeile zeigte je Wert das
Editor-Feld ("Highlight 1/2/3", "Wirkstoff", "Staerke", ...), also war
gerade die Highlight-Liste sichtbar nach Feld sortiert und jeder Typ anders
behandelt. GatheredScreen rendert jetzt ueber alle Felder eines Typs
gleich: nur noch der Text plus gathered_meta (n× · Datum) und
optional der Ø-Abstand aus scanRecurringPatterns. Der showField-Parameter
und JournalTypeUi.gatherFieldLabel sind entfallen, die neun
gathered_field_*-Strings in DE+EN mit. Das Zusammenfuehren bleibt
feld-skaliert — das Zielmenue listet weiter nur Werte desselben Feldes
(items.filter { it.field == item.field && ... }), ein Wirkstoff laesst
sich also weiterhin nicht in eine Dosis fuehren; genau das war mit
FR-J-113 (High) gemeint. Die Sortierung bleibt count absteigend mit
entryType/field/text als Tiebreak, das Label war ohnehin nur Deko.
SRS 1.8.0.
versionCode 140 -> 141. CONTEXT.md updated.
Status 2026-09-30 (140)
Secretary Journal 140 (versionCode 140): Gesammelte Texte statt "Gesammelte Trigger & Skills" – der Screen sammelt jetzt jeden Freitext aus **jedem Eintragstyp; die Einstellungs-Sektion heisst nicht mehr "Datenschutz", sondern "Verbergen"**.
(1) GatherEngine über alle Eintragstypen (SRS 4.12, FR-J-112/113). Die
compute-Filterung auf TRIGGER/SKILL ist entfernt: GatherEngine sammelt
jetzt über JournalEntry.gatheredTexts() jedes nicht-leere Textfeld eines
Eintrags – Highlights (3 Felder), Medikament (Name, Wirkstoff, Stärke, Grund),
Essen (Beschreibung) bzw. Getränk (Name), Trigger, Skill und Gewohnheit
(text). Damit ein Wert eindeutig bleibt und eine Umbenennung nicht das
falsche Feld trifft, trägt jeder Wert jetzt neben entryType ein neues
field: GatherField; MOOD und EXCRETA haben keine Textfelder (gatherFields
= leer). Drei Helfer in GatherEngine.kt bilden die Brücke zwischen Modell
und Screen: gatherFields (Textfelder eines Typs in Anzeigereihenfolge),
gatheredTextOf(field) (aktueller Text) und withGatheredText(field, value)
(Kopie mit gesetztem Feld). Sonderfälle: ein Getränk liefert nur
drinkName, eine Mahlzeit/Snack nur foodText, und der Medikamenten-Name
wird übersprungen, wenn er nur den Wirkstoff spiegelt (seit v57 wird er beim
Speichern so gesetzt) – sonst stünde jeder Wirkstoff zweimal in der Liste.
Vorlagen sind ausgeschlossen: sie sind keine geloggten Eintraege und
wuerden nur die Zaehler aufblaehen. ProposalEngine.scanRecurringPatterns
hat dieselbe Sicht und traegt field in RecurringPattern mit.
renameGatheredText/mergeGatheredTexts im JournalViewModel nehmen dadurch
(type, field, …) und schreiben ueber withGatheredText nur dieses Feld
(withRenamedGatheredText zieht den gespiegelten Medikamenten-Namen mit, wenn
der Wirkstoff umbenannt wird; ein Legacy-Name, der vom Wirkstoff abweicht,
bleibt stehen).
GatheredScreen rendert eine Sektion je Eintragstyp (Ueberschrift ueber
entryTypeLabel, Farbe ueber entryTypeColor, Reihenfolge EntryType-Ordinal,
leere Typen erscheinen gar nicht) statt zwei fest verdrahteter Trigger-/
Skill-Listen; bei Typen mit mehreren Textfeldern (Highlights, Medikament)
steht das Feld-Label (gatheredFieldLabel) in der Meta-Zeile. Das
Merge-Zielmenue listet nur Werte desselben Feldes – ein Wirkstoff laesst
sich nicht in eine Dosis zusammenfuehren – und die Menu-Oeffnung vergleicht
mergeSource per Identitaet statt per Text (sonst wuerde ein Text, der in
mehreren Feldern vorkommt, zwei Menues gleichzeitig oeffnen). Der
Trigger-/Skill-Editor filtert seine Vorschlage zusaetzlich auf
field == TEXT, damit nicht Wirkstoffe oder Begruendungen als
Ausloeser-Vorschlag auftauchen. Settings-/Screen-/Tutorial-Texte, DE+EN,
angepasst (gathered_section_triggers/_skills entfallen zugunsten der
Typ-Labels, neu gathered_field_*). SRS 1.7.0.
(2) Einstellungs-Sektion "Datenschutz" -> "Verbergen". Der Weichzeichner
(Aus / 7 / 14 / 30 Tage) ist unveraendert, nur die Ueberschrift war falsch –
sie beschrieb eine Absicht (Datenschutz), nicht das, was die Einstellung tut.
settings_section_privacy heisst jetzt settings_section_hide
("Verbergen" / "Hide"). PrivacySettings (KDoc, Repo-Prefs
privacyBlurDays, Blur im Karussell) bleibt unangetraendert. SRS 1.7.0.
(3) Tutorial: "Stimmung & Auswertung" -> Bericht, Medikamenten-Seite
korrigiert. Die Tutorial-Seite tutorial_eval_* ("Stimmung & Auswertung")
war doppelt falsch: Sie versprach ein einstellbares Auswertungsfenster
(7–365 Tage) in den Einstellungen – das gibt es nicht mehr, seit v93 ist die
Auswertungs-Karte entfernt und evaluationWindowDays() fest 30 Tage. Sie
heisst jetzt "Bericht für den Arzt" / "Doctor's report"
(tutorial_report_*, Icon Icons.Filled.Description statt Insights) und
beschreibt den Klartext-Bericht: chronologisch, ohne Vorlagen, vor dem
Erstellen waehlbare Eintragstypen, erreichbar ueber Einstellungen →
Sicherung → Bericht (export_title DE "Sicherung" / EN "Backup",
ReportCard). Die Statistik-Seite bleibt unberuehrt – der Statistik-Screen
deckt weiterhin nur Trigger/Skills ab, wie tutorial_stats_body sagt.
Die Medikamenten-Seite behauptete zudem, "Medikamenten-Erinnerungen loggen
die Einnahme direkt ins Journal". Das ist seit v125 nicht mehr die
Besonderheit von Medikamenten, sondern eine Einstellung je Vorlage
(direct:add, edit_direct_add_on, seit v125 fuer alle Eintragstypen):
tutorial_medicine_body beschreibt jetzt Vorlage + die Wahl zwischen
direkt eintragen und Editor mit vorausgefuelltem Eintrag. Die
Medikamenten-Erinnerungen aus den Einstellungen (MedicineReminderSettings,
drainPendingMedicine → writeMedicineDraftNow) loggen weiterhin direkt –
nur ist das nicht mehr die Aussage der Tutorial-Seite.
(4) Sprache folgt dem System, kein Schalter mehr. Die Einstellungen hatten
zwei Sprach-Buttons (Deutsch/Englisch), die ueber LocalePrefs eine Praeferenz
in den SharedPreferences speicherten und die Activity neu erzeugten. Der
Schalter ist ersatzlos entfallen: die App zeigt Deutsch auf einem deutschen
System und ueberall sonst Englisch. Dazu die Speicherrichtung gedreht –
res/values/strings.xml (bisher Deutsch) ist jetzt Englisch und der
bisherige values-en-Ordner traegt Deutsch als res/values-de/strings.xml.
Das ist die Konvention, die der Launcher schon hatte (EN default, DE
qualifiziert) und die Android von selbst richtig aufloest; die
values-en-Datei loest nur noch bei englischer Systemsprache, nicht mehr bei
jedem Nicht-Deutsch. LocalePrefs.kt ist geloescht, ebenso die beiden
attachBaseContext-Ueberladungen, die die Activity-Kontexte in die
gespeicherte Sprache umhiengen. SecretaryJournalApp.localizedContext()
liefert damit einfach baseContext und bleibt nur als Zugriffspunkt fuer
VM-Texte und Receiver-Benachrichtigungen bestehen. AndroidManifest listet
locale nicht unter configChanges, ein Systemsprachwechsel erzeugt die
Activity also ohnehin neu – deshalb reicht der Wegfall des Schalters voll
aus. settings_section_language und settings_language_* (4 Strings) sind
weg, beide Sprachdateien haben denselben Schluesselbestand (378 Namen).
SRS 1.7.0, FR-J-62/121.
(5) Gemeinsamer Einstellungs-Screen: Versionszeile statt Namensraum. Der
collectionNamespace-Parameter und die Karte Namensraum sind aus
SecretarySettingsScreen entfernt; Journal, Launcher, Links, Notizen,
Secrets und Tasks rufen die Funktion jetzt ohne das Argument auf (die
Konstanten LINKS_NAMESPACE, NotesRepository.NAMESPACE,
TasksRepository.NAMESPACE, LauncherRepository.NAMESPACE und "/secrets/"
sind an den Aufrufstellen danach unbenutzt und die Importe mit verschwunden;
die Konstanten selbst bleiben, sie sind der CalDAV-Basispfad). Die Karte
zeigte eine Konstante, die der Nutzer ohnehin in der Collection-Liste sieht –
Information ohne Handlung, also weg. Die Karte Sammlungspräfix
(Kalender, Kontakte) bleibt, dort ist der Wert konfigurierbar. Neu ist die
letzte Zeile des Screens: die Version der jeweils laufenden App, gelesen aus
der PackageInfo des eigenen Pakets (versionName, ersatzweise versionCode
fuer API 26/27, wo es longVersionCode noch nicht gibt, PackageInfoFlags
ab API 33) – jedes Modul zeigt so seine eigene Nummer, ohne sie
durchzureichen. Das betrifft alle acht Apps, weil sie den Screen gemeinsam
nutzen. Ein settings_version-String liegt in common DE+EN, die Karte
Sammlungspräfix (Kalender, Kontakte) bleibt unangetastet. SRS journal 1.7.0
FR-J-64, SRS common 1.3.0.
versionCode 139 -> 140. CONTEXT.md updated.
Status 2026-09-30 (139)
Secretary Journal 139 (versionCode 139): keine Code-Aenderung - der
Quelltext ist derselbe wie bei 138. Veraendert wurde in diesem Zug nur der
Launcher (Korrektur am Konfigurations-Sync, dort 460). Die Nummer geht trotzdem
hoch, weil ein Release alle acht Clients und beide Serverpakete zusammen
ausliefert: das Buildsystem ueberspringt einen Lauf, dessen Zieldateinamen alle
bereits im Archiv liegen, und ein gleichnamiges Paket mit gleichem Inhalt
waere auf dem Geraet nicht von 138 zu unterscheiden - bei einer APK
zusaetzlich ein versionCode, den ein Geraet nicht neu installiert. Server und
check-links gehen mit auf 0.24.0. versionCode 138 -> 139.
Status 2026-09-29 (138)
Secretary Journal 138 (versionCode 138): Abschluss des Release-Zugs, der
Signiermaterial aus einer Umgebungsvariable in eine Datei verlagert hat (siehe
137). Der Sprung ist der von 4d6b02eee5 für alle acht Module gemeinsam
gesetzte: BuildManager vergleicht Dateinamen, nicht Inhalte, also liefert
derselbe Code ohne neue versionCode exakt denselben Namen und der Build wird
als „bereits im Repo“ abgewiesen. Am Journal änderte sich in diesem Schritt kein
Funktionscode. versionCode 137 -> 138.
Status 2026-09-29 (137)
Secretary Journal 137 (versionCode 137): alle acht Clients signieren ihre
Release-APKs, nicht nur der Launcher. Vorher konnte nur der Launcher
überhaupt ein signiertes APK liefern, die sieben anderen Module hatten gar kein
signingConfig und bauten deshalb *-unsigned.apk. Zwei Nacharbeiten blieben
in derselben Version: der Default-Pfad für das Keystore war um eine Ebene zu
kurz, und die Zugangsdaten wurden aus dem Prozess-Environment in eine Datei
verlagert, damit ein Release nicht von einer in keinem --help genannten
Umgebungsvariable abhängt. versionCode 136 -> 137.
Status 2026-09-29 (136)
Secretary Journal 136 (versionCode 136): Signiermaterial in ein eigenes
Fossil-Repository signing-certs ausgelagert (vorher lag es im
Secretary-Repository selbst, zwischen Anwendungscode und Release-Skripten). Am
Journal änderte das keine Zeile Funktionscode; die Version trägt die neue
Signierkonfiguration und macht damit überhaupt erst ein signiertes Release-APK
möglich. versionCode 135 -> 136.
Status 2026-09-29 (135)
Secretary Journal 135 (versionCode 135): Konto, gemeinsamer
Einstellungs-Screen und Konfigurations-Sync für den Launcher. Der Commit hielt
die versionCode aller acht Module gleichzeitig fest, damit der Release-Zug
überhaupt laufen konnte. Am Journal selbst änderte sich dabei keine Zeile; die
Funktionsänderung betraf ausschließlich den Launcher. Die Nummer 134 wurde nie
vergeben — dieser Commit sprang von 133 auf 135. versionCode 133 -> 135.
Status 2026-09-26 (133)
Secretary Journal 133 (versionCode 133): Typewriter-Launcher-Icon
[:-)] (vorher [☺]). Die Glyphe wird jetzt wie bei allen anderen Apps
mit Special Elite gerendert — : , - und ) deckt der Font ab, nur
☺ (U+263A) fehlte, weshalb bisher das gebündelte Liberation Mono nötig
war. Da das : in der Glyphe den Trenner der APPS-Tabelle kollidiert hat,
ist das Schema auf |-getrennte Felder umgestellt (Kommentar in
tools/generate-icons.sh entsprechend angepasst, SMILEY_FONT heißt jetzt
FALLBACK_FONT; der font-override-Mechanismus bleibt für Glyphen
erhalten, die Special Elite nicht deckt). Accent #5A7A3E und
Adaptive-Icon-XML unverändert, die 5 Foreground-PNGs neu erzeugt.
versionCode 132 -> 133. CONTEXT.md updated.
Status 2026-09-24 (132)
Secretary Journal 132 (versionCode 132): Typewriter-Launcher-Icon
[☺]. Das Journal bekommt das gemeinsame Secretary-Icon-Schema der
übrigen Apps (tools/generate-icons.sh): eine weiße Glyphe auf dem
App-Akkzent #5A7A3E. Da Special Elite das Smiley-Zeichen ☺ (U+263A)
nicht abdeckt, rendert der Generator das [☺] im gebündelten
Liberation Mono (SIL OFL 1.1, tools/liberation-mono/); die
APPS-Tabelle unterstützt dafür ein optionales fünftes Feld
font-override. Die 5 Foreground-PNGs liegen wie bei den anderen Apps in
mipmap-{mdpi..xxxhdpi}/ic_launcher_foreground.png, der Adaptive-Icon-XML
referenziert @mipmap/ic_launcher_foreground, die alte Vektor-Foreground-
Datei (drawable/ic_launcher_foreground.xml) ist entfernt, der
Hintergrund bleibt #5A7A3E. versionCode 131 -> 132. CONTEXT.md updated.
Status 2026-09-23 (131)
Secretary Journal 131 (versionCode 131): Fixes: „Direkt eintragen"- Vorlagen öffnen trotzdem den Editor; bei mehreren aktiven Erinnerungen verwechseln die Sofort-Aktionen Einträge.
(1) Stale Vorlagen-Snapshot (Editor öffnet trotz direct:add).
PendingTemplateQueue.enqueuePending überschrieb einen vorhandenen Snapshot
nicht (Dedup-Skip) — ein Snapshot wurde beim ersten arm() eingefroren
und nie aktualisiert. Ein späterer Vorlagen-Edit (z. B. directAdd
einschalten) kam also nie im Snapshot an, und performAccept klonte den
alten Snapshot: der Editor öffnete trotz „Beim Annehmen direkt eintragen".
Neu ersetzt enqueuePending einen vorhandenen Eintrag (Upsert) — jeder
arm() über rearmAll (Speichern/Start/onResume) frischt den Snapshot mit
dem aktuellen Vorlagen-Stand (inkl. directAdd, Text, …) auf; ebenso
ersetzt enqueuePendingEdit ältere Entwürfe derselben Vorlage (jüngster
Accept gewinnt).
(2) Sofort-Aktionen verwechseln Einträge bei mehreren aktiven Erinnerungen.
Zwei Ursachen behoben: (a) PendingIntent-Kollisionen: alle
Vorlagen-/Medikament-PendingIntents trugen ihre Identität nur in Extras +
Request-Code (BASE + (hash mod 100000) + Slot-Offset, Feuer-Slots
±63 → Kollisionsfenster) mit FLAG_UPDATE_CURRENT; eine Kollision
überschrieb die Extras eines bereits geposteten Benachrichtigungs-Actions,
die Accept/Reject-Feuerung lief dann für die falsche Vorlage. Neu trägt
jeder Intent eine eindeutige data-URI (secretary-journal://template/
<uid>/<code> bzw. …/medicine/<id>/<index>[/confirm]), sodass
filterEquals die Tokens unabhängig vom Request-Code unterscheidet —
TemplateAlarmScheduler, TemplateReceiver (Accept/Reject) und die
Medikamenten-Alarme/-Actions. (b) Direct-Add-Wedge: die
Direkt-Protokollierung lief durch editingEntry = draft; saveEntry()
(asynchron) — bis die Speicherung fertig war, war editingEntry belegt,
weitere Accepts wurden geparkt und später FIFO (falsche Reihenfolge/stale)
geöffnet; ein fehlgeschlagener Save (kein activeCollection) ließ
editingEntry dauerhaft belegt, wodurch alle weiteren Accepts
stehen blieben und nach Entsperren/Editor-Schließen fremde Entwürfe
aufsprangen. Neu loggt der Direct-Add-Pfad ohne editingEntry
(writeTemplateDraftNow, analog writeMedicineDraftNow; bei Fehlschlag
wird der Entwurf wieder eingereiht und nach Collections-/Entries-Load
erneut versucht via drainDirectAddDrafts), handleTemplateAccept
prüft per peekPendingEdit auf Direct-Add, und die FIFO-Drains
(drainPendingTemplateEdits/drainIdlePendingTemplateEdit) drainen
Direct-Add-Entwürfe direkt und öffnen nur den ersten Editor-Entwurf;
runTemplateNow („Jetzt eintragen") nutzt denselben Direct-Add-Pfad.
Die Sofort-Aktionen sind damit unabhängig von einem offenen Editor und
von kollidierenden Request-Codes. versionCode 130 -> 131. CONTEXT.md
updated.
Status 2026-09-22 (130)
Secretary Journal 130 (versionCode 130): Neuer Eintragstyp „Gewohnheit"
(Habit). EntryType.HABIT("habit") (Reihenfolge der entries am Ende,
FAB-/Checklisten-Block automatisch) mit einem Freitextfeld
(text, HabitEntryBody im Editor: edit_habit_question; verschlüsselbar
wie TRIGGER/SKILL als einzelner sj1:-Blob, JSON-Schlüssel text bleibt,
kein Schema-Bump) und ohne Tendenz (Statistik/Gathered unberührt).
Persistiert als VJOURNAL SUMMARY=habit, DESCRIPTION = Text,
CATEGORIES=[habit, is:template, rrule:*, rand:N, direct:add, at:*] — d. h.
vollständig Vorlagen-tauglich (fest/zufällig, Direct-Add, Accept/Reject,
„Jetzt eintragen"), der Type-agnostische Scheduler/Receiver braucht keine
Änderung. Neu in JournalViewModel: openHabitEntryForDate /
createNewHabitEntry, HABIT in den Entschlüsselungs-Pfaden und der
Import-Mergung. Icon Icons.Filled.Checklist, Farbe HabitColor
(Indigo 0xFF3F51B5), Labels type_habit / edit_subtype_habit
(GEWOHNHEIT/HABIT) DE+EN. Editor, FAB, Kalender-FAB/-Teilen-Text,
JournalTypeUi (Icon/Label/Farbe/Titel) und Klartext-Bericht erweitert;
der Report-Dialog (ReportCard) listet den Typ automatisch über
EntryType.entries. versionCode 129 -> 130. CONTEXT.md updated.
Status 2026-09-19 (129)
Secretary Journal 129 (versionCode 129): Eigener Namespace-Root
/journal/ statt /calendars/journal-* (Namespace-Migration, server
0.16.0). Das Journal legt seine Sammlungen jetzt unpräfixiert unter dem
top-level Root /journal/ an (kanonische Sammlung: main unter
/journal/main/; zuvor /calendars/journal-main/). JournalRepository
nutzt baseCollectionPath = "/journal/" (neue CaldavClient.collectionRoot),
der NotesCodec ist NotesCodec(collectionBasePath = "/journal/")
(unpräfixiert), die Sync-Sektion zeigt „Namensraum" statt
„Sammlungspräfix". Der Offline-Cache wird beim ersten Lesen automatisch
über die neue GOfflineStore.legacyPrefix = "journal-"-Eigenschaft
migriert (/calendars/journal-* → /journal/…, idempotent; die lokale
Pseudo-Collection /local/ bleibt unangetastet). runServerSync filtert
zusätzlich /journal/ (Legacy-/calendars/, /addressbooks/ bleiben im
Filter), der leere Server legt main an. Deployment-Reihenfolge: erst
Server auf 0.16.0 updaten + migrate-namespaces.sh laufen lassen, dann die
App ausrollen. versionCode 128 -> 129. CONTEXT.md updated.
Status 2026-09-18 (128)
Secretary Journal 128 (versionCode 128): Fix: „Eintragen"-Benachrichtigung öffnet den falschen (oder keinen) Eintrags-Editor.
Root cause. Beim Kaltstart über die Accept-Benachrichtigung lief
JournalViewModel.init sein FIFO-drainPendingTemplateEdits() vor dem
per-UID-Accept (MainActivity.handleTemplateAccept): Es hob den ältesten
Entwurf aus der Pending-Edit-Queue ab (ein liegengebliebener Entwurf eines
früheren, nie geöffneten Accepts — z. B. wenn die App beim Annehmen gesperrt
war oder der Editor offen), öffnete dessen Editor (falscher Typ) und der
eigentliche Accept brach wegen editingEntry != null ab — bzw. gar kein
Dialog, wenn der stale Entwurf direct:add war und direkt speicherte. Zusätzlich
konnte editingEntry nach dem Verlassen des Editors über System-Zurück
(kein onClose) non-null bleiben, sodass spätere Accepts in der Queue
parkten und als falscher Typ aufpoppten. Korrektur: (1) Accept ist jetzt
strikt uid-basiert — drainPendingTemplateEdits() wird nicht mehr bei jedem
Start gerufen (nur noch nach Entsperren), der kalte Start verarbeitet den
angenommenen templateUid über handleTemplateAccept → drainPendingEdit(uid)
und öffnet immer den Editor des angenommenen Typs. (2) System-Zurück ==
Editor-schließen: Der EDIT-Route im NavGraph hat ein BackHandler, das
dieselbe Close-Kette ausführt (closeEditor() + popBackStack() +
drainIdlePendingTemplateEdit()), sodass kein Entwurf mehr verwaist.
(3) Stale-Expiry: PendingTemplateQueue.loadEdits() verwirft Entwürfe
älter als 24 h (Schlüssel occurredAt = Accept-Zeit) und persistiert die
Bereinigung — der betroffene, monopol laufende Entwurf wird so von Geräten
abgeräumt und kann nie wieder als falscher Typ erscheinen.
Tages-Highlight (FREQ=DAILY, TEXT) auch im Accept-Pfad find-or-open.
Die v121-FREQ=DAILY-Kopie im Vitual-/Accept-Pfad war tot, weil
TemplateReceiver.performAccept den Entwurf mit isTemplate=false und
rrule="" klonte. Neu behält ein Nicht-Direct-Add TEXT+FREQ=DAILY-Entwurf
seine isTemplate/rrule-Identität (übersteht den JSON-Round-Trip der
Pending-Edit-Queue), und openPendingTemplateDraft routet ihn wieder auf
openTextEntryForDate(LocalDate.now()) — der bereits vorhandene Tages-TEXT-
Eintrag (Highlights) wird geöffnet bzw. neu angelegt statt eine Duplikat-
Kopie zu erzeugen. In allen Nicht-Highlight-Pfaden (Direct-Add und Fall-through)
werden isTemplate/rrule vor dem Editor strikt entfernt — ein Entwurf kann
nie als Vorlage gespeichert werden oder die Vorlagen-Maske zeigen; Verhalten
konsistent mit runTemplateNow. versionCode 127 -> 128. CONTEXT.md updated.
Status 2026-09-18 (127)
Secretary Journal 127 (versionCode 127): Datenschutz-Weichzeichner (Privacy Blur) + Tendenz-basierte Stimmungs-Anpassung (SRS §4.14, FR-J-130–134).
(1) Privacy Blur. Neue Einstellungs-Sektion „Datenschutz"
(PrivacySettings, in SettingsScreen zwischen Ruhezeit und Stimmung):
wählbar Aus / 7 / 14 / 30 Tage (Default Aus,
JournalRepository.privacyBlurDays()/savePrivacyBlurDays, Prefs-Key
privacy_blur_days). Ist sie aktiv, rendert JournalCarouselScreen alle
Tag-Zeilen der Eintragsliste unabhängig vom Alter hinter einem
Weichzeichner (Modifier.blur(10.dp), blurred-Parameter an DayListRow),
nur der Stimmungs-Smiley (Hero) oben bleibt klar sichtbar; die
Vorlagen-Liste und die übrigen Kopfbereiche (Sync, Tendenz-Zählzeile)
bleiben ungeblurrt. Tippen bleibt funktionsfähig (öffnet weiter den Editor).
(2) Tendenz-basierte Stimmungs-Anpassung. Neue Einstellungs-Sektion
„Stimmung" (TendencyMoodSettings): ein Schalter „Stimmung automatisch
anpassen" (Default Aus, Prefs-Key tendency_mood_enabled) plus eine
Schwelle X = 1/2/3 (Default 2, tendencyMoodThreshold()/
saveTendencyMoodThreshold, Prefs-Key tendency_mood_threshold). Der
ViewModel liefert neu displayedDominantMood: Ist der Schalter an und
liegt mindestens ein Stimmungs-Eintrag vor, zählt er die Tendenzen aller
Nicht-Vorlagen-Einträge nach dem zeitlich letzten Stimmungs-Eintrag
(entryTimeMs), net = up − down; bei net ≥ X wird die Stimmung eine
Stufe höher, bei net ≤ −X eine Stufe tiefer angezeigt
(Mood.numericValue ± 1, über die fünf Stufen begrenzt), sonst
unverändert. Der Karussell-Hero nutzt vm.displayedDominantMood statt
vm.latestMood. Reine Anzeige-Kuration: gespeicherte Einträge, Statistik,
gesammelte Werte und Export bleiben unberührt (FR-J-134). DE/EN-Strings
settings_section_privacy/settings_privacy_blur_* und
settings_section_mood/settings_tendency_mood_* ergänzt. SRS 1.5.0.
versionCode 126 -> 127. CONTEXT.md updated.
Status 2026-09-18 (126)
Secretary Journal 126 (versionCode 126): Fix: Einträge nach App-Start verschwunden (bis zum Sync) + stale Vorlagen-Editor-Dialog.
(1) Cache-Korruption durch die lokale Pseudo-Collection. Seit der
Single-Flavor-Zusammenführung lief ensureLocalCollection() unbedingt
bei jedem Start: Fehlte im Store eine Collection mit der exakten Id
journal, überschrieb es die gesamte Collection-Liste des Stores mit nur
der lokalen Pseudo-Collection (id "journal", href "/local/"). Echte
Server-Collections heißen aber nie journal (das Journal legt sie als
journal-journal über NotesCodec("journal-") an), die Guard schlug also
immer fehl → der Store war nach jedem Start korrupt: activeCollection()
lieferte die leere Pseudo-Collection, der Start-Cache blieb leer („alle
Einträge weg") und saveEntry PUT auf "/local/<uid>.ics" → Server-400
DavException („Speichern schlägt fehl"), bis ein erfolgreicher Sync die
Collections neu lud. Gestalt der Korrektur: (1) ensureLocalCollection()
wirkt nur noch im lokalen Modus und merged die Pseudo-Collection
dazu statt die Liste zu ersetzen (Remote-Modus: die Store-Collection-Liste
ist der Server-Cache und bleibt unangetastet). (2) activeCollection()
filtert im Remote-Modus die Pseudo-Collection heraus (id journal + href
/local/) — Selektion und Journal-supportsJournal-Fallback laufen nur
gegen echte Server-Collections; im Lokal-Modus bevorzugt die Funktion den
Pseudo-Eintrag nur, wenn er tatsächlich Einträge trägt (sonst fällt sie auf
eine Collection mit Einträgen zurück, z. B. nach Logout). (3) Self-Healing
für bereits korrupte Caches: recoveredRemoteCollection() leitet die echte
Server-Collection aus den gecachten Item-hrefs (/calendars/<id>/…) und
den Pending-PutItem-hrefs ab (bevorzugt last_collection),
healAwareCollections() blendet sie effektiv ein und
healRemoteCollectionCache() persistiert sie (gstore.setCollections,
saveLastCollectionId); gerufen im init-Koroutinen-Zweig (Remote), in
loadStartupCache und in loadFromCache (Offline-Pfad). Damit zeigt auch
ein bereits beschädigter Cache beim nächsten Start sofort wieder seine
Einträge — ohne auf einen Sync warten zu müssen. Der v120-Filter
(runServerSync sendet nur /calendars/- bzw. /addressbooks/-hrefs) und
der bestehende Offline-Handoff bleiben unverändert.
(2) Staler Vorlagen-Editor. Wurde eine Vorlage per Benachrichtigung
angenommen, während der Editor bereits offen war (editingEntry != null),
blieb der Entwurf in der Pending-Edit-Queue liegen und wurde in derselben
Sitzung nie mehr geöffnet — beim nächsten Start popte
drainPendingTemplateEdits() den uralten Entwurf ungefragt als „stale
Edit-Dialog" auf. Zusätzlich wurde der One-Shot-Zähler templateEditRequest
nie zurückgesetzt: der LaunchedEffect(templateEditRequest) im NavGraph
navigierte dadurch bei jeder frischen Recomposition (z. B. nach dem
Entsperren) erneut auf Routes.EDIT, auch ohne neuen Vorlagen-Auftrag.
Korrektur: (1) Der EDIT-onClose im NavGraph ruft nach closeEditor() +
popBackStack() jetzt vm.drainIdlePendingTemplateEdit() auf — ein
währenddessen angenommener Entwurf wird unmittelbar im Editor geöffnet
(Chain), ein zurückgestellter Entwurf kann nicht mehr über Nacht „verklumpt"
erscheinen. (2) consumeTemplateEditRequest() setzt den Zähler direkt nach
dem Navigieren auf 0 — die Editor-Auto-Öffnung ist wieder einmalig pro
Entwurf; Unlock-/Start-Pfade (drainPendingTemplateEdits) bleiben.
versionCode 125 -> 126. CONTEXT.md updated.
Status 2026-09-18 (125)
Secretary Journal 125 (versionCode 125): Vorlagen-Fixes: Direct-Add funktioniert für alle Typen + ehrliche Zufalls-Zeiten per Teil-Methode (FR-J-71/84/85).
(1) Direct-Add-Fix: Bei Vorlagen mit „Direkt eintragen" (direct:add)
wurde beim Annehmen nie ein Eintrag angelegt — performAccept klont die
Vorlage in einen Entwurf mit isTemplate=false, daher war der direkte
Protokoll-Pfad unerreichbar: openPendingTemplateDraft verlangte
decrypted.isTemplate (immer false) und zusätzlich entryType ==
TEXT. Neu: if (decrypted.directAdd) reicht, und auch runTemplateNow
(„Jetzt eintragen") verlangt statt isTemplate && entryType == TEXT &&
directAdd nur noch isTemplate && directAdd. Damit loggt eine
Direct-Add-Vorlage beim Annehmen (bzw. „Jetzt eintragen") für alle
Eintragstypen direkt ohne Editor (z. B. Medikamente). Die Kommentare am
Accept-Pfad sind bereinigt (Vorlagen-Entwurf trägt nach dem Klon
stets isTemplate=false).
(2) Zufalls-Zeiten ehrlich (Teil-Methode): Die alte randomBlock zog
für den ersten kommenden Vorkommens-Tag count Slots in das gegen „jetzt"
beschnittene Fenster — jedes Accept/Reject (Re-Arm) zog dadurch count
frische Slots im Restfenster von heute, verdoppelte Termine und zählte nie
ehrlich. Neu (SRS FR-J-84/85): Die Tages-Feuerzeit (ganzer Tag minus
Ruhezeit, zusammenhängende Minuten-Spannen aus dayFiringChunks(),
Total in totalMinutes) wird in count gleiche aufeinanderfolgende Teile
geteilt; jedes Teil liefert genau einen deterministischen Zufalls-Slot
(DeviceTimePolicy.pickRandomMillis(uid, day, partStart*60_000,
partEnd*60_000, salt = k*1013+k)), bereit im Teil bereits abgelaufene
Teile werden übersprungen. Dadurch bleibt die Anzahl pro Tag bei count
(geteilt nach dedup), Re-Arm reproduziert exakt dieselben absoluten Zeiten
und das Fenster verschiebt sich nicht: überfällige Teile fallen weg,
restliche Teile bleiben auf ihren bewaffneten Zeiten; sind alle Teile des
heutigen Tages vorbei, wandert der Rest auf die folgenden Vorkommens-Tage
(Guard < 60), bis count zukünftige Slots stehen. randomBlock ist
signature-bereinigt ((template, base) ohne context, beide Aufrufer
arm/nextRandomFire angepasst) und die KDoc am Scheduler und
randomBlock beschreiben die Teil-Methode. SRS 1.4.0. versionCode 124 -> 125.
CONTEXT.md updated.
Status 2026-09-17 (124)
Secretary Journal 124 (versionCode 124): Passwort-only-Verschlüsselung
(FR-J-90/95/96/97). Das bisherige Master-Key-Schema (zufälliger
AES-256-Schlüssel, per PBKDF2-Passwort gewrappt) ist ersetzt: der
PBKDF2-HmacSHA256-abgeleitete Schlüssel (210k Iterationen, salzfrei) dient
direkt als AES-256-GCM-Schlüssel — es gibt keinen separaten Master-Key
mehr. Damit genügt das Passwort allein, um das Journal nach Neuinstallation,
Reconnect oder Import wieder zu entschlüsseln. JournalCipher:
enable()/disable()/changePassword() arbeiten auf dem abgeleiteten
Schlüssel; die Passwortprüfung läuft über ein Verifier-Token
(KEY_VERIFIER, AES-GCM über den festen Text secretary-journal-verifier);
Alt-Installationen bleiben über den Legacy-Wrap (KEY_PW_WRAP,
unwrapLegacyMaster) entsperrbar, bis ihre Einträge neu kodiert sind. Die
Biometrie wrappt jetzt den Session-Schlüssel. Setzen/Entfernen/Ändern
verschlüsselt bzw. entschlüsselt alle Einträge
(JournalViewModel.runMigration + pushAllEntries(onProgress),
CryptoMigration-State) und wird im UI von einem Warn-Dialog
(CryptoWarningDialog, Wirkung auf alle N Einträge) und einem
nicht-abbrechbaren Fortschritts-Overlay (CryptoMigrationDialog,
„Eintrag X von Y wird verschlüsselt/entschlüsselt") begleitet. Das Tutorial
hat die Verschlüsselungs-Einrichtung als letzten Schritt
(TutorialTry.ENCRYPT -> Einstellungen). DE/EN-Strings ergänzt. SRS 1.3.0.
versionCode 123 -> 124. CONTEXT.md updated.
Status 2026-09-17 (123)
Secretary Journal 123 (versionCode 123): Vorlagen-Maske visuell
unterscheidbar (FR-J-82/83). Der Editor zeigt beim Erstellen/Bearbeiten
einer Vorlage jetzt eine eigene, klar erkennbare Maske statt einer
Eintrags-Maske mit Zusatzfeldern: (1) Header-Badge — statt der
Datums-Unterzeile mit Typ + Uhrzeit steht „VORLAGE · <TYP>"
(edit_template_subtitle, DE/EN), ergänzt die SRS FR-J-82; (2) eigener
Vorlagen-Abschnitt — der Template-only-Block (Zeitpunkt/Wiederholung/
Zufallsplan) ist unter dem Section-Titel „VORLAGE" gruppiert, die
Wiederholung heißt „Wiederholung der Vorlage" (edit_template_recurrence),
ein Hinweistext erklärt, dass die Vorlage wiederholt erinnert und erst beim
Annehmen ein Eintrag daraus entsteht (edit_template_fires_hint); (3)
Vorlagen-Wortlaut — Speichern-Button „Vorlage speichern"
(edit_save_template) und Löschen-Dialog „Vorlage löschen"/
edit_delete_template_{title,text} statt Eintrag-Wording. Normale Einträge
zeigen die bisherige Eintrags-Maske unverändert (kein Vorlagen-Badge, kein
Zufallsplan/Wiederholung). versionCode 122 -> 123. CONTEXT.md updated.
Status 2026-09-17 (122)
Secretary Journal 122 (versionCode 122): Ruhezeit-Korrektur: v93-Umbenennung
jetzt durchgängig (Buttons zeigen 22:00–07:00 statt 07:00–22:00), Scheduler
feuert außerhalb der Ruhezeit. Seit v93 ist die Einstellung der
„Ruhezeit" (Quiet time) als Zeitraum ohne Erinnerungen definiert, der
Code war aber nie gefolgt – JournalRepository.randomWindow() fiel weiter auf
das alte Aktivfenster TimeRange.DEFAULT (07:00–22:00) zurück (die Buttons
zeigten „Von 07:00 – Bis 22:00", der Info-Text darunter behauptete
„Standard: 22:00–07:00") und die Validierung start <= end lehnte den
Mitternacht-überspannenden Ruhezeit-Standard 22:00–07:00 beim Rücklesen ab.
Neu: (1) randomWindow() gibt als Default die Ruhezeit 22:00–07:00
(quietDefault()) zurück, akzeptiert Wrap-Around-Bereiche (start > end,
gleiche Start-/Endzeit = ganzer Tag ruhig) und migriert den v93-Legacy-
Default 07:00–22:00 (unverändert gespeicherter alter Aktivzeitraum) auf den
neuen Ruhezeit-Default – der Einstellungs-Screen zeigt damit konsistent
„Von 22:00 – Bis 07:00". (2) TemplateAlarmScheduler behandelt das Fenster
als Ruhezeit und feuert in deren Komplement: firingTimeRanges() bildet
aus dem (ggf. über Mitternacht verlaufenden) Ruhefenster ein bis zwei
nicht-wrappende Tagesfenster ab (z. B. Ruhezeit 22:00–07:00 → Feuerfenster
07:00–22:00; Ruhezeit 07:00–22:00 → die zwei Nachtsegmente 22:00–23:59 und
00:00–07:00), clampQuiet() wählt das erste mit DeviceTimePolicy.clampWindow
gültige Fenster; randomBlock (Arm) und deferRandom (DND-Deferral) nutzen
denselben Pfad. Damit bleiben die tatsächlichen Alarmzeiten auf frischen
Installationen und nach der Legacy-Migration identisch (07:00–22:00), während
ein gesetztes Ruhefenster jetzt wirklich bedeutet, dass dort keine
Zufalls-Erinnerungen feuern. RandomWindowSettings-KDoc und Scheduler-KDoc
aktualisiert. versionCode 121 -> 122. CONTEXT.md updated.
Dazu liefert dieser Build die abgeschlossene, zuvor abgebrochene
secretary-common-android-Änderung mit: der gemeinsame RecurrenceDialog
verliert das Freitext-RRULE-Feld („Benutzerdefinierte Regel", Kategorie
showCustom/customRrule/customValid); der Aufbau ist rein
Form-basiert (formRrule), eine bestehende nicht-parsebare RRULE wird
unverändert übernommen (effective = currentRrule, wenn spec == null).
Das unterbrochene Halbedit (Syntaxfehler, TimerText = remember) ist
komplettiert, .bak-Datei entfernt, common-Unit-Tests grün.
Status 2026-09-16 (121)
Secretary Journal 121 (versionCode 121): Vorlagen-Erweiterung: Tages-Highlight + Direct-Add. Neue Themen aus den Nutzer-Antworten:
1) Tages-Highlight-Vorlage (FREQ=DAILY, TEXT). „Jetzt" (FAB) bzw.
„Eintragen" (Notification) öffnet den bereits vorhandenen Tages-TEXT-
Eintrag statt eine weitere Kopie zu erzeugen (find-or-open über
openTextEntryForDate(LocalDate.now()), in runTemplateNow und im
Accept-Pfad openPendingTemplateDraft). Nur für TEXT-EINTRAEGE mit
FREQ=DAILY in der RRULE.
2) directAdd-Schalter (nur im Vorlagen-Editor). Ein neuer Schalter
„Beim Annehmen direkt eintragen (kein Editor)" ist nur in der
Editor-Ansicht der Vorlage sichtbar (if (vm.editingIsTemplate), nicht bei
normalen Einträgen in JournalEditScreen.kt). Ist er aktiv, wird ein
überfälliger Vorlagen-Eintrag beim Annehmen direkt geloggt (kein
Editor), z. B. Medikamente, die sich nicht ändern und nur geloggt werden.
Gespeichert als Kategorie direct:add + JSON-Feld directAdd
(JournalModels.kt Feld directAdd: Boolean = false, JournalTransfer
put/optBoolean). versionCode 120 -> 121. CONTEXT.md updated.
Secretary Journal 120 (versionCode 120): Fix: „Sync fehlgeschlagen:
Sync-Dienst 400" beim App-Start. runServerSync() reichte jedes
Collection mit nicht-leerem href an den Server weiter – auch die lokale
Pseudo-Collection (id "journal", href = "/local/", wird bei jedem Start
von ensureLocalCollection in den Store/das collections-State gesetzt).
Der secretary-server akzeptiert aber nur Pfade unter /calendars/ oder
/addressbooks/; für /local/ antwortet POST /sync/start mit 400
„Collection muss unter /calendars oder /addressbooks liegen" und der
ganze Sync-Meldungs-Zyklus schlug beim Start fehl („always starts with
sync error 400"). Neu filtert runServerSync die Collections auf echte
Server-Sammlungen (href.startsWith("/calendars/") bzw.
/addressbooks/): die lokale /local/-Collection wird nie mehr
übertragen, Server-Sync läuft sauber. versionCode 119 -> 120.
CONTEXT.md updated.
Status 2026-09-16 (119)
Secretary Journal 119 (versionCode 119): Fix: Endlos-Loop im Sync
(Spinner bleibt für die gesamte Sitzung auf „Synchronisiere…").
runServerSync() lief direkt nach dem Start bzw. Login, während
loadCollectionsInternal die Collections noch asynchron lädt – collections
war in diesem Moment leer. Mit leerer Collection-Liste blieb der
while (done.any { !it })-Poll-Loop unausgeführt, syncStatus blieb auf
RUNNING (0/0) stehen und der Guard if (syncStatus?.state == RUNNING) return
blockierte jede spätere runServerSync()-Wiederholung für den Rest der
Sitzung – der Sync hing endlos fest (Verhalten passte dazu, dass erst ein
App-Neustart half: dann wurden die Collections wieder aus dem Store geladen).
runServerSync bricht jetzt bei leerer Collection-/Job-Liste sauber ab
(syncStatus = null, kein RUNNING, der Guard blockiert nichts mehr).
Zusätzlich ist der Poll-Loop hart begrenzt (maxPolls = 200 ≈ 100 s bei
500 ms): bleibt ein Server-Job unerwartet dauerhaft RUNNING, wird der Status
nach Ablauf auf FAILED („Sync timed out") gesetzt statt den Loop endlos zu
pollieren – der Endlos-Zustand kann damit nicht mehr entstehen.
versionCode 118 -> 119. CONTEXT.md updated.
Status 2026-09-16 (118)
Secretary Journal 118 (versionCode 118): Härtung der gemeinsamen
Sync-Engine (secretary-common-android v0.30.0) – kein Journal-Code, nur
Dependency-Bump + Rebuild. Die OfflineSyncEngine ist so gehärtet, dass der
Rollout in Tasks/Calendar/Contacts/Notes/Links ohne Datenverlust möglich
ist: (1) Pending-Delete-Filter – Ressourcen, deren DeleteItem noch in
der Write-Behind-Queue liegt, werden aus dem gemergten Cache ausgeschlossen
und nie re-hochgeladen (verhindert die Auferstehung lokal gelöschter
Einträge in der UI bzw. ein Re-PUT auf dem Server, solange der DELETE nicht
geflusht wurde; vorher fehlte das im Engine-Vertrag, das Journal braucht es
nicht, alle anderen Apps schon). (2) prepare-null behält die Cache-
Kopie statt sie zu verwerfen (ein nicht entschlüsselbarer/nicht
uploadfähiger Eintrag bleibt im Cache und wird beim nächsten Sync erneut
versucht – niemals Datenverlust). (3) Stale-Queue-Put-Cleanup – nach
einem erfolgreichen Inline-Upload wird der zugehörige PutItem aus der
Queue entfernt, sodass flushPending keinen veralteten (z. B. anders
verschlüsselten) Body über die frisch hochgeladene Ressource legt. Neue
Tests in common: OfflineSyncEngineTest jetzt 16 Tests (Server-Item +
Cache-Item mit DeleteItem-Queue, prepare-null-Keep, Inline-Upload
räumt Queue-Put); Gesamt-Suite 67 Tests grün. versionCode 118 ==
versionCode/intern 117 -> 118.
Status 2026-09-16 (117)
Secretary Journal 117 (versionCode 117): Single-Flavor-Journal an der
gemeinsamen Sync-Engine aus secretary-common-android v0.29.0 (on-demand).
Die Handoff-Logik (Fetch, Re-Homing device-only-Uids, Cache-Ersetzung,
Offline-Erkennung) lebt nicht mehr im Journal, sondern in der neuen
gemeinsamen OfflineSyncEngine (secretary-common-android/src/main/java/
org/beowulf/secretary/common/OfflineSyncEngine.kt): ItemRemote
(listItemsRemote/saveItem/saveItemOffline), ItemsLoadResult
(Synced/Offline) und CrudItemRemote (Produktions-Seam um
CrudManager). Das Journal delegiert in loadEntriesInternal an
OfflineSyncEngine(codec, gstore, CrudItemRemote(makeCrud())) und
parametrisiert sie mit einem prepare-Lambda
(JournalEntry.toNote(JournalEntry.fromNote(note, decryptEntryTexts()),
encryptText()), runCatching → null überspringt den Upload, behält die
Cache-Kopie) und
onDavError → logErr. Damit nutzt das Journal dieselbe verlifizierte
Engine wie Tasks/Calendar/Contacts statt einer eigenen Kopie. Wichtigster
nebenläufiger Fix (aus der gemeinsamen Verallgemeinerung übernommen):
DavException (extends IOException) wird vor dem IOException-Branch
gefangen – ein Server-Reject hält den Eintrag im Cache und meldet ihn über
onDavError, statt in die Offline-Queue zu wandern. Die Test-Suite ist
komplett nach common verlagert und generalisiert:
secretary-common-android/src/test/.../OfflineSyncEngineTest.kt
(16 Tests, JUnit4 + runTest, getrieben über NotesCodec/Note und einen
FakeRemote) deckt ab: lokaler Modus (Store als einzige Quelle, Persistenz,
keine Pending-Queue bei reinen Store-Writes), erster Connect (Re-Homing+Upload
device-only, Server-only/Shared-Uid-Merge ohne Re-Upload, leeres No-Op-Sync),
prepare (Re-Encode für den Upload, null → Upload ausgelassen, Cache-Kopie
behalten), Sicherheit (pending-gelöschte Ressourcen bleiben aus dem Cache/
werden nie neu hochgeladen, erfolgreicher Inline-Upload räumt den stale
Queue-Put), Transport-Fehler beim
Upload (IOException → saveItemOffline), Server-Reject (DavException →
Cache + onDavError, nichts gequeued), Fetch-Fehler (IOException →
Offline + Cache unangetastet, DavException propagiert) und Persistenz des
gemergten Zustands. Gesamte common-Suite grün (67 Tests, davon 16 Engine).
Die Journal-eigenen JournalSyncEngine.kt/JournalSyncEngineTest.kt
(app/src/test) sind gelöscht, die Test-Abhängigkeiten (org.json,
kotlinx-coroutines-test, isReturnDefaultValues) aus app/build.gradle.kts
entfernt (dort liegen sie in common). versionCode 116 -> 117.
Status 2026-09-16 (116)
Secretary Journal 116 (versionCode 116): Single-Flavor-Journal
(offline-first, sync als Add-on). Die Flavor-Duplikation
(remote/local) ist in einem einzigen Code-Strang aufgehoben: localMode =
!repo.isConfigured(); ohne Konto ist die App rein lokal (Cache als
einzige Quelle), nach Login kommt CalDAV als Add-on dazu (erster Connect
re-homt lokal angelegte Uids auf den Server-Pfad und lädt sie hoch; der
gemergte Stand ersetzt den Cache; Logout behält den Store). Enthalten:
JournalTransfer, die gemeinsame SecretarySettingsScreen
(onLogin/connectLabel-Parameter, Einträge-Sektion „Verbinden"),
settings_connect_*-Strings DE/EN, TutorialPrefs gelöscht, Flavor-
Verzeichnisse, des Buildsystems Single-APK. Außerdem: keine
Status-Bar-Hiding-Änderungen. versionCode 115 -> 116.
Status 2026-09-16 (115)
Secretary Journal 115 (versionCode 115): Version bump nach Reset auf
v93. Der trunk wurde auf den Stand vor dem v94-Flavour-Merge
(20699bfc3a, v93) zurückgesetzt; die Flavour-Merge-Linie (v94–v114) samt
merge-redo liegt jetzt versteckt/geschlossen auf dem Abzweig
abandoned-flavor-merge. Versionierung folgt weiter dem Repository-Stand
(115 > 114, damit das Build-System ein frisches Artefakt liefert).
versionCode 114 -> 115.
Status 2026-09-14 (93)
Secretary Journal 93 (versionCode 93): Einstellungen: „Zufalls-Zeitfenster"
→ „Ruhezeit" umbenannt, Auswertungs-Karte entfernt, PayPal-Unterstützungs-
Karte hinzugefügt. Die Einstellung für das Zeitfenster, in dem keine
Erinnerungen stattfinden, heißt jetzt „Ruhezeit" (DE) / „Quiet time"
(EN) – der Hinweistext beschreibt den invertierten Zweck (keine Erinnerungen
und Vorschläge), der Standardwert ist 22:00–07:00 (statt 07:00–22:00).
Die Auswertungs-Karte (Tag-Intervall-Pills 7/14/30/90/365 Tage) ist aus
beiden Settings-Screens (remote + local) entfernt; der Bewertungszeitraum ist
auf 30 Tage hardcodiert (JournalRepository.evaluationWindowDays(),
Default bleibt 30). Importierte/verbleibende SharedPreferences-Werte werden
weiter gelesen. Die PillRow-/Pill-Imports und der evalWindowDays-State sind
aus beiden SettingsScreens entfernt. Unterm Abschnitt „Lizenz & Quellen" gibt
es einen neuen Abschnitt „Unterstützen" (DE) / „Support" (EN) mit
einem Hinweis-Text und einem klickbaren PayPal-Link
(https://www.paypal.com/paypalme/beowulfof). Die Tutorial-Seite
„Vorlagen & Erinnerungen" (tutorial_templates_body, DE+EN) erwähnt die
Ruhezeit/Quiet time als Zeitraum ohne Erinnerungen und Vorschläge.
RandomWindowSettings-KDoc aktualisiert. versionCode 92 -> 93.
Status 2026-09-14 (92)
Secretary Journal 92 (versionCode 92): Trigger-/Skill-Editor auf
gesammelte-Werte-Dropdown umgestellt; Korrelation/Karten entfernt; nach
Trigger-Erfassung Skill-Vorschlag als Erinnerung. Im gemeinsamen
TendencyTextBody (beide Flavor) ist das Freitextfeld für Trigger/Skill jetzt
ein editierbares Dropdown (GatheredValueField:
ExposedDropdownMenuBox + ExposedDropdownMenuAnchorType.PrimaryEditable,
gefilterte Vorschläge live, take(8), sortiert nach Häufigkeit aus
vm.gatheredData des jeweiligen Typs) – neuer Text bleibt frei eingebbar
(updateEntryText), Tippen übernimmt einen gesammelten Wert. Entfernt sind
die drei Editor-Karten/-Sektionen: TriggerCorrelationSection
(„Bewährte Gegenmittel"/„Risiko-Muster"), TriggerSkillProposalsSection
(„Skill-Vorschläge" mit Kopieren) und SkillCorrelationSection
(„Auslöser der letzten %d Tage"); dadurch entfallen auch editorCorrelation
in beiden ViewModels sowie in ProposalEngine der komplette
v40-Korrelationsblock (TriggerSkillLink, CorrelationPattern,
correlationPattern, correlateSkillAt, correlateTriggerWithText,
skillUid; proposeSkillsAfterTrigger + SkillProposal + entryTimeMs
bleiben). Stattdessen: Beim Speichern eines Trigger-Eintrags
(keine Vorlage) setzt saveEntry nach dem Persistieren den Top
Skill-Vorschlag (proposeSkillsAfterTrigger gegen die aktualisierten
entries) in die neuen One-Shot-State skillReminderProposal/
skillReminderTriggerText; der NavGraph zeigt darüber (Box-Overlay über dem
NavHost, Route-unabhängig) den SkillReminderDialog („Trigger erfasst –
Skill-Vorschlag"): Body mit Trigger-Text, Skill-Text, %dx · ↗ n · Stimmung
besser n; „Skill erfassen" ruft adoptSkillReminder() (= öffnet
openSkillEntryForDate(LocalDate.now()) + copy(text = Vorschlag) und
navigiert zum Editor), „Verwerfen" ruft dismissSkillReminder().
DE/EN-Strings: corr_* + prop_* gelöscht; neu edit_gathered_hint/
edit_gathered_empty/remind_skill_title/remind_skill_body/
remind_skill_add/remind_skill_dismiss; tutorial_trigger_body/
tutorial_skill_body (Editor-Korrelations-Claim entfernt). Beide Flavor
kompilieren sauber (v71-Standard). versionCode 91 -> 92.
Status 2026-09-14 (91)
Secretary Journal 91 (versionCode 91): Tutorial um „Gesammelte
Trigger & Skills"-Seite erweitert. Das interaktive Tutorial (v85/v84,
inzwischen 15 Seiten) bekommt nach der Statistik-Seite eine neue Seite
„Gesammelte Trigger & Skills" (Icon Icons.Filled.CollectionsBookmark,
tutorial_gathered_title/tutorial_gathered_body, DE+EN): Sie erklärt den
GatheredScreen – der Screen sammelt jeden Trigger- und Skill-Text aus dem
Journal, Tippen benennt einen Wert um, Gedrückthalten führt ihn mit
einem anderen zusammen, beides wirkt auch auf alle bisherigen Einträge
(rückwärts); erreichbar über Einstellungen → „Gesammelte Trigger & Skills".
Kein TutorialTry-Action-Button (die Seite öffnet den Screen nicht, nur
Textkarte). Entfernbarer Zugriff unverändert über den Tutorial-Button in
beiden Settings-Screens bzw. den Auto-Start der lokalen Edition.
versionCode 90 -> 91.
Status 2026-09-14 (90)
Secretary Journal 90 (versionCode 90): Gesammelte Werte: Bedienung auf
Tipp/Gedrückthalten umgestellt. Im GatheredScreen (v89) ersetzt eine
naturlichere Gesten-Bedienung die Checkboxen und Buttons: ein kurzer Tap auf
einen Eintrag öffnet direkt den Umbenennen-Dialog, ein langer Druck öffnet
ein Dropdown-Menü (wie ItemContextMenu, combinedClickable), das alle
anderen gesammelten Werte desselben Typs auflistet – Auswahl führt diesen
Wert mit dem angetippten zusammen (mergeGatheredTexts mit einem Quelltext,
das bestehende Einträge via copy(text=…) + pushAllEntries()/persist()
rückwirkend umschreibt). Die bisherigen Zeilen-Checkboxen, der
„%d ausgewählt"-Zähler und der Zusammenführen-Button samt MergeDialog
(mit Ziel-Textfeld) sind entfernt; je Sektion zeigt eine neue Hinweiszeile
(gathered_gesture_hint) die Gesten. Entfernte DE/EN-Strings:
gathered_merge, gathered_merge_title, gathered_merge_target,
gathered_merge_hint, gathered_select_cd, gathered_selected_count; neu
gathered_merge_with/gathered_gesture_hint. versionCode 89 -> 90.
Status 2026-09-14 (89)
Secretary Journal 89 (versionCode 89): Gesammelte Trigger & Skills wieder
eingeführt (fresh, rein aus den Einträgen abgeleitet) + gewichtete
Skill-Vorschläge nach Trigger. In beiden Einstellungen-Screens (remote +
local) gibt es im neuen Abschnitt „Gesammelte Trigger & Skills" einen Button
„Gesammelte Werte verwalten", der den neuen Screen GatheredScreen (Route
gathered, wie die anderen Screens mit ScreenHeader) öffnet: Je Liste
(Trigger/Skill) zeigt er jeden distinct Freitext mit Anzahl (n×), letztem
Auftreten (dd.MM.yyyy) und — aus dem neuen Wiederholungs-Scan —
durchschnittlichem Abstand in Tagen (Ø alle X Tage). Die Daten kommen nie
serverseitig, sondern live aus dem Eintrags-Cache über die neue reine
GatherEngine (GatheredItem: entryType/text/count/lastSeen) und
ProposalEngine.scanRecurringPatterns (RecurringPattern:
occurrences/averageGapDays/lastOccurrence) — kein kuratiertes GatheredStore,
die Listen sind per Definition deckungsgleich mit der Historie (Abkehr vom
v59-„GatheredStore"-Konzept). In der Zeile kann man per Checkbox mehrere Werte
fürs Zusammenführen auswählen sowie jeden Wert umbenennen: Beides
wirkt als Rückwärts-Anpassung in allen historischen Einträgen (entries =
entries.map + copy(text = …), remote danach pushAllEntries(), local
withContext(Dispatchers.IO) { persist() }; neu in beiden ViewModels
renameGatheredText/mergeGatheredTexts). Der Trigger-Editor zeigt unter
der bestehenden Korrelation eine neue Sektion „Skill-Vorschläge"
(TriggerSkillProposalsSection, getrieben von
ProposalEngine.proposeSkillsAfterTrigger): Sie bewertet Skills, die in den
FOLLOWUP_WINDOW_DAYS (3 Tage) auf einen Trigger gleichen Texts folgten, mit
weight = Belege + 0.5 × positive Belege, wobei ein Beleg positiv ist,
wenn der Trigger Tendenz hoch bekam oder die Stimmung nach dem Skill
höher war als vor dem Trigger (Mood-numericValue, regelbasierter
Vergleich über den nächstliegenden Mood-Eintrag); pro Vorschlag zeigt die Zeile
Meta n× · ↗ n · Stimmung besser n (proof/tendencyUp/moodLift) und den Rang,
Tippen kopiert den Text in die Zwischenablage (Toast). DE/EN-Strings
settings_section_gathered/settings_gathered_*/gathered_* und prop_*
ergänzt. versionCode 88 -> 89.
Status 2026-09-13 (88)
Secretary Journal 88 (versionCode 88): Kategorie-Parsing gehärtet +
Wiederholungs-Korrektur übernommen (secretary-common-android v0.26.0).
Die gemeinsame Bibliothek baut jetzt mit dem CATEGORIES-Escape-Fix: Der
VJournal.parseNote-Fix (v0.25.0) – Splitt der CATEGORIES-Liste nur an
unescaped-gespeicherten Kommas statt an jedem , – sorgt dafür, dass
Wochentags-Regeln (RRULE:FREQ=WEEKLY;BYDAY=MO\,WE\,FR) beim erneuten
Öffnen des Wiederholungs-Editors wieder vollständig mit allen
ausgewählten Tagen gelesen werden. v0.26.0 verallgemeinert dasselbe
Escaping-Verhalten auf VTODO/VEVENT/VCARD (betrifft Tasks/Calendar/
Contacts, nicht das Journal). versionCode 87 -> 88.
Status 2026-09-13 (87)
Secretary Journal 87 (versionCode 87): Lokale APK heißt jetzt
journal-<version>.apk. Seit v81 teilen beide Flavor dieselbe
applicationId (org.beowulf.secretary.journal) und denselben App-Namen
„Journal" — nur das APK-Artefakt des Buildsystems der lokalen Edition hieß weiterhin
secretary-journal-local-<version>.apk. Neu wird die lokale Edition unter
journal-<version>.apk in das Paket-Repository kopiert
(das Buildsystem: die Bauanzeige nennt secretary-journal-<version>.apk für
Remote und journal-<version>.apk für Local, der Copy-Schritt benutzt
journal-{version}.apk); die Remote-Edition bleibt unverändert
secretary-journal-<version>.apk. Alte secretary-journal-local-*-Artefakte
im Repository bleiben unberührt. versionCode 87 == versionName 87 (local:
87-lokal).
Status 2026-09-13 (86)
Secretary Journal 86 (versionCode 86): Fixes im interaktiven Tutorial
(v85). Zwei Fehler behoben: (1) Der „Ausprobieren"-Button begrenzte seine
Höhe fest auf 48dp und schnitt dadurch umbrechende/mehrzeilige Labels ab —
ersetzt durch defaultMinSize(minHeight = 48.dp), sodass die Taste mit dem
Text wächst. (2) Beim Verlassen des Editors über den Zurück-Pfeil (der Editor
wird vom Tutorial aus geöffnet) landete man auf der ersten statt der
vorherigen Tutorial-Seite: Die Seitenvariable page nutzte remember und
ging beim Wegkomponieren der Tutorial-Route (Nutzen von Routes.EDIT) verloren.
Mit rememberSaveable bleibt der Seitenindex über die Navigation erhalten und
das Tutorial kehrt auf dieselbe Seite zurück, von der aus der Durchlauf
gestartet wurde. versionCode 86 == versionName 86 (local: 86-lokal).
Status 2026-09-13 (85)
Secretary Journal 85 (versionCode 85): Interaktiver Tutorial-Durchlauf
(„Ausprobieren"). Auf jeder Eintrags-Tutorialseite (Highlights,
Stimmung, Stuhl & Urin, Medikamente, Essen & Getränke, Trigger, Skill) gibt
es unter der Textkarte einen Button „Eintrag anlegen und ausprobieren"
(tutorial_try_entry), auf der Vorlagen-Seite den Button „Tägliche
Highlights-Vorlage anlegen" (tutorial_try_template). Beide öffnen den
Editor vorausgefüllt direkt über dem Tutorial (Route EDIT wird auf den
Tutorial-Stapel gelegt; Speichern/Abbrechen führt zurück ins Tutorial).
Dafür bekommt TutorialScreen den neuen Callback onTry(TutorialTry) und
jedes TutorialPage ein optionales tryAction-Attribut; NavGraph mappt
die Aktion: Eintragsseiten rufen das jeweilige vm.open*EntryForDate
(LocalDate.now(), Highlights weiterhin find-or-create/fortführen) auf,
die Vorlagen-Seite legt einen frischen TEXT-Entwurf mit isTemplate = true
und RRULE FREQ=DAILY an (createNewTextEntry + setEditingTemplate(true)
updateRrule), dann wird jeweils aufRoutes.EDITnavigiert. So kann man jeden Eintragstyp direkt aus dem Tutorial real anlegen und eine einmal täglich wiederkehrende Highlights-Vorlage durchspielen. versionCode 85 == versionName 85 (local:85-lokal).
Status 2026-09-13 (84)
Secretary Journal 84 (versionCode 84): Tutorial automatisch beim ersten
Start (lokale Edition) + Eintragstypen-Walkthrough. Nur die lokale
Edition öffnet das Tutorial beim ersten App-Start automatisch (Route
tutorial, TutorialPrefs in data/: Flag tutorial_auto_started in den
flavor-eigenen Prefs secretary_journal_local bzw. secretary_journal;
NavGraph navigiert per LaunchedEffect(loggedIn) nur bei BuildConfig.FLAVOR
== "local" und setzt das Flag beim Anzeigen, danach bleibt es im Einstellungen-
Button erreichbar). Das Tutorial ist auf 14 Seiten erweitert und geht
seit der Aufteilung der bisherigen Eintragstypen-Übersicht durch alle
Eintragstypen: Highlights (nur einmal pro Tag, wird beim erneuten Öffnen
fortgeführt – explizit im tutorial_highlights_body), Stimmung (fünf Stufen,
auch mehrmals täglich), Stuhl & Urin (Bristol 1–7 / Armstrong 1–8), Medikamente
(Wirkstoff/Darreichungsform/Dosis, Erinnerung), Essen & Getränke (kJ/ml),
Trigger und Skill (je mit Tendenz). Die Folge-Seiten (Willkommen, Einträge
anlegen, Übersicht, Auswertung, Vorlagen/Erinnerungen, Statistik, Sicherheit/
Sicherung) bleiben. Die bisherigen tutorial_0_*…tutorial_6_*-Strings sind
durch sprechende Namen ersetzt (tutorial_welcome_*…tutorial_security_*).
versionCode 84 == versionName 84 (local: 84-lokal).
Status 2026-09-13 (83)
Secretary Journal 83 (versionCode 83): Fix: Deprecation-Warnung im
Tutorial. Die MenuBook-Icon auf der Willkommensseite des Tutorials
verwendet jetzt die AutoMirrored-Variante
(Icons.AutoMirrored.Filled.MenuBook statt des deprecated
Icons.Filled.MenuBook) – beide Flavor kompilieren wieder ohne Warnungen
(v71-Standard). Kein funktionaler Unterschied, nur der Referenzwechsel für
die RTL-Auto-Mirroring-Warnung. versionCode 83 == versionName 83 (local:
83-lokal).
Status 2026-09-13 (82)
Secretary Journal 82 (versionCode 82): In-App-Tutorial. In beiden
Einstellungen-Screens (remote + local) gibt es im neuen Abschnitt
„Tutorial" einen Button „Tutorial starten", der einen seitenbasierten
Tutorial-Screen (Route tutorial, TutorialScreen in ui/, wie die
anderen Screens mit ScreenHeader, Zurück/Weiter/Fertig-Navigation und
Punkt-Indikator) öffnet. Sieben Seiten führen durch die Funktionen:
Willkommen (Server/CalDAV oder lokal), Einträge anlegen (+ bzw.
Smiley, Datum + Uhrzeit), Eintragstypen (Highlights, Stimmung,
Stuhl/Urin, Medikamente, Essen/Getränke, Trigger/Skill mit Tendenz),
Stimmung & Auswertung (fünf Stufen, einstellbares Fenster 7–365 Tage),
Vorlagen & Erinnerungen (fest/zufällig, Medikamenten-Erinnerungen),
Trigger & Skills (Statistik, bewährte Gegenmittel, Risiko-Muster) und
Sicherheit & Sicherung (Passwort-Verschlüsselung, Biometrie,
Export/Import, Klartext-Bericht). DE/EN-Strings
settings_section_tutorial/settings_tutorial_hint/settings_tutorial_button
und tutorial_* ergänzt. versionCode 82 == versionName 82 (local:
82-lokal).
Status 2026-09-13 (81)
Secretary Journal 81 (versionCode 81): Lokale Edition heißt nur noch
„Journal“ – Name und Paket. Der app_name-Override der lokalen Edition
(app/src/local/res/values/strings.xml) lautet nicht mehr „Journal lokal“,
sondern „Journal“ – identisch zur Remote-Edition. Außerdem trägt die lokale
Edition jetzt dasselbe applicationId org.beowulf.secretary.journal
(statt org.beowulf.secretary.journal.local), die versionNameSuffix-
Versionierung bleibt (81-lokal); die Flavor-Daten bleiben getrennt
(secretary_journal_local-Prefs). versionCode 81 == versionName 81
(local: 81-lokal).
Status 2026-09-13 (80)
Secretary Journal 80 (versionCode 80): Emoji-Gesichter statt kawaii-
Canvas-Smiley. Die gezeichneten kawaii-Stimmungsgesichter (KawaiiMoodFace)
sind ersetzt: MoodEmojiFace zeigt jetzt nur noch das echte Unicode-Emoji
(Mood.emoji, dieselben Emojis wie in Eintragslisten und Editor)
proportional zur Kachelgröße (maxHeight * 0.78). Betroffen sind das Hero-
Smiley (dominante Stimmung, 150dp) und die Mood-Einträge in der Liste/
Vorlagenliste (44dp). Damit sind Stimmung, Gesichtsausdruck und
-Farbgebung identisch zu den Emojis, die bei der Auswahl/Listung der
Einträge verwendet werden. versionCode 80 == versionName 80 (local:
80-lokal).
Status 2026-09-12 (79)
Secretary Journal 79 (versionCode 79): Stimmungs-Gesichter auf
Kachelgröße vereinheitlicht. In den Eintragszeilen (DayEntryRow) wurden
die kawaii-Stimmungsgesichter von 52dp auf 44dp reduziert – dieselbe
Größe wie die farbigen Typ-Kacheln der übrigen Einträge und wie der danebenstehende
Tendenz-Pfeil; der isMood-Sonderfall für die Bildgröße ist entfernt
(KawaiiMoodFace skaliert proportional). versionCode 79 == versionName 79
(local: 79-lokal).
Status 2026-09-12 (78)
Secretary Journal 78 (versionCode 78): Liste zurückgebaut: Tag+Datum als
eigene Kopfzeile, alte Tendenz-Pfeile, Eintrag = Icon + Pfeil + Text.
Der kräftige Canvas-Pfeil TendencyArrow aus v77 ist wieder entfernt –
alle Tendenz-Anzeigen nutzen wieder das dünne Material-Icon tendencyIcon
(TrendingUp/TrendingDown mit tendencyColor-Tint): Eintrags- und
Vorlagen-Zeilen, das Tendenz-Badge am Hero-Smiley und die beiden
Korrelations-Zeilen im Editor (Trigger-Row, Skill-Liste samt zugehöriger
semantics/CircleShape-Imports). Die Tageszeile (DayListRow) hat keine
92dp-Indexspalte mehr: Wochentag + Datum stehen als eigene vollbreite
Kopfzeile (heute * fett unterstrichen primär, Sa/So rot, Hintergrund je
isShadedDay täglich alternierend), darunter alle Einträge dieses Datums.
Jede Eintragszeile (DayEntryRow) ist Icon links, direkt daneben der
Tendenz-Pfeil in gleicher Größe (44dp-Kachel bzw. 52dp-Kawaii-Gesicht,
Mood ohne Tendenz), dann der Text im restlichen Zeilenraum (mehrzeiliger
Umbruch). Highlights (TEXT) stellen jede der drei Felder in einer eigenen
Zeile dar (goodOne/goodTwo/goodThree, leere Felder übersprungen)
bei nur einem Icon pro Eintrag; Zeit (entryTimeText) als zweite Zeile.
Die Vorlagen-Zeile nutzt denselben Icon+Pfeil+Text-Aufbau ohne Disc/Overlay.
versionCode 78 == versionName 78 (local: 78-lokal).
Status 2026-09-12 (77)
Secretary Journal 77 (versionCode 77): Liste verfeinert: Zeit statt
Datum, kräftige Tendenz über dem Icon, tägliche Schattierung,
Vorlagen-Liste im gleichen Stil. Da die Einträge in der Hauptansicht
chronologisch nach Tag gruppiert sind (Tagesindex links), zeigt jede
Eintragszeile (DayEntryRow) nur noch die Uhrzeit (entryTimeText,
HH:mm, leere Zeile bei Datum-ohne-Zeit-Einträgen) statt dd.MM.yyyy,
HH:mm. Die Tendenz sitzt nicht mehr rechts am Zeilenende, sondern als
kräftiger Pfeil über der unteren rechten Ecke des Entry-Icons auf einem
opaken runden surface-Disk (EntryIconTile: 52dp-Kawaii-Gesicht bzw.
44dp-Typ-Kachel, Disk ≈ tile/2.4, Pfeil ≈ tile/2.8). Der Pfeil ist kein
dünnes Material-Icon mehr, sondern der neue gemeinsame TendencyArrow
(Canvas: dicker runder Schaft mit 26 %-Strichbreite plus gefüllter
dreieckiger Spitze ↗/↘, in JournalTypeUi) — konsistent überall:
Eintrags-Kacheln und Vorlagen-Zeilen, das Tendenz-Badge unten rechts am
großen Smiley (Hero) und die zwei Korrelations-Zeilen im Editor
(Trigger-Row, Skill-Liste); alle tendencyIcon-Material-Aufrufe sind
durch TendencyArrow ersetzt. Der Zeilen-Hintergrund wechselt nicht
mehr je ISO-Woche, sondern täglich (isShadedDay, gerades Epoch-Day
hell/dunkel wie bisher, benachbarte Tage alternieren). Die Vorlagen-Liste
ist im selben Stil umgebaut (TemplateListRow ohne Card): Icon-Kachel
mit optionaler Tendenz-Überlagerung, einzeiliger Titel, „Nächstes Mal"-
Zeile und der Play-Button „Jetzt eintragen"; die bisherigen
Karten-Umrandung und PaddingValues/Card-Import sind entfernt.
versionCode 77 == versionName 77 (local: 77-lokal).
Status 2026-09-12 (75)
Secretary Journal 75 (versionCode 75): Kalender-Tagesliste statt
Eintragskarten + 5-Stufen-Stimmung. Die Hauptansicht zeigt jetzt eine Liste
wie im secretary-calendar: Die Einträge sind nach Datum gruppiert
(neueste zuerst, neueste oben), links steht der Tagesindex (Wochentag-
Kürzel plus Tag, heute mit *-Präfix fett unterstrichen in Primärfarbe),
Sa/So und das Datum sind rot (error-Farbe) und der Zeilen-Hintergrund
wechselt hell/dunkel je ISO-Kalenderwoche (gerade Woche heller,
ungerade dunkler, isShadedWeek). Rechts neben dem Index stehen die
Einträge: Stimmungs-Einträge zeigen die kawaii-Gesichter nun
deutlich größer (52dp, KawaiiMoodFace), andere Typen ihr Icon in
farbiger Kachel, daneben Titel (mit Umbruch, mehrzeilig), Zeitstempel
und die Tendenz rechts; der Wort-Umbruch erlaubt mehrzeilige Zeilen.
Dafür wird die Eintragsliste in JournalCarouselScreen nicht mehr als
flache EntryListRow-Karten (maxLines = 1) gezeichnet, sondern je
Tag (DayListRow/DayEntryRow) mit Trennlinie. Zudem ist die Stimmung
auf 5 Stufen erweitert: Mood hat neu VERY_SAD (💧😭) und
VERY_HAPPY (😄) zwischen den bisherigen Werten, JournalTypeUi
liefert Icons/Farben/Labels für alle fünf, beide ViewModels nutzen die
Schwellen (≥3.5/≥2.5/≥1.5/≥0.5 → veryHappy/happy/normal/sad/verySad,
happy = HAPPY||VERY_HAPPY, sad = SAD||VERY_SAD), KawaiiMoodFace zeichnet
fünf Gesichter (verySad: großer Frown + 2 Tränen + hängende Lider, sad:
Frown + 1 Träne, normal: sanftes Lächeln, happy: offenes Lächeln, veryHappy:
geschlossene Freude-Augen „^ ^" + breites Lächeln mit Zunge) und der
Stimmungs-Editor zeigt die fünf Zellen in FlowRow (wrap-fähig).
DE/EN-Strings für die neuen Stufen ergänzt (mood_very_sad/mood_very_happy),
mood_happy/mood_neutral angepasst (Gut/Good, Normal/Neutral). Alte
Einträge mit mood:sad|normal|happy bleiben lesbar. versionCode 75 ==
versionName 75 (local: 75-lokal).
Status 2026-09-12 (74)
Secretary Journal 74 (versionCode 74): Bäckchen entfernt. Aus dem
KawaiiMoodFace aus v73 sind die rosigen Blush-Bäckchen entfernt – das
Gesicht besteht nur noch aus Gesichts-Disc, Augen und Mund (Zunge bleibt).
versionCode 74 == versionName 74 (local: 74-lokal).
Status 2026-09-12 (73)
Secretary Journal 73 (versionCode 73): Kawaii-Smiley statt Mood-Orbit-Ring.
Der in v72 eingeführte Mood-Orbit-Ring (drei Emojis auf proportionalen
Kreisbögen) ist wieder entfernt – der Verweis auf einen stilisierten
Mood-Tracker-UI macht deutlich, dass der Ring der gewünschten Ästhetik nicht
entsprach. Stattdessen zeichnet KawaiiMoodFace (Canvas, reines Compose) für
die dominante Stimmung ein kawaii-artiges Gesicht in der jeweiligen
Mood-Farbe: weiches Gesichts-Disc mit Ton-Ring, große glänzende Augen mit
Spiegelpunkten (traurig: hängende Lider + Träne), rosige Bäckchen und
stimmungsabhängiger Mund (happy: breites Lächeln mit Zunge, normal: sanftes
Lächeln, sad: Frown + Teardrop). Der Platzhalter „–" bleibt bei fehlenden
Stimmungsdaten, das Tendenz-Badge unten rechts und die Jung/Alt-Zählzeile
unverändert. Unbenutzte Imports (Icons.Mood/MoodBad/SentimentNeutral,
border, offset, cos/sin) entfernt. versionCode 73 == versionName 73
(local: 73-lokal).
Status 2026-09-12 (72)
Secretary Journal 72 (versionCode 72): Typewriter-Vereinheitlichung und
Mood-Orbit-Ring. Die Stimmungskennzahl im Karussell ist kein stimmungsloser
Platzhalter mehr, sondern nutzt displayLarge (Special Elite). Zeitstempel
(labelMedium) und Vorlagen-Vorschau (labelSmall) erscheinen in der
Monospace-Metadaten-Schrift. Die Kalender-Tageszahlen verwenden die
Typewriter-Font (heute titleMedium fett, sonst titleSmall). Der bisherige
einfache Mood-Donut wird durch den Mood-Orbit-Ring ersetzt: drei Mood-Emojis
(happy oben, normal unten-rechts, sad unten-links) sitzen auf dem Ring;
proportionale farbige Kreisbögen zeigen die Verteilung, die dominante Stimmung
ist als Chip vergrößert und hervorgehoben. Reines Canvas, keine neuen
Abhängigkeiten. versionCode 72 == versionName 72 (local: 72-lokal).
Status 2026-09-11 (71)
Secretary Journal 71 (versionCode 71): Deprecation-Warnungen entfernt.
Zwei Kotlin-Warnungen beim Debug-Build sind behoben (kein @Suppress,
Ursachen-Lösung): CrashReporter liest die Version über
PackageInfoCompat.getLongVersionCode statt des deprecated
PackageInfo.versionCode (Int-Feld, seit API 28 deprecated) und
LocalePrefs.wrap erzeugt die Locale über Locale.forLanguageTag statt des
deprecated Locale(String)-Konstruktors (Java 19). Beide Flavor kompilieren
ohne Warnungen; das JSON-Report-Feld versionCode enthält weiterhin eine
Zahl (nun Long). versionCode 71 == versionName 71 (local: 71-lokal).
Status 2026-09-11 (70)
Secretary Journal 70 (versionCode 70): Editor-Vereinheitlichung.
Eintragsfelder sind jetzt homogen: Bei Essen/Snack steht der Text (Was
gegessen?) vor der Energie (kJ) — beim Getränk Name vor Menge (ml),
Werte kommen überall nach der Beschreibung. Die Tendenz-Auswahl ist ans
untere Ende des Editors gewandert und steht direkt über dem Speichern-
Button (IME-Padding bleibt erhalten, beides ist bei offener Tastatur
scrollbar erreichbar). Alle Chip-Reihen (Essensart, Excreta-Art,
Darreichungsform, Tendenz) nutzen jetzt FlowRow statt horizontalem Scroll,
sodass Chips nie aus dem sichtbaren Bereich laufen. Die Essensart hat
nur noch drei Chips (Mahlzeit/Snack/Getränk) — „Keine" ist entfernt; das
Abwählen der Auswahl funktioniert weiterhin per erneutem Tippen auf den
gewählten Chip. Die gekapselten FilterChip-Funktionen bleiben unverändert.
versionCode 70 == versionName 70 (local: 70-lokal).
Status 2026-09-11 (69)
Secretary Journal 69 (versionCode 69): Version bump. Property bump
nach v68 – Versionierung folgt dem Repository-Stand (der das Buildsystem
Build-Manager überspringt die Erstellung, wenn eine Ziel-APK gleicher Version
bereits im Repo liegt). versionCode 69 == versionName 69 (local: 69-lokal).
Status 2026-09-11 (68)
Secretary Journal 68 (versionCode 68): Fix: „Eintragen" einer fälligen
Vorlage tut nichts (v64). Der Accept-Button der Vorlagen-Benachrichtigung
lief als PendingIntent.getActivity direkt auf die MainActivity; die
Entwurfs-Anlage, die Benachrichtigungs-Verwerfung und das Neu-Armen wurden
aber seit v64 ausschließlich im Broadcast-Pfad (TemplateReceiver.handleAccept)
erledigt, den niemand mehr auslöste. Die Pending-Edit-Queue blieb leer →
vm.handleTemplateAccept kehrte bei drainPendingEdit ?: return zurück und
die Benachrichtigung blieb stehen. Neu ist der Accept-Button weiterhin ein
activity PendingIntent auf MainActivity (zuverlässig, da
Notification-Taps von den Android-Background-Activity-Start-Einschränkungen
ausgenommen sind); die Entwurfs-Klonung, die Benachrichtigungs-Verwerfung und
das Neu-Armen sind aber aus dem unerreichbaren Broadcast-Pfad in eine neue
Companion-Function TemplateReceiver.performAccept(context, uid) verlagert,
die beide MainActivitys (remote + local) in handleTemplateAccept vor
vm.handleTemplateAccept aufrufen – dadurch wird die Edit-Queue korrekt
befüllt und der vorausgefüllte Editor öffnet sich zuverlässig. Der
ACTION_TEMPLATE_ACCEPT-Zweig im Broadcast-Empfänger ist entfernt.
versionCode 68 == versionName 68 (local: 68-lokal).
Status 2026-09-11 (67)
Secretary Journal 67 (versionCode 67): Crash-fix: System-Dateidialog
(und alle Activity-Result-Launcher) unter FragmentActivity. Beide
Flavor-MainActivitys erweitern jetzt androidx.activity.ComponentActivity
(statt FragmentActivity, das seit v28 für BiometricPrompt benötigt wurde).
Hintergrund: androidx.activity's ActivityResultRegistry vergibt seit 1.2.0
Request-Codes in den oberen 16 Bits (0x10000–Int.MAX), FragmentActivity.
startActivityForResult erzwingt aber den 0–65535-Bereich (checkForValidRequestCode,
„Can only use lower 16 bits for requestCode"). Dadurch crashte jeder Launcher-
Start deterministisch – nachgewiesen in zwei Crash-Reports der FP5
(ReportCard.kt:129, „Erstellen" des Berichts öffnet nicht den Dateidialog):
Betroffen waren der Bericht (CreateDocument("text/plain")) sowie auch
Export/Import (CreateDocument/OpenDocument). ComponentActivity führt diese
Prüfung nicht aus; die App ist reine Compose ohne Fragments. Damit ist auch das
Biometrie-Hosting kein Problem mehr: rememberBiometricPrompt nutzt jetzt die
neue rememberAuthenticationLauncher-API (androidx.biometric:biometric-compose
1.4.0-alpha07, basierend auf registerForAuthenticationResult(), der Nachfolger
von BiometricPrompt im old-Style, der nur FragmentActivity/Fragment kennt;
ersetzt die alte BiometricPrompt(FragmentActivity, …)-Konstruktion aus v28).
biometricAuthRequest(context, title, subtitle, crypto) baut einen
Class-3-Authentifizierungsrequest (Abbruch = CustomOption-Fallback statt
negativem Button); enc_enable_biometric_title/-sub, unlock_title/-sub und
der Zeichensatz bleiben unverändert. BiometricCommon.findFragmentActivity/
findActivity entfallen. versionCode 67 == versionName 67 (local: 67-lokal).
Status 2026-09-11 (66)
Secretary Journal 66 (versionCode 66): Klartext-Bericht für den Arzt.
In beiden Einstellungen-Screens (remote + local) gibt es im Abschnitt
„Sicherung" unter Export/Import eine neue Karte „Bericht" (ReportCard,
ui/crypto/): Ein Klick auf „Bericht erstellen" öffnet einen Dialog, in dem
man die einzubeziehenden Eintragstypen per Checkbox einschließen/
ausschließen kann (Highlights, Stimmung, Excreta, Medikamente, Essen,
Trigger, Skill, Standard: alle); „Erstellen" öffnet den System-Dateidialog
(CreateDocument("text/plain"), Vorschlag journal-report-<Datum>.txt)
und schreibt einen Zeilen-basierten Klartext-Bericht aller passenden
Einträge. Der Bericht (journalReportText in ui/JournalReport.kt,
abgerufen über vm.reportData(uri, includedTypes) in beiden ViewModels):
sortiert chronologisch (älteste zuerst), schließt Vorlagen aus, ist
immer Klartext (bei aktiver Verschlüsselung werden die Einträge vorher
JournalTransfer.decryptEntries()-entschlüsselt; bei gesperrtem Journal
erscheint der Hinweis report_locked statt der Datei) und führt je Eintrag
Zeitpunkt (dd.MM.yyyy, HH:mm) + Typ-Label und darunter alle Felder aus
(drei Gute-Dinge-Zeilen, Stimmung mit Emoji, Stuhl/Urin mit Bristol-/Armstrong-
Beschreibung, Medikament mit Dosis und Grund, Essen/Getränk mit kJ bzw. ml,
Trigger/Skill-Text, optional Tendenz). Zweck: die Daten einfach und lesbar
einem Arzt zur Auswertung zu übergeben. DE/EN-Strings report_* +
vm_report_created. versionCode 66 == versionName 66 (local: 66-lokal).
Status 2026-09-11 (64)
Secretary Journal 64 (versionCode 64): Vorlagen-Erinnerung „Eintragen"
öffnet den Editor vorausgefüllt statt den Eintrag sofort anzulegen. Bisher
legte das Accept einer fälligen Vorlage (TemplateReceiver) einen fertigen
Eintrag an (Clone in die Accept-Queue, dann via drainPendingTemplates
in beiden ViewModels persistiert). Neu legt Accept nur einen Entwurf ab:
TemplateReceiver.handleAccept klont die Vorlage (neue uid, isTemplate=false,
rrule="", randomSchedule=null, Datum heute / occurredAt=jetzt) in die
neue Pending-Edit-Queue (PendingTemplateQueue.edits, ersetzt die
Accept-Queue samt ACTION_ACCEPTED-Broadcast), armt das nächste Vorkommen
neu, verwirft die Benachrichtigung und startet die App (Activity-PendingIntent
FLAG_ACTIVITY_NEW_TASK|SINGLE_TOP). BeideMainActivitys reichen das Accept-Intent anvm.handleTemplateAccept(uid)weiter; beide ViewModels öffnen daraus den Editor für den Vorlagen-Eintragstyp vorausgefüllt (editingEntry= Entwurf,templateEditRequest-Signal an denNavGraph, der aufRoutes.EDITnavigiert;JournalTransfer.decryptEntriesbei aktiver Verschlüsselung; Entwurf bleibt bei gesperrter App oder offenem Editor in der Queue und wird beim StartdrainPendingTemplateEdits()bz. nach Entsperren geöffnet). Der Eintrag wird erst beim Speichern im Editor geschrieben – auch der „Jetzt eintragen"-Play-Button der Vorlagen-Liste (runTemplateNow) öffnet nur noch den vorausgefüllten Editor. versionCode 64 == versionName 64 (local:64-lokal).
Status 2026-09-11 (63)
Secretary Journal 63 (versionCode 63): „Nächstes Mal" für
Zufalls-Vorlagen zeigt jetzt den nächsten echten Zufalls-Slot statt des
RRULE-Basisauftretens. Der Vorlagen-Zeilen-Label
(nextTemplateOccurrence in JournalCarouselScreen) berechnete bisher für
jede Vorlage den nächsten RRULE-Auftritt (TemplateAlarmScheduler.nextOccurrence)
– bei einer täglichen Wiederholung mit Basiszeit in der Vergangenheit (Vorlage
z. B. heute um 14:00 angelegt, „Nächstes Mal" = morgen 14:00). Die
Zufalls-Alarme für heute waren trotzdem korrekt bewaffnet (3 deterministische
Slots im Einstellungs-Fenster), aber unsichtbar. Neu nutzt der Label für
Vorlagen mit randomSchedule den frühesten bewaffneten Zufalls-Slot
(TemplateAlarmScheduler.nextRandomFire, gleiche Fenster-/Vorkommens-Logik
wie arm inkl. isOccurrenceDay), sodass z. B. eine heute angelegte
„Stimmung"-Vorlage mit 3×/Tag + täglich „Nächstes Mal: <heute, HH:mm>"
zeigt; erst wenn das heutige Fenster bereits vorbei ist, wandert der Eintrag
auf den nächsten Vorkommens-Tag. FIXED-Vorlagen (RRULE) zeigen unverändert
das RRULE-Auftreten. versionCode 63 == versionName 63 (local: 63-lokal).
Status 2026-09-11 (62)
Secretary Journal 62 (versionCode 62, auf secretary-common-android
v0.24.0): Entweder fixe Zeit oder Zufall mit Anzahl pro Tag + Zeitfenster
in den Einstellungen (Standard 07:00–22:00), Wiederholung zusätzlich.
RandomSchedule ist auf den reinen Zähler geschrumpft (N = X zufällige
Zeiten pro Tag; Persistenz rand:N, Export-Schema 10); das
Zeitfenster ist kein Eintrags-Attribut mehr, sondern eine globale
Einstellung in beiden Settings-Screens (RandomWindowSettings, Abschnitt
„Zufalls-Zeitfenster" mit Von/Bis-Zeitpicks, Werte als Minuten-seit-Mitternacht
in den prefs secretary_journal[_local]: random_window_start/_end, fehlend
→ 07:00–22:00). Der Scheduler (TemplateAlarmScheduler) liest das Fenster
bei jedem arm()/deferRandom() aus den Einstellungen
(SecretaryJournalApp.instance.repository.randomWindow()), behält die
deterministischen Slots (Seed uid+Tag+Slot) und die System-Anpassung
(DND +30 min, nächster Wecker −30 min, DeviceTimePolicy) bei; der
TemplateReceiver-DND-Deferral nutzt dasselbe Einstellungs-Fenster. Daraus
folgt der Editor-Workflow: normale Einträge = nur fixe Zeit (wie gehabt),
Vorlagen = Fest/Zufällig-Umschalter; im Zufallsmodus wählt man nur noch die
Anzahl pro Tag (Stepper), das Zeitfenster steuert man global in den
Einstellungen — die Wiederholung (RRULE, bestimmt die Vorkommens-Tage)
bleibt als zusätzliche Option. RandomPeriod, die Fenster-Pills,
pro-Tag/pro-Woche-Chips und der Geräte-Hinweis im gemeinsamen Block sind
entfernt (OccurrenceStrings).
RandomSchedule.decode akzeptiert weiterhin das alte
HHmm-HHmm:N:day|week-v61-Format (Fenster/Periode werden ignoriert, Schema-9-
Exporte bleiben lesbar). DE/EN-Strings: occ_count_label („Anzahl pro Tag"),
neu settings_section_random/settings_random_hint/settings_random_from/
settings_random_to/settings_random_default; gelöscht occ_range_label/
occ_period_day/occ_period_week/occ_device_hint. versionCode 62 ==
versionName 62 (local: 62-lokal).
Status 2026-09-11 (61)
Secretary Journal 61 (versionCode 61): Gemeinsamer Zeitpunkt-/Wiederholungs-
Block mit Zufalls-Erinnerungszeiten (proof of concept, auf
secretary-common-android v0.23.0). Der Editor nutzt jetzt für alle
Eintragstypen das neue gemeinsame Composable DateTimeOccurrenceFields
(common ui/): Datum-Pill (nativer DatePicker) und für gewöhnliche Einträge
nur fixe Uhrzeit (TimePicker) — normale Einträge bleiben wie gewünscht
rein FIXED. Vorlagen haben zusätzlich einen Umschalter „Fest / Zufällig":
Im Zufallsmodus wählt man ein Zeitfenster (Von/Bis-Zeitpicks), eine
Anzahl X pro Tag oder pro Woche und optional weiterhin die Wiederholung
(RRULE, bestimmt die Vorkommens-Tage). Persistiert wird der Zufalls-Plan als
VJOURNAL-Kategorie rand:<HHmm>-<HHmm>:<X>:<day|week> (RandomSchedule,
JSON-Schlüssel randomSchedule, Export-Schema 9). Der
TemplateAlarmScheduler bewaffnet je Vorlage mehrere exakte Alarme
(Slot-Request-Codes 100+): je Tag/Woche werden X deterministisch gestreute
Zeiten in das Fenster gelegt (Seed = uid + Tag + Slot, dadurch beim Re-Arm
reproduzierbar). System-Anpassung (DND + Schlaf): DeviceTimePolicy
(common) erkennt den aktuell aktiven Nicht-stören-Modus
(NotificationManager.getCurrentInterruptionFilter) und die nächste
Weckerzeit (Settings.System.NEXT_ALARM_FORMATTED; es gibt keine öffentliche
Schlafenszeit-API — Digital-Wellbeing-Bedtime ist intern, der Wecker dient als
Aufwach-Anker). Das Zufallsfenster wird gegen jetzt, aktive DND (+30 min
Sicherheitsabstand) und den nächsten Wecker (−30 min) beschnitten. Fällt ein
Zufalls-Alarm aus, während DND aktiv ist, deferiert der TemplateReceiver
ihn auf einen späteren Zufalls-Slot desselben Tages (begrenzt auf 8
Wiederholungen, danach wird trotzdem benachrichtigt). Vorlagen-Speichern
erlaubt RRULE oder Zufallsplan (bisher musste eine RRULE gesetzt sein);
neue DE/EN-Strings occ_*. versionCode 61 == versionName 61
(local: 61-lokal).
Status 2026-09-11 (60)
Secretary Journal 60 (versionCode 60): Tägliche Erinnerung entfernt
(kann über Vorlagen abgebildet werden). Der Abschnitt „Benachrichtigungen"
in beiden Einstellungen-Screens (Toggle „Tägliche Erinnerung" +
Erinnerungszeit-Zeitpicker) ist entfernt; dahinter liegt der komplette
journal-Erinnerungs-Stack: JournalNotificationScheduler/
JournalReminderReceiver gelöscht, der Manifest-Receiver entfernt,
scheduleAll-Aufrufe aus beiden MainActivities/BootReceivers entfernt,
die Prefs-Methoden (notificationsEnabled/saveNotificationsEnabled/
reminderHour/reminderMinute/saveReminderTime in beiden Repositorys)
und die DE/EN-Strings notif_channel_journal/notif_title/notif_text/
settings_section_notifications/settings_daily_reminder/
settings_daily_reminder_sub/settings_reminder_time gelöscht.
openAppIntent (aus dem Journal-Scheduler) ist in den
MedicineReminderScheduler umgezogen, den der Medikamenten-Receiver nutzt.
Die „wann soll ich mich ans Tagebuch erinnern"-Funktion lässt sich jetzt über
die Eintragsvorlagen (RRULE) inklusive Benachrichtigung abbilden.
Medikamenten-Erinnerungen und Vorlagen-Alarme bleiben unberührt (POST_NOTIFICATIONS
und SCHEDULE_EXACT_ALARM bleiben). versionCode 60 == versionName 60
(local: 60-lokal).
Status 2026-09-11 (59)
Secretary Journal 59 (versionCode 59): Proposals komplett entfernt
(Gesammelte Listen + Vorschlags-Neuberechnung) + gemeinsame
Einstellungs-Sektion angepasst. Der Screen „Gesammelte Listen" (Route
gathered, GatheredScreen/GatheredStore) und der Collections-Änderungs-
Screen (Route collections, CollectionsScreen/
JournalCollectionsContract) wurden komplett entfernt; die Routen, der
Header-Button „Sammlungen" (onCollections/collectionsLabel in Carousel
und Kalender, AppHeader) und die Navigation entfallen. Beide ViewModels
verlieren den gesamten Vorschlags-Zustand (proposalSet, gathered-Listen,
maybeRecalcProposals u. w.) und die Collections-Verwaltung (CRUD, Selektion,
collectionBusy, pendingCollectionIds/recomputePending); drei Todos um
Medikament/Vorlagen etc. bleiben. ProposalEngine ist auf die Trigger/Skill-
Korrelation (Editor) verschlankt; ProposalRecalcScheduler/
ProposalRecalcReceiver gelöscht, der Manifest-Receiver und der
Settings-Abschnitt „Vorschläge" (Zeitpicker + „Gesammelte Listen
verwalten"-Button) in beiden Settings-Screens entfernt. Die gemeinsame
SecretarySettingsScreen (common) bekommt die Option
showContextMenuSettings (Default true, Journal übergibt false), sodass
die „Eintrags-Kontextmenü"-Einstellung je App unterdrückbar ist. Beim Start
(SecretaryJournalApp.onCreate) wird die alte Prefs
secretary_journal_gathered geleert. Entfernte DE/EN-Strings: gathered_*,
settings_section_proposals, settings_proposals_hint, settings_recalc_time,
settings_manage_gathered, collections_subtitle, coll_*,
vm_journal_create_failed, vm_journal_rename_failed, vm_journal_copy_failed,
vm_friendly_delete. loadCollections()/loadEntriesInternal(collection)/
moveEntry bleiben (Einträge hängen weiter an der Journal-Collection).
versionCode 59 == versionName 59 (local: 59-lokal).
Status 2026-09-10 (57)
Secretary Journal 57 (versionCode 57): Medikament nur mit Wirkstoff,
keine Vorschlags-Chips mehr + vereinfachte Eintrags-/Vorlagen-Titel. Der
Medikamenten-Editor hat nur noch das Feld „Wirkstoff": Das "Name"-Feld
ist entfernt; beim Speichern wird medicineName (für
Anzeige/Sammeln/Teilen) automatisch auf den Wirkstoff gesetzt, falls er leer
blieb (Legacy-Einträge mit Name bleiben gelesen). Alle Vorschlags-Chips in
den Editoren sind entfernt: Highlights (edit_proposals_historic),
Medikament, Essen und Trigger/Skill (jeweils edit_already) – die
AssistChip-Zeilen fallen weg. In beiden ViewModels sind die dafür
ungenutzten Getter (proposals, triggerProposals, skillProposals,
foodProposals, medicineProposals, skillRecommendations) und das
ungenutzte updateMedicineName entfernt; die tägliche Vorschlags-
Neuberechnung-Infrastruktur bleibt bestehen. Eintragslisten-Titel
verschlankt: Medikament zeigt nur den Wirkstoff (ohne Dosis), Getränk nur
den Namen (ohne Menge/ml), Essen nur die Art (Mahlzeit/Snack, ohne Text und
kJ); Highlights zeigen weiterhin nur den Highlight-Text. Vorlagen-Zeilen
zeigen in der zweiten Zeile das nächste Auftreten („Nächstes Mal:
dd.MM.yyyy, HH:mm", berechnet via TemplateAlarmScheduler.nextOccurrence)
statt des RRULE-Labels (neuer String template_next); ohne RRULE bleibt das
„Vorlage"-Badge. Die zugehörigen DE/EN-Strings (edit_proposals_historic,
edit_already, edit_name_label, edit_name_placeholder) sind gelöscht.
versionCode 57 == versionName 57 (local: 57-lokal).
Status 2026-09-10 (56)
Secretary Journal 56 (versionCode 56): Eintragsvorlagen (Templates)
mit Accept/Reject-Benachrichtigung. Die Überschrift „Einträge" in der
Hauptansicht (Karussell) ist jetzt tippbar und schaltet zwischen der
Eintragsliste und einer Vorlagen-Liste um (SwapVert-Icon, leere Hinweis-
Zeile, Badge erscheint). Der Typ des Extended-FAB wechselt mit („Neue
Vorlage"); Vorlagen sind alle bekannten Eintragstypen über das
isTemplate-Flag auf JournalEntry (im VJOURNAL als Kategorie
is:template, im JSON-Export Schema 8 als isTemplate), gespeichert wird
die Wiederholung als RRULE (rrule:<rule>-Kategorie), der Editor zeigt
dafür eine neue Sektion „Wiederholung" (FilterChip „Keine"/Wiederholung
über den gemeinsamen RecurrenceDialog). Vorlagen lassen sich nur mit
RRULE speichern (sonst template_requires_rrule-Fehler). TemplateAlarmScheduler
bewaffnet für jede Vorlage einen exakten Alarm auf das nächste Auftreten
(RFC-5545-Expander aus secretary-common-android) und legt in
PendingTemplateQueue einen Snapshot ab; beim Auslösen zeigt
TemplateReceiver eine High-Priority-Benachrichtigung mit Eintragen
(Accept) und Überspringen (Reject): Accept klont den Snapshot in einen
echten Eintrag (neu uid+href, isTemplate=false, rrule="",
„Akzeptiert"-Zeit in occurredAt), legt ihn in der Accepted-Queue ab und
armt die nächste Wiederholung neu; Reject verwirft nur und armt neu. Beide
ViewModels (remote + local) drainen die Accepted-Queue beim Start,
persistieren die Einträge (remote per CalDAV+Cache, local per JSON-Datei)
und rufen rearmAll beim Start, Speichern/Löschen und nach Boot auf
(beide BootReceiver/Manifest-Receiver registriert). Die Zeile einer
Vorlage zeigt Titel + RRULE und einen Play-Button „Jetzt eintragen"
(runTemplateNow speichert sofort einen echten Eintrag ohne RRULE). Die
Eintragsliste nennt außerdem Stuhl/Urin jetzt explizit („Stuhl Typ X"/„Urin
Stufe X") und die Eintragskarten sind kompakter (halbierte Höhe, einzeilig).
DE/EN-Strings ergänzt. versionCode 56 == versionName 56 (local: 56-lokal).
Status 2026-09-10 (55)
Secretary Journal 55 (versionCode 55): Eintragswiederholung (Recurrence)
komplett entfernt. Die per Eintrag setzbare RRULE-Wiederholung aus v49 ist
kein Feature mehr: JournalEntry trägt kein rrule-Feld mehr, VJOURNAL-
RRULE:-Kategorien werden beim Lesen ignoriert und beim Schreiben nicht mehr
erzeugt (JournalTransfer bleibt Schema 7, Ex- und Importe älterer Schemata
werden weiter gelesen, rrule wird verworfen). Entfernt wurden der
Wiederholungs-Button samt RecurrenceDialog im Editor (updateRrule in
beiden ViewModels), die Scheduler/Receiver-Dateien
JournalRecurrenceScheduler/JournalRecurrenceReceiver, die
PendingRecurrenceQueue (Accept/Reject-Benachrichtigung) samt
Manifest-Receiver und Re-Arm-Aufrufen in MainActivity/BootReceiver, der
Recurrence-Fade in entryOpacity sowie alle Recurrence-Strings (DE/EN).
Damit entfällt, dass ein akzeptierter wiederkehrender Eintrag ohne
Wiederholungsflag angelegt wurde und man zum Stoppen der Serie den
Ursprungseintrag suchen musste. versionCode 55 == versionName 55 (local:
55-lokal). Zudem nennt die gemeinsame Einstellungs-Sektion in
secretary-common-android den Langdruck-Kontextmenü-Block jetzt
„Entry-Contextmenu".
Status 2026-09-10 (51)
Secretary Journal 51 (versionCode 51): Getränk in den Food-Typ
integriert + nur Highlights einmal pro Tag. Der seit v50 eigenständige
Eintragstyp „Getränk" wurde in den Typ „Essen" als dritte
Unterart „Getränk" verschmolzen: EntryType.DRINK ist entfernt
(EntryType-Reihenfolge TEXT/MOOD/EXCRETA/MEDICINE/FOOD/TRIGGER/SKILL);
FoodFlavour hat neu DRINK("drink","Drink") und der Food-Editor zeigt
neben Mahlzeit/Snack automatisch den dritten Chip „Getränk". Bei
Drink-Flavour werden Getränkename + Menge in ml editiert (Vorschläge aus
der Historie setzen den Namen, übernimmt updateDrinkName), sonst kJ +
Text. Serialisierung: VJOURNAL bleibt SUMMARY=food, DESCRIPTION = Name
bei Drink (einzeln verschlüsselbar), CATEGORIES=[food, food:drink,
drinkml:<N>] (kein kj:); JournalTransfer ist auf Schema 7 gestellt
und liest v50-Exporte mit entryType:"drink" als FOOD+DRINK
(foodFlavour-Fallback, drinkName-Entschlüsselung statt foodText).
FAB-/Typauswahl (Kalender + Karussell, EntryTypePrefs normalisiert legacy
drink→food), Recurrence (Queue/Scheduler-Parse alter drink-Einträge,
Receiver ohne DRINK, FOOD-Summary mit Drink-Name), Icons/Farben
(entryIcon(entry) zeigt LocalDrink + Drink-Cyan für Drink-Flavour;
Kacheln/Zeilen), Teilen-Text, syncGatheredFromEntries/ProposalEngine
(Drink-Namen statt Food-Text in die Listen) und die Import-Zusammenführung
beider ViewModels (FOOD kopiert jetzt auch drinkName/drinkAmountMl)
sind angepasst. Nur noch Highlights (TEXT) sind einmal pro Tag
(openTextEntryForDate weiter find-or-create); alle übrigen Typen sind
mehrfach pro Tag und openMood/Excreta/Trigger/Skill/Medicine/FoodEntryForDate
legen immer einen neuen Eintrag an. DE/EN-Strings: food_drink neu,
edit_subtype_drink entfernt, edit_drink_*/type_drink bleiben.
versionCode 51 == versionName 51 (local: 51-lokal).
Status 2026-09-10 (50)
Secretary Journal 50 (versionCode 50): Excreta-Typ (Stuhl/Urin) +
eigener Getränke-Typ. Die Eintragstypen „Stuhlgang" und „Hydration"
wurden zu einem Typ „Excreta" zusammengeführt (ein Editor mit
Untertyp-Auswahl Stuhl/Urin, ExcretaKind; Speicher-Tags umbenannt:
VJOURNAL SUMMARY=excreta, CATEGORIES excreta:stool + stool:<N>
bzw. excreta:urine + urine:<N>). Beide Untertypen haben wie bisher eine
Skala (Bristol 1-7 bzw. Armstrong/Urinfarbe 1-8, UrineType neu benannt
statt HydrationType); beim Wechsel des Untertyps wird die andere Skala
geleert; der Editor zeigt je Untertyp die richtige Skala im selben
Maskenaufbau wie Essen. Alte Daten bleiben lesbar:
EntryType.fromSummary mappt stool/hydration → EXCRETA,
UrineType.fromCategories akzeptiert legacy hydration:<N>,
JournalTransfer liest Schema-≤5-Exporte mit hydrationType-Fallback
(Schema 6). Neu ist der Typ „Getränk": VJOURNAL SUMMARY=drink,
DESCRIPTION = Name (einzeln verschlüsselbar), CATEGORIES=[drink,
drinkml:<N>]; der Editor bietet optionales Namensfeld und Mengenfeld in ml.
Neuanlage von Excreta/Drink ist mehrfach pro Tag möglich
(openExcretaEntryForDate/openDrinkEntryForDate, immer neuer Eintrag); die
Schnell-Dialoge für Stuhl/Hydration (Karussell + Kalender) und
saveStoolEntry/saveHydrationEntry wurden entfernt. FAB-Namen, Icons/
Farben (Stuhlgrün/Urin-Cyan), Kalender-Kacheln, Teilen-Text,
Recurrence-UI/-Receiver, EntryTypePrefs (Legacy-Normalisierung
stool/hydration → excreta) und die Import-Zusammenführung beider
ViewModels sind angepasst. versionCode 50 == versionName 50 (local:
50-lokal).
Status 2026-09-10 (48)
Secretary Journal 48 (versionCode 48): Sprachunterstützung (Deutsch/
Englisch). Alle hartcodierten deutschen UI-/ViewModel-Texte wurden in
Android-String-Ressourcen ausgelagert: app/src/main/res/values/strings.xml
(Deutsch, Standard) und app/src/main/res/values-en/strings.xml (Englisch).
Ein neuer Abschnitt „Sprache" in beiden Einstellungen-Screens (remote +
local, mit LocalePrefs + App-recreate) schaltet zwischen Deutsch und
Englisch um; die App liest Texte über SecretaryJournalApp.instance
.localizedContext(). Betroffen sind alle Screens (Login, Einstellungen,
Kalender, Karussell, Editor, Statistik, Gesammelte Listen, Sammlungen,
Verschlüsselung/Passwort/Biometrie, Export/Import, Entsperren), die
Erinnerungs-Benachrichtigungen und sämtliche ViewModel-Meldungen (Fehler,
friendly()-Fehler des Remote-Flavors, Export/Import-Rückmeldungen).
Deutsche KDoc/Kommentare wurden ins Englische übersetzt. versionCode 48 ==
versionName 48 (local: 48-lokal).
Status 2026-09-10 (49)
Secretary Journal 49 (versionCode 49): Optionale Eintragswiederholung
mit Accept/Reject-Benachrichtigung. Jeder Eintragstyp außer MOOD kann
jetzt ein optionales RRULE (rrule-Feld) tragen – gespeichert als
RRULE:<rule> in VJOURNAL CATEGORIES (Schema 5 in JournalTransfer).
Wenn ein nicht-leeres rrule vorhanden ist, bewaffnet der
JournalRecurrenceScheduler einen exakten Alarm für das nächste Auftreten
(IEEE RFC 5545 über den gemeinsamen Recurrence-Expander); beim Auslösen
zeigt JournalRecurrenceReceiver eine HIGH-Wichtigkeitsbenachrichtigung
mit zwei Aktionen an:
- Eintragen (Accept): klonst den Eintrag mit neuem
uid, aktuellem Zeitstempel (date= heutiger Tag,occurredAt= jetzt),rrule = "", speichert ihn inPendingRecurrenceQueueund armt die nächste Wieder- holung des Originals (One-Off-Protokollierung ohne Selbst-Wiederholung). - Überspringen (Reject): verwirft nur, bewahrt keine Notiz, armt die nächste Wiederholung des Originals.
Die vollständigen Einträge werden in SharedPreferences
(secretary_journal_recurrence) als JSON gespeichert, sodass Alarme
nach einem Neustart über JournalRecurrenceScheduler.rearmAll()
wiederhergestellt werden; beide BootReceiver und MainActivity.onResume
rufen rearmAll auf. Die ViewModelle beider Editionen (remote + local)
waffen beim Speichern/Löschen via scheduleEntry/cancel, drainen
PendingRecurrenceQueue bei App-Start, nach Entsperren und auf
ACTION_ACCEPTED-Broadcasts (exakt wie PendingMedicineQueue).
Der Editor zeigt unter der Uhrzeit (nicht bei MOOD) die neue Sektion
„Wiederholung" mit dem aktuellen Wert aus recurrenceLabel(); Tippen
öffnet den bestehenden RecurrenceDialog aus secretary-common-android.
updateRrule(rrule) in beiden ViewModels passt den Entwurf an. DE/EN-
String-Ressourcen hinzugefügt. versionCode 49 == versionName 49 (local:
49-lokal).
Status 2026-09-10 (47)
Secretary Journal 47 (versionCode 47): Optionale Stimmung (zweiter
Eintrag) und optionale Tendenz an allen Einträgen. Jeder Eintrag außer
Stimmung kann optional ergänzt werden: Der Editor zeigt direkt unter dem
Zeitpunkt-Abschnitt für alle nicht-Stimmungs-Typen (Highlights/Stuhl/
Hydration/Trigger/Skill) eine neue Sektion „Stimmung miterfassen (zweiter
Eintrag)" – Auswahl „Keine" oder Smiley-Wert (Glücklich/Normal/Traurig,
FilterChips mit Emoji). Beim Speichern legt ein gewählter Wert einen
eigenen Stimmungs-Eintrag (MOOD) zusätzlich an (Same-Date, gleiche
occurredAt-Zeit wie der Haupt-Eintrag; remote + local online wie offline,
Abstract im eigenen saveMoodSecondEntryFor). Die Auswahl ist reine
Anlege-Kuration: sie wird nie vorbelegt, löscht nie bestehende
Stimmungs-Einträge (deselect = einfach nicht anlegen; ein vorhandener
Stimmungs-Eintrag des Tages bleibt unberührt und ist über seinen eigenen
Editor änder-/löschbar) und gilt nur für den nächsten Speichervorgang.
Zusätzlich hat jeder nicht-Stimmungs-Typ eine optionale Tendenz (↗ Hoch /
↘ Runter / Keine, FilterChips mit Deselect). Für Trigger/Skill ersetzt die
gemeinsame Sektion die bisherige Tendenz-Auswahl (jetzt auch abwählbar),
für Highlights/Stuhl/Hydration ist sie neu. Die Tendenz wird wie bei
Trigger/Skill als tendency:up|down-Kategorie im selben VJOURNAL gespeichert
(und von JournalTransfer als tendency serialisiert – Schema 4 bleibt);
fromNote liest sie jetzt auch für TEXT/STOOL/HYDRATION. Stimmungs-Einträge
bleiben ohne Tendenz (wie ab v42). Der Teilen-Text des Kalenders hängt die
Tendenz-Zeile generisch an jede Eintragsart an. versionCode 47 == versionName
47 (local: 47-lokal).
Status 2026-09-10 (46)
Secretary Journal 46 (versionCode 46): Armstrong-Hydrations-Skala als
Eintragstyp + wählbarer Zeitpunkt für neue Einträge.
1. Neuer Eintragstyp „Hydration": protokolliert den Hydrationsgrad über
die Armstrong-Skala (Urinfarbe, Stufe 1 „Sehr hell, fast klar" bis
8 „Braun"; HydrationType mit level, label, description, Default
Stufe 4). Völlig analog zur Bristol-Stuhl-Skala: HydrationScaleDialog
listet alle acht Stufen mit Farbkreis je Urinfarbe
(hydrationLevelColor(level)) und Beschreibung; im FAB-Typauswahl-Sheet
(EntryTypePickerSheet) wie im Kalender speichert die Auswahl einen
Hydration-Eintrag direkt ohne Editor (saveHydrationEntry, remote + local,
mit at:<millis>-Voreinstellung); im Editor zeigt HydrationEntryBody
(Subtitle „HYDRATION") die gewählte Stufe und öffnet die Skala neu
(updateHydrationType). Persistiert als VJOURNAL SUMMARY=hydration,
CATEGORIES=hydration:<N>; JournalTransfer speichert hydrationType
(optional, Schema 4 bleibt unverändert, alte Exporte parsen mit null).
Kalender-Tageskacheln (Icon LocalDrink, Farbe „Hydration cyan"
HydrationColor), Eintragsliste (entryTypeIcon/entryTitle/entryColor),
Teilen-Text und die Import-Zusammenführung aller fünf Typen in beiden
ViewModels verstehen den neuen Typ.
2. Datum & Uhrzeit bei neuen Einträgen: Der Editor zeigt oben den
Abschnitt „Zeitpunkt" mit Datum- und Uhrzeit-Schaltfläche (native
DatePickerDialog/TimePickerDialog, Uhrzeit im 24h-Format, dd.MM.yyyy/
HH:mm). Neue Entwürfe nutzen JournalEntry.defaultOccurredAtFor(date)
statt fester Jetzt-Zeit: exakt jetzt bei heute, sonst der geöffnete
Kalendertag zur aktuellen Uhrzeit; setEntryDateTime(millis) re-anchort
date (Kalendertag) und occurredAt gemeinsam (z. B. Eintrag für gestern
22:15). Alle createNewXEntry-Funktionen (TEXT/MOOD/STOOL/HYDRATION/TRIGGER/
SKILL) beider ViewModels verwenden die Voreinstellung; der Stuhl- und der
Hydrations-Schnellspeicher erben sie ebenfalls. versionCode 46 == versionName
46 (local: 46-lokal).
Status 2026-09-10 (45)
Secretary Journal 45 (versionCode 45): Bristol-Stuhl-Skala mit Bildern.
Die Typauswahl (BristolStoolDialog) zeigt statt des farbigen Punkts je Typ
das Abbild der Stuhlform aus der Wikipedia/Bristol-Stuhlformen-Skala
(Bristol_stool_scale) auf einem hellen Chip (128 px breit, transparent).
Die Einzel-Bilder bristol_1.png…bristol_7.png
(app/src/main/res/drawable-nodpi/, 123×52, aus den Commons-Dateien
BristoStool_1.png…BristoStool_7.png) stammen aus
File:BristolStoolChart.png von Jmarchn und sind unter
CC BY-SA 3.0 lizenziert. Beide Einstellungen-Screens (remote + local)
tragen dafür einen neuen Abschnitt „Lizenz & Quellen" mit der
Attribution (Autor, Quelle, Lizenz) und einem klickbaren
„Lizenz ansehen (CC BY-SA 3.0)"-Link (öffnet creativecommons.org). Die
Zuordnung BristoStool_1..7 → Typ 1..7 erfolgt im Dialog über
BristolType.numericValue. versionCode 45 == versionName 45 (local:
45-lokal).
Status 2026-09-10 (44)
Secretary Journal 44 (versionCode 44): GET_ACCOUNTS für das zentrale
Konto (remote). Die Remote-Edition deklariert jetzt
android.permission.GET_ACCOUNTS (neben dem legacy READ_ACCOUNT). Das
gemeinsame Sekretär-Konto (AccountManager, Typ org.beowulf.secretary)
wird damit direkt lesbar und hängt nicht mehr ausschließlich an der
Signer-Visibility-Provisionierung des Android-Kontos – ein Update der
App konnte diese Provisionierung abwerfen, sodass AccountResolver.resolve()
ein leeres Konto lieferte (Login-Screen, keine Daten, Passwort-Gedächtnis
weg), während andere Sekretär-Apps (mit GET_ACCOUNTS) das Konto weiter
nutzten. Server-Daten (VJOURNALs) bleiben unberührt. versionCode 44 ==
versionName 44 (local: 44-lokal).
Status 2026-09-10 (43)
Secretary Journal 43 (versionCode 43): Uhrzeit in allen
Eintrags-Zeitpunkten. Der Editor zeigt in der Trigger/Skill-Korrelation
(„Auslöser der letzten 3 Tage", „Bewährte Gegenmittel"/„Risiko-Muster") jetzt
je Zeile die exakte Uhrzeit des Eintrags (dd.MM., HH:mm) statt nur das
Datum; ProposalEngine.TriggerSkillLink trägt dafür die genauen
Log-Zeitpunkte (triggerOccurredAt/skillOccurredAt, null für alte
datum-only-Einträge) und die Verkettung/Tendenz-Verordnung ordnet innerhalb
eines Tages nach exakter Zeit (Fallback Mitternacht). Auch der
Teilen-Text des Kalenders enthält die Uhrzeit (dd.MM.yyyy, HH:mm). Damit
bleibt die Timeline auch bei mehreren Einträgen desselben Typs am selben Tag
eindeutig. versionCode 43 == versionName 43 (local: 43-lokal).
Status 2026-09-09 (42)
Secretary Journal 42 (versionCode 42): Keine Tendenz mehr für
Stimmung. Die Tendenz-Auswahl (↗/↘) wurde aus dem Stimmungs-Editor
entfernt – ein Stimmungs-Eintrag ist nur noch eine Stimmung (wie ursprünglich
in v37 zugeordnet); Stimmungs-Editor zeigt nur noch die Smiley-Auswahl.
Bestehende Stimmungs-Einträge mit persistierter Tendenz bleiben lesbar,
Trigger/Skill behalten ihre Tendenz. versionCode 42 == versionName 42
(local: 42-lokal).
Status 2026-09-09 (41)
Secretary Journal 41 (versionCode 41): Statistik-Screen für Trigger &
Skills. Neue StatsEngine (lokal, rein; teilt sich mit ProposalEngine
das „nie serverseitig"-Prinzip) berechnet aus der Eintrags-Historie:
Trigger-Häufigkeit und Skill-Häufigkeit (je Text: Gesamtzahl plus
Tendenz-Aufschlüsselung ↗/↘/neutral, sortiert nach Häufigkeit, Display auf
Top-20 mit „+ n weitere") sowie den Tendenz-Verlauf: wochenweise
(Montag-Start, WeekFields deutsch) kombinierte Trigger+Skill-Tendenz-
Zählungen von der Woche des ältesten Tendenz-Eintrags bis zur aktuellen Woche.
Beide ViewModels exponieren journalStats (reaktiver Getter). Neuer Screen
StatsScreen (Route stats, erreichbar über den neuen Einstellungen-Button
„Statistik ansehen" in einem eigenen Abschnitt „Statistik", remote + local):
Bars über „Trigger-Häufigkeit"/„Skill-Häufigkeit" (mit ↗ n / ↘ n je Zeile)
und eine Canvas-Balkengrafik des Tendenz-Verlaufs (grüne Balken = Hoch,
rote = Runter, Skalierung auf das Maximum, Lücken = Wochen ohne Einträge)
mit Datumsspanne und Legende darunter; Leerzustände, wenn noch nichts erfasst
wurde. versionCode 41 == versionName 41 (local: 41-lokal).
Status 2026-09-09 (40)
Secretary Journal 40 (versionCode 40): Trigger/Skill-Evaluation im
Editor. Beim Bearbeiten eines Skill- oder Trigger-Eintrags zeigt der
Editor jetzt eine Tages-Korrelation zwischen Triggern und Skills mit
farbigen Hinweisen. Die neue, live gerechnete Engine-Funktion
ProposalEngine.correlateSkillAt(entries, date, skillTendency) verkettet
alle Auslöser der letzten FOLLOWUP_WINDOW_DAYS (3 Tage inkl. heute) mit
dem aktuell bearbeiteten Skill; correlateTriggerWithText(entries, text)
liefert aus der Historie alle Skill-Vorkommen bis 3 Tage nach einem
Trigger gleichen Texts (exakter Textmatch wie bei den Skill-Empfehlungen).
Jede Kante (ProposalEngine.TriggerSkillLink) wird per
correlationPattern(triggerTendency, skillTendency) klassifiziert:
COUNTERMEASURE (Auslöser ↘ + Skill ↗ = bewährtes Gegenmittel,
grün CorrelationGoodColor), DEGRADATION (Auslöser ↗ + Skill ↘ =
Risiko-Muster/Belastungszeichen, orange CorrelationWarnColor) und NEUTRAL.
Die ViewModels beider Editionen exponiieren editorCorrelation (getter,
reaktive Sicht auf entries/editingEntry). Der Skill-Editor zeigt
unter der Tendenz-Auswahl die „Auslöser der letzten 3 Tage" als Zeilen mit
Tendenzpfeil, Datum und farbigem Hintergrund je Muster plus eine
Insight-Zeile („Gegenmittel-Muster …"/„Risiko-Muster …"/Aufforderung zur
Tendenz-Wahl); der Trigger-Editor zeigt „Bewährte Gegenmittel" (↗-Skills,
n×) in Grün bzw. „Risiko-Muster" (↘-Skills) in Orange für den eingegebenen
Text – bei leerem Text hilft der Hinweis, den Auslöser einzutragen.
versionCode 40 == versionName 40 (local: 40-lokal).
Status 2026-09-09 (39)
Secretary Journal 39 (versionCode 39): FAB + ganztägige Eintragsliste +
Uhrzeit je Eintrag + Tendenz für Stimmung + Verwaltung gesammelter Listen mit
Rückwirkung. Die Hauptansicht (Karussell-Screen) bekommt ein
Extended-FloatingActionButton „Neuer Eintrag", das die gemeinsame
Typauswahl öffnet; Tippen auf den Smiley öffnet direkt den heutigen
Stimmungs-Eintrag (Langpressen weiterhin Kalender). Stimmungs-Einträge
haben jetzt wie Trigger/Skill eine manuelle Tendenz hoch/runter
(TendencyCell-Auswahl im Editor; gespeichert als tendency:up|down-Kategorie
und in JournalTransfer als tendency); die Hauptansicht zeigt die
aktuelle Tendenz (letzter Stimmungs-Eintrag) als Badge unten rechts am
Smiley plus die Zählung aller ↗/↘ über die gesamte Historie. Unter dem Smiley
ersetzt eine vollständige Eintragsliste (neueste zuerst bis älteste) die
bisherigen „nur-heute"-Karten: jede Zeile zeigt Typ-Icon/-Farbe, Text bzw.
Smiley-Label, dd.MM.yyyy, HH:mm und den Tendenz-Pfeil, Tippen öffnet den
Editor. Dafür trägt jeder JournalEntry ein occurredAt (device-time
epoch millis, beim Anlegen gesetzt, beim Speichern ergänzt), persistiert als
at:<millis>-Kategorie im VJOURNAL und als occurredAt in JournalTransfer
(Schema 4; alte Einträge bleiben datum-only und sortieren nach Datum+uid).
Für die Verwaltung der Vorschläge gibt es GatheredStore (kuratierte
Listen je Highlights/Trigger/Skill, JSON in Prefs secretary_journal_gathered)
und den neuen Screen „Gesammelte Listen" (Route gathered, erreichbar aus
beiden Settings-Screens über „Gesammelte Listen verwalten"): pro Liste
Anzeige (x-fach notiert, zuletzt am …), Hinzufügen ohne Eintrag,
Umbenennen/Zusammenführen und Entfernen – Änderungen werden durch
Rückwärts-Anpassung in allen historischen Einträgen umgesetzt (TEXT:
goodOne/Two/Three, TRIGGER/SKILL: text; remote per pushAllEntries, local per
persist()). ProposalEngine.compute bevorzugt die kuratierten Listen und
fällt bei leeren Listen auf aus den Einträgen abgeleitete Vorschläge zurück;
neue Eintragstexte werden beim Laden/Speichern automatisch in die Listen
übernommen. versionCode 39 == versionName 39 (local: 39-lokal).
Status 2026-09-09 (38)
Secretary Journal 38 (versionCode 38): Trigger und Skill als
neue Eintragstypen + Umbenennung „Gute Dinge" → „Highlights". Der
Tagebucheintrag umfasst jetzt fünf Typen: Highlights (ehem. „Gute Dinge",
drei Textfelder), Stimmung, Stuhlgang, Trigger (Freitext +
Tendenz hoch/runter) und Skill (Freitext + Tendenz hoch/runter).
Trigger/Skill sind eigene VJOURNALs: SUMMARY = trigger/skill,
DESCRIPTION = freier Text (verschlüsselbar als einzelner Blob wie TEXT),
CATEGORIES = [trigger|skill, tendency:up|down] (Tendency per
Tendency.fromCategories() geparst; fromString() akzeptiert up/down
auch in Kategorien ohne Tendenz-Tag als null). JournalTransfer
Serialisiert text + tendency (JSON-Schema 3) und verschlüsselt
TRIGGER/SKILL-Freitext wie TEXT-Blobs. ProposalEngine (lokal, nie
serverseitig) berechnet Vorschläge: Highlight-Vorschläge aus gesammelten
Highlights, Trigger/Skill-Vorschläge aus jüngsten Einträgen desselben Typs,
Skill-Empfehlungen je Trigger (Korrelation: Skill-UP nach Trigger-DOWN
und umgekehrt, Fenster 3 Tage). ProposalRecalcScheduler (AlarmManager)
ruft täglich um konfigurierbare Uhrzeit ProposalRecalcReceiver auf, der den
Timestamp speichert und den ACTION_RECALC_RESULT-Broadcast sendet; die
VMs empfangen diesen und aktualisieren proposalSet. Settings-Screen zeigt
jetzt einen Vorschlag-Neuberechnungs-Zeitpicker (zusätzlich zum
Erinnerungszeitpicker). EntryTypePickerSheet ist jetzt ein gemeinsames
Composable (shared ui/ package) mit allen fünf Optionen (Highlights /
Stimmung / Trigger / Skill / Stuhlgang); die privaten Kopien in Calendar
und Carousel wurden entfernt. JournalTypeUi.kt definiert gemeinsame
Icon-/Farb-Helpers (TriggerIconColor, SkillIconColor, moodIcon,
moodColor, entryTypeIcon, tendencyIcon, tendencyColor). Kalender-Tageskachel
zeigt bis zu vier Typ-Icons (sortiert nach EntryType-Ordinal) für die fünf
Typen. Karussell zeigt heutige Trigger/Skill-Sektionen unter dem
Highlight-Block. Kein Backward-Compat-Workflow für alte drei-Felder-Einträge;
v36/v37-Einträge的有效 text-entries were already reinterpreted in v37 via
fromNote() fallback. versionCode 38 == versionName 38 (local: 38-lokal).
Status 2026-09-09 (37)
Secretary Journal 37 (versionCode 37): Drei Eintragstypen (remote +
local). Der Tagebucheintrag ist jetzt ein TEXT-Eintrag (max. einer pro
Tag) mit drei Textfeldern „Drei gute Dinge" (goodOne/goodTwo/
goodThree, als JSON im CalDAV-DESCRIPTION bzw. verschlüsselten Blob;
JSON-Schema 2, Schema-1-Import wird ins Feld 1 migriert). Stimmung und
Bristol-Stuhlgang wurden eigene Eintragstypen (Entwarnung: der bisher
ungenutzte CalDAV-SUMMARY-Tag wird als Typ-Marker text/mood/stool
verwendet; CATEGORIES tragen mood:<name> bzw. stool:<N>). Stimmung und
Stuhlgang sind mehrfach pro Tag möglich und werden über das neue
FAB-Bottom-Sheet (Gute Dinge / Stimmung / Stuhlgang) angelegt; Stuhlgang
öffnet die Bristol-Stuhl-Skala-Dialog (BristolStoolDialog) und speichert
direkt (ohne Editor). Das Karussell zeigt unter dem Donut die heutigen guten
Dinge, der Kalender pro Kachel bis zu drei Typ-Icons. Der Editor ist
typabhängig: drei Gute-Dinge-Felder mit Vorschlags-Chips aus allen
gesammelten guten Dingen (nachträglich), Stimmungs-Smiley-Zellen oder
Stuhltyp-Anzeige. Die Erinnerung in den Einstellungen adressiert nur noch den
Text-Eintrag. System-Kalender-Spiegel komplett entfernt (privates
Journal: keine READ/WRITE_CALENDAR-Berechtigung, kein Boot-Sync,
JournalSystemSyncAdapter/JournalSystemScheduler gelöscht). versionCode 37
== versionName 37 (local: 37-lokal).
Status 2026-09-09 (36)
Secretary Journal 36 (versionCode 36): Sammlungsverwaltung mit
Langdruck-Kontextmenü (remote; secretary-common-android v0.19.0). Neue
CollectionsScreen (Route collections, Button „Sammlungen" im
AppHeader von Karussell- und Kalender-Screen, nur in der Remote-Edition)
zeigt alle Journal-Sammlungen als Karten mit Umbenennen / Kopieren /
Löschen (CollectionContextMenu), FAB „Journal" zum Anlegen
(CreateCollectionDialog) und PendingBadge bei offline-pending
Änderungen. Neue JournalViewModel-Aktionen
createJournalCollection/renameJournalCollection/copyJournalCollection/
deleteJournalCollection über den gemeinsamen CrudManager
(Write-Behind-Queue, „<Name> (Kopie)" inkl. aller Einträge), dazu
pendingCollectionIds (PendingSync.snapshotState) und collectionBusy-Guard
(offline → Banner + friendly-Fehler). Die Einträge folgen jetzt der
aktiv gewählten Sammlung (selectJournalCollection, persistiert über
last_collection, Fallback: erste VJOURNAL-Sammlung) – Anlegen/Auswahl
laden deren Einträge, das Verschieben-/Duplizieren des
Eintrags-Kontextmenüs läuft gegen die aktive Sammlung. Die lokale Edition
implementiert das gemeinsame JournalCollectionsContract leer (kein
Internet/Konto) und zeigt den Sammlungs-Button nicht. versionCode 36 ==
versionName 36 (local: 36-lokal).
Status 2026-09-09 (35)
Secretary Journal 35 (versionCode 35): Rebuild auf
secretary-common-android v0.18.0. Kein App-Code geändert; der APK
enthält jetzt die 412-Auto-Recovery (bedingte PUTs mit veraltetem
If-Match-ETag holen einmalig die aktuelle Server-ETag und wiederholen den
Schreibvorgang statt des „Notiz wurde auf dem Server geaendert"-Fehlers).
versionCode 35 == versionName 35 (local: 35-lokal).
Status 2026-09-08 (34)
Secretary Journal 34 (versionCode 34): Konfigurierbares Kontextmenü.
Die Aktionen Teilen / Kopieren / Verschieben / Löschen des Langdruck-Menüs auf
der Tageskachel lassen sich in den Einstellungen (gemeinsame Sektion
„Langdruck-Kontextmenü" aus secretary-common-android v0.16.0) per Checkbox
aktivieren/deaktivieren (UiPreferences, Default: alle aktiv). ItemContextMenu
blendet deaktivierte Aktionen aus und sperrt das Menü komplett, wenn alle vier
aus sind (dann verhält sich die Kachel wie eine gewöhnliche klickbare Karte).
versionCode 34 == versionName 34 (local: 34-lokal).
Status 2026-09-08 (33)
Secretary Journal 33 (versionCode 33): Gemeinsames Kontextmenü im
Kalender-Raster (remote + local). Tage mit Eintrag haben jetzt ein
Langdruck-Kontextmenü (ItemContextMenu aus secretary-common-android
v0.15.0) direkt auf der Kalender-Kachel: Bearbeiten, Teilen
(Text via Share-Sheet), Kopieren (Duplikat in derselben Journal-Collection
via CrudManager.copyItem/copyItemOffline – remote; lokale Edition legt
einen zweiten lokalen Eintrag an), Verschieben… (MoveCollectionDialog
bei mehreren Journal-Collections; CrudManager.moveItem/moveItemOffline –
remote; lokale Edition ist no-op) und Löschen (ConfirmDeleteDialog).
versionCode 33 == versionName 33 (local: 33-lokal).
Status 2026-09-07 (30)
Secretary Journal 30 (versionCode 30): Aufgeräumter Header ohne
Status-Chip. Der moderne Haupt-Header (ModernAppHeader in
secretary-common-android) zeigt keinen Online-Status-Chip mehr; die
Aktionsleiste (Sync, Einstellungen) sitzt jetzt rechts oben direkt im
Hero-Header. Alle Überschriften verwenden die neue Typewriter-Schrift
Special Elite (gebündelt in secretary-common-android,
res/font/special_elite.ttf, Apache 2.0). versionCode 30 == versionName 30
(local: 30-lokal).
Status 2026-09-07 (29)
Secretary Journal 29 (versionCode 29): Crash-fix: Biometrie-Aktivierung.
Der BiometricPrompt erfordert bei nur-stark-biometrischen Prompts
(setAllowedAuthenticators(BIOMETRIC_STRONG)) einen negativen Button
(setNegativeButtonText); ohne ihn wirft PromptInfo.Builder.build() ein
IllegalArgumentException: Negative text must be set and non-empty. Der
biometricPromptInfo setzt nun „Abbrechen". versionCode 29 == versionName 29
(local: 29-lokal).
Status 2026-09-07 (28)
Secretary Journal 28 (versionCode 28): Crash-fix: Settings-Screen /
Biometrie. Beide Flavor-MainActivities erweitern jetzt FragmentActivity
(statt ComponentActivity), damit BiometricPrompt einen gültigen Activity
findet. Ohne dies crashtete die App beim Öffnen der Einstellungen aufgrund
eines requireNotNull in rememberBiometricPrompt. versionCode 28 ==
versionName 28 (local: 28-lokal).
Status 2026-09-07 (27)
Secretary Journal 27 (versionCode 27): Verschlüsselungs-Migration
aller Einträge. Das Aktivieren eines Passworts verschlüsselt nun sofort
alle vorhandenen Einträge (remote: pushAllEntries schreibt jede
verschlüsselte Notiz an den Server + Cache; local: persist() speichert
die gesamte Datei verschlüsselt). Das Entfernen eines Passworts
entschlüsselt ebenfalls alle Einträge (remote: pushAllEntries schreibt
Klartext zurück an Server + Cache; local: persist() speichert Klartext).
Außerdem: Biometrie-Prompt bindet den authentifizierten Cipher (kein
frischer Cipher in onSuccess); MaterialTheme.colorScheme statt Colors.
versionCode 27 == versionName 27 (local: 27-lokal).
Status 2026-09-07 (26)
Secretary Journal 26 (versionCode 26): Zwei Flavor + Verschlüsselung +
Export/Import. Das Project baut über Gradle Product Flavors eine
remote-Edition (org.beowulf.secretary.journal, sync/account/system-calendar)
und eine local-Edition (org.beowulf.secretary.journal.local, rein
on-device, kein Internet/Konto, JSON-Datei journal_local.json). Flavor-eigener
Code liegt doppelt unter app/src/{remote,local}/java/…, geteilter Code in
app/src/main/. Textverschlüsselung (JournalCipher): AES-256-GCM-Master-Key,
per PBKDF2-HmacSHA256-Passwort (210k) und optionalem Android-Keystore-Biometrie-Wrap
(BiometricPrompt) geschützt; bei aktiver Verschlüsselung werden Texte als
sj1:-Blobs gespeichert (auch serverseitig; Systemkalender-Spiegel zeigt dann
nur Stimmung/Datum, kein Text). Gesperrt erscheint statt der Navigation der
UnlockScreen (Biometrie/PW). Export/Import als JSON über den System-Dateidialog
(SAF), verschlüsselt bei aktiver Verschlüsselung, Import mischt nach Datum.
das Buildsystem baut beide APKs (secretary-journal-26.apk + secretary-journal-local-26.apk).
versionCode 26 == versionName 26 (local: 26-lokal).
Status 2026-09-07 (25)
Secretary Journal 25 (versionCode 25): System-Kalender-Spiegel. Jeder
Journal-Eintrag erscheint als ganztägiges Ereignis (Titel <Stimmung> ·
<Datum>, Text im Beschreibungsfeld) im Android-Kalender – im geschützten
Spiegel-Kalender secretary-journal (Constants in SystemCalendarMirror,
nicht löschbar durch den Aufgaben-Spiegel bzw. das Spiegel-Modul der
Kalender-App). Auslöser: App-Start/onResume, Login, Laden/Refresh, jede
Änderung/Offline-Sync, Boot und der Button „Jetzt in System-Kalender
synchronisieren" in den Einstellungen (Abschnitt „Systemkalender"). Dafür
wird die Kalender-Berechtigung einmalig angefragt (READ/WRITE_CALENDAR,
JournalSystemSyncAdapter/JournalSystemScheduler). versionCode 25 ==
versionName 25.
Status 2026-09-07 (24)
Secretary Journal 24 (versionCode 24): Hauptansicht aufgeräumt. Die textlichen Prozentangaben unter dem Donut-Smiley und die Hilfszeile „Tippen: neuer Eintrag · Halten: Kalender" wurden entfernt. Übrig bleiben Donut-Chart, der Smiley des letzten Eintrags und der (Optionale) Offline-Hinweis. versionCode 24 == versionName 24.
Status 2026-09-07 (23)
Secretary Journal 23 (versionCode 23): Einzel-Smiley mit Donut-Chart,
konfigurierbares Auswertungsfenster. Die Hauptansicht zeigt nicht mehr drei
überlagerte Smileys, sondern den Smiley des zuletzt erstellten Eintrags; um
ihn herum zeichnet ein Donut-Chart (Canvas, MoodDonut) die Anteile
Glücklich/Normal/Traurig im Auswertungsfenster. Das Fenster ist in den
Einstellungen (Abschnitt „Auswertung") als Tage-Intervall (7/14/30/90/365T)
wählbar, Standard 30 Tage (evaluation_window_days, JournalRepository).
Der ViewModel berechnet moodPercentages/averageMood/latestMood über das
konfigurierte Fenster. versionCode 23 == versionName 23.
Status 2026-09-02 (22)
Secretary Journal 22 (versionCode 22): Nur noch „Karussell"-Theme. Alle klassischen/MODERN-Zweige entfernt, UiStyle (secretary-common-android) auf das einzelne CAROUSEL-Enum reduziert. Klassische Screen-Varianten (Login, Einstellungen, Editor, Kalender, Hauptansicht), der Stil-Umschalter in den Einstellungen sowie alle uiStyle-Parameter entfernt. Die App verwendet durchgehend das moderne Editorial-Ledger-Design. versionCode 22 == versionName 22.
Status 2026-09-02 (21)
Secretary Journal 21 (versionCode 21): Smiley zentriert, Kalender als eigener Screen. Das Stimmungs-Composite-Smiley ist jetzt vertikal zentriert (weighted Spacer above/below). Long-Tap navigiert zum eigenen Kalender-Screen (Routes.CAROUSEL → Routes.CALENDAR), statt den Kalender inline ein-/auszublenden. Die Hilfszeile zeigt nur noch „Tippen: neuer Eintrag · Halten: Kalender". versionCode 21 == versionName 21.
Status 2026-09-02 (20)
Secretary Journal 20 (versionCode 20): Smiley-Tap Aktion, Kalender versteckt. FAB-Button komplett entfernt; Tippen auf das große Stimmungs-Composite (240dp, Icons 144dp) erstellt direkt einen neuen Eintrag für heute. Halten (Long-Tap) zeigt/versteckt den Monatskalender unterhalb. Die untere Hilfszeile informiert über die verfügbaren Aktionen. versionCode 20 == versionName 20.
Status 2026-09-02 (19)
Secretary Journal 19 (versionCode 19): Karussell entfernt – Stimmungs-Overlay
mit Kalender. Der alte HorizontalPager-Karussell wurde komplett entfernt. Die
„Karussell"-Ansicht zeigt jetzt ein 160dp-Composite-Smiley in der oberen
Hälfte: drei gestapelte Material-Icons (MoodBad/SentimentNeutral/Mood) überlagern
sich mit je einer Opazität proportional zum prozentualen Anteil der jeweiligen
Stimmung der letzten 30 Tage. Darunter Prozentangaben pro Emoji, in der unteren
Hälfte der volle Monatskalender mit Monatsnavigation. moodPercentagesLast30Days
im ViewModel liefert die Stimmungsverteilung. versionCode 19 == versionName 19.
Status 2026-09-01 (16)
Secretary Journal 16 (versionCode 16): Einheitlicher Moderner Header –
alle secretary-Apps teilen jetzt denselben modernen Haupt-Header
(ModernAppHeader in secretary-common-android): Hero mit Monogramm +
Status-Chip und darunter die identische Aktionsleiste (Sync, Einstellungen).
Die Journal-Hauptansicht hat damit wieder wie im klassischen Design Sync- und
Einstellungen-Buttons im Kopfbereich; der verdoppelte zweite Header (kleiner
Screen-Header oder Einträge + Hero) wurde entfernt. versionCode 16 ==
versionName 16.
Status 2026-09-01 (15)
Secretary Journal 15 (versionCode 15): Komplett modernisierte Oberfläche (Moderner Stil). Kalender-Monatsansicht, Eintrags-Editor und Einstellungen haben jetzt einen vollständigen „Moderner Stil"-Zweig nach dem gemeinsamen Editorial-Ledger-Design (secretary-common-android): Serifen-Display-Typo, Pill-artige Karten, Hero-Header mit Monogramm, Status-Chips, Monats-Navigation mit tonalen Pfeilen, Stimmungs-Auswahl, moderne Leerszustände; der klassische Stil bleibt unverändert erhalten. Umschaltung über den globalen Schalter „Moderner Stil"; das Theme liefert im modernen Modus die secretaryModernTypography. versionCode 15 == versionName 15.
Status 2026-08-29 (12)
Secretary Journal 12 (versionCode 12): Sync-Fortschritt: kein Endlos-Spinner
mehr nach Abschluss/Fehler – Fix im gemeinsamen SyncProgressUi
(secretary-common-android): sobald ein Sync-Job beendet ist (DONE/FAILED),
wird der Spinner/Progressbar nicht mehr gezeichnet – es erscheint nur noch der
einmalige Toast. Vorher blieb der Status gesetzt und die Inline-SyncProgressUi
zeigte bei beendetem/fehlgeschlagenem Sync dauerhaft einen Spinner bei 0/0.
Server-Init-Sync läuft jetzt gegen den aktualisierten secretary-server 0.10.0
mit den /sync/*-Endpunkten. versionCode 12 == versionName.
Status 2026-08-29 (11)
Secretary Journal 11 (versionCode 11): Server-gesteuerter Sync mit
Fortschritt – über den gemeinsamen SyncJobClient
(secretary-common-android, POST /sync/start + GET /sync/status/{id}) startet
JournalViewModel.runServerSync() beim manuellen Refresh
(loadCollections/refresh) für jedes Journal-Collection einen Server-Sync-Job
und pollt den Fortschritt. JournalCalendarScreen zeigt über das gemeinsame
SyncProgressUi während des Syncs einen Spinner + Determinat-Progressbar
(processed / total) und einmalig einen Toast („Sync abgeschlossen" /
„fehlgeschlagen"). versionCode 11 == versionName.
Roadmap (Kurz)
- v43: Kalender-Filter nach EntryType (nur Trigger/Skill/Highlights anzeigen)
- v44: Widget für heutige Trigger/Skill-Empfehlungen