v1.2.5 : edge-to-edge propre (fix du double espace en haut de l'écran)

- enableEdgeToEdge() dans MainActivity (Material You)
- insets consommés UNE SEULE FOIS : TopAppBar M3 = barre de statut,
  NavigationBar = barre de navigation
- Scaffold racine + imbriqués (Doses/Analyses) : contentWindowInsets = 0
  pour ne pas cumuler (avant : fenêtre AppCompat + padding interne TopAppBar
  = double espace vide en haut)
- docs : §10 (pattern insets), §14 bug #33, historique, CHANGELOG
- versionCode 8, versionName 1.2.5
This commit is contained in:
Siphonight 2026-09-05 20:15:33 +02:00
parent 5d04667ea9
commit eb7c4c1110
8 changed files with 49 additions and 5 deletions

View File

@ -9,7 +9,7 @@ sauvegarde JSON. **100 % local, aucun compte, aucun serveur.**
> à titre informatif — ce ne sont pas des mesures. Fie-toi toujours à tes analyses de > à titre informatif — ce ne sont pas des mesures. Fie-toi toujours à tes analyses de
> sang et aux consignes de ton endocrinologue. > sang et aux consignes de ton endocrinologue.
- **Statut** : v1.2.4 — build Android ✅, **62 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.5 — build Android ✅, **62 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) - **Journal des versions** : [docs/CHANGELOG.md](docs/CHANGELOG.md)
- **Guide utilisateur** : [docs/GUIDE_INSTALLATION.md](docs/GUIDE_INSTALLATION.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) - **Doc de développement** (architecture, maths, décisions, bugs) : [docs/DEVELOPPEMENT.md](docs/DEVELOPPEMENT.md)

View File

