From 0347a354efce103310884fb1a1fd8a02daaab630 Mon Sep 17 00:00:00 2001 From: mark-cachy Date: Sat, 4 Apr 2026 19:25:55 +0200 Subject: [PATCH] hgkj --- lib/main.dart | 42 +++- lib/theme.dart | 73 ------- lib/theme/theme.dart | 189 ++++++++++++++++++ lib/theme/theme_bloc.dart | 17 ++ lib/theme/theme_events.dart | 17 ++ lib/theme/theme_state.dart | 30 +++ lib/ui/anagrafiche/anagrafiche_main_view.dart | 2 +- lib/ui/dashboard/dashboard_view.dart | 2 +- lib/ui/home_screen.dart | 74 ++++--- lib/ui/settings/settings.dart | 39 ++++ lib/ui/settings/settings_view.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 1 + 13 files changed, 377 insertions(+), 113 deletions(-) delete mode 100644 lib/theme.dart create mode 100644 lib/theme/theme.dart create mode 100644 lib/theme/theme_bloc.dart create mode 100644 lib/theme/theme_events.dart create mode 100644 lib/theme/theme_state.dart create mode 100644 lib/ui/settings/settings.dart diff --git a/lib/main.dart b/lib/main.dart index a2fbcf3..fe0ef6f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,19 @@ import 'package:flutter/material.dart'; -import 'package:flux/theme.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flux/theme/theme.dart'; +import 'package:flux/theme/theme_bloc.dart'; import 'package:flux/ui/home_screen.dart'; +import 'package:flux/ui/settings/settings.dart'; +import 'package:get_it/get_it.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -void main() { +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + final GetIt getIt = GetIt.instance; + getIt.registerSingleton( + await SharedPreferences.getInstance(), + ); + getIt.registerSingleton(AppSettings()); runApp(const MainApp()); } @@ -11,11 +22,34 @@ class MainApp extends StatelessWidget { @override Widget build(BuildContext context) { + AppTheme appTheme = GetIt.I.get().appTheme; + ThemeData themeData; + switch (appTheme) { + case AppTheme.dark: + themeData = fluxDarkTheme; + break; + case AppTheme.light: + themeData = fluxLightTheme; + break; + default: + themeData = ThemeMode.system == ThemeMode.dark + ? fluxDarkTheme + : fluxLightTheme; + break; + } return MaterialApp( title: 'FLUX Gestionale', debugShowCheckedModeBanner: false, - theme: fluxDarkTheme, // Applica il tema FLUX - home: const HomeScreen(), + theme: themeData, // Applica il tema FLUX + home: MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ThemeBloc(initialAppTheme: appTheme), + ), + ], + + child: const HomeScreen(), + ), ); } } diff --git a/lib/theme.dart b/lib/theme.dart deleted file mode 100644 index d890256..0000000 --- a/lib/theme.dart +++ /dev/null @@ -1,73 +0,0 @@ -// lib/theme.dart -import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class FluxColors { - // Palette Tech Dark da loghi generati - static const Color background = Color(0xFF0A0E17); // Nero profondo/Blu scuro - static const Color surface = Color(0xFF161B22); // Pannelli scuri - static const Color primaryBlue = Color(0xFF007BFF); // Blu Elettrico del logo - static const Color accentTurquoise = Color(0xFF17A2B8); // Turchese del flusso - static const Color textPrimary = Colors.white; - static const Color textSecondary = Color(0xFF8B949E); // Grigio fumo -} - -ThemeData fluxDarkTheme = ThemeData( - useMaterial3: true, - brightness: Brightness.dark, - primaryColor: FluxColors.primaryBlue, - scaffoldBackgroundColor: FluxColors.background, - colorScheme: const ColorScheme.dark( - primary: FluxColors.primaryBlue, - secondary: FluxColors.accentTurquoise, - surface: FluxColors.surface, - background: FluxColors.background, - onPrimary: Colors.white, - onSurface: FluxColors.textPrimary, - ), - - // Font moderno sans-serif (es. Montserrat o Poppins coerente con descrizione) - textTheme: GoogleFonts.poppinsTextTheme(ThemeData.dark().textTheme).copyWith( - headlineMedium: GoogleFonts.poppins( - color: FluxColors.textPrimary, - fontWeight: FontWeight.w600, - letterSpacing: 0.5, - ), - titleLarge: GoogleFonts.poppins( - color: FluxColors.textPrimary, - fontWeight: FontWeight.w500, - ), - bodyMedium: GoogleFonts.poppins(color: FluxColors.textSecondary), - ), - - appBarTheme: const AppBarTheme( - backgroundColor: FluxColors.background, - elevation: 0, - centerTitle: false, - titleTextStyle: TextStyle( - color: FluxColors.textPrimary, - fontSize: 20, - fontWeight: FontWeight.w600, - ), - ), - - cardTheme: const CardThemeData( - color: FluxColors.surface, - elevation: 2, - margin: EdgeInsets.all(8), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(12)), - ), - ), - - // Stile per i pulsanti (es. "Nuova Operazione") - elevatedButtonTheme: ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - backgroundColor: FluxColors.primaryBlue, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - textStyle: GoogleFonts.poppins(fontWeight: FontWeight.w500), - ), - ), -); diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart new file mode 100644 index 0000000..2d4dd73 --- /dev/null +++ b/lib/theme/theme.dart @@ -0,0 +1,189 @@ +// lib/theme.dart +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class FluxColors { + // === Palette comune (dal logo) === + static const Color primaryBlue = Color( + 0xFF007BFF, + ); // Blu Elettrico (Affidabilità) + static const Color accentTurquoise = Color( + 0xFF17A2B8, + ); // Turchese (Flusso/Tech) + + // === Palette Tech Dark (esistente) === + static const Color darkBackground = Color(0xFF0A0E17); + static const Color darkSurface = Color(0xFF161B22); + static const Color darkTextPrimary = Colors.white; + static const Color darkTextSecondary = Color(0xFF8B949E); + + // === Palette Tech Light (NUOVA) === + static const Color lightBackground = Color( + 0xFFF0F2F5, + ); // Grigio chiarissimo "pulito" + static const Color lightSurface = Colors.white; // Pannelli bianchi puri + static const Color lightTextPrimary = Color( + 0xFF1C1E21, + ); // Quasi nero per contrasto + static const Color lightTextSecondary = Color(0xFF606770); // Grigio medio +} + +// --- Configurazione Tipografica Comune --- +TextTheme _buildFluxTextTheme( + TextTheme base, + Color primaryColor, + Color secondaryColor, +) { + return GoogleFonts.poppinsTextTheme(base).copyWith( + headlineMedium: GoogleFonts.poppins( + color: primaryColor, + fontWeight: FontWeight.w600, + letterSpacing: 0.5, + ), + titleLarge: GoogleFonts.poppins( + color: primaryColor, + fontWeight: FontWeight.w500, + ), + titleSmall: GoogleFonts.poppins( + color: + FluxColors.accentTurquoise, // Sempre turchese per i titoli di sezione + fontWeight: FontWeight.w600, + letterSpacing: 1.2, + ), + bodyMedium: GoogleFonts.poppins(color: secondaryColor), + ); +} + +// ========================================== +// === TEMA SCURO (esistente, ottimizzato) === +// ========================================== +ThemeData fluxDarkTheme = ThemeData( + useMaterial3: true, + brightness: Brightness.dark, + primaryColor: FluxColors.primaryBlue, + scaffoldBackgroundColor: FluxColors.darkBackground, + colorScheme: const ColorScheme.dark( + primary: FluxColors.primaryBlue, + secondary: FluxColors.accentTurquoise, + surface: FluxColors.darkSurface, + onPrimary: Colors.white, + onSurface: FluxColors.darkTextPrimary, + ), + + textTheme: _buildFluxTextTheme( + ThemeData.dark().textTheme, + FluxColors.darkTextPrimary, + FluxColors.darkTextSecondary, + ), + + appBarTheme: const AppBarTheme( + backgroundColor: FluxColors.darkBackground, + elevation: 0, + centerTitle: false, + iconTheme: IconThemeData(color: FluxColors.darkTextPrimary), + titleTextStyle: TextStyle( + color: FluxColors.darkTextPrimary, + fontSize: 20, + fontWeight: FontWeight.w600, + ), + ), + + cardTheme: const CardThemeData( + color: FluxColors.darkSurface, + elevation: 2, + margin: EdgeInsets.all(8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + ), + + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: FluxColors.primaryBlue, + foregroundColor: Colors.white, + elevation: 3, + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + ), + + // Colore delle icone non attive nella BottomNav + unselectedWidgetColor: FluxColors.darkTextSecondary, +); + +// ========================================== +// === TEMA CHIARO (NUOVO) === +// ========================================== +ThemeData fluxLightTheme = ThemeData( + useMaterial3: true, + brightness: Brightness.light, + primaryColor: FluxColors.primaryBlue, + // Sfondo chiarissimo per staccare dalle card bianche + scaffoldBackgroundColor: FluxColors.lightBackground, + + colorScheme: const ColorScheme.light( + primary: FluxColors.primaryBlue, + secondary: FluxColors.accentTurquoise, + surface: FluxColors.lightSurface, + onPrimary: Colors.white, + onSurface: FluxColors.lightTextPrimary, + ), + + // Applica la stessa tipografia ma con colori scuri + textTheme: _buildFluxTextTheme( + ThemeData.light().textTheme, + FluxColors.lightTextPrimary, + FluxColors.lightTextSecondary, + ), + + appBarTheme: const AppBarTheme( + backgroundColor: FluxColors.lightSurface, // AppBar bianca + elevation: 1, // Leggera ombra per staccare dallo sfondo + centerTitle: false, + iconTheme: IconThemeData(color: FluxColors.lightTextPrimary), + titleTextStyle: TextStyle( + color: FluxColors.lightTextPrimary, + fontSize: 20, + fontWeight: FontWeight.w600, + ), + ), + + cardTheme: const CardThemeData( + color: FluxColors.lightSurface, // Card bianca pura + elevation: 4, // Ombra più marcata su sfondo chiaro + margin: EdgeInsets.all(8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + ), + + // Il pulsante principale rimane Blu Elettrico, molto visibile + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: FluxColors.primaryBlue, + foregroundColor: Colors.white, + elevation: 4, + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + ), + + // TabBar (usata nelle Anagrafiche) ottimizzata per il chiaro + tabBarTheme: const TabBarThemeData( + labelColor: FluxColors.primaryBlue, + unselectedLabelColor: FluxColors.lightTextSecondary, + indicatorColor: FluxColors.accentTurquoise, + indicatorSize: TabBarIndicatorSize.label, + ), + + // BottomNavigationBar (usata nella HomeScreen) + bottomNavigationBarTheme: const BottomNavigationBarThemeData( + backgroundColor: FluxColors.lightSurface, + selectedItemColor: FluxColors.primaryBlue, + unselectedItemColor: FluxColors.lightTextSecondary, + elevation: 8, + ), + + // Colore delle icone generiche + iconTheme: const IconThemeData(color: FluxColors.lightTextSecondary), +); diff --git a/lib/theme/theme_bloc.dart b/lib/theme/theme_bloc.dart new file mode 100644 index 0000000..0e4a1a2 --- /dev/null +++ b/lib/theme/theme_bloc.dart @@ -0,0 +1,17 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:equatable/equatable.dart'; + +part 'theme_events.dart'; +part 'theme_state.dart'; + +class ThemeBloc extends Bloc { + final AppTheme initialAppTheme; + ThemeBloc({required this.initialAppTheme}) + : super( + ThemeState(status: ThemeStatus.success, appTheme: initialAppTheme), + ) { + on((event, emit) async { + emit(state.copyWith(appTheme: event.appTheme)); + }); + } +} diff --git a/lib/theme/theme_events.dart b/lib/theme/theme_events.dart new file mode 100644 index 0000000..958e15c --- /dev/null +++ b/lib/theme/theme_events.dart @@ -0,0 +1,17 @@ +part of 'theme_bloc.dart'; + +abstract class ThemeEvent extends Equatable { + const ThemeEvent(); + + @override + List get props => []; +} + +class ChangeThemeEvent extends ThemeEvent { + const ChangeThemeEvent({required this.appTheme}); + + final AppTheme appTheme; + + @override + List get props => [appTheme]; +} diff --git a/lib/theme/theme_state.dart b/lib/theme/theme_state.dart new file mode 100644 index 0000000..588ef78 --- /dev/null +++ b/lib/theme/theme_state.dart @@ -0,0 +1,30 @@ +part of 'theme_bloc.dart'; + +enum ThemeStatus { initial, success } + +enum AppTheme { + dark(name: 'dark'), + light(name: 'light'), + system(name: 'system'); + + final String name; + + const AppTheme({required this.name}); +} + +class ThemeState extends Equatable { + const ThemeState({required this.status, required this.appTheme}); + + final ThemeStatus status; + final AppTheme appTheme; + + @override + List get props => [status, appTheme]; + + ThemeState copyWith({ThemeStatus? status, AppTheme? appTheme}) { + return ThemeState( + status: status ?? this.status, + appTheme: appTheme ?? this.appTheme, + ); + } +} diff --git a/lib/ui/anagrafiche/anagrafiche_main_view.dart b/lib/ui/anagrafiche/anagrafiche_main_view.dart index ee2e526..39e0461 100644 --- a/lib/ui/anagrafiche/anagrafiche_main_view.dart +++ b/lib/ui/anagrafiche/anagrafiche_main_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flux/theme.dart'; +import 'package:flux/theme/theme.dart'; class AnagraficheMainView extends StatelessWidget { const AnagraficheMainView({super.key}); diff --git a/lib/ui/dashboard/dashboard_view.dart b/lib/ui/dashboard/dashboard_view.dart index 35052e6..090b7a7 100644 --- a/lib/ui/dashboard/dashboard_view.dart +++ b/lib/ui/dashboard/dashboard_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flux/theme.dart'; +import 'package:flux/theme/theme.dart'; class DashboardView extends StatelessWidget { const DashboardView({super.key}); diff --git a/lib/ui/home_screen.dart b/lib/ui/home_screen.dart index 250ea2f..242120b 100644 --- a/lib/ui/home_screen.dart +++ b/lib/ui/home_screen.dart @@ -1,5 +1,7 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; -import 'package:flux/theme.dart'; +import 'package:flux/theme/theme.dart'; +import 'package:flux/theme/theme_bloc.dart'; import 'package:flux/ui/anagrafiche/anagrafiche_main_view.dart'; import 'package:flux/ui/dashboard/dashboard_view.dart'; import 'package:flux/ui/settings/settings_view.dart'; @@ -29,38 +31,46 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - body: Center(child: _widgetOptions.elementAt(_selectedIndex)), - bottomNavigationBar: BottomNavigationBar( - items: const [ - BottomNavigationBarItem( - icon: Icon(Icons.dashboard_outlined), - activeIcon: Icon(Icons.dashboard), - label: 'Dashboard', + return BlocBuilder( + builder: (context, state) { + return Scaffold( + body: Center(child: _widgetOptions.elementAt(_selectedIndex)), + bottomNavigationBar: BottomNavigationBar( + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.dashboard_outlined), + activeIcon: Icon(Icons.dashboard), + label: 'Dashboard', + ), + BottomNavigationBarItem( + icon: Icon(Icons.history_edu_outlined), + activeIcon: Icon(Icons.history_edu), + label: 'Operazioni', + ), + BottomNavigationBarItem( + icon: Icon(Icons.people_alt_outlined), + activeIcon: Icon(Icons.people_alt), + label: 'Anagrafiche', + ), + BottomNavigationBarItem( + icon: Icon(Icons.settings_outlined), + activeIcon: Icon(Icons.settings), + label: 'Impostazioni', + ), + ], + currentIndex: _selectedIndex, + selectedItemColor: FluxColors.accentTurquoise, + unselectedItemColor: state.themeMode == ThemeMode.dark + ? FluxColors.darkTextSecondary + : FluxColors.lightTextSecondary, + backgroundColor: state.themeMode == ThemeMode.dark + ? FluxColors.darkSurface + : FluxColors.lightSurface, + type: BottomNavigationBarType.fixed, + onTap: _onItemTapped, ), - BottomNavigationBarItem( - icon: Icon(Icons.history_edu_outlined), - activeIcon: Icon(Icons.history_edu), - label: 'Operazioni', - ), - BottomNavigationBarItem( - icon: Icon(Icons.people_alt_outlined), - activeIcon: Icon(Icons.people_alt), - label: 'Anagrafiche', - ), - BottomNavigationBarItem( - icon: Icon(Icons.settings_outlined), - activeIcon: Icon(Icons.settings), - label: 'Impostazioni', - ), - ], - currentIndex: _selectedIndex, - selectedItemColor: FluxColors.accentTurquoise, - unselectedItemColor: FluxColors.textSecondary, - backgroundColor: FluxColors.surface, - type: BottomNavigationBarType.fixed, - onTap: _onItemTapped, - ), + ); + }, ); } } diff --git a/lib/ui/settings/settings.dart b/lib/ui/settings/settings.dart new file mode 100644 index 0000000..9d10d27 --- /dev/null +++ b/lib/ui/settings/settings.dart @@ -0,0 +1,39 @@ +import 'package:flux/theme/theme_bloc.dart'; +import 'package:get_it/get_it.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class AppSettings { + late AppTheme _appTheme; + late SharedPreferences _prefs; + + // Singleton + + static final AppSettings _instance = AppSettings._internal(); + + factory AppSettings() { + return _instance; + } + + AppSettings._internal() { + _prefs = GetIt.I.get(); + String theme = _prefs.getString('theme') ?? 'light'; + switch (theme) { + case 'dark': + _appTheme = AppTheme.dark; + break; + case 'light': + _appTheme = AppTheme.light; + break; + default: + _appTheme = AppTheme.system; + break; + } + } + + AppTheme get appTheme => _appTheme; + + void setAppTheme(AppTheme theme) { + _appTheme = theme; + _prefs.setString('theme', theme.name); + } +} diff --git a/lib/ui/settings/settings_view.dart b/lib/ui/settings/settings_view.dart index 97ce608..d5cfce4 100644 --- a/lib/ui/settings/settings_view.dart +++ b/lib/ui/settings/settings_view.dart @@ -1,6 +1,6 @@ // lib/ui/impostazioni/impostazioni_view.dart import 'package:flutter/material.dart'; -import 'package:flux/theme.dart'; +import 'package:flux/theme/theme.dart'; class SettingsView extends StatelessWidget { const SettingsView({super.key}); diff --git a/pubspec.lock b/pubspec.lock index 6ebe43b..ebd2f93 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -489,7 +489,7 @@ packages: source: hosted version: "0.28.0" shared_preferences: - dependency: transitive + dependency: "direct main" description: name: shared_preferences sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf diff --git a/pubspec.yaml b/pubspec.yaml index 37d4e01..ca4d516 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: get_it: ^9.2.1 google_fonts: ^8.0.2 intl: ^0.20.2 + shared_preferences: ^2.5.5 supabase_flutter: ^2.12.2 dev_dependencies: