From 262b3aa42f983e99694f4d8b11b6eba8bf3aadf5 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 28 Jul 2025 09:42:20 +0300 Subject: [PATCH] local auth fail handling and improvements. --- lib/controllers/api_routes/api_manager.dart | 1 - .../firebase_notification_manger.dart | 1 - .../notification/notification_manger.dart | 23 ++----- .../providers/api/notifications_provider.dart | 1 - .../api/service_requests_provider.dart | 4 +- .../service_request/service_request.dart | 2 - .../service_request_detail_provider.dart | 1 - .../components/internal_request.dart | 5 +- .../single_item_drop_down_menu.dart | 3 +- .../forget_passwod_verify_otp.dart | 37 +++++----- lib/new_views/pages/splash_page.dart | 41 +++++++---- .../dialoge/local_auth_failed_dialog.dart | 68 +++++++++++++++++++ .../add_supplier_engineer_bottom_sheet.dart | 3 +- .../requests/create_service_request_page.dart | 5 -- .../parts/auto_complete_parts_field.dart | 7 +- lib/views/widgets/sound/sound_player.dart | 4 +- .../widgets/status/single_status_menu.dart | 56 +++++++-------- 17 files changed, 153 insertions(+), 109 deletions(-) create mode 100644 lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart index 64ee3010..20c55464 100644 --- a/lib/controllers/api_routes/api_manager.dart +++ b/lib/controllers/api_routes/api_manager.dart @@ -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); diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index 50371c4f..16abd263 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -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( diff --git a/lib/controllers/notification/notification_manger.dart b/lib/controllers/notification/notification_manger.dart index b101bd3f..ab1df81a 100644 --- a/lib/controllers/notification/notification_manger.dart +++ b/lib/controllers/notification/notification_manger.dart @@ -31,7 +31,6 @@ class NotificationManger { } else if (Platform.isAndroid) { final AndroidFlutterLocalNotificationsPlugin? androidImplementation = localNotificationsPlugin.resolvePlatformSpecificImplementation(); 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 cancelNotificationById(int notificationId) async { await localNotificationsPlugin.cancel(notificationId); - print("Notification with ID $notificationId has been canceled."); } } diff --git a/lib/controllers/providers/api/notifications_provider.dart b/lib/controllers/providers/api/notifications_provider.dart index 2fc424d3..53d97eaa 100644 --- a/lib/controllers/providers/api/notifications_provider.dart +++ b/lib/controllers/providers/api/notifications_provider.dart @@ -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"]; diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 2ceeacf5..f9d24e20 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -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 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 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; diff --git a/lib/models/service_request/service_request.dart b/lib/models/service_request/service_request.dart index e2de1b54..f29eb77a 100644 --- a/lib/models/service_request/service_request.dart +++ b/lib/models/service_request/service_request.dart @@ -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 { diff --git a/lib/modules/cm_module/service_request_detail_provider.dart b/lib/modules/cm_module/service_request_detail_provider.dart index c5860eea..743dad6a 100644 --- a/lib/modules/cm_module/service_request_detail_provider.dart +++ b/lib/modules/cm_module/service_request_detail_provider.dart @@ -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) { diff --git a/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart b/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart index 74053c1f..a214591d 100644 --- a/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart +++ b/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart @@ -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 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) { diff --git a/lib/new_views/common_widgets/single_item_drop_down_menu.dart b/lib/new_views/common_widgets/single_item_drop_down_menu.dart index ae83c245..e552af1c 100644 --- a/lib/new_views/common_widgets/single_item_drop_down_menu.dart +++ b/lib/new_views/common_widgets/single_item_drop_down_menu.dart @@ -77,9 +77,8 @@ class _SingleItemDropDownMenuState 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 { diff --git a/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart b/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart index e6c81c27..955852a5 100644 --- a/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart +++ b/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart @@ -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 data={}; + Map data = {}; - ForgetPasswordVerifyOtpView({Key ?key,required this.data}) : super(key: key); + ForgetPasswordVerifyOtpView({Key? key, required this.data}) : super(key: key); @override State createState() => _ForgetPasswordVerifyOtpViewState(); @@ -25,7 +24,7 @@ class ForgetPasswordVerifyOtpView extends StatefulWidget { class _ForgetPasswordVerifyOtpViewState extends State { String otp = ''; - Timer? _timer; + Timer? _timer; int _remainingSeconds = 180; // 3 minutes in seconds @override @@ -111,17 +110,16 @@ class _ForgetPasswordVerifyOtpViewState extends State(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(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(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())); } } diff --git a/lib/new_views/pages/splash_page.dart b/lib/new_views/pages/splash_page.dart index b577179e..c250c7b0 100644 --- a/lib/new_views/pages/splash_page.dart +++ b/lib/new_views/pages/splash_page.dart @@ -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 { 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 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 { animation: "splash", callback: (animation) async { bool isSafe = await checkDeviceSafety(); - print('is safe is ${isSafe}'); + if (!isSafe) { Navigator.pushNamedAndRemoveUntil(context, UnsafeDeviceScreen.routeName, (_) => false); } else { diff --git a/lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart b/lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart new file mode 100644 index 00000000..b4aff661 --- /dev/null +++ b/lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart @@ -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(); + }, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart b/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart index 7f13df6c..fbc606dc 100644 --- a/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart +++ b/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart @@ -127,8 +127,7 @@ class _AddSupplierEngineerBottomSheetState extends State { _serviceRequest.requestedThrough = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null); _serviceRequest.type = Provider.of(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(); diff --git a/lib/views/widgets/parts/auto_complete_parts_field.dart b/lib/views/widgets/parts/auto_complete_parts_field.dart index bf9703cf..649d2d38 100644 --- a/lib/views/widgets/parts/auto_complete_parts_field.dart +++ b/lib/views/widgets/parts/auto_complete_parts_field.dart @@ -32,7 +32,6 @@ class _AutoCompletePartsFieldState extends State { @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 { 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 { labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), ), textInputAction: TextInputAction.search, - onChanged: (text){ - fieldTextEditingController.text =text; + onChanged: (text) { + fieldTextEditingController.text = text; }, onSubmitted: (String value) { onFieldSubmitted(); diff --git a/lib/views/widgets/sound/sound_player.dart b/lib/views/widgets/sound/sound_player.dart index 055379f9..edf8b377 100644 --- a/lib/views/widgets/sound/sound_player.dart +++ b/lib/views/widgets/sound/sound_player.dart @@ -158,7 +158,6 @@ class _ASoundPlayerState extends State { 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 { ).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)), ], ), ], diff --git a/lib/views/widgets/status/single_status_menu.dart b/lib/views/widgets/status/single_status_menu.dart index 52a6fbb8..003d6dac 100644 --- a/lib/views/widgets/status/single_status_menu.dart +++ b/lib/views/widgets/status/single_status_menu.dart @@ -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? statuses;// Nullable list + final List? 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 { @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 { @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 { @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 { 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( value: _selectedStatus, @@ -107,22 +97,22 @@ class _SingleStatusMenuState extends State { 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>((value) { + : (Lookup? newValue) { + // Nullable Lookup + setState(() { + _selectedStatus = newValue; + }); + widget.onSelect?.call(newValue); // Use null-aware operator + }, + items: widget.statuses?.map>((value) { return DropdownMenuItem( 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(), ), ], ), @@ -130,4 +120,4 @@ class _SingleStatusMenuState extends State { ), ); } -} \ No newline at end of file +}