diff --git a/lib/core/widgets/flux_text_field.dart b/lib/core/widgets/flux_text_field.dart index f8ddc5e..0c72498 100644 --- a/lib/core/widgets/flux_text_field.dart +++ b/lib/core/widgets/flux_text_field.dart @@ -1,5 +1,6 @@ // lib/ui/common/flux_text_field.dart import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flux/core/theme/theme.dart'; class FluxTextField extends StatefulWidget { @@ -16,6 +17,8 @@ class FluxTextField extends StatefulWidget { final Function(String)? onChanged; final int? maxLength; final String? Function(String?)? validator; + final List? inputFormatters; + final TextCapitalization? textCapitalization; const FluxTextField({ super.key, // Usiamo super.key per Flutter moderno @@ -32,6 +35,8 @@ class FluxTextField extends StatefulWidget { this.onChanged, this.maxLength, this.validator, + this.inputFormatters, + this.textCapitalization, }); @override @@ -104,6 +109,8 @@ class _FluxTextFieldState extends State { onFieldSubmitted: widget.onSubmitted, onChanged: widget.onChanged, maxLength: widget.maxLength, + inputFormatters: widget.inputFormatters, + textCapitalization: widget.textCapitalization ?? TextCapitalization.none, ); } } diff --git a/lib/features/onboarding/ui/store_onboarding_form.dart b/lib/features/onboarding/ui/store_onboarding_form.dart index d8fd4d2..fa8039a 100644 --- a/lib/features/onboarding/ui/store_onboarding_form.dart +++ b/lib/features/onboarding/ui/store_onboarding_form.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; // <-- IMPORTANTE per i formatter import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/widgets/flux_text_field.dart'; import 'package:flux/features/master_data/store/models/store_model.dart'; @@ -50,111 +51,62 @@ class _StoreOnboardingFormState extends State { "Dove si trova il tuo punto vendita principale? (Potrai aggiungerne altri in seguito).", style: TextStyle(fontSize: 16), ), - const SizedBox(height: 16), + const SizedBox(height: 32), + FluxTextField( controller: _nameCtrl, label: "Nome del Negozio", - validator: (value) { - if (value == null || value.isEmpty) { - return "Il nome del negozio è obbligatorio"; - } - return null; - }, + validator: (value) => + value == null || value.isEmpty ? "Obbligatorio" : null, ), const SizedBox(height: 16), + FluxTextField( controller: _addressCtrl, label: "Indirizzo", - validator: (value) { - if (value == null || value.isEmpty) { - return "L'indirizzo è obbligatorio"; - } - return null; - }, + validator: (value) => + value == null || value.isEmpty ? "Obbligatorio" : null, ), const SizedBox(height: 16), + + // IL LAYOUT RESPONSIVO PREMIUM LayoutBuilder( builder: (context, constraints) { - if (constraints.maxWidth < 600) { + final isDesktop = constraints.maxWidth >= 600; + + if (isDesktop) { + // --- DESKTOP: Tutti su una riga --- + return Row( + crossAxisAlignment: CrossAxisAlignment + .start, // Allinea in alto se ci sono errori + children: [ + Expanded(flex: 2, child: _buildZipField()), + const SizedBox(width: 16), + Expanded(flex: 5, child: _buildCityField()), + const SizedBox(width: 16), + Expanded(flex: 2, child: _buildProvField()), + ], + ); + } else { + // --- MOBILE: Comune sopra, CAP e Provincia sotto --- return Column( children: [ - SizedBox( - width: constraints.maxWidth, - child: FluxTextField( - label: 'Comune', - controller: _cityCtrl, - keyboardType: TextInputType.name, - ), - ), + _buildCityField(), const SizedBox(height: 16), Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - width: constraints.maxWidth * 0.4, - child: FluxTextField( - label: 'CAP', - controller: _zipCodeCtrl, - maxLength: 5, - keyboardType: TextInputType.number, - ), - ), + Expanded(flex: 3, child: _buildZipField()), const SizedBox(width: 16), - SizedBox( - width: constraints.maxWidth * 0.2, - child: FluxTextField( - label: 'Prov.', - controller: _provinceCtrl, - keyboardType: TextInputType.text, - onChanged: (value) => - _provinceCtrl.text = value.toUpperCase(), - maxLength: 2, - ), - ), + Expanded(flex: 2, child: _buildProvField()), ], ), ], ); - } else { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 160, - child: FluxTextField( - label: 'CAP', - controller: _zipCodeCtrl, - maxLength: 5, - keyboardType: TextInputType.number, - ), - ), - - SizedBox( - width: constraints.maxWidth * 0.5, - child: FluxTextField( - label: 'Comune', - controller: _cityCtrl, - keyboardType: TextInputType.name, - ), - ), - - SizedBox( - width: 120, - child: FluxTextField( - label: 'Prov.', - controller: _provinceCtrl, - keyboardType: TextInputType.text, - onChanged: (value) => - _provinceCtrl.text = value.toUpperCase(), - maxLength: 2, - ), - ), - ], - ); } }, ), + const Spacer(), ElevatedButton( style: ElevatedButton.styleFrom( @@ -165,12 +117,14 @@ class _StoreOnboardingFormState extends State { ), onPressed: () { if (_formKey.currentState!.validate()) { + // MIRACOLO DELLA FACTORY EMPTY! final newStore = StoreModel.empty().copyWith( nome: _nameCtrl.text.trim(), indirizzo: _addressCtrl.text.trim(), comune: _cityCtrl.text.trim(), cap: _zipCodeCtrl.text.trim(), - provincia: _provinceCtrl.text.trim(), + // Formattiamo in maiuscolo qui, al momento del salvataggio! + provincia: _provinceCtrl.text.trim().toUpperCase(), ); context.read().saveStore(newStore); } @@ -186,4 +140,35 @@ class _StoreOnboardingFormState extends State { ), ); } + + // --- WIDGET ESTRATTI PER PULIZIA --- + + Widget _buildCityField() { + return FluxTextField( + label: 'Comune', + controller: _cityCtrl, + keyboardType: TextInputType.name, + ); + } + + Widget _buildZipField() { + return FluxTextField( + label: 'CAP', + controller: _zipCodeCtrl, + keyboardType: TextInputType.number, + // Trucchetto Premium: Limita i caratteri ma NASCONDE il contatore UI + inputFormatters: [LengthLimitingTextInputFormatter(5)], + ); + } + + Widget _buildProvField() { + return FluxTextField( + label: 'Prov.', + controller: _provinceCtrl, + keyboardType: TextInputType.text, + // Rende la tastiera del telefono automaticamente maiuscola + textCapitalization: TextCapitalization.characters, + inputFormatters: [LengthLimitingTextInputFormatter(2)], + ); + } }