Theme
This commit is contained in:
363
lib/app.dart
363
lib/app.dart
@@ -6,6 +6,10 @@ import 'package:kmobile/security/secure_storage.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import './l10n/app_localizations.dart';
|
||||
import 'config/themes.dart';
|
||||
import 'config/theme_controller.dart';
|
||||
import 'config/theme_mode_controller.dart';
|
||||
import 'package:kmobile/features/auth/controllers/theme_cubit.dart';
|
||||
import 'package:kmobile/features/auth/controllers/theme_state.dart';
|
||||
import 'config/routes.dart';
|
||||
import 'di/injection.dart';
|
||||
import 'features/auth/controllers/auth_cubit.dart';
|
||||
@@ -17,7 +21,6 @@ import 'features/dashboard/screens/dashboard_screen.dart';
|
||||
import 'features/auth/screens/mpin_screen.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
//import 'package:flutter_neumorphic/flutter_neumorphic.dart';
|
||||
|
||||
class KMobile extends StatefulWidget {
|
||||
const KMobile({super.key});
|
||||
@@ -32,42 +35,43 @@ class KMobile extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _KMobileState extends State<KMobile> {
|
||||
bool _showSplash = false;
|
||||
Locale? _locale;
|
||||
bool showSplash = true;
|
||||
Locale? _locale;
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadLocale();
|
||||
// Simulate a splash screen delay
|
||||
loadPreferences();
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
setState(() {
|
||||
_showSplash = false;
|
||||
showSplash = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadLocale() async{
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
Future<void> loadPreferences() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
// Load Locale
|
||||
final String? langCode = prefs.getString('locale');
|
||||
if (langCode != null) {
|
||||
setState(() {
|
||||
_locale = Locale(langCode);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void setLocale(Locale locale) {
|
||||
setState(() {
|
||||
_locale = locale;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
@override
|
||||
/* @override
|
||||
Widget build(BuildContext context) {
|
||||
// Set status bar color
|
||||
// Set status bar color
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
@@ -75,8 +79,12 @@ class _KMobileState extends State<KMobile> {
|
||||
),
|
||||
);
|
||||
|
||||
if (_showSplash) {
|
||||
return MaterialApp(
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<AuthCubit>(create: (_) => getIt<AuthCubit>()),
|
||||
BlocProvider<ThemeCubit>(create: (_) => getIt<ThemeCubit>()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
locale: _locale,
|
||||
supportedLocales: const [
|
||||
@@ -89,69 +97,67 @@ class _KMobileState extends State<KMobile> {
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
home: const SplashScreen(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<AuthCubit>(create: (_) => getIt<AuthCubit>()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
title: 'kMobile',
|
||||
// debugShowCheckedModeBanner: false,
|
||||
theme: AppThemes.lightTheme,
|
||||
// darkTheme: AppThemes.darkTheme,
|
||||
themeMode: ThemeMode.system, // Use system theme by default
|
||||
|
||||
// Dynamic Theme and ThemeMode
|
||||
theme: AppThemes.getLightTheme(_themeController.currentTheme),
|
||||
darkTheme: AppThemes.getDarkTheme(_themeController.currentTheme),
|
||||
themeMode: _themeModeController.currentThemeMode,
|
||||
|
||||
onGenerateRoute: AppRoutes.generateRoute,
|
||||
initialRoute: AppRoutes.splash,
|
||||
home: const AuthGate(),
|
||||
home: showSplash ? const SplashScreen() : const AuthGate(),
|
||||
),
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
@override
|
||||
}*/
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Set status bar color
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
);
|
||||
// Set status bar color and brightness
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
);
|
||||
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<AuthCubit>(create: (_) => getIt<AuthCubit>()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
locale: _locale, // Dynamic locale
|
||||
supportedLocales: const [
|
||||
Locale('en'),
|
||||
Locale('hi'),
|
||||
],
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
title: 'kMobile',
|
||||
theme: AppThemes.lightTheme,
|
||||
// darkTheme: AppThemes.darkTheme,
|
||||
themeMode: ThemeMode.system,
|
||||
onGenerateRoute: AppRoutes.generateRoute,
|
||||
initialRoute: AppRoutes.splash,
|
||||
home: _showSplash ? const SplashScreen() : const AuthGate(),
|
||||
),
|
||||
);
|
||||
}
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<AuthCubit>(create: (_) => getIt<AuthCubit>()),
|
||||
BlocProvider<ThemeCubit>(create: (_) => getIt<ThemeCubit>()),
|
||||
],
|
||||
child: BlocBuilder<ThemeCubit, ThemeState>(
|
||||
builder: (context, themeState) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
locale: _locale ?? const Locale('en'),
|
||||
supportedLocales: const [
|
||||
Locale('en'),
|
||||
Locale('hi'),
|
||||
],
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
title: 'kMobile',
|
||||
//theme: themeState.lightTheme,
|
||||
//theme: AppThemes.getLightTheme(themeState.themeType),
|
||||
theme: themeState.lightTheme,
|
||||
darkTheme: AppThemes.getDarkTheme(themeState.themeType),
|
||||
themeMode: themeState.themeMode,
|
||||
onGenerateRoute: AppRoutes.generateRoute,
|
||||
initialRoute: AppRoutes.splash,
|
||||
home: showSplash ? const SplashScreen() : const AuthGate(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
class AuthGate extends StatefulWidget {
|
||||
const AuthGate({super.key});
|
||||
|
||||
@@ -210,105 +216,6 @@ class _AuthGateState extends State<AuthGate> {
|
||||
}
|
||||
}
|
||||
|
||||
/* @override
|
||||
Widget build(BuildContext context) {
|
||||
if (_checking) {
|
||||
return const SplashScreen();
|
||||
}
|
||||
if (_isLoggedIn) {
|
||||
if (_hasMPin) {
|
||||
if (_biometricEnabled) {
|
||||
return FutureBuilder<bool>(
|
||||
future: _tryBiometric(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const SplashScreen();
|
||||
}
|
||||
if (snapshot.data == true) {
|
||||
// Authenticated with biometrics, go to dashboard
|
||||
return const NavigationScaffold();
|
||||
}
|
||||
// If not authenticated or user dismissed, show mPIN screen
|
||||
return MPinScreen(
|
||||
mode: MPinMode.enter,
|
||||
onCompleted: (_) {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const NavigationScaffold()),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return MPinScreen(
|
||||
mode: MPinMode.enter,
|
||||
onCompleted: (_) {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(builder: (_) => const NavigationScaffold()),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return MPinScreen(
|
||||
mode: MPinMode.set,
|
||||
onCompleted: (_) async {
|
||||
final storage = getIt<SecureStorage>();
|
||||
final localAuth = LocalAuthentication();
|
||||
|
||||
// 1) Prompt user to opt‐in for biometric
|
||||
final optIn = await showDialog<bool>(
|
||||
context: context,
|
||||
barrierDismissible: false, // force choice
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Enable Fingerprint Login?'),
|
||||
content: const Text(
|
||||
'Would you like to enable fingerprint authentication for faster login?',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(false),
|
||||
child: const Text('No'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(true),
|
||||
child: const Text('Yes'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// 2) If opted in, perform biometric auth
|
||||
if (optIn == true) {
|
||||
final canCheck = await localAuth.canCheckBiometrics;
|
||||
bool didAuth = false;
|
||||
if (canCheck) {
|
||||
didAuth = await localAuth.authenticate(
|
||||
localizedReason: 'Authenticate to enable fingerprint login',
|
||||
options: const AuthenticationOptions(
|
||||
stickyAuth: true,
|
||||
biometricOnly: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
await storage.write(
|
||||
'biometric_enabled', didAuth ? 'true' : 'false');
|
||||
} else {
|
||||
await storage.write('biometric_enabled', 'false');
|
||||
}
|
||||
|
||||
// 3) Finally go to your main scaffold
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(builder: (_) => const NavigationScaffold()),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
return const LoginScreen();
|
||||
}
|
||||
}*/
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -430,124 +337,6 @@ class _AuthGateState extends State<AuthGate> {
|
||||
}
|
||||
}
|
||||
|
||||
/*@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_checking) {
|
||||
return const SplashScreen();
|
||||
}
|
||||
|
||||
if (_isLoggedIn) {
|
||||
if (_hasMPin) {
|
||||
if (_biometricEnabled) {
|
||||
return FutureBuilder<bool>(
|
||||
future: _tryBiometric(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const SplashScreen();
|
||||
}
|
||||
|
||||
if (snapshot.data == true) {
|
||||
return const NavigationScaffold(); // Authenticated
|
||||
}
|
||||
|
||||
// Failed or dismissed biometric → Show MPIN
|
||||
return MPinScreen(
|
||||
mode: MPinMode.enter,
|
||||
onCompleted: (_) {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const NavigationScaffold(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return MPinScreen(
|
||||
mode: MPinMode.enter,
|
||||
onCompleted: (_) {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(builder: (_) => const NavigationScaffold()),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return MPinScreen(
|
||||
mode: MPinMode.set,
|
||||
onCompleted: (_) async {
|
||||
final storage = getIt<SecureStorage>();
|
||||
final localAuth = LocalAuthentication();
|
||||
final optin = await showDialog<bool>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).enableFingerprintLogin,
|
||||
),
|
||||
content: Text(
|
||||
AppLocalizations.of(context).enableFingerprintMessage,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(false),
|
||||
child: Text(AppLocalizations.of(context).no),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(true),
|
||||
child: Text(AppLocalizations.of(context).yes),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (optin == true) {
|
||||
final canCheck = await localAuth.canCheckBiometrics;
|
||||
bool didAuth = false;
|
||||
|
||||
if (canCheck) {
|
||||
didAuth = await localAuth.authenticate(
|
||||
localizedReason: AppLocalizations.of(
|
||||
context,
|
||||
).authenticateToEnable,
|
||||
options: const AuthenticationOptions(
|
||||
stickyAuth: true,
|
||||
biometricOnly: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await storage.write(
|
||||
'biometric_enabled',
|
||||
didAuth ? 'true' : 'false',
|
||||
);
|
||||
} else {
|
||||
await storage.write('biometric_enabled', 'false');
|
||||
}
|
||||
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(builder: (_) => const NavigationScaffold()),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 🔻 Show Welcome screen before login if not logged in
|
||||
if (_showWelcome) {
|
||||
return WelcomeScreen(
|
||||
onContinue: () {
|
||||
setState(() {
|
||||
_showWelcome = false;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
return const LoginScreen();
|
||||
}
|
||||
}*/
|
||||
|
||||
class NavigationScaffold extends StatefulWidget {
|
||||
const NavigationScaffold({super.key});
|
||||
|
||||
@@ -612,8 +401,8 @@ class _NavigationScaffoldState extends State<NavigationScaffold> {
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
currentIndex: _selectedIndex,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
backgroundColor: const Color(0xFFE0F7FA), // Light blue background
|
||||
selectedItemColor: Colors.blue[800],
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor, // Light blue background
|
||||
selectedItemColor: Theme.of(context).primaryColor,
|
||||
unselectedItemColor: Colors.black54,
|
||||
onTap: _onItemTapped,
|
||||
items: [
|
||||
|
Reference in New Issue
Block a user