biometricPermission&Authentication
This commit is contained in:
parent
3108093686
commit
8fb84abe83
@ -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?")),
|
||||
],
|
||||
|
56
pubspec.lock
56
pubspec.lock
@ -472,6 +472,62 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.4"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.10"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -45,6 +45,7 @@ dependencies:
|
||||
flutter_svg: ^2.1.0
|
||||
local_auth: ^2.3.0
|
||||
material_symbols_icons: ^4.2815.0
|
||||
shared_preferences: ^2.5.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
x
Reference in New Issue
Block a user