basta localizzazioni per ora

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-30 10:25:52 +02:00
parent 8d3ca62304
commit 11c1e28aaa
23 changed files with 720 additions and 213 deletions

View File

@@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/data/constants.dart';
import 'package:flux/core/utils/app_message.dart';
import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
part 'auth_state.dart';
@@ -41,7 +42,9 @@ class AuthCubit extends Cubit<AuthState> {
emit(
state.copyWith(
status: AuthStatus.initial,
infoMessage: "Controlla la tua email per confermare l'account!",
infoMessage: AppMessage(
key: 'authCubitCheckEmailToConfirmAccount',
),
),
);
} else {
@@ -82,7 +85,10 @@ class AuthCubit extends Cubit<AuthState> {
emit(
state.copyWith(
status: AuthStatus.pwResetSent,
infoMessage: "Email per reset password inviata a $email!",
infoMessage: AppMessage(
key: 'authCubitResetPasswordEmailSentTo',
argument: email,
),
),
);
}

View File

@@ -6,7 +6,7 @@ class AuthState extends Equatable {
final AuthStatus status;
final bool isLoginMode;
final String? errorMessage;
final String? infoMessage;
final AppMessage? infoMessage;
const AuthState({
this.status = AuthStatus.initial,
@@ -19,7 +19,7 @@ class AuthState extends Equatable {
AuthStatus? status,
bool? isLoginMode,
String? errorMessage,
String? infoMessage,
AppMessage? infoMessage,
}) {
return AuthState(
status: status ?? this.status,

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/theme/theme.dart';
import 'package:flux/core/utils/extensions.dart';
import 'package:flux/core/widgets/flux_logo.dart';
import 'package:flux/core/widgets/flux_text_field.dart';
import 'package:flux/features/auth/bloc/auth_cubit.dart';
@@ -55,7 +56,7 @@ class _AuthScreenState extends State<AuthScreen> {
if (state.infoMessage != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.infoMessage!),
content: Text(state.infoMessage!.translatedMessage(context)),
backgroundColor: Colors.blueAccent, // O context.accent
),
);
@@ -77,7 +78,9 @@ class _AuthScreenState extends State<AuthScreen> {
// --- TITOLO DINAMICO ---
Text(
state.isLoginMode ? 'BENTORNATO' : 'CREA ACCOUNT',
state.isLoginMode
? context.l10n.authScreenWelcomeBack
: context.l10n.authScreenCreateAccount,
style: TextStyle(
color: context.primaryText,
fontSize: 24,
@@ -88,8 +91,10 @@ class _AuthScreenState extends State<AuthScreen> {
const SizedBox(height: 8),
Text(
state.isLoginMode
? 'Accedi per gestire il tuo business'
: 'Inizia oggi a digitalizzare il tuo negozio',
? context.l10n.authScreenLoginToManageYourBusiness
: context
.l10n
.authScreenStartTodayToDigitalizeYourStore,
textAlign: TextAlign.center,
style: TextStyle(color: context.secondaryText),
),
@@ -97,7 +102,7 @@ class _AuthScreenState extends State<AuthScreen> {
// --- CAMPI INPUT ---
FluxTextField(
label: 'Email Aziendale',
label: context.l10n.authScreenBusinessEmail,
icon: Icons.email_outlined,
controller: _emailController,
keyboardType: TextInputType.emailAddress,
@@ -130,7 +135,9 @@ class _AuthScreenState extends State<AuthScreen> {
),
)
: Text(
state.isLoginMode ? 'ACCEDI' : 'REGISTRATI',
state.isLoginMode
? context.l10n.authScreenLogin
: context.l10n.authScreenSignUp,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
@@ -147,12 +154,15 @@ class _AuthScreenState extends State<AuthScreen> {
child: RichText(
text: TextSpan(
text: state.isLoginMode
? "Non hai un account? "
: "Hai già un account? ",
? context.l10n.authScreenDontHaveAccount
: context.l10n.authScreenAlreadyHaveAccount,
style: TextStyle(color: context.secondaryText),
children: [
TextSpan(
text: state.isLoginMode ? "Registrati" : "Accedi",
text: state.isLoginMode
? context.l10n.authScreenSignUp
: context.l10n.authScreenLogin,
style: TextStyle(
color: context.accent,
fontWeight: FontWeight.bold,
@@ -169,7 +179,7 @@ class _AuthScreenState extends State<AuthScreen> {
.read<AuthCubit>()
.requestPasswordReset(_emailController.text.trim()),
child: Text(
'Pw dimenticata/Invito scaduto?',
context.l10n.authScreenForgotPassword,
style: TextStyle(
color: context.accent,
fontWeight: FontWeight.bold,

View File

@@ -22,5 +22,5 @@ class CompanyState extends Equatable {
}
@override
List<Object?> get props => [status, errorMessage];
List<Object?> get props => [status, errorMessage, company];
}

View File

@@ -17,7 +17,7 @@ class CompanyRepository {
} on PostgrestException catch (e) {
throw e.message;
} catch (e) {
throw 'Errore imprevisto durante la creazione dell\'azienda';
throw e.toString();
}
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/company/bloc/company_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/theme/theme.dart';
@@ -69,7 +70,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Configurazione Azienda'),
title: Text(context.l10n.createCompanyScreenCompanyConfiguration),
actions: [
IconButton(
icon: const Icon(Icons.logout_rounded),
@@ -98,7 +99,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
state.errorMessage ?? 'Errore durante il salvataggio',
state.errorMessage ?? context.l10n.commonSavingError,
),
backgroundColor: Colors.redAccent,
),
@@ -118,10 +119,12 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
const SizedBox(height: 32),
// --- SEZIONE 1: IDENTITÀ FISCALE ---
_SectionTitle(title: 'DATI FISCALI'),
_SectionTitle(
title: context.l10n.createCompanyScreenFiscalData,
),
const SizedBox(height: 16),
FluxTextField(
label: 'Ragione Sociale',
label: context.l10n.createCompanyScreenCompanyName,
icon: Icons.business,
controller: _ragioneSocialeController,
),
@@ -130,7 +133,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
children: [
Expanded(
child: FluxTextField(
label: 'Partita IVA',
label: context.l10n.createCompanyScreenVatId,
icon: Icons.numbers,
controller: _pIvaController,
),
@@ -138,7 +141,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
const SizedBox(width: 12),
Expanded(
child: FluxTextField(
label: 'Codice Fiscale',
label: context.l10n.createCompanyScreenFiscalCode,
icon: Icons.badge_outlined,
controller: _cfController,
),
@@ -147,7 +150,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
),
const SizedBox(height: 16),
FluxTextField(
label: 'Codice Univoco (SDI) / PEC',
label: context.l10n.createCompanyScreenSdiPec,
icon: Icons.send_and_archive_outlined,
controller: _univocoController,
),
@@ -155,10 +158,13 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
const SizedBox(height: 32),
// --- SEZIONE 2: SEDE LEGALE ---
_SectionTitle(title: 'SEDE LEGALE'),
_SectionTitle(
title:
context.l10n.createCompanyScreenCompanyLegalAddress,
),
const SizedBox(height: 16),
FluxTextField(
label: 'Indirizzo e n. civico',
label: context.l10n.commonAddress,
icon: Icons.home_work_outlined,
controller: _indirizzoController,
),
@@ -168,7 +174,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
Expanded(
flex: 2,
child: FluxTextField(
label: 'Città',
label: context.l10n.commonCity,
icon: Icons.location_city,
controller: _cittaController,
),
@@ -176,7 +182,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
const SizedBox(width: 12),
Expanded(
child: FluxTextField(
label: 'CAP',
label: context.l10n.commonZipCode,
icon: Icons.map_outlined,
controller: _capController,
),
@@ -184,7 +190,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
const SizedBox(width: 12),
Expanded(
child: FluxTextField(
label: 'Prov',
label: context.l10n.commonProvince,
icon: Icons.explore_outlined,
controller: _provinciaController,
),
@@ -232,7 +238,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
Icon(Icons.cloud_upload_outlined, color: context.accent, size: 32),
const SizedBox(height: 12),
Text(
'Carica Logo Aziendale',
context.l10n.createCompanyScreenUploadLogo,
style: TextStyle(
color: context.primaryText,
fontWeight: FontWeight.bold,
@@ -240,7 +246,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
),
const SizedBox(height: 4),
Text(
'Verrà usato per le tue stampe e ricevute',
context.l10n.createCompanyScreenWillBeUsedForReceipts,
textAlign: TextAlign.center,
style: TextStyle(color: context.secondaryText, fontSize: 12),
),
@@ -259,7 +265,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
: () => _onSave(),
child: state.status == CompanyStatus.loading
? const CircularProgressIndicator()
: const Text('SALVA AZIENDA'),
: Text(context.l10n.createCompanyScreenSaveCompany),
),
);
}
@@ -282,7 +288,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
),
const SizedBox(height: 24),
Text(
'Configura la tua Azienda',
context.l10n.createCompanyScreenSetupYourCompany,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
color: context.primaryText,
@@ -290,7 +296,7 @@ class _CreateCompanyScreenState extends State<CreateCompanyScreen> {
),
const SizedBox(height: 12),
Text(
'FLUX ha bisogno dei tuoi dati fiscali per gestire correttamente le fatturazioni e le attivazioni dei tuoi negozi.',
context.l10n.createCompanyScreenFluxNeedsYourFiscalData,
style: TextStyle(
color: context.secondaryText,
fontSize: 15,

View File

@@ -21,7 +21,7 @@ class CustomerRepository {
.single();
return CustomerModel.fromMap(response);
} catch (e) {
throw 'Errore durante il salvataggio del cliente: $e';
throw '$e';
}
}
@@ -35,7 +35,7 @@ class CustomerRepository {
.single();
return CustomerModel.fromMap(response);
} catch (e) {
throw 'Errore durante la modifica del cliente: $e';
throw '$e';
}
}
@@ -54,7 +54,7 @@ class CustomerRepository {
return (response as List).map((c) => CustomerModel.fromMap(c)).toList();
} catch (e) {
throw 'Errore nel recupero clienti';
throw '$e';
}
}
@@ -102,7 +102,7 @@ class CustomerRepository {
.map((f) => CustomerFileModel.fromMap(f))
.toList();
} catch (e) {
throw 'Errore recupero file: $e';
throw '$e';
}
}
@@ -131,7 +131,7 @@ class CustomerRepository {
try {
// Usiamo bytes invece del path per massima compatibilità
if (pickedFile.bytes == null && pickedFile.path == null) {
throw 'Impossibile leggere il contenuto del file';
throw 'File read error';
}
// Se siamo su desktop/mobile abbiamo il path, su web abbiamo i bytes
@@ -153,7 +153,7 @@ class CustomerRepository {
return CustomerFileModel.fromMap(response);
} catch (e) {
throw 'Errore durante l\'upload: $e';
throw '$e';
}
}
@@ -186,14 +186,10 @@ class CustomerRepository {
// 3. Cancellazione MASSIVA dallo Storage
await _supabase.storage.from('documents').remove(storagePaths);
debugPrint("Eliminati con successo ${files.length} file.");
} on PostgrestException catch (e) {
debugPrint("Errore DB: ${e.message}");
throw 'Errore database: ${e.message}';
throw e.message;
} catch (e) {
debugPrint("Errore generico: $e");
throw 'Errore durante l\'eliminazione dei file: $e';
throw '$e';
}
}
}

View File

@@ -58,31 +58,31 @@ class HomeScreen extends StatelessWidget {
),
delegate: SliverChildListDelegate([
_buildDashboardWidget(
title: context.l10n.expiring_contracts,
title: context.l10n.homeExpiringContracts,
icon: Icons.assignment_late_outlined,
color: Colors.orange,
context: context,
),
_buildDashboardWidget(
title: context.l10n.sticky_notes,
title: context.l10n.commonStickyNotes,
icon: Icons.sticky_note_2_outlined,
color: Colors.yellow.shade700,
context: context,
),
_buildDashboardWidget(
title: context.l10n.my_tasks,
title: context.l10n.homeMyTasks,
icon: Icons.check_box_outlined,
color: Colors.green,
context: context,
),
_buildDashboardWidget(
title: context.l10n.latestServices,
title: context.l10n.homeLatestServices,
icon: Icons.design_services_outlined,
color: Colors.blue,
context: context,
),
_buildDashboardWidget(
title: 'Ultime Assistenze',
title: context.l10n.homeLatestServiceTickets,
icon: Icons.support_agent_outlined,
color: Colors.purple,
context: context,
@@ -118,7 +118,7 @@ class HomeScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Bentornato, ${user!.name}! 👋",
context.l10n.homeWelcomeBack(user?.name ?? "Utente"),
style: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
letterSpacing: -0.5,
@@ -152,7 +152,7 @@ class HomeScreen extends StatelessWidget {
Icon(Icons.storefront, size: 16, color: context.primary),
const SizedBox(width: 8),
Text(
currentStore?.nome ?? "Nessun negozio",
currentStore?.nome ?? context.l10n.homeNoStoreFound,
style: TextStyle(
fontWeight: FontWeight.w600,
color: context.primary,
@@ -184,7 +184,7 @@ class HomeScreen extends StatelessWidget {
children: [
QuickActionButton(
icon: Icons.add,
label: "Servizio",
label: context.l10n.commonService,
color: Colors.blue,
onTap: () {
// Entriamo nel form! Nessun parametro extra = Nuovo Servizio
@@ -194,7 +194,7 @@ class HomeScreen extends StatelessWidget {
const SizedBox(width: 12),
QuickActionButton(
icon: Icons.handyman,
label: "Assistenza",
label: context.l10n.homeNewServiceTicket,
color: Colors.redAccent,
onTap: () {
// TODO: Quando avrai la rotta per la nuova assistenza
@@ -204,7 +204,7 @@ class HomeScreen extends StatelessWidget {
const SizedBox(width: 12),
QuickActionButton(
icon: Icons.note_add,
label: "Nota",
label: context.l10n.commonNote,
color: Colors.amber,
onTap: () {
// TODO: Quando faremo il modale/pagina delle note
@@ -213,7 +213,7 @@ class HomeScreen extends StatelessWidget {
const SizedBox(width: 12),
QuickActionButton(
icon: Icons.task_alt,
label: "Task",
label: context.l10n.commonTask,
color: Colors.teal,
onTap: () {
// TODO: Quando faremo i task
@@ -281,7 +281,7 @@ class HomeScreen extends StatelessWidget {
const Spacer(),
Center(
child: Text(
"(Coming Soon)",
context.l10n.commonComingSoon,
style: TextStyle(
color: context.secondaryText.withValues(alpha: 0.7),
fontStyle: FontStyle.italic,