@ -12,8 +12,8 @@ android {
applicationId = "com.hormonetrack" applicationId = "com.hormonetrack"
minSdk = 26 minSdk = 26
targetSdk = 36 targetSdk = 36
versionCode = 7 versionCode = 8
versionName = "1.2.4" versionName = "1.2.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {

View File

@ -6,6 +6,7 @@ import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
@ -25,6 +26,13 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val container = (application as HormoneTrackApp).container val container = (application as HormoneTrackApp).container
// Edge-to-edge (Material You) : le contenu s'étend sous les barres système.
// Les insets sont alors consommés UNE SEULE FOIS — par les TopAppBar
// Material 3 (barre de statut) et la NavigationBar (barre de navigation).
// Avant : la fenêtre poussait déjà le contenu sous la barre de statut ET
// les TopAppBar rajoutaient leur padding interne → double espace vide en haut.
enableEdgeToEdge()
lifecycleScope.launch { lifecycleScope.launch {
val lang = container.settings.language.first() val lang = container.settings.language.first()
val locales = if (lang == "system") { val locales = if (lang == "system") {

View File

@ -1,5 +1,6 @@
package com.hormonetrack.ui package com.hormonetrack.ui
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Home
@ -55,6 +56,10 @@ fun HormoneTrackRoot(initialOpenLogDose: Boolean, initialTreatmentId: Long) {
val currentRoute = backStack?.destination?.route val currentRoute = backStack?.destination?.route
Scaffold( Scaffold(
// Insets à zéro : les TopAppBar des écrans consomment elles-mêmes la
// barre de statut, la NavigationBar ci-dessous la barre de navigation —
// sinon les deux se cumulent (double espace en haut, bug v1.2.5).
contentWindowInsets = WindowInsets(0, 0, 0, 0),
bottomBar = { bottomBar = {
if (currentRoute in tabs.map { it.route }) { if (currentRoute in tabs.map { it.route }) {
NavigationBar { NavigationBar {

View File

@ -2,6 +2,7 @@ package com.hormonetrack.ui.screens
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -87,6 +88,8 @@ fun DosesScreen() {
val timeFmt = remember { DateTimeFormatter.ofPattern("HH:mm") } val timeFmt = remember { DateTimeFormatter.ofPattern("HH:mm") }
Scaffold( Scaffold(
// Insets à zéro : le TopAppBar interne consomme déjà la barre de statut
contentWindowInsets = WindowInsets(0, 0, 0, 0),
floatingActionButton = { floatingActionButton = {
FloatingActionButton(onClick = { showLogDialog = true }) { FloatingActionButton(onClick = { showLogDialog = true }) {
Icon(Icons.Filled.Add, contentDescription = stringResource(R.string.add_dose)) Icon(Icons.Filled.Add, contentDescription = stringResource(R.string.add_dose))

View File

@ -2,6 +2,7 @@ package com.hormonetrack.ui.screens
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -81,6 +82,8 @@ fun LabsScreen() {
} }
Scaffold( Scaffold(
// Insets à zéro : le TopAppBar interne consomme déjà la barre de statut
contentWindowInsets = WindowInsets(0, 0, 0, 0),
floatingActionButton = { floatingActionButton = {
FloatingActionButton(onClick = { showLabDialog = true }) { FloatingActionButton(onClick = { showLabDialog = true }) {
Icon(Icons.Filled.Add, contentDescription = stringResource(R.string.add_lab)) Icon(Icons.Filled.Add, contentDescription = stringResource(R.string.add_lab))

View File

@ -1,7 +1,21 @@
# Changelog — HormoneTrack # Changelog — HormoneTrack
Format : [Keep a Changelog](https://keepachangelog.com/fr-FR/1.1.0/). Format : [Keep a Changelog](https://keepachangelog.com/fr-FR/1.1.0/).
Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.2.4`, …). Versionnage : [SemVer](https://semver.org/). Releases taguées dans git (`v1.2.5`, …).
## [1.2.5] — 2026-09-05 (versionCode 8)
### Corrigé
- **Espace vide en haut de l'écran** (contenu trop bas) : double consommation des
insets — la fenêtre poussait déjà le contenu sous la barre de statut (thème
AppCompat) ET les `TopAppBar` Material 3 rajoutaient leur padding de barre de
statut interne. Passage en **edge-to-edge propre** (`enableEdgeToEdge()`) :
- les `TopAppBar` consomment la barre de statut (une seule fois) ;
- les `Scaffold` (racine + imbriqués Doses/Analyses) ont
`contentWindowInsets = 0` pour ne pas cumuler ;
- la `NavigationBar` consomme la barre de navigation système.
Le contenu remonte, les listes défilent visuellement sous la barre de statut
(comportement Material You standard).
## [1.2.4] — 2026-09-05 (versionCode 7) ## [1.2.4] — 2026-09-05 (versionCode 7)

View File

@ -64,6 +64,7 @@ Fonctionnalités v1 :
| 5 sept. 2026 (session tests/docs) | Correction de toutes les erreurs de compilation (dont 3 vrais bugs logiciels trouvés par les tests), **24 tests unitaires verts**, APK debug généré (18 MB), documentation complète (README + docs/), préparation repo git. | | 5 sept. 2026 (session tests/docs) | Correction de toutes les erreurs de compilation (dont 3 vrais bugs logiciels trouvés par les tests), **24 tests unitaires verts**, APK debug généré (18 MB), documentation complète (README + docs/), préparation repo git. |
| 5 sept. 2026 (session v1.1.0) | Bugs remontés par l'utilisatrice : courbes vides (casse EEn) + pas d'édition des doses → corrigés ; régression épinglée sur ses données réelles ; APK v1.1.0. | | 5 sept. 2026 (session v1.1.0) | Bugs remontés par l'utilisatrice : courbes vides (casse EEn) + pas d'édition des doses → corrigés ; régression épinglée sur ses données réelles ; APK v1.1.0. |
| 5 sept. 2026 (session v1.2.0) | **Repo git initialisé** (commits par couche + tags de release) ; montée toolchain AGP 9.4/Gradle 9.7.1/Kotlin 2.3.21/BOM 2026.08.00/compileSdk 37 ; panoramique du chart, superposition des deux modèles, prévision par « Fréquence », calibration automatique optionnelle, intervalles entre doses, TimePicker centré ; **36 tests verts**, APK v1.2.0 (23 MB). | | 5 sept. 2026 (session v1.2.0) | **Repo git initialisé** (commits par couche + tags de release) ; montée toolchain AGP 9.4/Gradle 9.7.1/Kotlin 2.3.21/BOM 2026.08.00/compileSdk 37 ; panoramique du chart, superposition des deux modèles, prévision par « Fréquence », calibration automatique optionnelle, intervalles entre doses, TimePicker centré ; **36 tests verts**, APK v1.2.0 (23 MB). |
| 5 sept. 2026 (session v1.2.5) | Bug graphique : double espace en haut (double insets) → **edge-to-edge propre** (`enableEdgeToEdge` + insets consommés une seule fois) ; 62 tests verts, APK v1.2.5 + release. |
| 5 sept. 2026 (session v1.2.4) | Bug `isActive` (simulation effacée) → sémantique « drapeau administratif » (§6.bis) ; régression n°3 sur le 3ᵉ export réel (transition EV inactif → EEn actif, 38 doses, 22 labs) ; **62 tests verts**, APK v1.2.4. | | 5 sept. 2026 (session v1.2.4) | Bug `isActive` (simulation effacée) → sémantique « drapeau administratif » (§6.bis) ; régression n°3 sur le 3ᵉ export réel (transition EV inactif → EEn actif, 38 doses, 22 labs) ; **62 tests verts**, APK v1.2.4. |
| 5 sept. 2026 (session push Gitea + v1.2.3) | Push initial vers **gitea.cloudyfy.fr/Siphonight/HormoneTrack** (privé) après **anonymisation de l'historique** (filter-branch : les premiers commits embarquaient les valeurs réelles des tests) ; **données de test réelles déplacées hors dépôt** (`local-test-data/` gitignoré, tests `Assume`-skippés) ; **releases avec APK en pièce jointe** ; pics/creux + calibration T par période d'ester ; **56 tests verts**. | | 5 sept. 2026 (session push Gitea + v1.2.3) | Push initial vers **gitea.cloudyfy.fr/Siphonight/HormoneTrack** (privé) après **anonymisation de l'historique** (filter-branch : les premiers commits embarquaient les valeurs réelles des tests) ; **données de test réelles déplacées hors dépôt** (`local-test-data/` gitignoré, tests `Assume`-skippés) ; **releases avec APK en pièce jointe** ; pics/creux + calibration T par période d'ester ; **56 tests verts**. |
| 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.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. |
@ -483,6 +484,12 @@ Sur la montre : remontée par Gadgetbridge **ou** Huawei Health (cf §17).
- Composants : `CurveChart` (§11), `DateTimeField` (DatePicker+TimePicker Material3, - Composants : `CurveChart` (§11), `DateTimeField` (DatePicker+TimePicker Material3,
LocalDateTime, **horloge centrée**), `DoseDialog` (create/edit + override d'ester), LocalDateTime, **horloge centrée**), `DoseDialog` (create/edit + override d'ester),
`LabDialog`, `formatDose()` (top-level, dans `DoseDialog.kt`) `LabDialog`, `formatDose()` (top-level, dans `DoseDialog.kt`)
- **Insets edge-to-edge (v1.2.5)** : `enableEdgeToEdge()` dans MainActivity ;
les insets sont consommés UNE FOIS — TopAppBar M3 (barre de statut, insets
par défaut) et NavigationBar (barre système) ; les `Scaffold` (racine
HormoneTrackRoot + imbriqués Doses/Labs) ont `contentWindowInsets = 0` pour
ne pas cumuler. Avant : fenêtre AppCompat + padding interne TopAppBar =
double espace vide en haut.
- Thème M3 custom (`ui/theme/Color.kt` : bleu #4F5BD5, rose #D6589E, labs orange, bandeau - Thème M3 custom (`ui/theme/Color.kt` : bleu #4F5BD5, rose #D6589E, labs orange, bandeau
TransSky/TransPink), dynamic color désactivé ; `MaterialExpressiveTheme` encore TransSky/TransPink), dynamic color désactivé ; `MaterialExpressiveTheme` encore
**internal** dans la ligne material3 pinnée (cf §3) → `MaterialTheme` standard **internal** dans la ligne material3 pinnée (cf §3) → `MaterialTheme` standard
@ -616,6 +623,10 @@ Historique complet — **à ne pas réintroduire** (utile pour diff/revert) :
titre `[1.2.3]` : l'extraction cherchait `[vX.Y.Z]` → fallback silencieux. titre `[1.2.3]` : l'extraction cherchait `[vX.Y.Z]` → fallback silencieux.
→ `scripts/gitea-release.py` (corps = section CHANGELOG, APK attaché). → `scripts/gitea-release.py` (corps = section CHANGELOG, APK attaché).
33. **Double insets edge-to-edge** (v1.2.5) : espace vide en haut de l'écran —
la fenêtre AppCompat poussait le contenu sous la barre de statut ET les
TopAppBar M3 rajoutaient leur padding interne. → `enableEdgeToEdge()` +
`contentWindowInsets = 0` sur les Scaffold, insets consommés une seule fois.
32. **`isActive` traité comme filtre de données** (v1.2.4) : passer un 32. **`isActive` traité comme filtre de données** (v1.2.4) : passer un
traitement à inactif effaçait sa simulation du graphique (écrans traitement à inactif effaçait sa simulation du graphique (écrans
collectaient `activeTreatments`) tout en permettant d'y loger des doses. collectaient `activeTreatments`) tout en permettant d'y loger des doses.
@ -819,4 +830,4 @@ Sur le téléphone de test (à compléter par l'utilisatrice) :
sur le graphique** et la calibration couvre toujours ses périodes sur le graphique** et la calibration couvre toujours ses périodes
--- ---
*Doc mise à jour le 5 sept. 2026 (v1.2.4) — build OK, 62/62 tests verts (44 sans les données locales), dépôt Gitea privé + releases APK, aucune donnée de santé dans le dépôt ni l'historique.* *Doc mise à jour le 5 sept. 2026 (v1.2.5) — build OK, 62/62 tests verts (44 sans les données locales), dépôt Gitea privé + releases APK, aucune donnée de santé dans le dépôt ni l'historique.*