fix(ev): pas de bouton de boost — trois modes et rien d'autre
Décision de Patrick, réaffirmée : « tu gardes tout, seulement le bouton boost on supprime ». Je l'avais écrit et posé quelques heures plus tôt, en lisant « le bouton de boost : ouvre-le quand tu veux » dans un message du moteur comme un feu vert — alors que la décision produit était déjà prise en sens inverse. Un avis technique sur la faisabilité ne révise pas un arbitrage de produit ; il fallait demander, pas inférer. Retiré : l'usage de `EvBoostButton` sur l'écran de la borne, son import, et le helper `_entreeTelemetrie` devenu orphelin. Gardé, sur instruction explicite : le widget, `setLoadDerogation` / `clearLoadDerogation`, le modèle `Derogation` / `DerogationEnded` et leurs 19 tests. Ce n'est pas de la donnée fabriquée comme `DayPlan.demo()` — c'est la lecture d'un contrat réel, testée, qui ne s'affiche nulle part et ne peut donc rien afficher de faux. Le jour où le boost revient, il se rebranche en trois lignes. Vérifié à l'écran : « Mode de recharge · lu : Min+PV », trois boutons Manuel / PV / Min+PV, Min+PV allumé parce que c'est ce que la box porte. Rien d'autre. Capture : docs/captures/2026-09-08_ev-trois-modes.png 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
0d1732dc61
commit
b0afba11c7
BIN
docs/captures/2026-09-08_ev-trois-modes.png
Normal file
BIN
docs/captures/2026-09-08_ev-trois-modes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 337 KiB |
@ -18,7 +18,6 @@ import '../../services/nymea_service.dart';
|
||||
import '../../services/rpc_schema.dart';
|
||||
import '../../theme/etm_tokens.dart';
|
||||
import '../../widgets/load_cards.dart';
|
||||
import '../../widgets/ev_boost_button.dart';
|
||||
import '../../widgets/ev_mode_buttons.dart';
|
||||
import '../../widgets/garde_brouillon.dart';
|
||||
import '../../widgets/schema_gated.dart';
|
||||
@ -510,28 +509,19 @@ class _SectionBorne extends StatelessWidget {
|
||||
onSetMode: (m) =>
|
||||
service.setChargingInfo(mode: m, evChargerId: borne.thingId),
|
||||
),
|
||||
// **Le boost est une ACTION à côté du sélecteur, pas une quatrième position.**
|
||||
// ── Pas de bouton de boost ici ────────────────────────────────────────
|
||||
//
|
||||
// Une dérogation se superpose au mode courant et s'efface ; elle ne le
|
||||
// remplace pas. La mettre dans le sélecteur ferait croire qu'on en sort en
|
||||
// choisissant autre chose, alors qu'elle finit d'elle-même.
|
||||
// Décision de Patrick, 2026-09-08 : l'écran garde **trois modes et rien
|
||||
// d'autre**. Le bouton d'action a été écrit puis retiré le jour même — j'avais
|
||||
// lu « ouvre-le quand tu veux » dans un message du moteur comme un feu vert,
|
||||
// alors que la décision produit était déjà prise en sens inverse. Un avis
|
||||
// technique ne remplace pas un arbitrage de produit.
|
||||
//
|
||||
// L'entrée de télémétrie vient de `loads[]` : `null` quand la borne n'est pas
|
||||
// arbitrée en ce moment. Le bouton se tait alors — « pas d'entrée » n'est pas
|
||||
// « pas de boost », c'est « on ne sait pas ».
|
||||
if (_entreeTelemetrie(telemetry, borne.thingId) != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
EvBoostButton(
|
||||
entry: _entreeTelemetrie(telemetry, borne.thingId),
|
||||
onSet: ({required int durationS, double? targetWh}) =>
|
||||
service.setLoadDerogation(
|
||||
loadId: _entreeTelemetrie(telemetry, borne.thingId)!.loadId,
|
||||
durationS: durationS,
|
||||
targetWh: targetWh),
|
||||
onClear: () => service.clearLoadDerogation(
|
||||
_entreeTelemetrie(telemetry, borne.thingId)!.loadId),
|
||||
),
|
||||
],
|
||||
// Ce qui reste en place : `EvBoostButton`, `setLoadDerogation` /
|
||||
// `clearLoadDerogation` et le modèle `Derogation`. Ce n'est pas de la donnée
|
||||
// fabriquée — c'est la lecture d'un contrat réel, testée, qui ne s'affiche
|
||||
// nulle part. Le jour où le boost revient, il se rebranche ici en trois
|
||||
// lignes.
|
||||
if (borne.isUnmanaged) ...[
|
||||
const SizedBox(height: 8),
|
||||
Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
@ -2338,18 +2328,3 @@ class _SectionObligationState extends State<_SectionObligation> {
|
||||
}
|
||||
}
|
||||
|
||||
/// L'entrée de télémétrie d'une borne, cherchée sur l'identifiant **nu**.
|
||||
///
|
||||
/// Les identifiants voyagent avec ou sans accolades selon l'appel (UI_data_contract §9) :
|
||||
/// comparer les chaînes brutes ferait rater la borne une fois sur deux, et l'écran
|
||||
/// conclurait « pas arbitrée » sur une borne qui l'est.
|
||||
LoadTelemetryEntry? _entreeTelemetrie(
|
||||
LoadTelemetryProvider telemetry, String thingId) {
|
||||
String nu(String x) =>
|
||||
x.replaceAll('{', '').replaceAll('}', '').toLowerCase();
|
||||
final cible = nu(thingId);
|
||||
for (final e in telemetry.telemetry?.loads ?? const <LoadTelemetryEntry>[]) {
|
||||
if (nu(e.loadId) == cible) return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user