hgkj
This commit is contained in:
@@ -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<SharedPreferences>(
|
||||
await SharedPreferences.getInstance(),
|
||||
);
|
||||
getIt.registerSingleton<AppSettings>(AppSettings());
|
||||
runApp(const MainApp());
|
||||
}
|
||||
|
||||
@@ -11,11 +22,34 @@ class MainApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppTheme appTheme = GetIt.I.get<AppSettings>().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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
);
|
||||
189
lib/theme/theme.dart
Normal file
189
lib/theme/theme.dart
Normal file
@@ -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),
|
||||
);
|
||||
17
lib/theme/theme_bloc.dart
Normal file
17
lib/theme/theme_bloc.dart
Normal file
@@ -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<ThemeEvent, ThemeState> {
|
||||
final AppTheme initialAppTheme;
|
||||
ThemeBloc({required this.initialAppTheme})
|
||||
: super(
|
||||
ThemeState(status: ThemeStatus.success, appTheme: initialAppTheme),
|
||||
) {
|
||||
on<ChangeThemeEvent>((event, emit) async {
|
||||
emit(state.copyWith(appTheme: event.appTheme));
|
||||
});
|
||||
}
|
||||
}
|
||||
17
lib/theme/theme_events.dart
Normal file
17
lib/theme/theme_events.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
part of 'theme_bloc.dart';
|
||||
|
||||
abstract class ThemeEvent extends Equatable {
|
||||
const ThemeEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class ChangeThemeEvent extends ThemeEvent {
|
||||
const ChangeThemeEvent({required this.appTheme});
|
||||
|
||||
final AppTheme appTheme;
|
||||
|
||||
@override
|
||||
List<Object> get props => [appTheme];
|
||||
}
|
||||
30
lib/theme/theme_state.dart
Normal file
30
lib/theme/theme_state.dart
Normal file
@@ -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<Object?> get props => [status, appTheme];
|
||||
|
||||
ThemeState copyWith({ThemeStatus? status, AppTheme? appTheme}) {
|
||||
return ThemeState(
|
||||
status: status ?? this.status,
|
||||
appTheme: appTheme ?? this.appTheme,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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});
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -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<HomeScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(child: _widgetOptions.elementAt(_selectedIndex)),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
items: const <BottomNavigationBarItem>[
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.dashboard_outlined),
|
||||
activeIcon: Icon(Icons.dashboard),
|
||||
label: 'Dashboard',
|
||||
return BlocBuilder<ThemeBloc, ThemeState>(
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
body: Center(child: _widgetOptions.elementAt(_selectedIndex)),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
items: const <BottomNavigationBarItem>[
|
||||
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,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
39
lib/ui/settings/settings.dart
Normal file
39
lib/ui/settings/settings.dart
Normal file
@@ -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<SharedPreferences>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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});
|
||||
|
||||
Reference in New Issue
Block a user