Siphonight d531ecae24 v1.10.1 : durcissement rappels — singleTop (onNewIntent vivant), instant planifié dans la garde, BootReceiver goAsync
- launchMode="singleTop" sur MainActivity : un tap notification app-ouverte
  délivre onNewIntent SANS recréer l'activité (l'ancien standard+CLEAR_TOP
  recréait tout et rendait le chemin v1.10.0 inopérant — code mort).
- EXTRA_PLANNED_AT : l'instant planifié voyage dans l'alarme (scheduleFor),
  le snooze le forward, le garde « créneau déjà honoré » évalue le jour du
  CRÉNEAU et non celui du feu (alarme inexacte/Doze glissant après minuit).
- BootReceiver : goAsync + coroutine (dette §20.bis #2), runBlocking supprimés.
- Audit doc : comptes résiduels 223 → 259 (§14 #64, §16.ter) ; §9/§20.bis à jour.

259 tests JVM + 14 UI + lint verts ; validations émulateur sur APK RELEASE
avec données réelles seedées (singleTop 0 recreation, planned_at A/B, 0 crash).
Web non concerné (aucune logique miroir touchée).
2026-09-28 21:49:06 +02:00

HormoneTrack

Language: Français · English (this file)

🤖 AI-assisted development: this project was designed and coded with an AI assistant. The human contribution was essential: continuous feedback, user reports (testing on a real phone, bug reports with real data exports), improvement suggestions and validation of every release. The session-by-session detail is documented in docs/DEVELOPPEMENT.md §2 (French).

Hormone therapy (HRT) tracker on Android, with hour-by-hour estimated curves of estradiol (E2) and testosterone (T), calibration against blood tests, reminders mirrored on a smartwatch (Huawei Watch GT 3 via Gadgetbridge or Huawei Health) and JSON backup. 100% local, no account, no server.

⚠️ Medical disclaimer: the curves are pharmacokinetic estimates for informational purposes — they are not measurements. Always rely on your blood tests and on your endocrinologist's guidance.

  • Status: v1.10.0 — Android build ✅, lint clean ✅, 259 unit tests ✅ (225 without the local test data; 6 regressions pinned on real data not committed to the repo), 14 Compose UI tests ✅ (emulator), smartwatch integration = notifications ✅, private Gitea repo + releases with APK ✅
  • Changelog: docs/CHANGELOG.md (French)
  • User guide: docs/GUIDE_INSTALLATION.md (French)
  • Development docs (architecture, math, decisions, bugs): docs/DEVELOPPEMENT.md (French)
  • Watch / Gadgetbridge: docs/MONTRE-GADGETBRIDGE.md (French)

Features

  • Hour-by-hour estimated curves: E2 (pg/mL) and T (ng/mL), 24 h / 7 d / 30 d views, dose markers (forecast and actual), configurable chart timezone (v1.4.5), pan (drag to scroll back in time), zoom (pinch or − / + buttons, 6 h → 300 d, adaptive sampling), displayable peaks & troughs with their estimated values (▲▼ triangles at local extrema, toggleable)
  • Two PK models, superimposable: Estrannaise (EstraNase) (hourly tables from the .ods spreadsheet) and Transfem Science — since v1.4.0 the TFS model is the official 3-compartment meta-analysis (exact closed form, parameters from the TFS simulator, article), covering 7 esters (EV, EU, EEn, EB, EC oil, EC suspension, PEP) — WHSAH covers 6 (no PEP). Displayed side by side with independent toggles (3 colors) — pre-checked according to your treatments' models (v1.4.7) and each model calibrated separately by your labs (v1.4.8 — scale factors adapt to each profile)
  • "Lab track" curve (v1.5.0, extended in v1.6.0): the curve anchored on your blood tests (Lab track chip, off by default) — the PK model's shape between labs, with the amplitude rescaled to pass EXACTLY through every E2 lab value; log-linear transition from one lab to the next, keeps out-of-action-window labs (#61); Extend chip (v1.6.0): the curve extends beyond the last lab (model × last lab ratio, horizon = model extinction, estimated part drawn faded + dedicated legend) — the curve is a COMPARISON reference, never an estimate of action (it never feeds the home screen or the alerts)
  • Analytical Estrannaise model (v1.9.0): the ESE model now uses the 3C closed form published by estrannaise.js (fidelity to the old tables pinned at RMS 0) — MCMC uncertainty cloud (Cloud chip, ESE-exclusive: 32 posterior curves showing the imprecision range, like the estrannaise website); 6 injectable esters (incl. EUCS, exclusive); the historical ODS is no longer used at runtime (fidelity = tests only); analytical terminal t½ (blood draw recommendation)
  • Configurable Bateman model (time to peak, half-life, bioavailability) for gel, patch and oral routes
  • Forecast simulation: set a Dosage interval (days) on a treatment → upcoming doses are projected on the chart (never saved); enabling forecast does not move the chart start but EXTENDS the window to the next dose (v1.4.4), and the projection is browsed by dragging left, up to 1 year
  • Dose log with exact date/time, dose in mg, per-injection ester (EV↔EU↔EEn switch like in the spreadsheet), editable (tap a row in Doses), interval in days between doses displayed
  • Inactive treatments: an archived treatment disappears from input and reminders, but its whole history stays simulated and calibrated — useful for a valerate → enanthate transition
  • Blood tests: E2 + T in a single entry (each optional), displayed side by side when they share the same date/time, editable (tap → pick the entry); T units: ng/mL, ng/dL, ng/L, nmol/L
  • Suggested next blood draw (v1.8.0, extended v1.8.1 to the Labs and Home pages): the Labs page recommends the estimated trough just before the next injection (the most comparable moment), at the first trough where your regimen is stabilized (~5 half-lives after your last change — dose, ester or interval) — derived from the curves and the Dosage interval; requires an active injectable E2 with a Dosage (a prompt suggests setting one otherwise); estimates, never medical advice
  • Calibration: per-treatment scale factor = median(lab ÷ model prediction), computed automatically (the .ods "Scale factor", automated) — or permanent automatic calibration (option, off by default) which calibrates each ester with the labs of its own period (valerate labs → valerate doses, enanthate labs → enanthate doses) and recalibrates the T model
  • Empirical T estimation T = floor + (base − floor) ÷ (1 + k·E2), with k calibrated per ester period (T suppression differs valerate vs enanthate), against the already-calibrated E2 — accepted T units: ng/mL, ng/dL, ng/L, nmol/L
  • Daily reminders with "Taken" / "Snooze 1 h" actions right in the notification; notifications are mirrored to the GT 3 watch (Gadgetbridge or Huawei Health); reminders follow the Dosage interval (v1.4.0): a treatment injected every 7 days only rings on injection day, not every day; a dose already logged on the day skips the notification (v1.10.0 — the next reminder resumes at the following slot)
  • Configurable alert thresholds (v1.4.2): E2 (pg/mL) and T (ng/mL) high/low limits in Settings → warning card on the home screen + notification every 15 min even with the app closed (WorkManager, anti-spam, dedicated channel) — evaluated on the estimated level, opt-in
  • Full JSON backup: treatments + doses + labs + T settings + parameters (language, auto-calibration, alert thresholds) (v1.4.2)
  • Daily automatic backup (v1.7.0, opt-in): IN ADDITION to the manual export — every day, a full JSON backup (same format, directly importable) is written to the folder you choose (e.g. a synchronized Owncloud folder). No storage permission (SAF, folder picked once, persistent revocable permission), configurable retention (1–30 copies, default 7 — timestamped file per run, never overwritten; manual exports and foreign files never touched), last run status in Settings, first backup immediately on activation
  • What's new on every update: automatic changelog dialog (dismissed = won't show again before the next version)
  • Time on HRT displayed at the top of the Doses page (since the first dose); next dose in days on the home screen when it is more than 24 h away (v1.4.1)
  • Exportable diagnostic logs (Settings) — useful for support
  • Calendar events: dose reminders can create a recurring (posology) event in a "HormoneTrack" calendar on your phone
  • Full JSON backup/restore (treatments + doses + labs + T settings + parameters, v1.4.2)
  • FR + EN (per-app language, independent of the system)
  • Jetpack Compose UI (BOM 2026.08, Material You); 100% local, no account

Quick start (building from source)

Prerequisites: JDK 17+ (Java 21 OK), Android SDK (platform 37 will be auto-downloaded by AGP if the licenses are signed). The wrapper downloads Gradle 9.7.1.

git clone <repo> && cd HormoneTrack
echo "sdk.dir=/path/to/android-sdk" > local.properties   # or ANDROID_HOME
./gradlew assembleDebug            # APK: app/build/outputs/apk/debug/app-debug.apk
./gradlew testDebugUnitTest        # 259 tests (225 without local test data)
./gradlew connectedDebugAndroidTest # 14 UI tests (emulator/device required)
./gradlew lint                     # clean lint required before a release

Installing on a phone: developer mode + USB debugging, then Android Studio (Run ▶️) or adb install -r app/build/outputs/apk/debug/app-debug.apk. No Play Store: the app is sideloaded. Step-by-step details (French): docs/GUIDE_INSTALLATION.md.

Git

Repositories: gitea.cloudyfy.fr and gitea.farewell.dev (mirror) — Siphonight/HormoneTrack on both (private), with tagged releases (v1.1.0 → v1.10.0) and two APKs per release (since v1.2.5) (downloadable without building, cf docs/DEVELOPPEMENT.md §16.bis): -release.apk (recommended, R8-optimized, 2.7 MB) and -debug.apk (20 MB):

git tag            # list releases
git log --oneline  # layer-by-layer history (toolchain / engine / UI / docs)
git push -u origin main --tags

Web port: since v1.4.10, the browser version lives in its own repository Siphonight/HormoneTrack-web (same instances) — aligned versions (web v1.4.10 = port of Android v1.4.10), synced releases (checklist §16 step 4.bis), separate changelogs.

Every release commit passes ./gradlew testDebugUnitTest (green required) and is an annotated tag. See docs/DEVELOPPEMENT.md §16.

Release signing: the release APK is signed with the debug key as long as no keystore.properties exists at the repo root; once created via scripts/make-release-keystore.sh (both files gitignored), assembleRelease signs with that keystore — phone migration documented in docs/DEVELOPPEMENT.md §16.quater.

The models in short

Each injection contributes dose_mg × profile(dt) where profile is the normalized response (pg/mL per mg); contributions superimpose. Three superimposable models:

  • Estrannaise = hourly tables from the .ods (8001 h), EV/EU/EEn
  • Transfem Science = 3-compartment meta-analysis (V3C, closed form, article), 7 esters (EV, EU, EEn, EB, EC, EC suspension, PEP)
  • WHSAH (v1.4.6) = "license-free" fit of the WHSAH Collective via Mona — same mathematical family but independent parameters with explicit bioavailability F < 1: faster rise at D+1 (EEn ~70 pg/mL at D+1 for 5 mg vs ~22 for TFS) and longer decay (EEn t½ 7.3 d vs 4.5 d). 6 esters (no PEP)

Reference peaks (pg/mL per mg):

Profile Model Peak (pg/mL/mg) Tmax Terminal t½
EV Estrannaise 61.1 ~45 h —
EU Estrannaise 3.4 ~55 h (long plateau) —
EEn Estrannaise 31.4 ~152 h —
EV Transfem Science 59.0 ~51 h 3.0 d
EU Transfem Science 10.1 ~198 h —
EEn Transfem Science 32.0 ~156 h 4.5 d
EB Transfem Science 194.2 ~16 h 1.2 d
EC (oil) Transfem Science 31.1 ~103 h 6.7 d
EC (susp.) Transfem Science 48.2 ~29 h 5.1 d
PEP Transfem Science 1.03 (~6.5× dose) ~18 d 28.4 d
EV WHSAH 73.5 ~41 h 3.1 d
EEn WHSAH 37.6 ~120 h 7.3 d
EB WHSAH 260.1 ~12 h 1.3 d
EC (oil) WHSAH 25.0 ~81 h 7.9 d
EC (susp.) WHSAH 53.5 ~16 h 7.1 d
EU WHSAH 4.9 ~67 h 31.7 d

Calibration (v1.4.8): the scale factor applies per ESTER and per injection PERIOD (median of lab ÷ prediction ratios, like the original spreadsheet's "Scale factor" column) — and per MODEL: every displayed curve (Estrannaise / Transfem Science / WHSAH) is calibrated with ITS OWN model's prediction → they all stick to your labs, whatever their shape. Auto-calibration is optional (off by default).

Privacy

  • The app is 100% local: Room database on the phone, no server, no telemetry; Gadgetbridge-compatible (FOSS) with no Huawei Health dependency
  • The repository contains no health data: code and docs are generic; the regression tests that use real exports load their data from local-test-data/ (gitignored, outside the repo — and the history was cleaned before the first push, cf docs/DEVELOPPEMENT.md §8.bis)
  • Backups = JSON files you store wherever you want (Owncloud, etc.)
  • The daily auto-backup (v1.7.0) only writes to the folder YOU picked yourself (system SAF picker, revocable permission) — nothing ever leaves the phone, no server
  • allowBackup=false (sensitive data); biometric lock planned for Phase 2
  • The repository is private: release APKs download while logged in; making the repo public would make the APKs downloadable without an account (no data risk, see above)

Repository structure

HormoneTrack/
├── README.md                     ← this file's French twin
├── docs/
│   ├── GUIDE_INSTALLATION.md     user guide (phone + watch, French)
│   ├── DEVELOPPEMENT.md          full dev docs (architecture, math, bugs, tests, French)
│   ├── CHANGELOG.md              detailed version history (French)
│   └── MONTRE-GADGETBRIDGE.md    Huawei GT 3 watch: options + limits (French)
├── scripts/
│   ├── gitea-release.py            publishes a release body (CHANGELOG + APK)
│   ├── publish-release.py          publishes a tag's 2 APKs (verified by download)
│   ├── seed-emulator.py            injects a JSON backup into an emulator DB
│   └── make-release-keystore.sh    generates the release keystore + properties (v1.9.8)
├── local-test-data/              ← gitignored: real backups for regression
│                                   tests (NEVER in the repo, cf §8.bis)
├── keystore.properties           ← gitignored: release signing (optional, §16.quater)
├── build.gradle.kts              root Gradle config (AGP/Kotlin/KSP pinned)
├── settings.gradle.kts
├── gradle.properties
├── gradle/wrapper/               Gradle 9.7.1 wrapper (jar + properties)
├── gradlew / gradlew.bat
└── app/
    ├── build.gradle.kts          dependencies (Compose, Room, DataStore, Gson…)
    ├── proguard-rules.pro
    └── src/
        ├── main/
        │   ├── AndroidManifest.xml
        │   ├── assets/pk_profiles.json          ← hourly tables (Estrannaise/TFS)
        │   ├── java/com/hormonetrack/
        │   │   ├── data/         (Room: models, DAOs, repository, backup)
        │   │   ├── pk/           (PK engine + profiles: Estrannaise/TFS/WHSAH, alerts, export)
        │   │   ├── reminder/     (exact alarms, notifs + actions, boot, alert worker)
        │   │   ├── settings/     (DataStore: TConfig, language)
        │   │   ├── ui/           (Compose: screens, components, theme)
        │   │   │   └── screens/settings/   ← Settings cards (v1.9.8 split)
        │   │   ├── HormoneTrackApp.kt
        │   │   └── MainActivity.kt
        │   └── res/              (FR/EN strings, theme, icons)
        ├── test/java/com/hormonetrack/          ← JVM unit tests
        │   ├── pk/               (engine, ESE/TFS/WHSAH profiles, per-model
        │   │                      calibration, reminders, data-driven regressions)
        │   ├── data/backup/      (Gson round-trip + parameters)
        │   ├── ui/               (chart window, source guard)
        │   ├── util/             (export file names, durations)
        │   └── reminder/ + settings/  (calendar RRULE, changelog)
        └── androidTest/java/com/hormonetrack/   ← Compose UI tests (v1.9.8)
            └── uitest/           (navigation, changelog dialog, settings)

Roadmap

  • v1: E2/T curves, dose log, labs + calibration, reminders, JSON backup, FR/EN
  • Compose UI tests (13) + dedicated release signing infrastructure (v1.9.8)
  • Biometric lock, widget, CSV export
  • Watch Phase 2: custom watchface and/or Lite Wearable mini-app (see docs/MONTRE-GADGETBRIDGE.md)

License

GPL-3.0 — see LICENSE. Consistent with the Gadgetbridge ecosystem. The PK models belong to their respective authors (Estrannaise, Transfem Science).

Description
No description provided
Readme GPL-3.0 8.3 MiB
v1.13.0 Latest
2026-10-07 09:59:19 +02:00
Languages
Kotlin 97.2%
Python 2.5%
Shell 0.3%