Biometric Auth

localization_aamir
Aamir.Muhammad 5 months ago
parent 7c84037601
commit cec6d171e0

@ -0,0 +1,56 @@
import 'package:flutter/services.dart';
import 'package:local_auth/local_auth.dart';
import 'package:local_auth_android/local_auth_android.dart';
import 'package:local_auth_ios/local_auth_ios.dart';
abstract class CommonAuthServices {
Future<bool> authenticate();
Future<List<BiometricType>> getAvailBio();
}
class CommonAuthImp implements CommonAuthServices {
final LocalAuthentication localAuth = LocalAuthentication();
Future<bool> authenticate() async {
try {
final availableBiometrics = await localAuth.getAvailableBiometrics();
if (availableBiometrics == null || availableBiometrics.isEmpty) {
return false;
}
final didAuthenticate = await localAuth.authenticate(
localizedReason: "Scan your fingerprint or face ID to authenticate",
options: const AuthenticationOptions(
stickyAuth: false,
biometricOnly: true,
sensitiveTransaction: true,
useErrorDialogs: true,
),
authMessages: [
const AndroidAuthMessages(
cancelButton: 'Cancel',
biometricHint: 'Please use your fingerprint or face ID',
goToSettingsButton: 'Settings',
goToSettingsDescription: 'Please set up your Touch ID.',
),
const IOSAuthMessages(
cancelButton: 'Cancel',
goToSettingsButton: 'Settings',
goToSettingsDescription: 'Please set up your Touch ID.',
lockOut: 'Please reenable your Touch ID',
),
],
);
return didAuthenticate;
} on PlatformException catch (e) {
print('Error during authentication: $e');
return false;
}
}
Future<List<BiometricType>> getAvailBio() async {
return await localAuth.getAvailableBiometrics();
}
}

