Merge remote-tracking branch 'origin/wala_plus' into wala_plus

wala_plus
FaizHashmi 1 day ago
commit a165bf695d

@ -13,6 +13,7 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/dependent/get_mobile_login_info_dependent_model.dart';
import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart';
import 'package:mohem_flutter_app/models/member_login_list_model.dart';
import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart';
class LoginApiClient {
static final LoginApiClient _instance = LoginApiClient._internal();
@ -21,6 +22,25 @@ class LoginApiClient {
factory LoginApiClient() => _instance;
static String? _cachedSignature;
static Future<String?> getSignature() async {
if (!Platform.isAndroid) return null;
if (_cachedSignature != null && _cachedSignature!.isNotEmpty) {
return _cachedSignature;
}
try {
String? sig = await SmsVerification.getAppSignature();
if (sig != null && sig.isNotEmpty) {
_cachedSignature = sig;
}
return sig;
} catch (e) {
debugPrint("Error getting app signature: $e");
return null;
}
}
Future<GetMobileLoginInfoListModel?> getMobileLoginInfoNEW(String deviceToken, String deviceType, {int? memberType}) async {
String url = "${ApiConsts.erpRest}Mohemm_GetMobileLoginInfo_NEW";
Map<String, dynamic> postParams = {};
@ -186,8 +206,15 @@ class LoginApiClient {
}, url, postParams);
}
Future<BasicMemberInformationModel?> mohemmSendActivationCodeByOTPNotificationType(int isMobileFingerPrint, String? mobileNumber, int optSendType, String? pUserName) async {
Future<BasicMemberInformationModel?> mohemmSendActivationCodeByOTPNotificationType(
int isMobileFingerPrint,
String? mobileNumber,
int optSendType,
String? pUserName, {
String? smsSignature,
}) async {
String url = "${ApiConsts.erpRest}Mohemm_SendActivationCodebyOTPNotificationType";
String? sig = smsSignature ?? await getSignature();
Map<String, dynamic> postParams = {
"IsMobileFingerPrint": isMobileFingerPrint,
"MobileNumber": mobileNumber,
@ -197,6 +224,8 @@ class LoginApiClient {
"NotificationCenterAppSeviceGUID": ApiConsts.notificationCenterLoginServiceGUID,
};
postParams.addAll(AppState().postParamsJson);
postParams["smsSignature"] = sig ?? "";
postParams["SMSSignature"] = sig ?? "";
return await ApiClient().postJsonForObject((json) => GenericResponseModel.fromJson(json).basicMemberInformation, url, postParams);
}
@ -228,8 +257,9 @@ class LoginApiClient {
return await ApiClient().postJsonForObject((json) => GenericResponseModel.fromJson(json).basicMemberInformation, url, postParams);
}
Future<GenericResponseModel?> sendPublicActivationCode(String? mobileNumber, String? pUsername) async {
Future<GenericResponseModel?> sendPublicActivationCode(String? mobileNumber, String? pUsername, {String? smsSignature}) async {
String url = "${ApiConsts.erpRest}SendPublicActivationCode";
String? sig = smsSignature ?? await getSignature();
Map<String, dynamic> postParams = {
"MobileNumber": mobileNumber,
"P_MOBILE_NUMBER": mobileNumber,
@ -238,6 +268,8 @@ class LoginApiClient {
"NotificationCenterAppSeviceGUID": ApiConsts.notificationCenterForgotPasswordServiceGUID,
};
postParams.addAll(AppState().postParamsJson);
postParams["smsSignature"] = sig ?? "";
postParams["SMSSignature"] = sig ?? "";
return await ApiClient().postJsonForObject((json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
AppState().postParamsObject?.setLogInTokenID = responseData.logInTokenID;
@ -361,8 +393,10 @@ class LoginApiClient {
required String mobileNumber,
required String logInTokenID,
BuildContext? context,
String? smsSignature,
}) async {
String url = "${ApiConsts.erpRest}Mohemm_SendOTP_Dependent";
String? sig = smsSignature ?? await getSignature();
Map<String, dynamic> postParams = {
"VersionID": 20,
"Channel": 31,
@ -374,6 +408,8 @@ class LoginApiClient {
"P_DEP_NATIONAL_ID": nationalId,
"P_USER_NAME": nationalId,
"LogInTokenID": logInTokenID,
"smsSignature": sig ?? "",
"SMSSignature": sig ?? "",
};
return await ApiClient().postJsonForObject((json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);

@ -2,7 +2,6 @@ import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
@ -13,7 +12,6 @@ import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/models/get_notifications_response_model.dart';
import 'package:mohem_flutter_app/ui/notifications/notification_details_page.dart';
import 'package:permission_handler/permission_handler.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
@ -29,20 +27,14 @@ class AppNotifications {
String _huaweiToken = '';
late BuildContext context;
bool _isInitialized = false;
Future<void> requestPermissions() async {
if (Platform.isIOS) {
await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()?.requestPermissions(alert: true, badge: true, sound: true);
} else if (Platform.isAndroid) {
AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
bool? granted = await androidImplementation?.requestNotificationsPermission();
if (granted == false) {
if (kDebugMode) {
print("-------------------- Permission Granted ------------------------");
print(granted);
}
await Permission.notification.request();
}
AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
await androidImplementation?.requestNotificationsPermission();
}
}
@ -53,13 +45,11 @@ class AppNotifications {
this.context = context;
await requestPermissions();
if (!_isInitialized) {
_isInitialized = true;
await requestPermissions();
}
AppState().setDeviceToken = firebaseToken;
await Permission.notification.isDenied.then((bool value) {
if (value) {
Permission.notification.request();
}
});
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) _handleMessage(initialMessage);
@ -80,7 +70,7 @@ class AppNotifications {
// await hmsApiAvailability.isHMSAvailable().then((value) async {
if (!(await Utils.isGoogleServicesAvailable())) {
huawei_push.Push.enableLogger();
var result = await huawei_push.Push.setAutoInitEnabled(true);
await huawei_push.Push.setAutoInitEnabled(true);
huawei_push.Push.onNotificationOpenedApp.listen((message) {
// newMessage(toFirebaseRemoteMessage(message));

@ -1,14 +1,17 @@
import 'dart:async';
import 'dart:io';
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/login_api_client.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/otp_widget.dart';
import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart';
final ValueNotifier<String> otpFieldClear = ValueNotifier<String>("");
@ -24,10 +27,6 @@ class OtpDialog {
Future<Null>? timer;
static BuildContext? _context;
static bool? _loading;
OtpDialog(this.context, this.type, this.mobileNo, this.onSuccess, this.onFailure, {required this.onResendCode});
GlobalKey? verifyAccountForm = GlobalKey<FormState>();
@ -53,7 +52,6 @@ class OtpDialog {
// ProjectViewModel projectProvider;
String displayTime = '';
String? _code;
dynamic setState;
bool stopTimer = false;
bool isCodeExpired = false;
@ -62,6 +60,7 @@ class OtpDialog {
void displayDialog(BuildContext context) async {
otpFieldClear.value = "";
_startListeningForSms();
showDialog(
context: context,
barrierColor: Colors.black.withOpacity(0.63),
@ -203,6 +202,7 @@ class OtpDialog {
);
}).then((_) {
stopTimer = true;
_stopListeningForSms();
});
}
@ -277,28 +277,100 @@ class OtpDialog {
stopTimer = true;
});
} catch (_) {}
_stopListeningForSms();
}
});
}
void hideSMSBox(context) {
stopTimer = true;
_stopListeningForSms();
onFailure();
}
void _onOtpCallBack(String otpCode, bool? isAutofill) {
if (isCodeExpired) return;
if (otpCode.length == 4) {
_stopListeningForSms();
otpFieldClear.value = otpCode;
onSuccess(otpCode, _pinPutController);
}
}
// static getSignature() async {
// // if (Platform.isAndroid) {
// // return await SmsRetriever.getAppSignature();
// // } else {
// // return null;
// // }
// }
void _startListeningForSms() {
if (!Platform.isAndroid) return;
try {
SmsVerification.startListeningSms().then((String? message) {
if (stopTimer || isCodeExpired) return;
if (message != null && message.isNotEmpty) {
debugPrint("SMS OTP Auto-Verify received message: $message");
String? otpCode = extractOtpCode(message);
if (otpCode != null && otpCode.length == 4) {
debugPrint("Auto-filling OTP: $otpCode");
_pinPutController.text = otpCode;
_pinPutController.selection = TextSelection.collapsed(offset: otpCode.length);
_onOtpCallBack(otpCode, true);
}
}
}).catchError((e) {
debugPrint("Error in startListeningSms: $e");
});
} catch (e) {
debugPrint("Error starting SMS listening: $e");
}
}
void _stopListeningForSms() {
if (!Platform.isAndroid) return;
try {
SmsVerification.stopListening();
} catch (e) {
debugPrint("Error stopping SMS listening: $e");
}
}
static String? extractOtpCode(String? message) {
if (message == null || message.trim().isEmpty) return null;
String normalized = _normalizeDigits(message);
// 1. Try matching with OTP context keyword if available
RegExp contextRegex = RegExp(
r'(?:code|otp|رمز|كود|تفعيل|تحقق)[^\d]{0,15}(\d{4})\b',
caseSensitive: false,
);
Match? contextMatch = contextRegex.firstMatch(normalized);
if (contextMatch != null && contextMatch.group(1) != null) {
return contextMatch.group(1);
}
// 2. Try exact 4-digit word boundary match
Iterable<Match> matches = RegExp(r'\b\d{4}\b').allMatches(normalized);
if (matches.isNotEmpty) {
return matches.first.group(0);
}
// 3. Fallback
try {
Iterable<Match> allDigits = RegExp(r'\d{4}').allMatches(normalized);
if (allDigits.isNotEmpty) {
return allDigits.first.group(0);
}
} catch (_) {}
return null;
}
static String _normalizeDigits(String input) {
const String arabic = '٠١٢٣٤٥٦٧٨٩';
const String english = '0123456789';
String res = input;
for (int i = 0; i < arabic.length; i++) {
res = res.replaceAll(arabic[i], english[i]);
}
return res;
}
static Future<String?> getSignature() async {
return await LoginApiClient.getSignature();
}
}

@ -1,5 +1,3 @@
import 'package:mohem_flutter_app/app_state/app_state.dart';
class PostParamsModel {
double? versionID;
int? channel;
@ -15,6 +13,7 @@ class PostParamsModel {
String? payrollCodeStr;
int? pSessionId;
String? userName;
String? sMSSignature;
PostParamsModel({
this.versionID,
@ -31,6 +30,7 @@ class PostParamsModel {
this.pSelectedEmployeeNumber,
this.payrollCodeStr,
this.pLegislationCode,
this.sMSSignature,
});
PostParamsModel.fromJson(Map<String, dynamic> json) {
@ -95,4 +95,6 @@ class PostParamsModel {
set setPLegislationCode(String? v) => pLegislationCode = v?.trim().toUpperCase();
set setPayrollCodeStr(String? v) => payrollCodeStr = v;
set setSMSSignature(String? v) => sMSSignature = v;
set setSmsSignature(String? v) => sMSSignature = v;
}

@ -706,6 +706,7 @@ class _LoginScreenState extends State<LoginScreen> {
await LoginApiClient().mohemmSendOTPDependent(nationalId: nationalId.text.trim(), mobileNumber: mobileNumber, logInTokenID: logInTokenID, context: context);
Utils.hideLoading(context);
Utils.showToast(LocaleKeys.verificationCodeResent.tr());
_showDependentOtpDialog(logInTokenID, mobileNumber);
} catch (ex) {
Utils.hideLoading(context);
if (Utils.isMazayaAccessRevoked(ex)) {

@ -145,7 +145,7 @@ dependencies:
dotted_border: ^2.0.0+3
webview_flutter: ^4.13.0
nfc_manager: ^3.2.0
sms_otp_auto_verify: ^2.2.0
# saf: ^1.0.3+4

Loading…
Cancel
Save