v1.2.9 : zoom du graphique (pinch + boutons, 6 h → 300 j, focal stable, pas adaptatif) + disclaimer IA dans le README
- ChartScreen : detectTransformGestures unique (pan 1 doigt + pinch 2 doigts, pas de conflit de consommation) ; zoom autour du point focal (le temps sous le doigt reste fixe) ; plage bornée 6 h → 300 j (MIN/MAX_RANGE_H) ; boutons − / + en accessibilité - CurveChart : stepForRange (15 min ≤ 12 h, 30 min ≤ 24 h, sinon 1 h) passé à computeCurve (courbes lisses à fort zoom) ; labels X adaptatifs 1 h/3 h - README : disclaimer IA en en-tête (développé avec l'IA, contribution humaine essentielle = feedback/retours/suggestions, renvoi §2 doc dev) ; DEVELOPPEMENT §1 mention IA-assistée, §11 zoom, §8 67 tests - ChartZoomTest : 3 tests stepForRange — 67 tests verts - versionCode 12, versionName 1.2.9
This commit is contained in:
parent
0eaaea40c1
commit
216606541b
14
README.md
14
README.md
@ -1,5 +1,12 @@
|
||||
# HormoneTrack
|
||||
|
||||
> **🤖 Développé avec l'IA** : ce projet a été conçu et codé avec un assistant IA.
|
||||
> La contribution humaine a été **essentielle** : feedback continu, retours
|
||||
> utilisateur (tests sur vrai téléphone, rapports de bugs accompagnés d'exports
|
||||
> réels), suggestions d'améliorations et validation de chaque release. Le
|
||||
> détail session par session est documenté dans
|
||||
> [docs/DEVELOPPEMENT.md §2](docs/DEVELOPPEMENT.md).
|
||||
|
||||
Suivi de thérapie hormonale (THS) sur Android, avec courbes estimées **heure par heure**
|
||||
d'estradiol (E2) et de testostérone (T), calibration sur les prises de sang, rappels
|
||||
affichés sur smartwatch (Huawei Watch GT 3 via Gadgetbridge ou Huawei Health) et
|
||||
@ -9,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.2.8 — build Android ✅, **64 tests unitaires** ✅ (44 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.2.9 — build Android ✅, **67 tests unitaires** ✅ (44 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)
|
||||
@ -18,8 +25,9 @@ sauvegarde JSON. **100 % local, aucun compte, aucun serveur.**
|
||||
## Fonctionnalités
|
||||
|
||||
- **Courbes estimées heure par heure** : E2 (pg/mL) et T (ng/mL), vue 24 h / 7 j / 30 j,
|
||||
**panoramique** (glisser pour remonter dans le passé), **pics & creux** affichables
|
||||
(triangles ▲▼ aux extrema locaux, toggle)
|
||||
**panoramique** (glisser pour remonter dans le passé), **zoom** (pinch ou boutons
|
||||
− / +, 6 h → 300 j, échantillonnage adaptatif), **pics & creux** affichables avec
|
||||
leurs **valeurs estimées** (triangles ▲▼ aux extrema locaux, toggle)
|
||||
- **Deux modèles PK au choix, superposables** (issus de la feuille `Estrogen.ods`) :
|
||||
**Estrannaise (EstraNase)** et **Transfem Science** pour les injections EV / EU / EEn,
|
||||
affichés côte à côte avec toggles indépendants
|
||||
|
||||
@ -12,8 +12,8 @@ android {
|
||||
applicationId = "com.hormonetrack"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 11
|
||||
versionName = "1.2.8"
|
||||
versionCode = 12
|
||||
versionName = "1.2.9"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@ -66,6 +66,17 @@ fun niceCeil(value: Double): Double {
|
||||
return nice * exp
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* (≤ 12 h → 15 min ; ≤ 24 h → 30 min ; sinon 1 h).
|
||||
*/
|
||||
fun stepForRange(rangeHours: Long): Long = when {
|
||||
rangeHours <= 12L -> 900_000L // 15 min
|
||||
rangeHours <= 24L -> 1_800_000L // 30 min
|
||||
else -> 3_600_000L // 1 h
|
||||
}
|
||||
|
||||
/**
|
||||
* Graphique Canvas pur, multi-séries :
|
||||
* - axe gauche = E2 (pg/mL), axe droit = T (ng/mL) ;
|
||||
@ -309,7 +320,10 @@ private fun DrawScope.drawXLabels(
|
||||
) {
|
||||
val paint = labelPaint(android.graphics.Paint.Align.CENTER)
|
||||
val spanH = (t1 - t0) / 3_600_000.0
|
||||
// Pas des labels X adaptatif — le zoom (v1.2.9) descend jusqu'à quelques heures
|
||||
val stepHours = when {
|
||||
spanH <= 8 -> 1
|
||||
spanH <= 18 -> 3
|
||||
spanH <= 25 -> 6
|
||||
spanH <= 25 * 7 -> 24
|
||||
else -> 24 * 5
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.hormonetrack.ui.screens
|
||||
|
||||
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
||||
import androidx.compose.foundation.gestures.detectTransformGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -9,12 +9,18 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Remove
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilledTonalIconButton
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@ -51,6 +57,9 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
private const val HOUR_MS = 3_600_000L
|
||||
private const val DAY_MS = 24 * HOUR_MS
|
||||
// Zoom (v1.2.9) : plage temporelle bornée 6 h → 300 j
|
||||
private const val MIN_RANGE_H = 6L
|
||||
private const val MAX_RANGE_H = 24L * 300
|
||||
|
||||
/**
|
||||
* Écran Graphiques.
|
||||
@ -79,6 +88,7 @@ fun ChartScreen() {
|
||||
val tConfig by container.settings.tConfig.collectAsState(initial = TConfig())
|
||||
val autoCalibrate by container.settings.autoCalibrate.collectAsState(initial = false)
|
||||
|
||||
// Zoom temporel (v1.2.9) : plage bornée 6 h → 300 j, pinch + boutons
|
||||
var rangeHours by remember { mutableLongStateOf(24L) }
|
||||
var panHours by remember { mutableLongStateOf(0L) }
|
||||
var showT by remember { mutableStateOf(true) }
|
||||
@ -144,10 +154,13 @@ fun ChartScreen() {
|
||||
}
|
||||
} else emptyList()
|
||||
val allDoses = doseLogs + forecastDoses
|
||||
// Pas d'échantillonnage adaptatif au zoom (v1.2.9)
|
||||
val step = com.hormonetrack.ui.components.stepForRange(rangeHours)
|
||||
if (showEse) {
|
||||
list.add(
|
||||
"ESE" to PharmacokineticEngine.computeCurve(
|
||||
effTreatments, allDoses, startMs, endMs,
|
||||
stepMs = step,
|
||||
tConfig = effTConfig, modelOverride = "ESE",
|
||||
scalePerEster = effScales,
|
||||
tKPerEster = effectiveAuto?.tKPerEster
|
||||
@ -158,6 +171,7 @@ fun ChartScreen() {
|
||||
list.add(
|
||||
"TFS" to PharmacokineticEngine.computeCurve(
|
||||
effTreatments, allDoses, startMs, endMs,
|
||||
stepMs = step,
|
||||
tConfig = effTConfig, modelOverride = "TFS",
|
||||
scalePerEster = effScales,
|
||||
tKPerEster = effectiveAuto?.tKPerEster
|
||||
@ -217,6 +231,20 @@ fun ChartScreen() {
|
||||
onClick = { rangeHours = 24L * 30 },
|
||||
label = { Text(stringResource(R.string.chart_30j)) }
|
||||
)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
// Zoom manuel (accessibilité — le pinch fonctionne aussi)
|
||||
FilledTonalIconButton(
|
||||
onClick = { rangeHours = (rangeHours * 2).coerceAtMost(MAX_RANGE_H) },
|
||||
enabled = rangeHours < MAX_RANGE_H
|
||||
) {
|
||||
Icon(Icons.Filled.Add, contentDescription = stringResource(R.string.zoom_in))
|
||||
}
|
||||
FilledTonalIconButton(
|
||||
onClick = { rangeHours = (rangeHours / 2).coerceIn(MIN_RANGE_H, MAX_RANGE_H) },
|
||||
enabled = rangeHours > MIN_RANGE_H
|
||||
) {
|
||||
Icon(Icons.Filled.Remove, contentDescription = stringResource(R.string.zoom_out))
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(8.dp))
|
||||
@ -268,15 +296,33 @@ fun ChartScreen() {
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.onSizeChanged { chartWidthPx = it.width }
|
||||
.pointerInput(rangeHours, maxPanHours) {
|
||||
// Glisser vers la droite = remonter dans le passé
|
||||
detectHorizontalDragGestures { change, dragAmount ->
|
||||
change.consume()
|
||||
if (chartWidthPx > 0 && maxPanHours > 0) {
|
||||
val hoursDragged = (dragAmount / chartWidthPx * rangeHours).toLong()
|
||||
.pointerInput(Unit) {
|
||||
// Pan (1 doigt) + pinch-zoom (2 doigts, v1.2.9) — un seul
|
||||
// handler pour éviter les conflits de consommation
|
||||
detectTransformGestures { centroid, pan, zoom, _ ->
|
||||
val forecastMs =
|
||||
(if (showForecast) (forecastHorizonHours ?: 0L) * HOUR_MS else 0L)
|
||||
if (chartWidthPx > 0) {
|
||||
// Pan horizontal : glisser à droite = remonter le temps
|
||||
val hoursDragged = (pan.x / chartWidthPx * rangeHours).toLong()
|
||||
if (hoursDragged != 0L) {
|
||||
panHours = (panHours + hoursDragged).coerceIn(0L, maxPanHours)
|
||||
}
|
||||
// Zoom autour du point focal : le temps sous le doigt
|
||||
// reste fixe pendant le pinch
|
||||
if (zoom != 1f && zoom > 0f) {
|
||||
val f = (centroid.x / chartWidthPx.toDouble()).coerceIn(0.0, 1.0)
|
||||
val newRange = (rangeHours / zoom).toLong()
|
||||
.coerceIn(MIN_RANGE_H, MAX_RANGE_H)
|
||||
if (newRange != rangeHours) {
|
||||
val endAnchor = nowMs + forecastMs - panHours * HOUR_MS
|
||||
val tFocal = endAnchor - ((1.0 - f) * rangeHours * HOUR_MS).toLong()
|
||||
val newEnd = tFocal + ((1.0 - f) * newRange * HOUR_MS).toLong()
|
||||
val newPan = ((nowMs + forecastMs - newEnd) / HOUR_MS).toLong()
|
||||
panHours = newPan.coerceIn(0L, maxPanHours)
|
||||
rangeHours = newRange
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
<string name="show_labs">Analyses</string>
|
||||
<string name="show_forecast">Prévision</string>
|
||||
<string name="show_extrema">Pics / creux</string>
|
||||
<string name="zoom_in">Zoom avant (fenêtre plus courte)</string>
|
||||
<string name="zoom_out">Zoom arrière (fenêtre plus longue)</string>
|
||||
<string name="legend_extrema">▲▼ pics & creux estimés (par courbe)</string>
|
||||
<string name="back_to_present">Revenir à maintenant</string>
|
||||
<string name="drag_hint">Fais glisser le graphique vers la droite pour remonter dans le passé.</string>
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
<string name="show_labs">Labs</string>
|
||||
<string name="show_forecast">Forecast</string>
|
||||
<string name="show_extrema">Peaks / troughs</string>
|
||||
<string name="zoom_in">Zoom in (shorter window)</string>
|
||||
<string name="zoom_out">Zoom out (longer window)</string>
|
||||
<string name="legend_extrema">▲▼ estimated peaks & troughs (per curve)</string>
|
||||
<string name="back_to_present">Back to now</string>
|
||||
<string name="drag_hint">Drag the chart to the right to travel into the past.</string>
|
||||
|
||||
31
app/src/test/java/com/hormonetrack/ui/ChartZoomTest.kt
Normal file
31
app/src/test/java/com/hormonetrack/ui/ChartZoomTest.kt
Normal file
@ -0,0 +1,31 @@
|
||||
package com.hormonetrack.ui
|
||||
|
||||
import com.hormonetrack.ui.components.stepForRange
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Pas d'échantillonnage adaptatif au zoom (v1.2.9) : plus la fenêtre est
|
||||
* courte, plus le pas est fin — sinon les courbes paraissent anguleuses.
|
||||
*/
|
||||
class ChartZoomTest {
|
||||
|
||||
@Test
|
||||
fun `deep zoom uses 15 minute steps`() {
|
||||
assertEquals(900_000L, stepForRange(6L))
|
||||
assertEquals(900_000L, stepForRange(12L))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `mid zoom uses 30 minute steps`() {
|
||||
assertEquals(1_800_000L, stepForRange(13L))
|
||||
assertEquals(1_800_000L, stepForRange(24L))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `wide ranges use hourly steps`() {
|
||||
assertEquals(3_600_000L, stepForRange(25L))
|
||||
assertEquals(3_600_000L, stepForRange(24L * 30))
|
||||
assertEquals(3_600_000L, stepForRange(24L * 300))
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,21 @@
|
||||
# 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.2.8`, …).
|
||||
Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.2.9`, …).
|
||||
|
||||
## [1.2.9] — 2026-09-05 (versionCode 12)
|
||||
|
||||
### Ajouté
|
||||
- **Zoom du graphique de simulation** : pinch à 2 doigts **et** boutons − / +
|
||||
(accessibilité), plage bornée **6 h → 300 j** ; le point focal du pinch reste
|
||||
fixe dans le temps ; échantillonnage adaptatif (15 min ≤ 12 h, 30 min ≤
|
||||
24 h, sinon 1 h — courbes lisses à fort zoom) ; labels X adaptatifs
|
||||
(1 h / 3 h). Un seul gestionnaire de gestes gère pan + zoom (pas de
|
||||
conflit de consommation).
|
||||
- **README : disclaimer IA** en en-tête — projet développé avec l'IA,
|
||||
contribution humaine essentielle (feedback, retours utilisateur, suggestions) ;
|
||||
mention factuelle reprise en §1/§2 de la doc de développement.
|
||||
- 3 tests `stepForRange` (67 au total).
|
||||
|
||||
## [1.2.8] — 2026-09-05 (versionCode 11)
|
||||
|
||||
|
||||
@ -45,6 +45,11 @@ Android, apps tierces au poignet quasi impossibles (cf §17). Utilisatrice équi
|
||||
**Gadgetbridge** (FOSS) sur son téléphone → v1 = **app téléphone + notifications miroir
|
||||
sur la montre** via GB (ou Huawei Health).
|
||||
|
||||
> **Développement IA-assisté** : le code a été produit avec un assistant IA ;
|
||||
> la contribution humaine = feedback continu, retours utilisateur (tests réels
|
||||
> sur téléphone, bugs avec exports), suggestions et validation des releases
|
||||
> (détail §2 — factuel, session par session).
|
||||
|
||||
Fonctionnalités v1 :
|
||||
- Courbes estimées heure par heure : E2 (pg/mL) + T (ng/mL) — 24 h / 7 j / 30 j
|
||||
- Deux modèles PK du `.ods` (Estrannaise / TFS) pour injections EV/EU/EEn ;
|
||||
@ -71,6 +76,7 @@ Fonctionnalités v1 :
|
||||
| 5 sept. 2026 (session v1.2.1) | Remontées UX/utilisateur : calibration **par période d'ester** (labs EV → doses EV, labs EEn → doses EEn — corrige les courbes gonflées), lab T "pg/mL" neutralisé, **édition des labs**, tap accueil → Graphiques + mini-légende, auto-cal fusionnée (E2+T, un seul switch) ; 2ᵉ régression épinglée sur le nouvel export ; **44 tests verts**, APK v1.2.1. |
|
||||
| 5 sept. 2026 (session v1.2.2) | Toggle T masque aussi les labs T ; **prise de sang E2 + T en une entrée** (chacune optionnelle) affichée **côte à côte** ; sélecteur d'édition par marqueur ; suppression par prise ; 4 tests de regroupement ; **48 tests verts**, APK v1.2.2. |
|
||||
| 5 sept. 2026 (session v1.2.6) | Valeurs estimées affichées sur les pics/creux (drawExtremum) ; **import JSON en mode écrasement** (bug : conflit d'IDs si données existantes) avec restauration du tConfig et reprogrammation des rappels ; docs ; 62 tests verts, APK v1.2.6 + 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. |
|
||||
| 5 sept. 2026 (session v1.2.8) | « Fréquence d'injection » → **« Posologie »** (terme adapté à toutes les voies) ; quirk Gitea découvert (noms d'assets normalisés à l'upload) → renommage PATCH dans le script ; releases avec les 2 APK ; 64 tests verts. |
|
||||
| 5 sept. 2026 (session v1.2.7) | Prévision : les créneaux passés ne sont plus simulés (bug oubli → faux pic historique) ; retard = décalage voulu ; mismatch doc-code §7.3b corrigé ; 2 tests ; **64 tests verts**, APK v1.2.7 + releases. |
|
||||
|
||||
@ -396,7 +402,7 @@ dépôt (ni maintenant, ni si le repo devient public un jour).
|
||||
- `.gitignore` contient `local-test-data/` → jamais commités ;
|
||||
- les tests font `Assume.assumeTrue(file.exists())` dans le `@Before` : **sans le
|
||||
fichier, la classe est IGNORÉE** (skipped, pas failed) — un clone neuf ou une CI
|
||||
exécute 44 tests au lieu de 56 ;
|
||||
exécute 44 tests au lieu de 67 ;
|
||||
- le workdir des tests Gradle est le dossier du module (`app/`) → les tests
|
||||
cherchent les fichiers à plusieurs chemins (`../local-test-data/…` en premier) ;
|
||||
- **pour les lancer** : exporter un backup JSON depuis l'app → l'enregistrer sous
|
||||
@ -455,7 +461,8 @@ 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) : plages 24 h/7 j/30 j ; **panoramique**
|
||||
- `ChartScreen` (v1.2, le plus riche) : plages 24 h/7 j/30 j + **boutons zoom − / +**
|
||||
(v1.2.9) ; **panoramique**
|
||||
(`detectHorizontalDragGestures` — tirer vers la droite remonte dans le passé,
|
||||
`panHours` borné à [0, âge de la 1ʳᵉ dose + plage], bouton « Revenir à maintenant ») ;
|
||||
**toggles indépendants Estrannaise/TFS** → deux `computeCurve` avec `modelOverride`
|
||||
@ -518,6 +525,15 @@ triangles ▲▼ via `PharmacokineticEngine.detectExtrema` **accompagnés de la
|
||||
valeur estimée** du pic (au-dessus) ou du creux (en dessous), dans la couleur
|
||||
de la série (`drawExtremum`).
|
||||
|
||||
**Zoom (v1.2.9)** : pinch **et** boutons − / + — plage temporelle bornée
|
||||
**6 h → 300 j** (`MIN_RANGE_H`/`MAX_RANGE_H`), point focal du pinch maintenu
|
||||
fixe dans le temps (formule centroid), échantillonnage **adaptatif**
|
||||
(`stepForRange` : 15 min ≤ 12 h, 30 min ≤ 24 h, sinon 1 h — courbes lisses à
|
||||
fort zoom) et labels X adaptatifs (1 h / 3 h ajoutés). Le pan ET le zoom
|
||||
partagent un seul `detectTransformGestures` (un handler = pas de conflit de
|
||||
consommation) ; le zoom/pan restent gérés **par le parent**, le Canvas demeure
|
||||
purement déclaratif.
|
||||
|
||||
Pièges :
|
||||
- `DrawScope` implémente `Density` → `X.dp.toPx()` direct ; ne PAS écrire de helper custom
|
||||
- Tout label passe par `drawContext.canvas.nativeCanvas` + `android.graphics.Paint`
|
||||
@ -918,6 +934,8 @@ Sur le téléphone de test (à compléter par l'utilisatrice) :
|
||||
- [ ] **v1.2.x** : édition d'une dose (tap ligne Doses) et d'un lab (tap ligne
|
||||
Analyses → sélecteur E2/T si paire) ; suppression par prise entière
|
||||
- [ ] **v1.2.x** : prise de sang E2 + T en une entrée (champs optionnels)
|
||||
- [ ] **v1.2.9** : zoom du graphique (pinch 2 doigts + boutons − / + ; labels
|
||||
X adaptatifs ; courbes lisses à fort zoom)
|
||||
- [ ] **v1.2.7** : prévision après un OUBLI (pas de faux pic dans le passé)
|
||||
et après un RETARD (prévision décalée, suivant la dernière prise)
|
||||
- [ ] **v1.2.6** : import d'un backup avec l'app déjà remplie → ÉCRASER &
|
||||
@ -927,4 +945,4 @@ Sur le téléphone de test (à compléter par l'utilisatrice) :
|
||||
sur le graphique** et la calibration couvre toujours ses périodes
|
||||
|
||||
---
|
||||
*Doc mise à jour le 5 sept. 2026 (v1.2.8) — build OK, 62/62 tests verts (44 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.*
|
||||
*Doc mise à jour le 5 sept. 2026 (v1.2.9) — build OK, 62/62 tests verts (44 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.*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user