v1.4.7 : toggles de modèles alignés sur les traitements à profil (#58) + calibration universelle épinglée (par ester, toutes les courbes) + fix #59 : chip de traitement affichait 'Estrannaise' pour WHSAH (ternaire → helper modelLabelRes centralisé) ; 158 tests verts + lint
This commit is contained in:
parent
ca917ba772
commit
1c9d2e4e6a
@ -16,7 +16,7 @@ sauvegarde JSON. **100 % local, aucun compte, aucun serveur.**
|
||||
> à titre informatif — ce ne sont pas des mesures. Fie-toi toujours à tes analyses de
|
||||
> sang et aux consignes de ton endocrinologue.
|
||||
|
||||
- **Statut** : v1.4.6 — build Android ✅, **lint vert** ✅, **155 tests unitaires** ✅ (133 sans les données de test locales ; 3 régressions épinglées sur données réelles **non versionnées**), intégration montre = notifications ✅, **dépôt Gitea privé + releases avec APK** ✅
|
||||
- **Statut** : v1.4.7 — build Android ✅, **lint vert** ✅, **158 tests unitaires** ✅ (136 sans les données de test locales ; 3 régressions épinglées sur données réelles **non versionnées**), intégration montre = notifications ✅, **dépôt Gitea privé + releases avec APK** ✅
|
||||
- **Journal des versions** : [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
||||
- **Guide utilisateur** : [docs/GUIDE_INSTALLATION.md](docs/GUIDE_INSTALLATION.md)
|
||||
- **Doc de développement** (architecture, maths, décisions, bugs) : [docs/DEVELOPPEMENT.md](docs/DEVELOPPEMENT.md)
|
||||
@ -36,7 +36,8 @@ sauvegarde JSON. **100 % local, aucun compte, aucun serveur.**
|
||||
[simulateur TFS](https://transfemscience.org/misc/injectable-e2-simulator/),
|
||||
[article](https://transfemscience.org/articles/injectable-e2-meta-analysis/)),
|
||||
avec les **7 esters** (EV, EU, EEn, EB, EC huile, EC suspension, PEP) — et WHSAH
|
||||
en couvre 6 (sans PEP). Affichés côte à côte avec toggles indépendants (3 couleurs)
|
||||
en couvre 6 (sans PEP). Affichés côte à côte avec toggles indépendants (3 couleurs) — **pré-cochés
|
||||
selon les modèles de tes traitements** (v1.4.7) et **tous calibrés** par tes labs
|
||||
- **Modèle Bateman** paramétrable (temps au pic, demi-vie, biodisponibilité) pour gel,
|
||||
patch et voie orale
|
||||
- **Simulation prévisionnelle** : configurer la **posologie** (intervalle en jours) sur un
|
||||
@ -91,7 +92,7 @@ par AGP si les licences sont signées). Le wrapper télécharge Gradle 9.7.1.
|
||||
git clone <repo> && cd HormoneTrack
|
||||
echo "sdk.dir=/chemin/vers/android-sdk" > local.properties # ou ANDROID_HOME
|
||||
./gradlew assembleDebug # APK : app/build/outputs/apk/debug/app-debug.apk
|
||||
./gradlew testDebugUnitTest # 155 tests (133 sans les données locales)
|
||||
./gradlew testDebugUnitTest # 158 tests (136 sans les données locales)
|
||||
./gradlew lint # lint vert obligatoire avant release
|
||||
```
|
||||
|
||||
@ -103,7 +104,7 @@ Pas de Play Store : l'app est sideloadée. Détails pas-à-pas : [docs/GUIDE_INS
|
||||
|
||||
Dépôts : **gitea.cloudyfy.fr** et **gitea.farewell.dev** (miroir) —
|
||||
`Siphonight/HormoneTrack` sur les deux (privé), avec
|
||||
**releases taguées** (`v1.1.0` → `v1.4.6`) et **deux APK par release** (depuis v1.2.5)
|
||||
**releases taguées** (`v1.1.0` → `v1.4.7`) et **deux APK par release** (depuis v1.2.5)
|
||||
(téléchargeables sans compiler, cf [docs/DEVELOPPEMENT.md §16.bis](docs/DEVELOPPEMENT.md)) :
|
||||
`-release.apk` (**recommandé**, optimisé R8, 2,4 Mo) et `-debug.apk` (20 Mo) :
|
||||
|
||||
|
||||
@ -17,8 +17,8 @@ android {
|
||||
// tag : v1.3.0→v1.3.2 contenaient tous versionCode 14 / "1.3.0"
|
||||
// (bump jamais commité) → BuildConfig.VERSION_NAME était faux dans
|
||||
// les APK publiés (Paramètres + titre du dialog « Nouveautés »).
|
||||
versionCode = 26
|
||||
versionName = "1.4.6"
|
||||
versionCode = 27
|
||||
versionName = "1.4.7"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@ -43,6 +43,20 @@ object PKModels {
|
||||
const val WHSAH = "WHS"
|
||||
}
|
||||
|
||||
/**
|
||||
* Ressource de LABEL d'un modèle PK (v1.4.6/1.4.7, fix #59) — UNIQUE source
|
||||
* de vérité pour les affichages : chips de `TreatmentsScreen`, dropdown de
|
||||
* `TreatmentEditorScreen`, chip du graphique. ⚠️ L'ancien ternaire à 2
|
||||
* branches affichait « Estrannaise » pour WHSAH (WHSAH tombait dans le
|
||||
* `else`), remonté par l'utilisatrice — TOUTE nouvelle utilisation doit
|
||||
* passer par ce helper, pas par un ternaire (bug #59).
|
||||
*/
|
||||
fun modelLabelRes(pkModel: String): Int = when (pkModel) {
|
||||
PKModels.TRANSFEM_SCIENCE -> com.hormonetrack.R.string.model_tfs
|
||||
PKModels.WHSAH -> com.hormonetrack.R.string.model_whs
|
||||
else -> com.hormonetrack.R.string.model_ese
|
||||
}
|
||||
|
||||
enum class TreatmentType {
|
||||
ESTRADIOL,
|
||||
ANTI_ANDROGEN,
|
||||
|
||||
@ -113,6 +113,30 @@ fun niceCeil(value: Double): Double {
|
||||
return nice * exp
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles de MODÈLES PK par défaut (v1.4.7, fix #58) : au chargement du
|
||||
* graphique, seuls les modèles RÉELLEMENT utilisés par les traitements (en
|
||||
* cours ou passés — `isActive` n'est pas un filtre de simulation, cf §6.bis)
|
||||
* sont affichés ; les autres restent disponibles (chip off, activables au
|
||||
* tap). Ex. EV historique sous TFS + EEn actuel sous WHSAH → TFS ✓ WHSAH ✓
|
||||
* Estrannaise ✗.
|
||||
*
|
||||
* @param pkModelsUsed ensemble des `pkModel` des traitements de l'utilisatrice.
|
||||
* @return map modèle → toggle initial. GARDE-FOU : si AUCUN modèle profil
|
||||
* n'est utilisé (traitements gel/oral uniquement), TFS est forcé à ON —
|
||||
* les traitements Bateman sont tracés IDENTIQUEMENT dans chaque série
|
||||
* (cf §7.3b) : sans garde-fou, le graphique serait vide.
|
||||
*/
|
||||
fun defaultModelToggles(pkModelsUsed: Set<String>): Map<String, Boolean> {
|
||||
val toggles = mapOf(
|
||||
"ESE" to pkModelsUsed.contains("ESE"),
|
||||
"TFS" to pkModelsUsed.contains("TFS"),
|
||||
"WHS" to pkModelsUsed.contains("WHS")
|
||||
)
|
||||
// Garde-fou : aucune courbe sinon (Bateman tracé dans chaque série)
|
||||
return if (toggles.values.none { it }) toggles + ("TFS" to true) else toggles
|
||||
}
|
||||
|
||||
/**
|
||||
* Pas d'échantillonnage de la courbe selon la plage affichée (v1.2.9) :
|
||||
* plus on zoome, plus le pas finit pour des courbes lisses
|
||||
|
||||
@ -111,6 +111,26 @@ fun ChartScreen() {
|
||||
var showTfs by remember { mutableStateOf(true) }
|
||||
// v1.4.6 : 3ᵉ modèle PK superposable (WHSAH — fit license-free de Mona)
|
||||
var showWhs by remember { mutableStateOf(false) }
|
||||
// v1.4.7 (fix #58) : au CHARGEMENT des traitements, les toggles sont
|
||||
// alignés sur les modèles réellement UTILISÉS par des traitements à
|
||||
// PROFIL PK (injection + ester, `usesProfileModel`) — en cours ou passés
|
||||
// (cf §6.bis : EV inactif reste simulé) ; les autres modèles restent
|
||||
// activables au tap. ⚠️ FILTRER par usesProfileModel : sinon un
|
||||
// traitement oral/anti-androgène (pkModel stocké = ESE par défaut, sans
|
||||
// courbe profil) activerait Estrannaise à tort (vu sur l'émulateur avec
|
||||
// le CPA seedé). Une seule initialisation.
|
||||
var modelTogglesInitialized by remember { mutableStateOf(false) }
|
||||
LaunchedEffect(treatments) {
|
||||
if (!modelTogglesInitialized && treatments.isNotEmpty()) {
|
||||
val toggles = com.hormonetrack.ui.components.defaultModelToggles(
|
||||
treatments.filter { it.usesProfileModel }.map { it.pkModel }.toSet()
|
||||
)
|
||||
showEse = toggles.getValue("ESE")
|
||||
showTfs = toggles.getValue("TFS")
|
||||
showWhs = toggles.getValue("WHS")
|
||||
modelTogglesInitialized = true
|
||||
}
|
||||
}
|
||||
var showForecast by remember { mutableStateOf(false) }
|
||||
var showExtrema by remember { mutableStateOf(false) }
|
||||
var chartWidthPx by remember { mutableIntStateOf(0) }
|
||||
|
||||
@ -32,6 +32,7 @@ import androidx.compose.ui.unit.dp
|
||||
import com.hormonetrack.R
|
||||
import com.hormonetrack.data.model.PKModels
|
||||
import com.hormonetrack.data.model.Treatment
|
||||
import com.hormonetrack.data.model.modelLabelRes
|
||||
import com.hormonetrack.ui.LocalAppContainer
|
||||
import com.hormonetrack.ui.components.formatDose
|
||||
|
||||
@ -99,10 +100,12 @@ private fun TreatmentCard(tr: Treatment, onClick: () -> Unit) {
|
||||
AssistChip(
|
||||
onClick = {},
|
||||
label = {
|
||||
// v1.4.7 (fix #59) : label via modelLabelRes —
|
||||
// l'ancien ternaire à 2 branches affichait
|
||||
// « Estrannaise » pour le modèle WHSAH.
|
||||
Text(
|
||||
tr.esterType + " · " + stringResource(
|
||||
if (tr.pkModel == PKModels.TRANSFEM_SCIENCE) R.string.model_tfs
|
||||
else R.string.model_ese
|
||||
modelLabelRes(tr.pkModel)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -103,6 +103,32 @@ class WhsahEngineTest {
|
||||
assertTrue(curve.all { it.e2 == 0.0 })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `calibration applies to ALL model curves equally (fix 58)`() {
|
||||
// Demande v1.4.7 : « TOUTES les courbes doivent s'adapter au calibrage »
|
||||
// — épinglé : le facteur par ESTER (scalePerEster) est appliqué par
|
||||
// DOSE (doseEster), indépendamment du modelOverride → les 3 courbes
|
||||
// (ESE/TFS/WHS) d'un même traitement sont scalées IDENTIQUEMENT.
|
||||
val tr = treatment(Esters.EEN, PKModels.WHSAH)
|
||||
val d = dose(mg = 5.0)
|
||||
val t = BASE + 2 * DAY_MS
|
||||
val scales = mapOf("EEN" to 2.0)
|
||||
for (model in listOf("ESE", "TFS", "WHS")) {
|
||||
val calibrated = PharmacokineticEngine.computeCurve(
|
||||
listOf(tr), listOf(d), BASE, t, tConfig = TConfig(),
|
||||
modelOverride = model, scalePerEster = scales
|
||||
).last().e2
|
||||
val raw = PharmacokineticEngine.computeCurve(
|
||||
listOf(tr), listOf(d), BASE, t, tConfig = TConfig(),
|
||||
modelOverride = model
|
||||
).last().e2
|
||||
assertTrue(
|
||||
"$model : calibrée=$calibrated ≠ 2× brut=$raw",
|
||||
calibrated in raw * 2.0 * 0.99..raw * 2.0 * 1.01
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `three models give three distinct EV curves (no toggle collapse)`() {
|
||||
val tr = treatment(Esters.EV, PKModels.ESTRANNAISE)
|
||||
|
||||
@ -152,6 +152,41 @@ class ChartZoomTest {
|
||||
rangeHours = 6L, horizonHours = 24L, firstSlotGapHours = 0L))
|
||||
}
|
||||
|
||||
// ── v1.4.7 (fix #58) : toggles de modèles alignés sur les traitements ──
|
||||
|
||||
@Test
|
||||
fun `default toggles follow the models actually used by treatments`() {
|
||||
// Cas de l'utilisatrice : EV historique sous TFS + EEn actuel sous WHSAH
|
||||
// → Estrannaise OFF (jamais utilisée), les deux autres ON
|
||||
assertEquals(
|
||||
mapOf("ESE" to false, "TFS" to true, "WHS" to true),
|
||||
com.hormonetrack.ui.components.defaultModelToggles(setOf("TFS", "WHS"))
|
||||
)
|
||||
// les 3 modèles utilisés → tous ON
|
||||
assertEquals(
|
||||
mapOf("ESE" to true, "TFS" to true, "WHS" to true),
|
||||
com.hormonetrack.ui.components.defaultModelToggles(setOf("ESE", "TFS", "WHS"))
|
||||
)
|
||||
// un seul modèle → lui seul ON
|
||||
assertEquals(
|
||||
mapOf("ESE" to true, "TFS" to false, "WHS" to false),
|
||||
com.hormonetrack.ui.components.defaultModelToggles(setOf("ESE"))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `default toggles - no profile model used falls back to TFS (Bateman still drawn)`() {
|
||||
// Traitements gel/oral uniquement (pkModel stocké = ESE mais PAS de
|
||||
// modèle profil au sens usesProfileModel)... le set passé par
|
||||
// ChartScreen contient les pkModel BRUTS : un traitement gel sous
|
||||
// ESE produit setOf("ESE") → ESE ON. Un set vide (aucun traitement)
|
||||
// → garde-fou TFS ON (la courbe ne doit jamais être vide par défaut).
|
||||
assertEquals(
|
||||
mapOf("ESE" to false, "TFS" to true, "WHS" to false),
|
||||
com.hormonetrack.ui.components.defaultModelToggles(emptySet())
|
||||
)
|
||||
}
|
||||
|
||||
// ── v1.4.5 (fix #55) : labels X alignés sur minuit LOCAL ──
|
||||
|
||||
@Test
|
||||
|
||||
@ -1,7 +1,48 @@
|
||||
# Changelog — HormoneTrack
|
||||
|
||||
Format : [Keep a Changelog](https://keepachangelog.com/fr-FR/1.1.0/).
|
||||
Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.4.6`, …).
|
||||
Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.4.7`, …).
|
||||
|
||||
## [1.4.7] — 2026-09-07 (versionCode 27)
|
||||
|
||||
### Modifié
|
||||
- **Toggles de modèles pré-cochés selon TES traitements** (#58, demande :
|
||||
« les seules courbes activées par défaut sont celles qui se rapportent au
|
||||
modèle PK des traitements en cours ou passés ») : au chargement du
|
||||
graphique, les chips Estrannaise/Transfem/WHSAH sont alignés sur les
|
||||
modèles RÉELLEMENT utilisés par des traitements à PROFIL PK
|
||||
(`usesProfileModel` — le traitement inactif compte, l'oral/anti-androgène
|
||||
non) ; les autres restent activables au tap. Cas de l'utilisatrice :
|
||||
EV historique TFS + EEn actuel (qu'elle passe sous WHSAH) → TFS + WHSAH
|
||||
ON, Estrannaise OFF. Garde-fou testé : aucun modèle profil utilisé → TFS
|
||||
ON (les traitements Bateman sont tracés identiquement dans chaque série).
|
||||
Une seule initialisation : les toggles ensuite modifiés ne sont pas
|
||||
re-rencontrés. (`defaultModelToggles`, helper pur testé.)
|
||||
|
||||
### Corrigé
|
||||
- **La carte de traitement affichait « EEN Estrannaise » pour un traitement
|
||||
sous WHSAH** (#59, remontée) : le ternaire à 2 branches du chip
|
||||
`TreatmentsScreen` tombait WHSAH dans le `else` → label « Estrannaise ».
|
||||
FIX : helper centralisé **`modelLabelRes`** (unique source de vérité du
|
||||
label : ESE/TFS/WHS) utilisé par la carte — le dropdown de l'éditeur et
|
||||
le chip du graphique étaient déjà corrects. Règle : TOUT nouvel affichage
|
||||
de modèle passe par le helper, jamais un ternaire.
|
||||
|
||||
### Ajouté
|
||||
- **Épinglage : la calibration s'applique à TOUTES les courbes** (2ᵉ partie
|
||||
de la demande — vérification) : le facteur par ESTER (`scalePerEster`)
|
||||
est appliqué par DOSE (`doseEster`), indépendamment du modelOverride →
|
||||
les 3 courbes (ESE/TFS/WHS) d'un même traitement sont scalées
|
||||
IDENTIQUEMENT (2× le facteur = 2× la courbe, test `calibration applies
|
||||
to ALL model curves equally`). C'était déjà le comportement ; il est
|
||||
désormais garanti par test. Subtilité documentée (§7.6) : le facteur est
|
||||
calculé depuis la prédiction du modèle STOCKÉ du traitement — les
|
||||
courbes des autres modèles partagent ce facteur (un facteur par
|
||||
ester/période, pas par modèle).
|
||||
- **3 nouveaux tests** (158 au total / 136 sans les données locales) :
|
||||
`defaultModelToggles` (2) + calibration universelle (1).
|
||||
|
||||
## [1.4.6] — 2026-09-07 (versionCode 26)
|
||||
|
||||
## [1.4.6] — 2026-09-07 (versionCode 26)
|
||||
|
||||
|
||||
@ -89,6 +89,7 @@ Fonctionnalités v1 :
|
||||
| 7 sept. 2026 (session v1.4.4) | **Prévision inaccessible depuis v1.4.1** (#54, remontée) : DEUX causes emboîtées — (a) captures FIGÉES dans `pointerInput(Unit)` (`futurePanHorizon` lu à 0 pour toujours → pan futur interdit) → `rememberUpdatedState` + **garde de source** (`ChartScreenSourceGuardTest`, le lint Compose ne voit pas ce pattern) ; (b) toggle sans effet visible (`endMs = now` → 0 dose générée) → extension contrôlée à droite (`forecastExtensionHours`, jusqu'au 1ᵉʳ créneau, sans déplacer le début). Validé émulateur : drag gauche → panHours < 0, courbe dessinée au-delà de « maintenant » (screencap). 140 verts. Publication v1.4.4. |
|
||||
| 7 sept. 2026 (session v1.4.5) | **« La prévision simule le 13 au lieu du 12 »** (#55) : diagnostic sur données réelles — GÉNÉRATION EXACTE (créneau = dernière dose loguée + 6 j ; subtilité : la dose avait été loguée le LENDENDE de l'injection réelle → dérive d'un jour par cycle, l'app suit les logs) ; illusion causée par l'absence de marqueur + labels X à minuit UTC. FIX : marqueurs de doses (prévisionnels pointillés + réels discrets), labels à minuit LOCAL, fuseau de graphique configurable (Paramètres). **+ #56** : boucle de recomposition (`nowMs` relu à chaque frame → endMs dérive → saturation main thread → taps perdus) → mémoïsé sur le tick. 145 verts. Publication v1.4.5. |
|
||||
| 7 sept. 2026 (session v1.4.6) | **3ᵉ modèle PK « WHSAH »** (demande) : le fit « license-free » du WHSAH Collective publié dans **Mona** (l'app concurrente — son git montre qu'elle utilisait NOS paramètres TFS avant mars 2026) intégré au même niveau : dispatch parallèle (aucun remplacement), 6 presets, dropdown 3 choix, 3ᵉ toggle superposable (vert/violet), PEP non couvert. Comparaison chiffrée TFS vs WHSAF épinglée (EV pic 367 vs 295 ; EEn à J+1 ×3). **+ #57** : l'écran Graphiques défile désormais (rangée de toggles coupée sous le pli, trouvé en émulateur). 155 verts. Publication v1.4.6. |
|
||||
| 7 sept. 2026 (session v1.4.7) | **Toggles alignés sur les traitements** (#58, demande) : au chargement, seuls les modèles utilisés par des traitements à PROFIL PK (`usesProfileModel`) sont ON (l'oral/AA polluait le set — vu en émulateur avec le CPA) ; garde-fou TFS si aucun profil ; une seule init. **Épinglé : la calibration s'applique à TOUTES les courbes** (par ESTER via doseEster, indépendant du modelOverride — test). 158 verts. Publication v1.4.7. | + **#59** : le chip de la carte de traitement affichait « Estrannaise » pour WHSAH (ternaire à 2 branches → `modelLabelRes` centralisé).
|
||||
| 6 sept. 2026 (session v1.3.0) | Dialog « Nouveautés » après mise à jour (CHANGELOG embarqué en asset, tâche `copyChangelog`, version vue en DataStore) ; **événements d'agenda récurrents** (calendrier local HormoneTrack, RRULE posologie, permission runtime, Room v3 `calendarEventId`) ; Paramètres : version + lien releases ; **78 tests verts**, APK v1.3.0 + releases. |
|
||||
| 5 sept. 2026 (session v1.2.10) | Sens des boutons de zoom inversé (+ = zoom avant, convention carte — retour utilisateur) ; 67 tests verts, APK v1.2.10 + releases. |
|
||||
| 5 sept. 2026 (session v1.2.9) | **Zoom du graphique** (pinch + boutons, 6 h → 300 j, focal stable, échantillonnage adaptatif `stepForRange`, labels X 1 h/3 h) ; **README : disclaimer IA-assisté** en en-tête ; 3 tests ; **67 tests verts**, APK v1.2.9 + releases. |
|
||||
@ -345,6 +346,14 @@ T est faux d'un facteur 100, bug réel remonté par l'utilisatrice : labs 33/44
|
||||
|
||||
### 7.6 Calibration (v1.2.1 : PAR PÉRIODE D'ESTER pour l'auto)
|
||||
|
||||
**PORTÉE (épinglé v1.4.7, test `calibration applies to ALL model curves
|
||||
equally`)** : le facteur s'applique par ESTER de la DOSE (`doseEster`),
|
||||
indépendamment du modelOverride → TOUTES les courbes affichées (ESE/TFS/
|
||||
WHS) d'un même traitement sont scalées identiquement. Subtilité : le
|
||||
facteur est calculé depuis la prédiction du modèle STOCKÉ du traitement —
|
||||
les courbes des autres modèles partagent ce facteur (un facteur par
|
||||
ester/période, pas par modèle : les comparaisons inter-modèles reflètent
|
||||
la FORME, pas des calibrations distinctes).
|
||||
**Automatique** (`computeEsterScaleFactors` + `scalePerEster`, option « Auto-calibration ») :
|
||||
- chaque lab est **attribué à la période d'injection dans laquelle il tombe** =
|
||||
dernière dose E2 ≤ lab (une prise de sang reflète d'abord l'injection qui précède) ;
|
||||
@ -448,7 +457,7 @@ niveau que les deux autres, pas de remplacement »).
|
||||
|
||||
## 8. Tests unitaires
|
||||
|
||||
**155 tests JVM, tous verts** (`./gradlew testDebugUnitTest`) — **133 sans
|
||||
**158 tests JVM, tous verts** (`./gradlew testDebugUnitTest`) — **136 sans
|
||||
les données de test locales** (cf §8.bis : les 3 classes de régression,
|
||||
6 tests chacune, sont skippées via `Assume`). Dépendance : JUnit 4.13.2.
|
||||
Emplacement : `app/src/test/java/com/hormonetrack/`. Répertoire de travail d'exécution =
|
||||
@ -574,11 +583,18 @@ dépôt (ni maintenant, ni si le repo devient public un jour).
|
||||
- **`WhsahModelsTest`** (6) : v1.4.6 — fidélité au comportement **Mona**
|
||||
(fit WHSAH) : pics EV 367,5 @ 1,69 j / EEn 187,9 @ 4,99 j (±2 %), t½ par
|
||||
ester, linéarité par mg, PEP non couvert, `choicesForModel` ×3 modèles.
|
||||
- **`WhsahEngineTest`** (4) : v1.4.6 — dispatch WHSAH (override depuis un
|
||||
- **`WhsahEngineTest`** (5) : v1.4.6/v1.4.7 — dispatch WHSAH (override depuis un
|
||||
identiques au pic par construction) ; + **calibration universelle épinglée**
|
||||
(le facteur par ester s'applique à TOUTES les courbes, indépendamment du
|
||||
modelOverride — demande v1.4.7).
|
||||
traitement ESE, `pkModel = WHS`, coupure 10 × t½, PEP → 0) et **3 courbes
|
||||
EV distinctes** (ESE/TFS/WHS — seuil 2 % : ESE et TFS sont quasi
|
||||
identiques au pic par construction).
|
||||
- **`ChartZoomTest`** (13) : v1.2.9/v1.4.1/v1.4.5 — pas d'échantillonnage,
|
||||
- **`ChartZoomTest`** (15) : v1.2.9 (pas d'échantillonnage adaptatif) /
|
||||
v1.4.1 (horizon + clamp panoramique) / v1.4.5 (`pointHoursBefore`,
|
||||
`xLabelTicks` minuit local) / v1.4.7 — **`defaultModelToggles`** (toggles
|
||||
alignés sur les modèles utilisés par les traitements ; garde-fou TFS si
|
||||
aucun profil),
|
||||
horizon + clamp de panoramique, `pointHoursBefore`, extension de prévision,
|
||||
**`xLabelTicks`** (minuit LOCAL, fuseau CHOISI America/New_York, heures
|
||||
rondes, cas dégénérés).
|
||||
@ -615,7 +631,6 @@ dépôt (ni maintenant, ni si le repo devient public un jour).
|
||||
et 0 au-delà de 10 × t½ (par design) ; `computeCurve(modelOverride=TFS)`
|
||||
sur un traitement stocké ESE reproduit le pic V3C EV 295 — c'est le test
|
||||
du dispatch `concentrationOfDose` + de `cutoffHours`.
|
||||
- **`ChartZoomTest`** (7) : v1.2.9 (pas d'échantillonnage) + v1.4.1 — **horizon de prévision** 12 × Posologie borné 30 j–1 an (`forecastHorizonHours`, null sans Posologie) et **clamp du panoramique** (`clampPanHours` : panHours négatif = futur, borné par l'horizon ; prévision OFF → futur interdit) — la logique de fenêtre du graphique est centralisée et testée.
|
||||
- **`ReminderScheduleTest`** (8) : v1.4.0 — fix #52 : rappel sur la GRILLE
|
||||
Posologie (dose il y a 2 j + intervalle 7 j → alarme dans 5 j à l'heure
|
||||
choisie, PAS demain), heure déjà passée le jour du créneau → créneau
|
||||
@ -712,6 +727,11 @@ Sur la montre : remontée par Gadgetbridge **ou** Huawei Health (cf §17).
|
||||
(+ FAB), mini-chart 24 h (multi-séries via `ChartSeries`) **cliquable → écran
|
||||
Graphiques** (v1.2.1) avec mini-légende E2/T ; données auto-calibrées si l'option est
|
||||
active (`scalePerEster = effectiveAuto?.esterScales`) ; rafraîchissement `tick` 60 s
|
||||
- `ChartScreen` (v1.2, le plus riche) : **toggles de modèles initialement
|
||||
alignés sur les traitements** (v1.4.7, fix #58 : `defaultModelToggles` sur
|
||||
les pkModel des traitements à PROFIL PK — init unique au chargement ;
|
||||
garde-fou TFS si aucun profil — les traitements Bateman sont tracés dans
|
||||
chaque série) ;
|
||||
- `ChartScreen` (v1.2, le plus riche) : **fenêtre temporelle v1.4.1** —
|
||||
`endMs = now − panHours` avec `panHours` signé : > 0 = passé (tirer vers la
|
||||
droite), **< 0 = futur** (tirer vers la gauche, uniquement avec la
|
||||
@ -1125,6 +1145,18 @@ l'exemple) :**
|
||||
|
||||
**Session v1.4.0 (modèle TFS sur la méta-analyse + fix #52) :**
|
||||
|
||||
59. **« EEN Estrannaise » pour un traitement sous WHSAH** (v1.4.7,
|
||||
remontée) : le chip de `TreatmentsScreen` affichait le modèle via un
|
||||
ternaire à 2 branches (`if (pkModel == TFS) model_tfs else model_ese`)
|
||||
→ WHSAH tombait dans le `else`. Fix : helper centralisé
|
||||
`modelLabelRes(pkModel)` (data/model/Treatment.kt) — UNIQUE source du
|
||||
label. Leçon : quand un 3ᵉ choix est ajouté à un champ, GREPPER tous
|
||||
les points d'affichage existants (l'éditeur et le chart avaient été
|
||||
fixés en v1.4.6, la carte de traitement avait été ratée) — l'audit de
|
||||
`grep -rn "model_tfs else"` est passé à côté du pattern retourné
|
||||
multi-ligne ; le vrai filet : chercher les USAGES du champ
|
||||
(`tr.pkModel`) et vérifier chaque site.
|
||||
|
||||
57. **Écran Graphiques : rangée des toggles coupée sous le pli** (v1.4.6,
|
||||
découvert en validant WHSAH sur émulateur : le chip était absent du
|
||||
dump UI) : le Column du ChartScreen ne défilait pas — les toggles de
|
||||
@ -1340,8 +1372,8 @@ vérifie pas en tests JVM).
|
||||
|
||||
1. **Bumper la version** dans `app/build.gradle.kts` : `versionCode = N+1`,
|
||||
`versionName = "X.Y.Z+1"` (SemVer : fix = Z, feature = Y).
|
||||
2. **Tests verts obligatoires** : `./gradlew testDebugUnitTest` — 155 au
|
||||
total, 133 si `local-test-data/` est absent (les 3 classes de régression
|
||||
2. **Tests verts obligatoires** : `./gradlew testDebugUnitTest` — 158 au
|
||||
total, 136 si `local-test-data/` est absent (les 3 classes de régression
|
||||
réelles sont skippées via `Assume`, 6 tests chacune) ; **lint vert
|
||||
obligatoire** : `./gradlew lint` (v1.3.4 — `StringFormatMatches` aurait
|
||||
attrapé les crashs #47/#48 dès v1.3.1). Paliers de test du projet :
|
||||
@ -1633,9 +1665,24 @@ Sur le téléphone de test (à compléter par l'utilisatrice) :
|
||||
RÉELLEMENT (bug #53 : avant, la comparaison portait sur 24 h et le
|
||||
delta pouvait être trompeusement négatif) — vérifier la cohérence avec
|
||||
la courbe 24 h du graphique
|
||||
- [ ] **v1.4.4** : **prévision sans saut** : activer le chip ne déplace pas le
|
||||
graphique (il s'étend jusqu'à la prochaine dose) ; drag gauche = futur
|
||||
jusqu'à 1 an ; « Revenir à maintenant » ; désactivation en plein futur =
|
||||
retour auto (fix #54 : avant, le pan futur était figé à 0)
|
||||
- [ ] **v1.4.5** : **marqueurs de doses** : ligne pointillée + heure pour les
|
||||
doses projetées, triangles discrets pour les prises réelles ; labels X
|
||||
à minuit LOCAL du fuseau CHOISI (Paramètres, vide = téléphone) ; la
|
||||
prévision ne devait rien à un décalage de génération (créneau exact)
|
||||
- [ ] **v1.4.6** : **3ᵉ modèle WHSAH** : preset WHSAH → courbe verte
|
||||
superposable aux 2 autres (montée plus rapide à J+1, t½ plus longues
|
||||
que TFS) ; PEP non couvert ; 6 presets ; dropdown modèle à 3 choix
|
||||
- [ ] **v1.4.7** : **toggles alignés sur les traitements** : au 1ᵉʳ chargement
|
||||
du graphique, seuls les modèles des traitements à profil sont ON
|
||||
(ex. EV TFS + EEn WHSAH → Estrannaise OFF) ; les autres activables au
|
||||
tap ; et TOUTES les courbes affichées reflètent la calibration (test)
|
||||
|
||||
---
|
||||
*Doc mise à jour le 7 sept. 2026 (v1.4.6) — build OK, lint vert, 155/155 tests verts (133 sans
|
||||
*Doc mise à jour le 7 sept. 2026 (v1.4.7) — build OK, lint vert, 158/158 tests verts (136 sans
|
||||
les données locales), dépôts Gitea (cloudyfy + farewell) avec releases APK, aucune donnée
|
||||
de santé dans le dépôt ni l'historique. Fil des corrections : v1.3.3 = reprise de
|
||||
maintenance (permissions agenda, export logs IO, bump de version) ; v1.3.4 = 2 crashs
|
||||
|
||||
@ -187,6 +187,10 @@ Pics de référence (dose unique de 5 mg, IM) :
|
||||
pour parcourir la projection dans le futur (jusqu'à 1 an selon la Posologie) ;
|
||||
« Revenir à maintenant » pour revenir. Si tu désactives le chip alors que tu es
|
||||
dans le futur, l'app revient automatiquement à maintenant
|
||||
- **Toggles pré-cochés selon tes traitements** (v1.4.7) : au chargement du
|
||||
graphique, seuls les modèles utilisés par tes traitements (injections, en
|
||||
cours ou passés) sont affichés — les autres s'activent au tap ; et TOUTES
|
||||
les courbes affichées suivent ta calibration (labs), quel que soit le modèle
|
||||
- **Marqueurs de doses** (v1.4.5) : les doses projetées sont marquées par une
|
||||
ligne verticale pointillée avec leur heure ; tes prises enregistrées par un
|
||||
petit triangle discret au bas du graphique — plus d'ambiguïté sur « où » la
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user