Refactor — Consolidamento token tema mobile
Commit:
refactor(theme): consolidate tokens, wire violet as tertiary· Branch:edit/mobile-audit-ux-polish· Audit di riferimento: Audit UX polish 2026-04-20
Problema
L’audit ha rilevato tre classi di debito nel file lib/core/theme/app_theme.dart:
- Token bugato —
radius32 = 24.0con commento “WAS 32. Reduced for density”. Il nome del token mente sul valore. Ogni sviluppatore che scrivevaAppTheme.radius32si aspettava 32 e ne otteneva 24 → valore sbagliato che si propaga nei consumer senza avvertire nessuno. - Alias ambigui —
textSecondary,textSecondaryLightetextPrimaryLightcon valori identici declared come literal separati (doppio source-of-truth). PiùtextSecondaryWarmcon un valore diverso ma nome non-semantico. - Violet non esposto nel tema —
ColorScheme.secondaryera impostato aprimary(coral), quindi Material FAB, chip selezionati, focus ring usavano tutti coral. Zero gerarchia cromatica; il violet — secondo colore brand — viveva solo in gradient decorativi.
Decisione
Token radius
- Rimosso
radius32(valore mentitorio). I 5 call-site esterni sono stati aggiornati caso per caso:
| File | Contesto | Nuovo token |
|---|---|---|
features/profile/screens/profile_screen.dart:209 | Container/Card | radius24 |
features/settings/screens/privacy_settings_screen.dart:530 | Top di bottom sheet | radius28 |
shared/widgets/feedback_survey_sheet.dart:105 | Top di bottom sheet | radius28 |
shared/widgets/guest_guard.dart:30 | Top di bottom sheet | radius28 |
shared/widgets/minimal_event_card.dart:369 | Card | radius24 |
Regola: radius28 per i top dei bottom sheet (coerente con bottomSheetTheme), radius24 per card e contenitori “hero”.
Token colore testo
Riorganizzata la sezione Text Colors in 3 token canonici + 3 alias legacy:
// Canonici — preferire in nuovo codice
static const Color textPrimary = Color(0xFF18181B); // Zinc 900
static const Color textSecondary = Color(0xFF52525B); // Zinc 600
static const Color textMuted = Color(0xFF9E9E9E); // Softer grey
static const Color textPrimaryDark = Color(0xFFFFFFFF);
static const Color textSecondaryDark = Color(0xFFA1A1AA);
// Legacy — non rimossi per evitare churn di 28 file, ora puntano agli canonici
static const Color textPrimaryLight = textPrimary;
static const Color textSecondaryLight = textSecondary;
static const Color textSecondaryWarm = textMuted;Il rename completo dei 147 call-site è deferito (troppo rischio di regressione in un singolo commit). I nuovi schermi vanno scritti usando solo i nomi canonici.
Token primaryBrand
Rimosso. Aveva un unico consumer (manage_event_types_screen.dart:119) sostituito con il token esplicito electricCoral. Non serviva un alias nominativo.
ColorScheme — gerarchia cromatica
// Prima
colorScheme: ColorScheme(
primary: electricCoral,
secondary: electricCoral, // ← duplicato
...
);
// Ora
colorScheme: ColorScheme(
primary: electricCoral, // main CTAs, brand signature
secondary: electricViolet, // brand complement, selected chips, highlights
onSecondary: pureWhite,
tertiary: mintGreen, // success accents, gamification states
onTertiary: inkBlack,
...
);Impatto visivo atteso
Con il wiring del nuovo ColorScheme, i seguenti widget cambiano colore senza modifiche al loro codice:
chat_screen.darttyping indicator (colorScheme.secondary) — da coral a violet (status muted, più raffinato).profile_avatar.dartcolor-from-hash — ora pesca fra coral / violet / mint, aumentando la varietà degli avatar generati.- Tutti i futuri consumer di
Theme.of(context).colorScheme.tertiaryora hanno un verde brand disponibile senza hardcodare.
Verifica
flutter analyze lib/core/theme/app_theme.dart \
lib/features/events/screens/manage_event_types_screen.dart \
lib/features/profile/screens/profile_screen.dart \
lib/features/settings/screens/privacy_settings_screen.dart \
lib/shared/widgets/feedback_survey_sheet.dart \
lib/shared/widgets/guest_guard.dart \
lib/shared/widgets/minimal_event_card.dart
# → No issues foundNon toccato (deferito)
- Shadow dark-mode (
shadowSM/MD/LGusanoColors.blackinvisibile suinkBlack) — L4 nell’audit. Richiede shadow brightness-aware o switch asurfaceTintMaterial 3; non blocca. - Rename dei 147 call-site da alias legacy a nomi canonici — task meccanico, va in un commit a sé.
- Shadow violet-tinted come alternativa brand — da valutare dopo che l’app è stilisticamente coerente.
Lessons
- Un commento non risolve un bug di naming. Il tipo
static const double radius32 = 24.0; // WAS 32è un antipattern che preserva il valore sbagliato dietro un nome che pretende il giusto. O si rinomina o si cambia valore — mai si lascia il mismatch con giustificazione archeologica. - ColorScheme vuoto ⇒ Material 3 inferisce male. Non impostare
tertiary/secondaryfa sì che Flutter deriva daprimarycon color-mixing automatico; il risultato è sempre color-blind-friendly ma mai brand-accurate. Esporre esplicitamente tutti e tre i livelli è l’unica strada per controllare la palette.