@ -4,10 +4,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
import 'package:local_auth/local_auth.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/user_models/basic_otp.dart';
import 'package:mc_common_app/models/user_models/change_email.dart';
@ -23,6 +25,7 @@ import 'package:mc_common_app/models/user_models/register_user.dart';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/models/user_models/verify_email.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/common_auth_service.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/shared_prefrence.dart';
@ -142,7 +145,8 @@ class UserVM extends BaseVM {
}
}
Future<void> performCompleteProfile(BuildContext context, {
Future<void> performCompleteProfile(
BuildContext context, {
required String password,
required String confirmPassword,
required String firstName,
@ -480,8 +484,7 @@ class UserVM extends BaseVM {
if (basicOtp.messageStatus == 1) {
showMDialog(context, child: OtpDialog(
onClick: (String code) async {
if (reloadPage == null)
pop(context);
if (reloadPage == null) pop(context);
Utils.showLoading(context);
RegisterUserRespModel user = await userRepo.basicVerify(
countryCode + phoneNum,
@ -508,4 +511,28 @@ class UserVM extends BaseVM {
Utils.showToast(basicOtp.message ?? "");
}
}
// Aamir Code
List<BiometricType>? availBio;
Future<void> verifiyAuth({BuildContext? context, String? userToken, AppType? apptype}) async {
bool auth = await CommonAuthImp().authenticate();
if (auth) {
performBasicOtpLoginSelectionPage(context!, userToken: userToken!, appType: apptype!);
}
}
Future<void> getAvailBio() async {
availBio = await CommonAuthImp().getAvailBio();
}
bool isBioAvailable(BiometricType bioType) {
logger.d(availBio);
if (availBio == null) return true;
if (availBio!.contains(bioType)) {
return false;
} else {
return true;
}
}
}

@ -1,4 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:local_auth/local_auth.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
@ -12,18 +15,23 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class LoginMethodSelectionPage extends StatelessWidget {
class LoginMethodSelectionPage extends StatefulWidget {
final String userToken;
const LoginMethodSelectionPage(this.userToken, {Key? key}) : super(key: key);
@override
State<LoginMethodSelectionPage> createState() => _LoginMethodSelectionPageState();
}
class _LoginMethodSelectionPageState extends State<LoginMethodSelectionPage> {
@override
Widget build(BuildContext context) {
UserVM userVM = context.read<UserVM>();
UserVM userVM = context.read<UserVM>();
AppState appState = injector.get<AppState>();
print("current: ${appState.currentAppType}");
return Scaffold(
appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.log_in.tr()),
appBar: CustomAppBar(isRemoveBackButton: true, title: LocaleKeys.log_in.tr()),
body: Container(
width: double.infinity,
height: double.infinity,
@ -31,29 +39,39 @@ class LoginMethodSelectionPage extends StatelessWidget {
child: SingleChildScrollView(
child: Column(
children: [
LocaleKeys.loginSelection.tr().toText(fontSize: 20, letterSpacing: -1.44,),
LocaleKeys.loginSelection.tr().toText(
fontSize: 20,
letterSpacing: -1.44,
),
30.height,
LocaleKeys.welcomeBack.tr().toText(fontSize: 20, letterSpacing: -1.44,),
LocaleKeys.welcomeBack.tr().toText(
fontSize: 20,
letterSpacing: -1.44,
),
40.height,
Row(
children: [
Expanded(
child: ShowImageButton(
onClick: () {
userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken,appType: appState.currentAppType);
userVM.verifiyAuth(context: context, userToken: widget.userToken, apptype: appState.currentAppType);
//userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken,appType: appState.currentAppType);
},
title: LocaleKeys.fingerPrint.tr(),
icon: MyAssets.icFingerprintSvg,
isDisabled: userVM.isBioAvailable(Platform.isAndroid ? BiometricType.weak : BiometricType.fingerprint),
),
),
20.width,
Expanded(
child: ShowImageButton(
onClick: () {
userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken,appType: appState.currentAppType);
// userVM.performBasicOtpLoginSelectionPage(context, userToken: widget.userToken, appType: appState.currentAppType);
userVM.verifiyAuth(context: context, userToken: widget.userToken, apptype: appState.currentAppType);
},
title: LocaleKeys.faceRecognition.tr(),
icon: MyAssets.icFace,
isDisabled: userVM.isBioAvailable(Platform.isAndroid ? BiometricType.strong : BiometricType.face),
),
),
],
@ -64,7 +82,7 @@ class LoginMethodSelectionPage extends StatelessWidget {
Expanded(
child: ShowImageButton(
onClick: () {
userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken,appType: appState.currentAppType);
userVM.performBasicOtpLoginSelectionPage(context, userToken: widget.userToken, appType: appState.currentAppType);
},
title: LocaleKeys.SMS.tr(),
icon: MyAssets.icSmsSvg,
@ -75,7 +93,7 @@ class LoginMethodSelectionPage extends StatelessWidget {
child: ShowImageButton(
onClick: () {
// navigateWithName(context, AppRoutes.dashboard);
userVM.performBasicOtpLoginSelectionPage(context, userToken: userToken,appType: appState.currentAppType);
userVM.performBasicOtpLoginSelectionPage(context, userToken: widget.userToken, appType: appState.currentAppType);
},
title: LocaleKeys.whatsapp.tr(),
icon: MyAssets.icWhatsAppSvg,
@ -89,5 +107,4 @@ class LoginMethodSelectionPage extends StatelessWidget {
),
);
}
}

@ -51,6 +51,7 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
}
scheduleMicrotask(() {
userVM = Provider.of(context, listen: false);
context.read<UserVM>().getAvailBio();
getCountryList();
});
}

@ -1,4 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
@ -6,16 +6,28 @@ import 'package:mc_common_app/extensions/string_extensions.dart';
import '../../theme/colors.dart';
class ShowImageButton extends StatelessWidget {
class ShowImageButton extends StatefulWidget {
String icon, title;
VoidCallback onClick;
bool isDisabled;
ShowImageButton({required this.icon, required this.title, required this.onClick, this.isDisabled = false});
ShowImageButton({required this.icon, required this.title, required this.onClick});
@override
State<ShowImageButton> createState() => _ShowImageButtonState();
}
class _ShowImageButtonState extends State<ShowImageButton> {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onClick,
highlightColor: widget.isDisabled ? Colors.transparent : null, // Semi-transparent blue highlight
splashColor: widget.isDisabled ? Colors.transparent : null,
onTap: widget.isDisabled
? () {
if (kDebugMode) print("disabled");
}
: widget.onClick,
child: Container(
width: double.infinity,
child: Column(
@ -24,22 +36,22 @@ class ShowImageButton extends StatelessWidget {
width: double.infinity,
height: 120,
child: Card(
color: MyColors.darkPrimaryColor,
color: widget.isDisabled ? MyColors.primaryColor : MyColors.darkPrimaryColor,
shape: RoundedRectangleBorder(
side: const BorderSide(color: Colors.transparent, width: 1),
borderRadius: BorderRadius.circular(8),
),
child: Padding(
padding: EdgeInsets.all(26),
padding: const EdgeInsets.all(26),
child: SvgPicture.asset(
icon,
color: Colors.white,
widget.icon,
color: widget.isDisabled ? MyColors.chipColor : Colors.white,
),
),
),
),
6.height,
title.toText(color: Colors.black, isBold: true, fontSize: 16),
widget.title.toText(color: widget.isDisabled ? MyColors.chipColor : Colors.black, isBold: true, fontSize: 16),
],
),
),

@ -581,6 +581,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.4"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
lints:
dependency: transitive
description:
@ -649,26 +673,26 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.0"
mime:
dependency: transitive
description:
@ -697,10 +721,10 @@ packages:
dependency: transitive
description:
name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.8.3"
version: "1.9.0"
path_drawing:
dependency: transitive
description:
@ -1154,14 +1178,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
web:
vm_service:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "0.3.0"
version: "13.0.0"
web_socket_channel:
dependency: transitive
description:

@ -52,6 +52,10 @@ dependencies:
geocoding: ^2.1.1
# Auth
local_auth: ^2.2.0
dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save