local auth fail handling and improvements.

design_3.0_demo_module
Sikander Saleem 8 months ago
parent 633c2da82a
commit 262b3aa42f

@ -157,7 +157,6 @@ class ApiManager {
headers.addAll(_headers);
Uri url0 = Uri.parse(url);
print(url0);
// print(headers);
// log(json.encode(body));
var request = http.Request('PUT', url0);

@ -204,7 +204,6 @@ class FirebaseNotificationManger {
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('notification i got is ${message.toMap()}');
if (Platform.isAndroid) {
if (message.data["notificationType"] != 'NurseConfirmArrive') {
NotificationManger.showNotification(

@ -31,7 +31,6 @@ class NotificationManger {
} else if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation = localNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
final bool granted = await androidImplementation?.requestNotificationsPermission() ?? false;
print('permission value is $granted');
if (!granted) {
if (kDebugMode) {
print("-------------------- Permission Granted ------------------------");
@ -43,7 +42,8 @@ class NotificationManger {
await localNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed);
} // push new notification
static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
'com.hmg.atoms',
'ATOMS',
channelDescription: 'Push notification service for ATOMS',
@ -76,7 +76,6 @@ class NotificationManger {
// groupKey: 'com.hmg.atoms',
// );
// const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails(
// categoryIdentifier: "atoms",
// );
@ -86,16 +85,9 @@ class NotificationManger {
await localNotificationsPlugin.show(hashcode, title, subtext, platformChannel, payload: payload);
}
static Future scheduleNotification(
{int?id,
String? title,
String? body,
String? payLoad,
required DateTime scheduledNotificationDateTime}) async {
print('time i got is ${scheduledNotificationDateTime}');
static Future scheduleNotification({int? id, String? title, String? body, String? payLoad, required DateTime scheduledNotificationDateTime}) async {
return localNotificationsPlugin.zonedSchedule(
id??0,
id ?? 0,
title,
body,
// tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)),
@ -103,13 +95,12 @@ class NotificationManger {
scheduledNotificationDateTime,
tz.local,
),
const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails),
const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime);
}
static Future<void> cancelNotificationById(int notificationId) async {
await localNotificationsPlugin.cancel(notificationId);
print("Notification with ID $notificationId has been canceled.");
}
}

@ -52,7 +52,6 @@ class NotificationsProvider extends ChangeNotifier {
response = await ApiManager.instance.post(URLs.getSystemNotifications, body: body);
stateCode = response.statusCode;
print('notifaction response is ${response.body}');
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List requestsListJson = json.decode(response.body)["data"];

@ -7,7 +7,6 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart';
@ -268,7 +267,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
Future<PendingAssetServiceRequest?> checkAssetPendingRequest(int assetId) async {
Response response;
try {
response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId",body: {});
response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId", body: {});
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {}
return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]);
@ -423,7 +422,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
Future<CallRequest?> getCallRequestForWorkOrder({required String callId}) async {
Response response;
print('call id i got is ${callId}');
try {
response = await ApiManager.instance.get(URLs.getCallRequestForWorkOrder + "?callId=$callId");
stateCode = response.statusCode;

@ -102,7 +102,6 @@ class ServiceRequest {
List list = parsedJson["attachmentsCallRequest"];
images = list.map((e) => URLs.getFileUrl(e["name"]!) as String).toList();
}
// print(parsedJson["requestedDate"]??"");
return ServiceRequest(
id: parsedJson["id"].toString(),
@ -180,7 +179,6 @@ class ServiceRequest {
}
return true;
}
}
class CallCreatedBy {

@ -812,7 +812,6 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
body: {},
);
print('response i got is ${response.body}');
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
@ -119,9 +118,7 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
onPick: (time) {
requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time;
},
timerProgress: (isRunning) {
print("timerProgress:$isRunning");
},
timerProgress: (isRunning) {},
onChange: (timer) async {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer;
if (timer.startAt != null && timer.endAt != null) {

@ -77,9 +77,8 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
@override
void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) {
if (widget.initialValue != null) {
// print("$provider:start3:${DateTime.now()}");
final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
// print("$provider:start4:${DateTime.now()}");
if (result?.isNotEmpty ?? false) {
_selectedItem = result?.first as T?;
} else {

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:pinput/pinput.dart';
import 'package:provider/provider.dart';
@ -10,14 +9,14 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/forget_password_module/reset_password_view.dart';
class ForgetPasswordVerifyOtpView extends StatefulWidget {
Map<String,dynamic> data={};
Map<String, dynamic> data = {};
ForgetPasswordVerifyOtpView({Key ?key,required this.data}) : super(key: key);
ForgetPasswordVerifyOtpView({Key? key, required this.data}) : super(key: key);
@override
State<ForgetPasswordVerifyOtpView> createState() => _ForgetPasswordVerifyOtpViewState();
@ -25,7 +24,7 @@ class ForgetPasswordVerifyOtpView extends StatefulWidget {
class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpView> {
String otp = '';
Timer? _timer;
Timer? _timer;
int _remainingSeconds = 180; // 3 minutes in seconds
@override
@ -111,17 +110,16 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
InkWell(
onTap: _remainingSeconds == 0
? () async {
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
String employeeId = widget.data['employeeId'];
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(
context: context,
employeeId: employeeId,
);
print('Response of send OTP: ${response.toJson()}');
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
String employeeId = widget.data['employeeId'];
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(
context: context,
employeeId: employeeId,
);
// Restart the timer
_startTimer();
}
// Restart the timer
_startTimer();
}
: null,
child: Text(
'Resend',
@ -150,15 +148,16 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
).paddingOnly(start: 20, end: 20, bottom: 16),
);
}
void verifyOtp() async{
void verifyOtp() async {
if (otp.isNotEmpty) {
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
GeneralResponseModel generalResponseModel = await _userProvider.forgetPasswordValidateOtp(
context: context,
employeeId:widget.data['employeeId'],
employeeId: widget.data['employeeId'],
otp: otp,
);
if (generalResponseModel.isSuccess==true) {
if (generalResponseModel.isSuccess == true) {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ResetPasswordView()));
}
}

@ -15,6 +15,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart';
import 'package:test_sa/new_views/pages/login_page.dart';
import 'package:test_sa/new_views/pages/unsafe_device_view.dart';
import 'package:test_sa/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart';
import 'package:test_sa/new_views/swipe_module/swipe_view.dart';
import 'package:test_sa/views/update_available_screen.dart';
@ -84,24 +85,38 @@ class _SplashPageState extends State<SplashPage> {
loading = false;
});
if (isValid && _settingProvider.isLocalAuthEnable) {
bool isSuccess = await checkDualAuthentication();
if (isSuccess) {
_userProvider.setUser(_settingProvider.user!);
if (_userProvider.user!.onlySwipe!) {
Navigator.of(context).pushNamedAndRemoveUntil(SwipeView.routeName, (routes) => true);
} else {
Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true);
}
} else {
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
}
handleLocalAuth();
} else {
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
}
}
}
void handleLocalAuth() async {
bool isSuccess = await checkDualAuthentication();
if (isSuccess) {
_userProvider.setUser(_settingProvider.user!);
if (_userProvider.user!.onlySwipe!) {
Navigator.of(context).pushNamedAndRemoveUntil(SwipeView.routeName, (routes) => true);
} else {
Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true);
}
} else {
showDialog(
context: context,
builder: (BuildContext cxt) => LocalAuthFailedDialog(
onRetry: () {
handleLocalAuth();
},
onLogin: () {
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
},
),
);
}
}
Future<bool> checkDualAuthentication() async {
return await _settingProvider.auth.authenticate(
localizedReason: Platform.isAndroid ? "Scan your fingerprint to authenticate" : "Scan with face id to authenticate",
@ -139,7 +154,7 @@ class _SplashPageState extends State<SplashPage> {
animation: "splash",
callback: (animation) async {
bool isSafe = await checkDeviceSafety();
print('is safe is ${isSafe}');
if (!isSafe) {
Navigator.pushNamedAndRemoveUntil(context, UnsafeDeviceScreen.routeName, (_) => false);
} else {

@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
class LocalAuthFailedDialog extends StatelessWidget {
final String? title;
final String? message;
final String? okTitle;
final String? retryBtnText;
final String? loginBtnText;
final VoidCallback onRetry;
final VoidCallback onLogin;
const LocalAuthFailedDialog(
{Key? key, this.title, this.message = "Authentication Failed, Please try again or login", this.okTitle, required this.onRetry, required this.onLogin, this.retryBtnText, this.loginBtnText})
: super(key: key);
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(),
insetPadding: const EdgeInsets.only(left: 21, right: 21),
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Confirm",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black87, height: 35 / 24, letterSpacing: -0.96),
).paddingOnly(top: 16, bottom: 8),
message != null ? message!.heading5(context).custom(color: AppColor.neutral50) : const SizedBox(),
28.height,
Column(
children: [
AppFilledButton(
label: retryBtnText ?? "Retry",
onPressed: () {
Navigator.of(context).pop();
onRetry();
},
buttonColor: AppColor.primary90,
),
16.height,
AppFilledButton(
label: loginBtnText ?? "Login",
buttonColor: Colors.white54,
textColor: AppColor.black10,
height: 48,
showBorder: true,
onPressed: () {
Navigator.of(context).pop();
onLogin();
},
),
],
),
],
),
),
);
}
}

@ -127,8 +127,7 @@ class _AddSupplierEngineerBottomSheetState extends State<AddSupplierEngineerBott
}
engineer.personRoleId = suppEngRole?.id;
// print(engineer.toJson());
// return;
SuppEngineerWorkOrders? suppEngineer = await snapshot.addSupplierEngineer(engineer);
if (suppEngineer == null) {
Fluttertoast.showToast(msg: context.translation.failedToCompleteRequest);

@ -378,11 +378,6 @@ class CreateServiceRequestPageState extends State<CreateServiceRequestPage> {
_serviceRequest.requestedThrough = Provider.of<RequestedThroughProvider>(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null);
_serviceRequest.type = Provider.of<TypeOfRequestProvider>(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null);
// print("_serviceRequest?.requestedThrough:${_serviceRequest?.requestedThrough.toJson()}");
// print("_serviceRequest?.type:${_serviceRequest?.type.toJson()}");
// print("_serviceRequest?.priority:${_serviceRequest?.priority.toJson()}");
// return;
if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) {
_formKey.currentState!.save();

@ -32,7 +32,6 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
@override
void initState() {
print('initial value i got is ${widget.initialValue}');
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@ -75,7 +74,7 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
displayStringForOption: (SparePartsWorkOrders option) => widget.byName ? option.sparePart?.partName ?? "" : option.sparePart?.partNo ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,
controller: _controller,
focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start,
@ -96,8 +95,8 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120),
),
textInputAction: TextInputAction.search,
onChanged: (text){
fieldTextEditingController.text =text;
onChanged: (text) {
fieldTextEditingController.text = text;
},
onSubmitted: (String value) {
onFieldSubmitted();

@ -158,7 +158,6 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
if (_audio != widget.audio) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
_audio = widget.audio;
print('audio position i got is $_audioPosition');
if (_isLocalFile) {
await _audioPlayer.setSourceDeviceFile(_audio);
} else {
@ -199,7 +198,8 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
).paddingOnly(start: 8, end: 8).expanded,
_failedToLoad
? Text("Failed to load", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60))
: Text("${format(_audioPosition??Duration.zero)}/${format(_audioTime??Duration.zero)}", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
: Text("${format(_audioPosition ?? Duration.zero)}/${format(_audioTime ?? Duration.zero)}",
style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
],
),
],

@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import '../../../new_views/app_style/app_color.dart';
class SingleStatusMenu extends StatefulWidget {
final List<Lookup>? statuses;// Nullable list
final List<Lookup>? statuses; // Nullable list
final Lookup? initialStatus; // Nullable
final Function(Lookup?)? onSelect; // Nullable function, accepts nullable Lookup
final bool enabled;
@ -35,9 +35,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override
void didUpdateWidget(covariant SingleStatusMenu oldWidget) {
_selectedStatus = widget.statuses?.firstWhere(
(element) => element == widget.initialStatus,
orElse: null);
_selectedStatus = widget.statuses?.firstWhere((element) => element == widget.initialStatus, orElse: null);
if (widget.initialStatus != _selectedStatus) {
widget.onSelect?.call(_selectedStatus); // Use null-aware operator
@ -48,10 +46,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override
void initState() {
print('status lenght is ${widget.statuses?.length}');
_selectedStatus = widget.statuses?.firstWhere(
(element) => element == widget.initialStatus,
orElse: () => Lookup());
_selectedStatus = widget.statuses?.firstWhere((element) => element == widget.initialStatus, orElse: () => Lookup());
if (widget.initialStatus != _selectedStatus) {
widget.onSelect?.call(_selectedStatus); // Use null-aware operator
@ -62,25 +57,22 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override
Widget build(BuildContext context) {
return Container(height: 60.toScreenHeight,
return Container(
height: 60.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
decoration: BoxDecoration(
color: context.isDark && (!widget.enabled || widget.statuses!.isEmpty)
? AppColor.neutral50
: (!widget.enabled || widget.statuses!.isEmpty)
? AppColor.neutral40
: AppColor.background(context),
? AppColor.neutral40
: AppColor.background(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)
],
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Stack(
alignment: Alignment.center,
children: [
if (widget.enabled)
const PositionedDirectional(
end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
if (widget.enabled) const PositionedDirectional(end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
@ -88,9 +80,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
if (widget.title != null)
Text(
widget.title!, // Use null assertion operator
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: context.isDark ? null : AppColor.neutral20,
fontWeight: FontWeight.w500),
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
DropdownButton<Lookup>(
value: _selectedStatus,
@ -107,22 +97,22 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
underline: const SizedBox.shrink(),
onChanged: !widget.enabled
? null
: (Lookup? newValue) { // Nullable Lookup
setState(() {
_selectedStatus = newValue;
});
widget.onSelect?.call(newValue); // Use null-aware operator
},
items: widget.statuses
?.map<DropdownMenuItem<Lookup>>((value) {
: (Lookup? newValue) {
// Nullable Lookup
setState(() {
_selectedStatus = newValue;
});
widget.onSelect?.call(newValue); // Use null-aware operator
},
items: widget.statuses?.map<DropdownMenuItem<Lookup>>((value) {
return DropdownMenuItem<Lookup>(
value: value,
child: Text(value.name ?? "", // Use null-aware operator
child: Text(
value.name ?? "", // Use null-aware operator
style: Theme.of(context).textTheme.bodyLarge,
),
);
})
.toList(),
}).toList(),
),
],
),

Loading…
Cancel
Save