feat(énergie): glisser sur trois jours — fenêtre fixe de 12 h, et la date avec
Demande de Patrick : élargir le glissement. 72 h chargées au quart d'heure, la fenêtre en montre 12 — on remonte donc sur trois jours sans changer d'onglet. TROIS CHOSES QUE CE CHANGEMENT RENDAIT NÉCESSAIRES. La taille de fenêtre était « la moitié du jeu de données ». Avec 24 h ça donnait 12 h ; avec 72 h ça en aurait donné 36, et la fenêtre aurait grandi avec les données au lieu de rester une fenêtre. Elle est fixée en DURÉE : la densité de lecture ne dépend plus de la profondeur chargée. La fenêtre s'ouvre sur le plus RÉCENT. Calée au début, elle aurait montré avant-hier soir à l'ouverture — la seule vue dont personne n'a besoin en premier. Et la plage visible porte sa DATE : « 8/9 21:00 → 9/9 09:00 ». Sur 24 h, « 09:00 » désignait sans ambiguïté ce matin ; sur trois jours, c'est l'un de trois matins, et l'axe n'affiche que des heures. Sans cette ligne, l'écran répondait à côté de la question « c'était quand ? ». Et les étiquettes des deux BORDS de l'axe sont retirées : fl_chart en pose une à `min` et à `max` en plus de celles de l'intervalle, et elles se superposaient à leur voisine — « 20:4500 » à gauche, « 08:1509:00 » à droite. J'avais corrigé le bord gauche sans penser que le droit avait le même défaut : la recherche auto-confirmante, appliquée à un axe. On ne perd rien, la ligne de plage donne les deux bornes exactes avec leur jour. Vérifié à l'écran : fenêtre 21:15 → 09:00 à l'ouverture, ligne de plage et indice de geste présents. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
This commit is contained in:
parent
f1547f674a
commit
2a1e7f2dbb
@ -79,7 +79,9 @@ class _EnergyScreenState extends State<EnergyScreen> {
|
||||
/// et personne ne pouvait obtenir la journée que le premier promettait. Corrigé le
|
||||
/// 2026-09-09 ; l'onglet « Année » manquait, puisque c'est « Mois » qui la montrait.
|
||||
static const _tabs = [
|
||||
_Tab('Heures', Duration(hours: 24), 'SampleRate15Mins', showTime: true),
|
||||
// 72 h au quart d'heure : la fenêtre n'en montre que 12, mais on peut remonter sur
|
||||
// trois jours sans changer d'onglet (demande de Patrick, 2026-09-09).
|
||||
_Tab('Heures', Duration(hours: 72), 'SampleRate15Mins', showTime: true),
|
||||
_Tab('Jour', Duration(days: 1), 'SampleRate1Hour',
|
||||
showTime: true, rendu: _Rendu.barres, journeeCivile: true),
|
||||
_Tab('Semaine', Duration(days: 7), 'SampleRate1Day',
|
||||
@ -110,10 +112,21 @@ class _EnergyScreenState extends State<EnergyScreen> {
|
||||
/// heures. Les séries restent entières, la fenêtre ne fait que cadrer.
|
||||
double _fenetreDebut = 0;
|
||||
|
||||
/// Nombre de points visibles à la fois. `null` = tout, donc rien à glisser.
|
||||
/// **Douze heures visibles à la fois**, quelle que soit la profondeur des données.
|
||||
///
|
||||
/// C'était « la moitié du jeu » : avec 24 h de données, ça donnait 12 h — mais en passant
|
||||
/// à 72 h ça en aurait donné 36, et la fenêtre aurait grandi avec les données au lieu de
|
||||
/// rester une fenêtre. Une durée fixe garde la même densité de lecture quel que soit
|
||||
/// l'historique chargé.
|
||||
static const Duration _fenetreDuree = Duration(hours: 12);
|
||||
|
||||
int? get _fenetreTaille {
|
||||
if (!_tabs[_tabIdx].showTime) return null; // seule la vue Heures glisse
|
||||
return _data.length > 40 ? _data.length ~/ 2 : null;
|
||||
final tab = _tabs[_tabIdx];
|
||||
if (tab.rendu != _Rendu.courbes) return null; // seules les courbes glissent
|
||||
final pas = _pasEchantillon(tab).inSeconds;
|
||||
if (pas <= 0) return null;
|
||||
final points = _fenetreDuree.inSeconds ~/ pas;
|
||||
return _data.length > points + 1 ? points : null;
|
||||
}
|
||||
|
||||
bool get _glissable => _fenetreTaille != null;
|
||||
@ -264,13 +277,17 @@ class _EnergyScreenState extends State<EnergyScreen> {
|
||||
]);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
// La fenêtre repart du début à chaque lecture : la garder ferait cadrer une plage
|
||||
// d'index qui ne désigne plus les mêmes heures.
|
||||
_fenetreDebut = 0;
|
||||
_data = results[0] as List<PowerBalanceEntry>;
|
||||
_socData = results[1] as List<HistoryEntry>;
|
||||
_conso = results[2] as ConsumerHistory;
|
||||
_bilan = results[3] as DailyBalance?;
|
||||
// **La fenêtre s'ouvre sur le plus RÉCENT.** Avec 72 h chargées, la caler au début
|
||||
// montrerait avant-hier soir à l'ouverture de l'écran — la seule vue dont personne
|
||||
// n'a besoin en premier. Recalculée à chaque lecture : garder l'ancienne cadrerait
|
||||
// une plage d'index qui ne désigne plus les mêmes heures.
|
||||
final taille = _fenetreTaille;
|
||||
_fenetreDebut =
|
||||
taille == null ? 0 : max(0, _data.length - 1 - taille).toDouble();
|
||||
_loading = false;
|
||||
_noData = _data.isEmpty;
|
||||
});
|
||||
@ -504,11 +521,16 @@ class _EnergyScreenState extends State<EnergyScreen> {
|
||||
),
|
||||
// L'indice ne sort que si le geste existe : une aide permanente
|
||||
// cesse d'être lue, et celle-ci serait fausse sur les autres vues.
|
||||
if (_glissable && _plageVisible() != null)
|
||||
_NoteEcran(
|
||||
icon: Icons.date_range_rounded,
|
||||
texte: _plageVisible()!,
|
||||
),
|
||||
if (_glissable)
|
||||
const _NoteEcran(
|
||||
icon: Icons.swipe_rounded,
|
||||
texte: 'Glissez horizontalement sur un graphe pour vous déplacer '
|
||||
'dans la journée. Les deux gardent le même cadrage.',
|
||||
texte: 'Glissez horizontalement pour remonter sur trois jours. '
|
||||
'Les deux graphes gardent le même cadrage.',
|
||||
),
|
||||
],
|
||||
// Les notes parlent des séries par consommateur : elles n'ont aucun
|
||||
@ -532,6 +554,24 @@ class _EnergyScreenState extends State<EnergyScreen> {
|
||||
|
||||
// ── ① Line chart : puissances + SOC ────────────────────────────────────────
|
||||
|
||||
/// **Ce qu'on regarde, avec sa date** — `null` hors vue glissable.
|
||||
///
|
||||
/// Sur 24 h, « 09:00 » désignait sans ambiguïté ce matin. Sur trois jours, la même
|
||||
/// étiquette peut être l'un de trois matins, et l'axe seul ne le dit pas : il n'affiche
|
||||
/// que des heures. La plage visible porte donc le jour, faute de quoi l'écran répond
|
||||
/// exactement à côté de la question « c'était quand ? ».
|
||||
String? _plageVisible() {
|
||||
if (!_glissable || _data.isEmpty) return null;
|
||||
final a = _data[_fenetreDebut.round().clamp(0, _data.length - 1)].timestamp;
|
||||
final b = _data[_fenetreFin.round().clamp(0, _data.length - 1)].timestamp;
|
||||
String jour(DateTime t) => '${t.day}/${t.month}';
|
||||
String heure(DateTime t) =>
|
||||
'${t.hour.toString().padLeft(2, '0')}:${t.minute.toString().padLeft(2, '0')}';
|
||||
return jour(a) == jour(b)
|
||||
? '${jour(a)} · ${heure(a)} → ${heure(b)}'
|
||||
: '${jour(a)} ${heure(a)} → ${jour(b)} ${heure(b)}';
|
||||
}
|
||||
|
||||
/// Rend un graphe **glissable à l'horizontale** quand la vue s'y prête.
|
||||
///
|
||||
/// Le geste convertit des pixels en points d'échantillon : glisser d'une largeur d'écran
|
||||
@ -681,11 +721,17 @@ class _EnergyScreenState extends State<EnergyScreen> {
|
||||
reservedSize: 22,
|
||||
interval: xInterval,
|
||||
getTitlesWidget: (v, meta) {
|
||||
// ⚠️ Pas d'étiquette sur le bord GAUCHE : fl_chart en pose une à `min` en
|
||||
// plus de celles de l'intervalle, et les deux se superposent quand `min`
|
||||
// n'est pas un multiple — « 20:4500 » à l'écran le 2026-09-09. Deux heures
|
||||
// imprimées l'une sur l'autre ne se lisent ni l'une ni l'autre.
|
||||
if (v <= meta.min) return const SizedBox.shrink();
|
||||
// ⚠️ **Aucune étiquette sur les deux BORDS.** fl_chart en pose une à `min`
|
||||
// et à `max` en plus de celles de l'intervalle : quand les bornes ne
|
||||
// tombent pas sur un multiple, elles se superposent à leur voisine —
|
||||
// « 20:4500 » à gauche, « 08:1509:00 » à droite, vus à l'écran le
|
||||
// 2026-09-09. Deux heures imprimées l'une sur l'autre ne se lisent ni
|
||||
// l'une ni l'autre.
|
||||
//
|
||||
// On ne perd rien : la ligne de plage sous le graphe donne les deux bornes
|
||||
// exactes, avec leur jour — ce que l'axe ne pouvait pas dire de toute
|
||||
// façon sur trois jours.
|
||||
if (v <= meta.min || v >= meta.max) return const SizedBox.shrink();
|
||||
final idx = v.round();
|
||||
if (idx < 0 || idx >= _data.length) return const SizedBox.shrink();
|
||||
return SideTitleWidget(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user