Lot Connexions multi-HEMS : - modèle Installation + InstallationStore (persistance par UUID ; métadonnées SharedPreferences, token via flutter_secure_storage) - ConnectionManager au-dessus de nymea_service : mono-connexion, switchTo, connectNew, enterDemo (démo = active factice), contrôle d'identité DHCP - nymea_service : connect() réveillé (ws://4444, token par UUID), capture Hello (uuid/name/initialSetupRequired), authenticate/createUser, resetState - écran Installations (3 états) + déverrouillage installateur depuis la racine - écran Connexion : auth 2 branches (JSONRPC.Authenticate / CreateUser), détection auto via initialSetupRequired, segmenteur de repli - gate de routage (redirect + refreshListenable merge[cm,svc]) ; hasActiveConnection = isSimulation || (connected && authenticated) - en-tête drawer cliquable → Installations - invalidation des caches au switch (service.resetState + clearForSwitch rôles/scheduler/tariff), sans persist() Lot Rôles & appareils : - EnergySetupProvider refondu en tri-état (present/absent/non-configuré) - écran roles_devices_screen (3 zones, drag-priorité, inférence solaire/batterie) - LoadDescriptor (etmvariableload, rév.2 : PAC exclue → SG-Ready) ; Energy.SetRootMeter réel, Get/SetLoadConfig en stub loggé Correctifs : - bug signe énergie : production +, consommation NÉGATIVE sur nymea 1.15.2 → consumptionW/home en .abs() (autoconso n'est plus clouée à 0) - UUID Hello brace-wrapped normalisé Tests : flutter analyze 0 erreur ; gate + zéro-fuite au switch (5/5 verts). Validé en vrai : login auth .120, .75 ouvert, switch, déverrouillage installateur. Note : embarque aussi le WIP dashboard/thème déjà présent dans l'arbre. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
141 lines
6.4 KiB
Dart
141 lines
6.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
|
|
/// Tokens de marque ETM PowerSync — source de vérité unique.
|
|
class EtmTokens {
|
|
EtmTokens._();
|
|
|
|
// ── Couleurs de marque (spec Dashboard v4) ────────────────────────────────
|
|
static const Color brand = Color(0xFF31A3DD);
|
|
static const Color solar = Color(0xFFFEC113);
|
|
static const Color solarDark = Color(0xFFFFCB33);
|
|
static const Color eco = Color(0xFF28A06A);
|
|
static const Color ecoDark = Color(0xFF33B87A);
|
|
static const Color heat = Color(0xFFEF8B2A);
|
|
static const Color water = Color(0xFF31A3DD);
|
|
static const Color gridColor = Color(0xFF8A98A3);
|
|
static const Color importColor = Color(0xFFE8806F);
|
|
|
|
// ── Legacy (compatibilité existante) ─────────────────────────────────────
|
|
static const Color navy = Color(0xFF0D2B3B);
|
|
static const Color navy2 = Color(0xFF10384C);
|
|
static const Color blue = Color(0xFF31A3DD);
|
|
static const Color amber = Color(0xFFFEC113);
|
|
static const Color green = Color(0xFF1DB86A);
|
|
static const Color greenDark= Color(0xFF159C58);
|
|
static const Color orange = Color(0xFFE8923A);
|
|
static const Color danger = Color(0xFFE8423F);
|
|
|
|
// ── Couleurs de flux ──────────────────────────────────────────────────────
|
|
static const Color solToHouse = Color(0xFFB8C34D);
|
|
static const Color solToEcs = Color(0xFF31A3DD);
|
|
static const Color solToVe = Color(0xFF28A06A);
|
|
static const Color solToBatt = Color(0xFF7FCF72);
|
|
static const Color solToGrid = Color(0xFFFEC113);
|
|
static const Color battToHouse = Color(0xFF2F6FB0);
|
|
static const Color gridToHouse = Color(0xFFE8806F);
|
|
|
|
// ── Neutres light ─────────────────────────────────────────────────────────
|
|
static const Color ink = navy;
|
|
static const Color muted= Color(0xFF5D6F7B);
|
|
static const Color faint= Color(0xFF8B9AA4);
|
|
static const Color line = Color(0xFFE4EAEE);
|
|
static const Color bg = Color(0xFFEEF2F5);
|
|
static const Color bg2 = Color(0xFFE4EAEE);
|
|
static const Color card = Color(0xFFFFFFFF);
|
|
|
|
// ── Neutres dark ──────────────────────────────────────────────────────────
|
|
static const Color bgDark = Color(0xFF06141D);
|
|
static const Color bg2Dark = Color(0xFF0A1F2B);
|
|
static const Color surfaceDark = Color(0xFF0D2B3B);
|
|
static const Color inkDark = Color(0xFFEAF3F7);
|
|
static const Color mutedDark = Color(0xFF9BB0BC);
|
|
static const Color faintDark = Color(0xFF6C8493);
|
|
|
|
// ── Soft fills (legacy light) ─────────────────────────────────────────────
|
|
static const Color greenSoft = Color(0xFFE7F8EF);
|
|
static const Color blueSoft = Color(0xFFE9F5FB);
|
|
static const Color amberSoft = Color(0xFFFFF6DD);
|
|
|
|
// ── Rayons ────────────────────────────────────────────────────────────────
|
|
static const double radius = 16;
|
|
static const double radiusLg = 22;
|
|
static const double radiusCard = 20;
|
|
static const double radiusCtrl = 13;
|
|
static const double radiusPill = 30;
|
|
|
|
// ── Context-aware ─────────────────────────────────────────────────────────
|
|
static bool _isDark(BuildContext c) =>
|
|
Theme.of(c).brightness == Brightness.dark;
|
|
|
|
static Color bgOf(BuildContext c) => _isDark(c) ? bgDark : bg;
|
|
static Color bg2Of(BuildContext c) => _isDark(c) ? bg2Dark : bg2;
|
|
static Color surfaceOf(BuildContext c) => _isDark(c) ? surfaceDark : card;
|
|
static Color inkOf(BuildContext c) => _isDark(c) ? inkDark : ink;
|
|
static Color mutedOf(BuildContext c) => _isDark(c) ? mutedDark : muted;
|
|
static Color faintOf(BuildContext c) => _isDark(c) ? faintDark : faint;
|
|
static Color ecoOf(BuildContext c) => _isDark(c) ? ecoDark : eco;
|
|
static Color solarOf(BuildContext c) => _isDark(c) ? solarDark : solar;
|
|
|
|
static Color lineOf(BuildContext c) => _isDark(c)
|
|
? const Color(0xFFFFFFFF).withValues(alpha: 0.09)
|
|
: navy.withValues(alpha: 0.10);
|
|
|
|
static Color lineStrongOf(BuildContext c) => _isDark(c)
|
|
? const Color(0xFFFFFFFF).withValues(alpha: 0.16)
|
|
: navy.withValues(alpha: 0.16);
|
|
|
|
// ── Typographie ───────────────────────────────────────────────────────────
|
|
static TextStyle sans({
|
|
double size = 14,
|
|
FontWeight weight = FontWeight.w400,
|
|
Color color = ink,
|
|
double? height,
|
|
double? letterSpacing,
|
|
}) =>
|
|
GoogleFonts.ibmPlexSans(
|
|
fontSize: size,
|
|
fontWeight: weight,
|
|
color: color,
|
|
height: height,
|
|
letterSpacing: letterSpacing,
|
|
);
|
|
|
|
static TextStyle mono({
|
|
double size = 14,
|
|
FontWeight weight = FontWeight.w600,
|
|
Color color = ink,
|
|
}) =>
|
|
GoogleFonts.ibmPlexMono(
|
|
fontSize: size,
|
|
fontWeight: weight,
|
|
color: color,
|
|
fontFeatures: const [FontFeature.tabularFigures()],
|
|
);
|
|
|
|
static TextStyle sectionLabel() => sans(
|
|
size: 12,
|
|
weight: FontWeight.w600,
|
|
color: faint,
|
|
letterSpacing: 1.2,
|
|
);
|
|
|
|
// ── Ombres ────────────────────────────────────────────────────────────────
|
|
static List<BoxShadow> get cardShadow => [
|
|
BoxShadow(
|
|
color: navy.withValues(alpha: 0.04),
|
|
blurRadius: 2,
|
|
offset: const Offset(0, 1),
|
|
),
|
|
BoxShadow(
|
|
color: navy.withValues(alpha: 0.06),
|
|
blurRadius: 30,
|
|
offset: const Offset(0, 10),
|
|
),
|
|
];
|
|
|
|
static List<BoxShadow> cardShadowOf(BuildContext c) => _isDark(c)
|
|
? []
|
|
: cardShadow;
|
|
}
|