biometricPermission&Authentication
This commit is contained in:
@@ -82,39 +82,4 @@ class AuthService {
|
||||
throw AuthException('Error fetching user profile: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> authenticateWithBiometrics(BuildContext context) async {
|
||||
final LocalAuthentication localAuth = LocalAuthentication();
|
||||
try {
|
||||
bool isBiometricAvailable = await localAuth.canCheckBiometrics;
|
||||
bool isAuthenticated = false;
|
||||
|
||||
if (isBiometricAvailable) {
|
||||
isAuthenticated = await localAuth.authenticate(
|
||||
localizedReason: 'Touch the fingerprint sensor',
|
||||
options: const AuthenticationOptions(
|
||||
biometricOnly: true,
|
||||
stickyAuth: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isAuthenticated) {
|
||||
// Navigate to Dashboard
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const NavigationScaffold()),
|
||||
);
|
||||
} else {
|
||||
// Show error/snack bar
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("Authentication failed")),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print("Biometric error: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
lib/app.dart
36
lib/app.dart
@@ -2,8 +2,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:kmobile/features/auth/screens/customer_info_screen.dart';
|
||||
import 'package:kmobile/security/secure_storage.dart';
|
||||
import 'api/services/auth_service.dart';
|
||||
import 'config/themes.dart';
|
||||
import 'config/routes.dart';
|
||||
import 'data/repositories/auth_repository.dart';
|
||||
import 'di/injection.dart';
|
||||
import 'features/auth/controllers/auth_cubit.dart';
|
||||
import 'features/auth/controllers/auth_state.dart';
|
||||
@@ -56,6 +59,10 @@ class KMobile extends StatelessWidget {
|
||||
return const _SplashScreen();
|
||||
}
|
||||
|
||||
if(state is ShowBiometricPermission){
|
||||
return const BiometricPermissionScreen();
|
||||
}
|
||||
|
||||
if (state is Authenticated) {
|
||||
return const NavigationScaffold();
|
||||
}
|
||||
@@ -168,4 +175,33 @@ class _NavigationScaffoldState extends State<NavigationScaffold> {
|
||||
}
|
||||
}
|
||||
|
||||
class BiometricPermissionScreen extends StatelessWidget {
|
||||
const BiometricPermissionScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cubit = context.read<AuthCubit>();
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text('Would you like to enable biometric authentication?'),
|
||||
ElevatedButton(
|
||||
onPressed: () => cubit.handleBiometricChoice(true),
|
||||
child: const Text('Yes'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => cubit.handleBiometricChoice(false),
|
||||
child: const Text('No, thanks'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -1,4 +1,10 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../../app.dart';
|
||||
import '../../../data/repositories/auth_repository.dart';
|
||||
import 'auth_state.dart';
|
||||
|
||||
@@ -47,4 +53,60 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
emit(AuthError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkFirstLaunch() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final isFirstLaunch = prefs.getBool('isFirstLaunch') ?? true;
|
||||
|
||||
if (isFirstLaunch) {
|
||||
emit(ShowBiometricPermission());
|
||||
} else {
|
||||
// Continue to authentication logic (e.g., check token)
|
||||
emit(AuthLoading()); // or Unauthenticated/Authenticated
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleBiometricChoice(bool enabled) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool('biometric_opt_in', enabled);
|
||||
await prefs.setBool('isFirstLaunch', false);
|
||||
|
||||
// Then continue to auth logic or home
|
||||
if (enabled) {
|
||||
authenticateBiometric(); // implement biometric logic
|
||||
} else {
|
||||
emit(Unauthenticated());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> authenticateBiometric() async {
|
||||
final LocalAuthentication auth = LocalAuthentication();
|
||||
|
||||
try {
|
||||
final isAvailable = await auth.canCheckBiometrics;
|
||||
final isDeviceSupported = await auth.isDeviceSupported();
|
||||
|
||||
if (isAvailable && isDeviceSupported) {
|
||||
final authenticated = await auth.authenticate(
|
||||
localizedReason: 'Touch the fingerprint sensor',
|
||||
options: const AuthenticationOptions(
|
||||
biometricOnly: true,
|
||||
stickyAuth: true,
|
||||
),
|
||||
);
|
||||
|
||||
if (authenticated) {
|
||||
// Continue to normal auth logic (e.g., auto login)
|
||||
emit(AuthLoading());
|
||||
await checkAuthStatus(); // Your existing method to verify token/session
|
||||
} else {
|
||||
emit(Unauthenticated());
|
||||
}
|
||||
} else {
|
||||
emit(Unauthenticated());
|
||||
}
|
||||
} catch (e) {
|
||||
emit(Unauthenticated());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ class AuthInitial extends AuthState {}
|
||||
|
||||
class AuthLoading extends AuthState {}
|
||||
|
||||
class ShowBiometricPermission extends AuthState {}
|
||||
|
||||
class Authenticated extends AuthState {
|
||||
final User user;
|
||||
|
||||
|
@@ -1,11 +1,9 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:kmobile/features/auth/controllers/auth_cubit.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
|
||||
import '../../../app.dart';
|
||||
import '../../dashboard/screens/dashboard_screen.dart';
|
||||
import '../../../api/services/auth_service.dart';
|
||||
import 'package:material_symbols_icons/get.dart';
|
||||
|
||||
class MPinScreen extends StatefulWidget {
|
||||
const MPinScreen({super.key});
|
||||
@@ -112,6 +110,8 @@ class MPinScreenState extends State<MPinScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cubit = context.read<AuthCubit>();
|
||||
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
@@ -131,7 +131,7 @@ class MPinScreenState extends State<MPinScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(onPressed: () {
|
||||
AuthService.authenticateWithBiometrics(context);
|
||||
cubit.authenticateBiometric();
|
||||
}, child: const Text("Try another way")),
|
||||
TextButton(onPressed: () {}, child: const Text("Register?")),
|
||||
],
|
||||
|
Reference in New Issue
Block a user