From dc9266a0dae8dc09b69f27b566671795e905e643 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 23 Oct 2024 17:05:30 +0300 Subject: [PATCH] approval bottom sheet added. & improvements. --- assets/lottie/waiting.json | 1 + lib/new_views/app_style/app_color.dart | 4 + .../views/components/asset_detail_card.dart | 10 +- .../views/components/history_log_view.dart | 2 +- .../service_request_detail_view.dart | 32 +++--- .../views/components/verify_arrival_view.dart | 58 +++++++---- ...request_approval_waiting_bottom_sheet.dart | 99 +++++++++++++++++++ 7 files changed, 163 insertions(+), 43 deletions(-) create mode 100644 assets/lottie/waiting.json create mode 100644 lib/views/widgets/bottom_sheets/request_approval_waiting_bottom_sheet.dart diff --git a/assets/lottie/waiting.json b/assets/lottie/waiting.json new file mode 100644 index 00000000..c80cc548 --- /dev/null +++ b/assets/lottie/waiting.json @@ -0,0 +1 @@ +{"nm":"Timer","ddd":0,"h":48,"w":48,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"seconds","sr":1,"st":0,"op":480,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-21.625,0.32,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[24.375,23.781,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[235],"t":0},{"s":[595],"t":479}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"s":{"a":0,"k":[4,16],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0.2392,0.6471,0.898],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2392,0.6471,0.898],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,6.25],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-21.625,0.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"minutes","sr":1,"st":0,"op":480,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-21.625,2.422,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[24.375,23.781,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":112,"ix":4},"s":{"a":0,"k":[4,20],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0.2392,0.6471,0.898],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2392,0.6471,0.898],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-21.625,-5.75],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"background","sr":1,"st":0,"op":480,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0.504,2.008,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[24.379,23.758,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[24.5,24.5],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0.2392,0.6471,0.898],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.7451,0.902,1],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[186.718,186.718],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0.5,2],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3}],"v":"5.5.4","fr":60,"op":480,"ip":0,"assets":[]} \ No newline at end of file diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index 4cea6dae..448d1950 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -148,6 +148,10 @@ class AppColor { return green70.withOpacity(.5); case "reject": return red30; + case "cancelled": + return red30; + case "canceled": + return red30; default: return Colors.white; } diff --git a/lib/service_request_latest/views/components/asset_detail_card.dart b/lib/service_request_latest/views/components/asset_detail_card.dart index 406836a0..9eb011ec 100644 --- a/lib/service_request_latest/views/components/asset_detail_card.dart +++ b/lib/service_request_latest/views/components/asset_detail_card.dart @@ -44,28 +44,26 @@ class AssetDetailCard extends StatelessWidget { }), ]), 6.height, - context.translation.assetSituation.heading6(context).custom(color: AppColor.black20), - 6.height, + Text( + context.translation.assetSituation, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), Text( '${context.translation.returnToService}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService?.toAssetDetailsFormat ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - 6.height, Text( '${context.translation.loanAvailability}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.name ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - 6.height, Text( '${context.translation.failureReason}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.failureReason?.name ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - 6.height, Text( '${context.translation.faultDescription}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.faultDescription?.name ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), - 6.height, Text( '${context.translation.solutions}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.solution ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), diff --git a/lib/service_request_latest/views/components/history_log_view.dart b/lib/service_request_latest/views/components/history_log_view.dart index 851ed5c3..09840e6c 100644 --- a/lib/service_request_latest/views/components/history_log_view.dart +++ b/lib/service_request_latest/views/components/history_log_view.dart @@ -99,7 +99,7 @@ class HistoryLogView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ object.step!.name!.bodyText(context).custom(color: AppColor.black10), - object.timeDifference.isNotEmpty ? object.timeDifference.bodyText2(context).custom(color: AppColor.green70) : const SizedBox(), + object.timeDifference.isNotEmpty ? object.timeDifference.tinyFont(context).custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120) : const SizedBox(), ], ), ), diff --git a/lib/service_request_latest/views/components/service_request_detail_view.dart b/lib/service_request_latest/views/components/service_request_detail_view.dart index 229d7d52..fe0c6dc8 100644 --- a/lib/service_request_latest/views/components/service_request_detail_view.dart +++ b/lib/service_request_latest/views/components/service_request_detail_view.dart @@ -14,7 +14,6 @@ import 'package:test_sa/models/new_models/work_order_detail_model.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/service_request_latest/service_request_detail_provider.dart'; -import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart'; import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/service_request_latest/views/components/asset_detail_card.dart'; import 'package:test_sa/service_request_latest/views/components/initial_visit_card.dart'; @@ -32,7 +31,6 @@ class ServiceRequestDetailView extends StatelessWidget { Widget build(BuildContext context) { UserProvider _userProvider = Provider.of(context, listen: false); return Consumer(builder: (pContext, requestProvider, _) { - return requestProvider.isLoading ? const CircularProgressIndicator(color: AppColor.primary10).center : requestProvider.currentWorkOrder == null @@ -183,7 +181,7 @@ class ServiceRequestDetailView extends StatelessWidget { // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), // ), Text( - '${context.translation.requestNo}: ${workOrder.workOrderNo}', + '${context.translation.cmNumber}: ${workOrder.workOrderNo}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( @@ -194,11 +192,6 @@ class ServiceRequestDetailView extends StatelessWidget { '${context.translation.date}: ${workOrder.requestedDate!.toString().toServiceRequestDetailsFormat}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), ), - //TODO confirm the value... - Text( - '${context.translation.cmNumber}: ${workOrder.workOrderNo}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), const Divider().defaultStyle(context), //... call response details starts here.... @@ -231,14 +224,19 @@ class ServiceRequestDetailView extends StatelessWidget { const Divider().defaultStyle(context), 8.height, Text( - '${context.translation.callComments}: ${workOrder.comments!}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + context.translation.callComments, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + Text( + workOrder.comments!, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], if (workOrder.workOrderAttachments.isNotEmpty ?? false) ...[ 8.height, const Divider().defaultStyle(context), - FilesList(images: workOrder.workOrderAttachments.map((toElement) => URLs.getFileUrl(toElement.name??'')??'').toList()), + FilesList(images: workOrder.workOrderAttachments.map((toElement) => URLs.getFileUrl(toElement.name ?? '') ?? '').toList()), ], if (workOrder.voiceNote?.isNotEmpty ?? false) ...[ const Divider().defaultStyle(context), @@ -305,8 +303,8 @@ class ServiceRequestDetailView extends StatelessWidget { // // ); // }), //set condition for show asset detail button... - if ((workOrder.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.verifyAssetDetail || - workOrder.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) && userProvider.user?.type == UsersTypes.engineer) ...[ + if ((workOrder.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.verifyAssetDetail || workOrder.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) && + userProvider.user?.type == UsersTypes.engineer) ...[ assetRetiredButton(context: context), ] ], @@ -351,22 +349,22 @@ class ServiceRequestDetailView extends StatelessWidget { } } } + Widget assetDetailCard({required ServiceRequestDetailProvider requestDetailProvider, required UserProvider userProvider}) { - if (userProvider.user?.type == UsersTypes.engineer&&requestDetailProvider.currentWorkOrder?.data?.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) { + if (userProvider.user?.type == UsersTypes.engineer && requestDetailProvider.currentWorkOrder?.data?.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) { WorkOrderData currentWorkOrderData = requestDetailProvider.currentWorkOrder!.data!; requestDetailProvider.engineerUpdateWorkOrderHelperModel = EngineerUpdateWorkOrderHelperModel( workOrderId: currentWorkOrderData.requestId, equipmentStatus: currentWorkOrderData.equipmentStatus, loanAvailability: currentWorkOrderData.loanAvailablity, failureReason: currentWorkOrderData.failureReasone, - faultDescription: currentWorkOrderData.faultDescription, + faultDescription: currentWorkOrderData.faultDescription, solution: currentWorkOrderData.faultDescription?.workPerformed, returnToService: currentWorkOrderData.returnToService, serviceType: currentWorkOrderData.serviceType, ); return const AssetDetailCard(); - } - else { + } else { return const SizedBox(); } } diff --git a/lib/service_request_latest/views/components/verify_arrival_view.dart b/lib/service_request_latest/views/components/verify_arrival_view.dart index 227c0dce..2ed7ea48 100644 --- a/lib/service_request_latest/views/components/verify_arrival_view.dart +++ b/lib/service_request_latest/views/components/verify_arrival_view.dart @@ -1,10 +1,12 @@ import 'dart:convert'; import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_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'; @@ -12,6 +14,7 @@ import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/service_request_latest/service_request_detail_provider.dart'; import 'package:test_sa/service_request_latest/views/components/verify_otp_view.dart'; +import 'package:test_sa/views/widgets/bottom_sheets/request_approval_waiting_bottom_sheet.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/qr/scan_qr.dart'; @@ -66,12 +69,7 @@ class _VerifyArrivalViewState extends State { ); } - Widget customListItem({ - required String icon, - required String heading, - required String subHeading, - required VoidCallback onTap, - }) { + Widget customListItem({required String icon, required String heading, required String subHeading, required VoidCallback onTap}) { return GestureDetector( onTap: onTap, // Handles the tap child: Card( @@ -143,20 +141,22 @@ class _VerifyArrivalViewState extends State { break; case 1: try { - int? status; - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - status = await requestDetailProvider.engineerConfirmArrival( - workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!, verificationTypeId: verificationTypeId ?? 1, photoInfo: '', otp: ''); - if (status == 200) { - Navigator.pop(context); - requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); - Navigator.pop(context); - requestDetailProvider.startTimer(); - } else { - Navigator.pop(context); - } + showWaitingBottomSheet(); + + // int? status; + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + // status = await requestDetailProvider.engineerConfirmArrival( + // workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!, verificationTypeId: verificationTypeId ?? 1, photoInfo: '', otp: ''); + // if (status == 200) { + // Navigator.pop(context); + // requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); + // Navigator.pop(context); + // requestDetailProvider.startTimer(); + // } else { + // Navigator.pop(context); + // } } catch (e) { - Navigator.pop(context); + //Navigator.pop(context); } break; case 2: @@ -227,4 +227,24 @@ class _VerifyArrivalViewState extends State { } return fileImage; } + + void showWaitingBottomSheet() async { + bool? isArrived = (await showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => RequestApprovalBottomSheet(), + )); + if (isArrived==null) { + //Requester not confirmed you arrival".showToast; + + } else if(isArrived) { + try { + // todo @waseeem call api to confirm + } catch (ex) {} + }else { + "Requester not confirmed you arrival".showToast; + } + } } diff --git a/lib/views/widgets/bottom_sheets/request_approval_waiting_bottom_sheet.dart b/lib/views/widgets/bottom_sheets/request_approval_waiting_bottom_sheet.dart new file mode 100644 index 00000000..bd70a032 --- /dev/null +++ b/lib/views/widgets/bottom_sheets/request_approval_waiting_bottom_sheet.dart @@ -0,0 +1,99 @@ +import 'dart:io'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/material.dart'; +import 'package:google_api_availability/google_api_availability.dart'; +import 'package:huawei_push/huawei_push.dart' as h_push; +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'; + +class RequestApprovalBottomSheet extends StatefulWidget { + RequestApprovalBottomSheet({Key? key}) : super(key: key); + + @override + _RequestApprovalBottomState createState() { + return _RequestApprovalBottomState(); + } +} + +class _RequestApprovalBottomState extends State { + @override + void initState() { + super.initState(); + listenForApproval(); + } + + void listenForApproval() async { + if (Platform.isAndroid && !(await isGoogleServicesAvailable())) { + h_push.Push.onMessageReceivedStream.listen((h_push.RemoteMessage remoteMessage) { + print("onMessageReceivedStream:${remoteMessage.toMap()}"); + }, onError: (Object error) { + print("onMessageReceivedStream:${error?.toString()}"); + }); + } else { + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + Map messageData = message.data; + if (messageData["notificaitonType"] != null && messageData["arrived"] != null) { + if (messageData["notificaitonType"] == "arrivalConfirmation") { + if ((messageData["arrived"].toString()) == "true") { + Navigator.pop(context, true); + } else { + Navigator.pop(context, false); + } + } + } + }); + } + } + + static Future isGoogleServicesAvailable() async { + GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); + String status = availability.toString().split('.').last; + if (status == "success") { + return true; + } + return false; + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + clipBehavior: Clip.antiAlias, + width: double.infinity, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 24.toScreenHeight), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Waiting...".heading4(context), + 12.height, + Text( + "Request Sent, Waiting for requester to confirm arrival", + style: TextStyle( + fontSize: 16.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ), + ), + 12.height, + "waiting".toLottieAsset(height: 100).center, + 12.height, + ], + ), + ); + ; + } +}