From ad1a01b7c6081481617265693a04a65cd5009f12 Mon Sep 17 00:00:00 2001 From: Muhammad Abbasi Date: Tue, 27 Aug 2024 10:59:59 +0300 Subject: [PATCH] initial commit --- .../gradle/wrapper/gradle-wrapper.properties | 2 +- assets/images/ask_otp_icon.svg | 4 + assets/images/ask_requester_icon.svg | 4 + assets/images/delete_icon.svg | 4 + assets/images/edit_icon.svg | 5 + assets/images/login_top_bg.png | Bin 0 -> 55685 bytes assets/images/maintenance_icon.svg | 3 + assets/images/overdue.svg | 6 +- assets/images/retired_asset_icon.svg | 4 + assets/images/scan_qr_icon.svg | 8 + assets/images/spare_part_icon.svg | 9 + assets/images/take_device_photo_icon.svg | 8 + lib/app_strings/app_asset.dart | 13 + lib/controllers/api_routes/urls.dart | 4 +- .../providers/api/all_requests_provider.dart | 145 ++- .../providers/api/notifications_provider.dart | 1 + .../api/service_requests_provider.dart | 55 +- lib/dashboard_latest/dashboard_view.dart | 139 +++ .../widgets/app_bar_widget.dart | 120 +++ lib/extensions/text_extensions.dart | 14 +- lib/extensions/widget_extensions.dart | 13 + lib/l10n/app_ar.arb | 46 + lib/l10n/app_en.arb | 46 + lib/new_views/app_style/app_color.dart | 23 +- .../common_widgets/app_dashed_button.dart | 4 +- .../common_widgets/app_text_form_field.dart | 7 +- .../common_widgets/default_app_bar.dart | 3 +- .../single_item_drop_down_menu.dart | 10 +- lib/new_views/common_widgets/tab_button.dart | 84 ++ .../progress_fragment.dart | 225 +++-- .../recent_activites_fragment.dart | 133 ++- .../request_category_fragment.dart | 265 ++++++ .../request_category_list.dart | 54 ++ .../requests_fragment.dart | 544 +++++++++-- lib/new_views/pages/land_page/land_page.dart | 3 +- .../my_request/all_requests_search_page.dart | 2 + .../my_request/my_requests_page.dart | 4 + .../requests/service_request_item_view.dart | 13 +- .../widgets/request_item_view_list.dart | 2 + lib/new_views/pages/login_page.dart | 311 +++++-- .../components/activities_list_view.dart | 146 +++ .../views/components/activity_card_view.dart | 88 ++ .../bottom_sheets/action_bottomsheet.dart | 89 ++ .../activity_type_bottomsheet.dart | 129 +++ .../initial_visit_bottomsheet.dart | 217 +++++ .../reject_request_bottomsheet.dart | 236 +++++ .../service_request_bottomsheet.dart | 860 ++++++++++++++++++ .../views/components/history_log_view.dart | 60 ++ .../views/components/scan_qr_view.dart | 72 ++ .../views/components/spare_part_request.dart | 250 +++++ .../views/components/verify_arrival_view.dart | 114 +++ .../views/components/verify_otp_view.dart | 124 +++ .../views/request_detail_view.dart | 393 ++++++++ lib/utilities/general_utils.dart | 48 + lib/utilities/request_utils.dart | 18 + lib/views/app_style/colors.dart | 2 +- .../pages/user/requests/requests_page.dart | 3 +- .../work_order/work_order_details_page.dart | 4 +- .../work_order/work_orders_list_page.dart | 122 +-- .../widgets/buttons/rounded_back_button.dart | 29 + .../widgets/date_and_time/date_picker.dart | 11 +- .../widgets/date_and_time/time_picker.dart | 160 ++-- .../requests/service_request_list.dart | 3 + lib/views/widgets/timer/app_timer.dart | 4 +- localization_error.txt | 9 + pubspec.lock | 32 + pubspec.yaml | 4 + 67 files changed, 5172 insertions(+), 395 deletions(-) create mode 100644 assets/images/ask_otp_icon.svg create mode 100644 assets/images/ask_requester_icon.svg create mode 100644 assets/images/delete_icon.svg create mode 100644 assets/images/edit_icon.svg create mode 100644 assets/images/login_top_bg.png create mode 100644 assets/images/maintenance_icon.svg create mode 100644 assets/images/retired_asset_icon.svg create mode 100644 assets/images/scan_qr_icon.svg create mode 100644 assets/images/spare_part_icon.svg create mode 100644 assets/images/take_device_photo_icon.svg create mode 100644 lib/app_strings/app_asset.dart create mode 100644 lib/dashboard_latest/dashboard_view.dart create mode 100644 lib/dashboard_latest/widgets/app_bar_widget.dart create mode 100644 lib/new_views/common_widgets/tab_button.dart create mode 100644 lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart create mode 100644 lib/new_views/pages/land_page/dashboard_fragments/request_category_list.dart create mode 100644 lib/service_request_latest/views/components/activities_list_view.dart create mode 100644 lib/service_request_latest/views/components/activity_card_view.dart create mode 100644 lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart create mode 100644 lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart create mode 100644 lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart create mode 100644 lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart create mode 100644 lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart create mode 100644 lib/service_request_latest/views/components/history_log_view.dart create mode 100644 lib/service_request_latest/views/components/scan_qr_view.dart create mode 100644 lib/service_request_latest/views/components/spare_part_request.dart create mode 100644 lib/service_request_latest/views/components/verify_arrival_view.dart create mode 100644 lib/service_request_latest/views/components/verify_otp_view.dart create mode 100644 lib/service_request_latest/views/request_detail_view.dart create mode 100644 lib/utilities/general_utils.dart create mode 100644 lib/utilities/request_utils.dart create mode 100644 lib/views/widgets/buttons/rounded_back_button.dart create mode 100644 localization_error.txt diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index cc5527d7..02e5f581 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip diff --git a/assets/images/ask_otp_icon.svg b/assets/images/ask_otp_icon.svg new file mode 100644 index 00000000..125c8ec9 --- /dev/null +++ b/assets/images/ask_otp_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/ask_requester_icon.svg b/assets/images/ask_requester_icon.svg new file mode 100644 index 00000000..27a23080 --- /dev/null +++ b/assets/images/ask_requester_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/delete_icon.svg b/assets/images/delete_icon.svg new file mode 100644 index 00000000..66b294bb --- /dev/null +++ b/assets/images/delete_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/edit_icon.svg b/assets/images/edit_icon.svg new file mode 100644 index 00000000..3b49167b --- /dev/null +++ b/assets/images/edit_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/login_top_bg.png b/assets/images/login_top_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..0034abc3431cdd53b9ea2e0e67affb765c2f15de GIT binary patch literal 55685 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 literal 0 HcmV?d00001 diff --git a/assets/images/maintenance_icon.svg b/assets/images/maintenance_icon.svg new file mode 100644 index 00000000..c58f5940 --- /dev/null +++ b/assets/images/maintenance_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/overdue.svg b/assets/images/overdue.svg index ee9de58c..ece17cbd 100644 --- a/assets/images/overdue.svg +++ b/assets/images/overdue.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/assets/images/retired_asset_icon.svg b/assets/images/retired_asset_icon.svg new file mode 100644 index 00000000..49b49b55 --- /dev/null +++ b/assets/images/retired_asset_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/scan_qr_icon.svg b/assets/images/scan_qr_icon.svg new file mode 100644 index 00000000..a9eec41b --- /dev/null +++ b/assets/images/scan_qr_icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/images/spare_part_icon.svg b/assets/images/spare_part_icon.svg new file mode 100644 index 00000000..6da137b4 --- /dev/null +++ b/assets/images/spare_part_icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/images/take_device_photo_icon.svg b/assets/images/take_device_photo_icon.svg new file mode 100644 index 00000000..a9eec41b --- /dev/null +++ b/assets/images/take_device_photo_icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/app_strings/app_asset.dart b/lib/app_strings/app_asset.dart new file mode 100644 index 00000000..ced32514 --- /dev/null +++ b/lib/app_strings/app_asset.dart @@ -0,0 +1,13 @@ +class AppAsset{ + static String loginTopBg = 'assets/images/login_top_bg.png'; + static String askOtpIcon = 'assets/images/ask_otp_icon.svg'; + static String askRequesterIcon = 'assets/images/ask_requester_icon.svg'; + static String scanQrIcon = 'assets/images/scan_qr_icon.svg'; + static String takeDevicePhotoIcon = 'assets/images/take_device_photo_icon.svg'; + static String maintenanceIcon = 'assets/images/maintenance_icon.svg'; + static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg'; + static String sparePartIcon = 'assets/images/spare_part_icon.svg'; + static String editIcon = 'assets/images/edit_icon.svg'; + static String deleteIcon = 'assets/images/delete_icon.svg'; + static String overDueIcon = 'assets/images/overdue.svg'; +} \ No newline at end of file diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f996ac10..11e73fde 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,8 +1,8 @@ class URLs { URLs._(); - static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local UAT url + // static const host1 = "https://atomsm.hmg.com"; // production url + static const host1 = "https://atomsmdev.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; static String _baseUrl = "$_host/v2/mobile"; // new V2 apis diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 742e8add..002350ec 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -17,15 +17,36 @@ class AllRequestsProvider extends ChangeNotifier { bool isOverdueLoading = false; bool isHighPriorityLoading = false; bool isCalendarLoading = false; + bool _isFilterRequestLoading = false; + + + + int _currentListIndex = 0; + + int get currentListIndex => _currentListIndex; + + set currentListIndex(int value) { + _currentListIndex = value; + notifyListeners(); + } int stateCode; AllRequestsAndCount allRequestsAndCount; - AllRequestsAndCount openRequests; - AllRequestsAndCount inProgressRequests; - AllRequestsAndCount completedRequests; + AllRequestsAndCount _openRequests; + AllRequestsAndCount _inProgressRequests; + AllRequestsAndCount _completedRequests; + AllRequestsAndCount _filterRequest; AllRequestsAndCount overdueRequests; AllRequestsAndCount highPriorityRequests; + + bool isLoadingList = false; + + updateIsLoadingList(value) { + isLoadingList = value; + notifyListeners(); + } + AllRequestsAndCount calendarRequests; final pageItemNumber = 10; @@ -41,6 +62,7 @@ class AllRequestsProvider extends ChangeNotifier { } void resetRequestsApiData() { + print('reset api data called..'); highPriorityRequests = null; overdueRequests = null; openRequests = null; @@ -51,13 +73,13 @@ class AllRequestsProvider extends ChangeNotifier { stateCode = null; } - void getRequests() { + Future getRequests() async { resetRequestsApiData(); - getHighPriorityRequests(pagination: true); - getOverdueRequests(pagination: true); - getOpenRequests(pagination: true); - getInProgressRequests(pagination: true); - getCompletedRequests(pagination: true); + await getHighPriorityRequests(pagination: true); + await getOverdueRequests(pagination: true); + await getOpenRequests(pagination: true); + await getInProgressRequests(pagination: true); + await getCompletedRequests(pagination: true); } SearchAllRequestsModel searchedModel; @@ -70,11 +92,7 @@ class AllRequestsProvider extends ChangeNotifier { try { if (search != null) { searchedModel = search; - } - - - - else { + } else { searchedModel = null; } final type = typeTransaction == null @@ -318,6 +336,7 @@ class AllRequestsProvider extends ChangeNotifier { } Future getInProgressRequests({bool pagination = false, bool reset = false}) async { + print('get inprogress request called..'); if (isInProgressLoading == true) return -2; if (reset) { inProgressRequests = null; @@ -343,13 +362,19 @@ class AllRequestsProvider extends ChangeNotifier { body["pageSize"] = pageItemNumber; } response = await ApiManager.instance.post(URLs.getAllRequestsAndCount, body: body); - + print('response body of inprogress is ${response.body}'); stateCode = response.statusCode; + print('state code is $stateCode'); if (response.statusCode >= 200 && response.statusCode < 300) { if (inProgressRequests == null) { + print('in in null check...'); inProgressRequests = AllRequestsAndCount.fromJson(json.decode(response.body)["data"][0]); + notifyListeners(); + print('data in null check is ${inProgressRequests.requestsDetails.length}'); } else { inProgressRequests.requestsDetails.addAll(AllRequestsAndCount.fromJson(json.decode(response.body)["data"][0]).requestsDetails); + print('data i have in provider is ${inProgressRequests.requestsDetails.length}'); + notifyListeners(); } if (inProgressRequests.requestsDetails.length >= pageItemNumber) { nextPage = true; @@ -370,6 +395,60 @@ class AllRequestsProvider extends ChangeNotifier { return -1; } } + Future getFilterRequests({bool pagination = false, int status}) async { + // if (filterRequest == null || pagination) { + // isFilterRequestLoading = true; + // notifyListeners(); + // } + isFilterRequestLoading = true; + Response response; + try { + Map body = { + "typeTransaction": [1, 2, 3, 4], + "statusTransaction": [status], + "priority": [], + "displayData": [] + }; + if (pagination) { + body["pageNumber"] = 0; + body["pageSize"] = 0; + } else { + body["pageNumber"] = pageNum++; + body["pageSize"] = pageItemNumber; + } + response = await ApiManager.instance.post(URLs.getAllRequestsAndCount, body: body); + print('response body is ${response.body}'); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + if (filterRequest == null) { + filterRequest = AllRequestsAndCount.fromJson(json.decode(response.body)["data"][0]); + isFilterRequestLoading = false; + notifyListeners(); + print('filter list data in provider is ${filterRequest.requestsDetails.length}'); + } else { + filterRequest.requestsDetails.addAll(AllRequestsAndCount.fromJson(json.decode(response.body)["data"][0]).requestsDetails); + isFilterRequestLoading = false; + notifyListeners(); + } + if (filterRequest.requestsDetails.length >= pageItemNumber) { + nextPage = true; + } else { + nextPage = false; + } + notifyListeners(); + } else { + filterRequest = null; + } + isFilterRequestLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isFilterRequestLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } Future getCompletedRequests({bool pagination = false, bool reset = false}) async { if (isCompleteLoading == true) return -2; @@ -405,6 +484,7 @@ class AllRequestsProvider extends ChangeNotifier { } else { completedRequests.requestsDetails.addAll(AllRequestsAndCount.fromJson(json.decode(response.body)["data"][0]).requestsDetails); } + print('completed request length is ${completedRequests.requestsDetails.length}'); if (completedRequests.requestsDetails.length >= pageItemNumber) { nextPage = true; } else { @@ -425,6 +505,41 @@ class AllRequestsProvider extends ChangeNotifier { } } + + AllRequestsAndCount get inProgressRequests => _inProgressRequests; + + set inProgressRequests(AllRequestsAndCount value) { + _inProgressRequests = value; + notifyListeners(); + } + + AllRequestsAndCount get completedRequests => _completedRequests; + + set completedRequests(AllRequestsAndCount value) { + _completedRequests = value; + notifyListeners(); + } + + AllRequestsAndCount get openRequests => _openRequests; + + set openRequests(AllRequestsAndCount value) { + _openRequests = value; + notifyListeners(); + } + + AllRequestsAndCount get filterRequest => _filterRequest; + + set filterRequest(AllRequestsAndCount value) { + _filterRequest = value; + notifyListeners(); + } + bool get isFilterRequestLoading => _isFilterRequestLoading; + + set isFilterRequestLoading(bool value) { + _isFilterRequestLoading = value; + notifyListeners(); + } + // Future getCloseRequests() async { // if (isCloseLoading == true) return -2; // isCloseLoading = true; diff --git a/lib/controllers/providers/api/notifications_provider.dart b/lib/controllers/providers/api/notifications_provider.dart index 4cbd1a7e..75fec696 100644 --- a/lib/controllers/providers/api/notifications_provider.dart +++ b/lib/controllers/providers/api/notifications_provider.dart @@ -53,6 +53,7 @@ class NotificationsProvider extends ChangeNotifier { response = await ApiManager.instance.post(URLs.getSystemNotifications, body: body); stateCode = response.statusCode; + print('notifaction response is ${response}'); if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received // List requestsListJson = json.decode(utf8.decode(response.bodyBytes)); diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 1d9cd6c1..e3890ddc 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -16,6 +16,7 @@ import 'package:test_sa/models/service_request/pending_service_request_model.dar import 'package:test_sa/models/service_request/service_report.dart'; import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/service_request/service_request_search.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; import 'package:test_sa/models/service_request/supplier_engineer_model.dart'; import 'package:test_sa/models/timer_model.dart'; @@ -41,13 +42,46 @@ class ServiceRequestsProvider extends ChangeNotifier { // like 400 customer request failed // 500 service not available int stateCode; + bool _isDetialLoading=false; - // true if there is next page in product list and false if not + bool get isDetialLoading => _isDetialLoading; + + set isDetialLoading(bool value) { + _isDetialLoading = value; + notifyListeners(); + } // true if there is next page in product list and false if not bool nextPage = true; + TimeOfDay _selectedTime ; + + TimeOfDay get selectedTime => _selectedTime; - // list of user requests + set selectedTime(TimeOfDay value) { + _selectedTime = value; + notifyListeners(); + } // list of user requests List serviceRequests; List workOrders = []; + List _sparePartList = []; + + + + SparePartsWorkOrders _initialSelectedSparePart = SparePartsWorkOrders(); + ServiceRequest _currentSelectedRequest; + int _selectedListIndex = 0; + + int get selectedListIndex => _selectedListIndex; + + set selectedListIndex(int value) { + _selectedListIndex = value; + notifyListeners(); + } + + ServiceRequest get currentSelectedRequest => _currentSelectedRequest; + + set currentSelectedRequest(ServiceRequest value) { + _currentSelectedRequest = value; + notifyListeners(); + } // when requests in-process _loading = true // done _loading = true @@ -591,13 +625,17 @@ class ServiceRequestsProvider extends ChangeNotifier { Future getServiceRequestObjectById({@required String requestId}) async { try { + isDetialLoading = true; Response response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId"); if (response.statusCode >= 200 && response.statusCode < 300) { + isDetialLoading=false; return ServiceRequest.fromJson(json.decode(response.body)["data"]); } else { + isDetialLoading=false; return null; } } catch (error) { + isDetialLoading=false; return null; } } @@ -693,4 +731,17 @@ class ServiceRequestsProvider extends ChangeNotifier { return res; } } + + SparePartsWorkOrders get initialSelectedSparePart => _initialSelectedSparePart; + + set initialSelectedSparePart(SparePartsWorkOrders value) { + _initialSelectedSparePart = value; + notifyListeners(); + } + List get sparePartList => _sparePartList; + + set sparePartList(List value) { + _sparePartList = value; + notifyListeners(); + } } diff --git a/lib/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart new file mode 100644 index 00000000..b5bf1cf6 --- /dev/null +++ b/lib/dashboard_latest/dashboard_view.dart @@ -0,0 +1,139 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +import 'package:test_sa/controllers/notification/notification_manger.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/dashboard_latest/widgets/app_bar_widget.dart'; +import 'package:test_sa/extensions/context_extension.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/models/user.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart'; +import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart'; +import 'package:test_sa/utilities/request_utils.dart'; + +import '../new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart'; + +class DashboardView extends StatefulWidget { + final VoidCallback onDrawerPress; + + const DashboardView({Key key, this.onDrawerPress}) : super(key: key); + + @override + State createState() => _DashboardViewState(); +} + +class _DashboardViewState extends State { + int _currentPage = 0; + bool isFCM = true; + User user; + + SettingProvider settingProvider; + UserProvider userProvider; + + AllRequestsProvider allRequestsProvider; + + NotificationsProvider notificationsProvider; + + @override + void initState() { + super.initState(); + getInitialData(); + } + + void getInitialData() { + scheduleMicrotask(() async { + userProvider = Provider.of(context, listen: false); + settingProvider = Provider.of(context, listen: false); + allRequestsProvider = Provider.of(context, listen: false); + user = userProvider.user; + await getAllRequests(); + + if (isFCM) { + FirebaseNotificationManger.initialized(context); + NotificationManger.initialisation((notificationDetails) { + FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload)); + }, (id, title, body, payload) async {}); + + isFCM = false; + } + }); + } + + Future getAllRequests() async { + allRequestsProvider.isAllLoading = true; + allRequestsProvider.isFilterRequestLoading = true; + allRequestsProvider.currentListIndex = 0; + allRequestsProvider.filterRequest = null; + var tabs = RequestUtils.getTabs(userType: userProvider.user.type, context: context); + Future.wait([ + allRequestsProvider.getRequests(), + allRequestsProvider.getFilterRequests(pagination: false, status: tabs[0]['status']), + ]).whenComplete(() { + allRequestsProvider.isAllLoading = false; + }); + + print('user provider user data is ${userProvider.user.type}'); + await notificationsProvider.getSystemNotifications(user: userProvider.user, resetProvider: true); + } + + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + // backgroundColor: AppColor.background(context), + appBar: PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight), + child: AppBarWidget( + onDrawerPress: widget.onDrawerPress, + )), + body: RefreshIndicator( + onRefresh: () async { + await getInitialData(); + return Future.delayed(const Duration(milliseconds: 250)); + }, + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.welcome, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + user == null ? "" : (user?.username ?? ""), + style: AppTextStyles.heading2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600), + ), + // 24.height, + + ProgressFragment(), + 35.height, + SizedBox(height: 105.toScreenHeight, child: const RequestsFragment()), + const RequestCategoryFragment() + ], + ).paddingOnly(start: 16, end: 16, top: 0, bottom: 8), + ], + ), + ), + ), + ); + } +} diff --git a/lib/dashboard_latest/widgets/app_bar_widget.dart b/lib/dashboard_latest/widgets/app_bar_widget.dart new file mode 100644 index 00000000..451436d7 --- /dev/null +++ b/lib/dashboard_latest/widgets/app_bar_widget.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_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/views/pages/user/notifications/notifications_page.dart'; + +import '../../controllers/providers/api/user_provider.dart'; +import '../../models/user.dart'; + +class AppBarWidget extends StatelessWidget { + final VoidCallback onDrawerPress; + const AppBarWidget({Key key, this.onDrawerPress}) : super(key: key); + + @override + Widget build(BuildContext context) { + return AppBar( + automaticallyImplyLeading: false, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + titleSpacing: 0, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Consumer(builder: (context, snapshot, _) { + return CircleAvatar( + radius: 24, + backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral40, + child: Padding( + padding: const EdgeInsets.all(1), // Border radius + child: ClipOval( + child: snapshot.profileImage != null + ? Image.file(snapshot.profileImage) + : (snapshot.user.profilePhotoName?.isNotEmpty ?? false) + ? Image.network(snapshot.user.profilePhotoName) + : const Icon(Icons.person, size: 24, color: Colors.white), + ), + ), + ); + }).onPress(onDrawerPress), + const Spacer(), + Consumer( + builder: (context, settingProvider,child) { + return Container( + padding: const EdgeInsets.fromLTRB(12, 6, 6, 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: AppColor.background(context), + boxShadow: const [ + BoxShadow( + color: Color(0x07000000), + blurRadius: 14, + offset: Offset(0, 0), + spreadRadius: 0, + ) + ], + ), + child: DropdownButton( + value: settingProvider.assetGroup, + //iconSize: 24, + isDense: true, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 8, + // dropdownColor: Colors.amber, + borderRadius: BorderRadius.circular(8), + style: TextStyle(color: Theme.of(context).primaryColor), + underline: const SizedBox.shrink(), + onChanged: (newValue) { + if (settingProvider.assetGroup != newValue) { + settingProvider.setAssetGroup(newValue); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).getRequests(); + Provider.of(context, listen: false).getSystemNotifications(user: Provider.of(context, listen: false).user, resetProvider: true); + }); + } + }, + items: Provider.of(context, listen: false).user.assetGroups.map>((value) { + return DropdownMenuItem( + value: value, + child: Text( + value?.name ?? "", + style: Theme.of(context).textTheme.bodyLarge, + ), + ); + })?.toList(), + ), + ); + } + ), + 16.width, + Stack( + alignment: Alignment.topRight, + children: [ + Icon(Icons.notifications, color: context.isDark ? AppColor.neutral30 : AppColor.neutral20, size: 30).paddingOnly(top: 6, end: 0), + // todo @sikander will add count for unread notifications + // Positioned( + // top: 0, + // right: 0, + // child: Container( + // padding: const EdgeInsets.all(4), + // decoration: const ShapeDecoration( + // color: Color(0xFFD02127), + // shape: CircleBorder(), + // ), + // child: Text("", style: AppTextStyles.bodyText), + // ), + // ) + ], + ).onPress(() { + Navigator.of(context).pushNamed(NotificationsPage.id); + }), + ], + ).paddingOnly(start: 16, end: 16), + ); + } +} diff --git a/lib/extensions/text_extensions.dart b/lib/extensions/text_extensions.dart index d33cee7d..325bded8 100644 --- a/lib/extensions/text_extensions.dart +++ b/lib/extensions/text_extensions.dart @@ -16,6 +16,7 @@ extension TextStyles on String { Text heading4(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading4, context.isDark ? AppColor.neutral30 : AppColor.neutral50); Text heading5(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading5, context.isDark ? AppColor.neutral30 : AppColor.neutral50); + Text customHeadingText(BuildContext context) => getTextWithStyle(this, AppTextStyles.customHeadingText, context.isDark ? AppColor.neutral30 : AppColor.neutral50); Text heading6(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading6, context.isDark ? AppColor.neutral30 : AppColor.neutral50); @@ -31,12 +32,15 @@ extension TextStyles on String { } extension CustomText on Text { - Text custom({Color color, FontWeight fontWeight, TextAlign align}) { + Text custom({Color color, FontWeight fontWeight, TextAlign align,double fontSize,double lineHeight,double letterSpacing}) { return Text( data, textAlign: align, style: style.copyWith( color: color, + height: lineHeight, + letterSpacing: letterSpacing, + fontSize: fontSize, fontWeight: fontWeight, ), ); @@ -81,6 +85,14 @@ abstract class AppTextStyles { fontStyle: FontStyle.normal, decoration: TextDecoration.none, ); + static const TextStyle customHeadingText = TextStyle( + fontFamily: 'Poppins', + fontSize: 27, // Font size in logical pixels + fontWeight: FontWeight.w500, // Equivalent to font-weight: 500 + height: 31 / 27, // Line height (in Flutter, it's a multiplier of font size) + letterSpacing: -0.04 * 27, // Letter spacing, converted to logical pixels + color: Colors.black, // Set your desired text color + ); static final TextStyle heading6 = TextStyle( fontSize: 16.toScreenWidth, diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index a2b9761c..75b08f86 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -53,6 +53,7 @@ extension WidgetExtensions on Widget { Widget toShadowContainer(BuildContext context, {bool showShadow = true, double padding = 16}) => showShadow ? Container( padding: EdgeInsets.all(padding), + width: double.infinity, decoration: ShapeDecoration( color: AppColor.background(context), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), @@ -61,6 +62,18 @@ extension WidgetExtensions on Widget { child: this, ) : this; + + Widget toShadowCircleContainer(BuildContext context, {bool showShadow = true, double padding = 16}) => showShadow + ? Container( + padding: EdgeInsets.all(padding), + decoration: BoxDecoration( + color: AppColor.background(context), + shape: BoxShape.circle, + boxShadow: [boxShadowR14], + ), + child: this, + ) + : this; } extension DividerExtension on Divider { diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 33f48a18..673ff6ad 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -15,11 +15,17 @@ "name": "الاسم", "email": "البريد الالكتروني", "phoneNumber": "رقم الهاتف", + "Sign in to your": "تسجيل الدخول إلى حسابك", + "account": "الحساب", "password": "كلمة المرور", "confirmPassword": "تاكيد كلمة المرور", "signIn": "تسجيل الدخول", + "letSignInToAccount": "لنقم بتسجيل الدخول إلى حسابك", "signUp": "انشاء حساب", + "sparePartDetails": "تفاصيل قطع الغيار", + "attachQuotation": "إرفاق العرض", "forgetPassword": "نسيت كلمة المرور", + "addSparePartActivity": "إضافة نشاط قطع الغيار", "acceptTermsAndConditions": "موافقة علي الشروط والاحكام", "emailValidateMessage": "البريد الالكتروني غير صحيح", "nameValidateMessage": "الاسم مطلوب", @@ -172,7 +178,24 @@ "number": "رقم", "operatingHours": "ساعات العمل", "partName": "اسم القطعة", + "startTime": "وقت البدء", + "endTime": "وقت الانتهاء", + "pickTime" : "اختر الوقت", + "readCompleteThread" : "اقرأ الموضوع بالكامل", + "askOtpFromRequester": "طلب رمز التحقق من مقدم الطلب", + "verify": "تحقق", + "resend": "إعادة الإرسال", + "resendIn": "إعادة الإرسال خلال", + "checkOutOtherMethods": "اطلع على طرق أخرى.", + "otpSentToNumber": "تم إرسال رمز التحقق إلى الرقم", + "havingTroubleReceivingOtp": "تواجه صعوبة في استلام رمز التحقق؟", "quantity": "كمية", + "oracleNo": "رقم أوراكل", + "no": "لا", + "yes": "نعم", + "fixed": "تم الإصلاح", + "fillDetails": "يرجى ملء التفاصيل أدناه", + "addSparePartActionHeading": "هل تريد إنشاء طلب قطع غيار آخر؟", "reasons": "الاسباب", "reason": "السبب", "reportStatus": "حالة التقرير", @@ -189,7 +212,30 @@ "assignedEmployee": "الموظف المعين", "assetSN": "رقم تسلسلي للاصل ", "assetName": "اسم الاصل", + "accept": "قبول", + "reject": "رفض", + "skipForLater": "تخطي لاحقًا", + "rejectionReason": "سبب الرفض", + "setVisitDate": "تحديد تاريخ الزيارة", + "verifyArrival": "التحقق من الوصول", + "scanQr": "مسح رمز QR", + "scanQrDetail": "قم بمسح رمز QR الخاص بالجهاز أو التقط صورة للجهاز من الموقع", + "askRequester": "اطلب من مقدم الطلب التحقق", + "askRequesterDetail": "اطلب من مقدم الطلب التحقق من وصولك من خلال تطبيق Atoms.", + "askOtp": "اطلب رمز OTP من مقدم الطلب", + "askOtpDetail": "اطلب رمز OTP من مقدم الطلب للتحقق من وصولك", + "takeDevicePhoto": "التقط صورة للجهاز", + "takeDevicePhotoDetail": "قم بمسح رمز QR الخاص بالجهاز أو التقط صورة للجهاز من الموقع", "assetNumber": "رقم الاصل", + "assetDetail": "تفاصيل الأصل", + "requestDetail": "تفاصيل الطلب", + "activities": "الأنشطة", + "selectActivityType": "اختر نوع النشاط", + "sparePartRequest": "طلب قطع غيار", + "sparePartRequestDetail": "اطلب من مقدم الطلب التحقق من وصولك من خلال تطبيق Atoms.", + "maintenanceRequest": "طلب صيانة", + "assetToBeRetired": "الأصل الذي سيتم إخراجه من الخدمة", + "createNewActivity": "إنشاء نشاط جديد", "site": "الموقع", "maintenanceSituation": "موقع الصيانه", "currentSituation": "الموقع الحالي", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2c157481..882498e7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -17,8 +17,12 @@ "phoneNumber": "Phone Number", "password": "Password", "confirmPassword": "Confirm Password", + "skipForLater": "Skip For Later", "signIn": "Sign In", + "letSignInToAccount": "Let’s sign in to your account", "signUp": "Sign Up", + "accept": "Accept", + "reject": "Reject", "forgetPassword": "Forget Password", "acceptTermsAndConditions": "Accept Terms And Conditions", "emailValidateMessage": "Not valid email", @@ -71,6 +75,9 @@ "details": "Details", "device": "Asset", "deviceArName": "Asset Ar Name", + "sparePartDetails": "Spare Part Details", + "attachQuotation": "Attach Quotation", + "addSparePartActivity": "Add Spare Part Activity", "deviceName": "Asset Name", "deviceImages": "Asset Images", "deviceModel": "Asset Model", @@ -109,6 +116,7 @@ "pickHospital": "Pick Site", "pickUnite": "Pick Unit", "policy": "Policy", + "fixed": "Fixed", "reason1": "The engineer didn't confirm visit date with 2 hours from the request time", "reason2": "The engineer change the visit date without coordination with me", "reason3": "the engineer didn't attend on date/time", @@ -175,7 +183,9 @@ "operatingHours": "Operating Hours", "partName": "Part Name", "quantity": "Quantity", + "oracleNo": "Oracle No.", "reasons": "Reasons", + "addSparePartActionHeading": "Do you want to create another spare part request?", "reason": "Reason", "reportStatus": "Report Status", "reportType": "Report Type", @@ -188,6 +198,8 @@ "assetSN": "Asset S.N", "assetName": "Asset Name", "assetNumber": "Asset Number", + "assetDetail": "Asset Detail", + "requestDetail": "Request Details", "site": "Site", "maintenanceSituation": "Maintenance Situation", "currentSituation": "Current Situation", @@ -200,6 +212,11 @@ "repairLocation": "Repair Location", "travelingExpense": "Traveling Expense", "startDate": "Start Date", + "startTime": "Start Time", + "endTime": "End Time", + "no": "No", + "fillDetails": "Please fill the below details", + "yes": "Yes", "requestedQuantity": "Requested Quantity", "deliveredQuantity": "Delivered Quantity", "endDate": "End Date", @@ -215,6 +232,8 @@ "pickFile" : "Pick File", "login" : "Login", "enterCredsToLogin" : "Enter your credential to login", + "signInToYour" : "Sign in to your", + "account" : "account", "forgotPassword" : "Forgot Password?", "password" : "Password", "username" : "Username", @@ -262,11 +281,22 @@ "filter" : "Filter", "pickAsset" : "Pick Asset", "firstAction" : "First Action", + "rejectionReason" : "Rejection Reason", "workOrder" : "Work Order", "workOrders" : "Work Orders", "viewWorkOrder" : "View All Work Order", "createWorkOrder" : "Create Work Order", "serviceDetails": "Service Details", + "setVisitDate": "Set Date Of Visit", + "verifyArrival": "Verify Arrival", + "scanQr": "Scan QR", + "scanQrDetail": "Scan QR Code of the device or take the photo of the device from location", + "askRequester": "Ask Requester to Verify", + "askRequesterDetail": "Ask requester to verify your arrival through Atoms Application.", + "askOtp": "Ask OTP From Requester", + "askOtpDetail": "Ask OTP from requester to verify you arrival", + "takeDevicePhoto": "Take Device Photo", + "takeDevicePhotoDetail": "Scan QR Code of the device or take the photo of the device from location", "priority" : "Request Priority", "equipmentStatus" : "Equipment Status", "jopStatus" : "Jop Status", @@ -305,6 +335,15 @@ "applyFilter" : "Apply Filter", "pmDateRange" : "PM Date Range", "pickDate" : "Pick Date", + "verify" : "Verify", + "resend": "Resend", + "resendIn": "Resend In", + "havingTroubleReceivingOtp": "Having trouble receiving OTP?", + "askOtpFromRequester" : "Ask OTP From Requester", + "checkOutOtherMethods": "Check out other methods.", + "otpSentToNumber": "An OTP sent to the number", + "pickTime" : "Pick Time", + "readCompleteThread" : "Read Complete thread", "pickADate" : "Pick a date", "firstActionStatus" : "First Action Status", "loanAvailability" : "Loan Availability", @@ -382,6 +421,13 @@ "solution" : "Solution", "technicalComment" : "Technical Comment", "recentActivities" : "Recent Activities", + "activities" : "Activities", + "createNewActivity" : "Create New Activity", + "selectActivityType" : "Select Activity Type", + "sparePartRequest" : "Spare Part Request", + "sparePartRequestDetail" : "Ask requester to verify your arrival through Atoms Application.", + "maintenanceRequest" : "Maintenance Request", + "assetToBeRetired" : "Asset to be retired", "problemDesc" : "Problem Description", "source": "Source", "costCodeName" : "Cost Code Name", diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index b5aaf79c..f8968378 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -5,11 +5,13 @@ class AppColor { AppColor._(); //primary + static const Color primary10 = Color(0xff3DA5E5); static const Color primary30 = Color(0xffA2E2F8); static const Color primary40 = Color(0xff75BDE0); static const Color primary50 = Color(0xff4A8DB7); static const Color primary60 = Color(0xff3B7097); static const Color primary70 = Color(0xff163A51); + static const Color primary80 = Color(0xff161D27); //texts static const Color neutral10 = Color(0xffBCBCBC); @@ -19,13 +21,24 @@ class AppColor { static const Color neutral50 = Color(0xff3B3D4A); static const Color neutral60 = Color(0xff2C2C31); static const Color neutral70 = Color(0xff111427); + static const Color neutral80 = Color(0xffF3F3F3); + static const Color neutral90 = Color(0xffF7F9FB); + static const Color neutral100 = Color(0xffF4F6FC); //background - static const Color backgroundLight = Color(0xffF7F9FB); + static const Color backgroundLight = Color(0xfff7f9fb); static const Color backgroundDark = Color(0xff111427); + //white + static const Color white20 = Color(0xffF7F9FB); + static const Color white30 = Color(0xffE7EBF2); + +//black + static const Color balck10 = Color(0xff3B3D4A); + //red static const Color red40 = Color(0xffFFDBDC); + static const Color red50 = Color(0xffD02127); static const Color red60 = Color(0xff8C050A); @@ -33,19 +46,23 @@ class AppColor { static const Color green40 = Color(0xffBAFFE1); static const Color green50 = Color(0xff62BE96); static const Color green60 = Color(0xff065E38); + static const Color green70 = Color(0xff54C166); //orange static const Color orange40 = Color(0xffFFEDBC); static const Color orange50 = Color(0xffCC9B14); static const Color orange60 = Color(0xff886400); - static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff1FA269) : green50; + // static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff1FA269) : green50; + static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff54C166) : green50; + // static Color blueStatus(BuildContext context) => context.isDark ? primary40 : primary50; static Color blueStatus(BuildContext context) => context.isDark ? primary40 : primary50; static Color redStatus(BuildContext context) => context.isDark ? const Color(0xffFFB6B8) : red40; - static Color yellowStatus(BuildContext context) => context.isDark ? const Color(0xffFFDA76) : orange40; + // static Color yellowStatus(BuildContext context) => context.isDark ? const Color(0xffFFDA76) : orange40; + static Color yellowStatus(BuildContext context) => context.isDark ? const Color(0xffFFC945) : orange40; static Color background(BuildContext context) => context.isDark ? neutral60 : Colors.white; diff --git a/lib/new_views/common_widgets/app_dashed_button.dart b/lib/new_views/common_widgets/app_dashed_button.dart index 6fc2c61e..7d2a0b02 100644 --- a/lib/new_views/common_widgets/app_dashed_button.dart +++ b/lib/new_views/common_widgets/app_dashed_button.dart @@ -22,11 +22,11 @@ class AppDashedButton extends StatelessWidget { child: DottedBorder( strokeWidth: 2, padding: EdgeInsets.symmetric(vertical: 16.toScreenHeight, horizontal: 16.toScreenWidth), - color: context.isDark ? AppColor.primary40 : AppColor.primary60, + color: context.isDark ? AppColor.primary40 : AppColor.primary10, dashPattern: const [4, 3], radius: const Radius.circular(10), borderType: BorderType.RRect, - child: title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : AppColor.primary60).center, + child: title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : AppColor.primary10).center, ), ).onPress(onPressed); } diff --git a/lib/new_views/common_widgets/app_text_form_field.dart b/lib/new_views/common_widgets/app_text_form_field.dart index 3fe19929..700eb011 100644 --- a/lib/new_views/common_widgets/app_text_form_field.dart +++ b/lib/new_views/common_widgets/app_text_form_field.dart @@ -15,6 +15,7 @@ class AppTextFormField extends StatefulWidget { final TextInputType textInputType; final String initialValue; final TextStyle style; + final TextStyle labelStyle; final bool enable; final TextAlign textAlign; final FocusNode node; @@ -28,6 +29,7 @@ class AppTextFormField extends StatefulWidget { final Color backgroundColor; final bool alignLabelWithHint; final bool showShadow; + final EdgeInsets contentPadding; final bool showWithoutDecoration; final void Function() onTap; @@ -37,6 +39,7 @@ class AppTextFormField extends StatefulWidget { this.validator, this.node, this.onChange, + this.labelStyle, this.obscureText, this.showPassword, this.hintText, @@ -45,6 +48,7 @@ class AppTextFormField extends StatefulWidget { this.initialValue, this.enable = true, this.style, + this.contentPadding, this.textAlign, this.suffixIcon, this.prefixIcon, @@ -98,7 +102,7 @@ class _AppTextFormFieldState extends State { focusedBorder: border, enabledBorder: border, errorBorder: border, - contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), + contentPadding:widget.contentPadding?? EdgeInsets.symmetric(vertical: 12.toScreenHeight, horizontal: 16.toScreenWidth), constraints: const BoxConstraints(), suffixIconConstraints: const BoxConstraints(minWidth: 0), filled: true, @@ -112,6 +116,7 @@ class _AppTextFormFieldState extends State { floatingLabelStyle: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), hintText: widget.hintText ?? "", labelText: widget.labelText ?? "", + labelStyle: widget.labelStyle, prefixIcon: widget.prefixIcon ?? (widget.prefixIconData == null ? null diff --git a/lib/new_views/common_widgets/default_app_bar.dart b/lib/new_views/common_widgets/default_app_bar.dart index e34be09d..d846fedc 100644 --- a/lib/new_views/common_widgets/default_app_bar.dart +++ b/lib/new_views/common_widgets/default_app_bar.dart @@ -22,9 +22,10 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { const Icon(Icons.arrow_back_ios).onPress(() { Navigator.of(context).pop(); }), + 10.width, Text( title ?? "", - style: AppTextStyles.heading3?.copyWith(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + style: AppTextStyles.heading3?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ).expanded, ], ), 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 4043a76b..d037fd06 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 @@ -19,6 +19,8 @@ class SingleItemDropDownMenu final bool showAsBottomSheet; final List staticData; final String title; + final double height; + final bool showShadow ; final Color backgroundColor; final bool loading; @@ -31,8 +33,10 @@ class SingleItemDropDownMenu this.onSelect, this.initialValue, this.enabled = true, + this.height, this.showAsBottomSheet = false, this.staticData, + this.showShadow=true, this.backgroundColor, this.loading, }) : super(key: key); @@ -116,7 +120,7 @@ class _SingleItemDropDownMenuState 0 && isSelected && !loading + ? badges.Badge( + badgeContent: Text( + count.toString(), + style: const TextStyle( + color: AppColor.white20, + fontWeight: FontWeight.normal, + ), + ), + badgeStyle: const badges.BadgeStyle(padding: EdgeInsets.symmetric(horizontal: 5, vertical: 3), badgeColor: AppColor.red50), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7), + color: isSelected ? AppColor.primary10 : AppColor.white30, + border: !isSelected ? Border.all(color: Colors.white54, width: 1) : null, + ), + child: Center( + child: Text( + label, + style: AppTextStyles.bodyText.copyWith( + color: isSelected ? Colors.white : Colors.black, + ), + )), + ).toShimmer(isShow: loading, radius: 7), + ) + : Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7), + color: isSelected ? AppColor.primary10 : AppColor.white30, + border: !isSelected ? Border.all(color: AppColor.white30, width: 1) : null, + ), + child: Center( + child: Text( + label, + style: AppTextStyles.bodyText.copyWith( + color: isSelected ? Colors.white : Colors.black, + ), + )), + ).toShimmer(isShow: loading, radius: 7), + ); + } +} + +class TabButtonData { + final String label; + final bool isSelected; + final int totalCount; + final VoidCallback onPressed; + + TabButtonData({ + @required this.label, + @required this.isSelected, + @required this.totalCount, + @required this.onPressed, + }); +} diff --git a/lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart b/lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart index 5d3afe75..3015288c 100644 --- a/lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart +++ b/lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart @@ -1,14 +1,163 @@ +// import 'package:flutter/material.dart'; +// // import 'package:test_sa/pie_chart/pie_chart.dart'; +// import 'package:provider/provider.dart'; +// import 'package:syncfusion_flutter_charts/charts.dart'; +// import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +// import 'package:test_sa/extensions/context_extension.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/pages/land_page/widgets/request_item_view_list.dart'; +// +// import '../../../../controllers/providers/api/user_provider.dart'; +// import '../../../../models/enums/user_types.dart'; +// +// class ProgressFragment extends StatelessWidget { +// ProgressFragment({Key key}) : super(key: key); +// +// UserProvider _userProvider; +// +// AllRequestsProvider _provider; +// +// @override +// Widget build(BuildContext context) { +// _userProvider = Provider.of(context); +// bool isCurrentUserNotEngineer = (_userProvider.user.type != UsersTypes.engineer); +// return Consumer( +// builder: (context, snapshot, _) { +// if (_provider == null) { +// _provider = snapshot; +// if (isCurrentUserNotEngineer) { +// _provider.getOpenRequests(reset: true); +// } +// _provider.getInProgressRequests(reset:true); +// _provider.getCompletedRequests(reset:true); +// } +// +// int total = (snapshot.completedRequests?.total?.count ?? 0) + (snapshot.inProgressRequests?.total?.count ?? 0) + (isCurrentUserNotEngineer ? (snapshot.openRequests?.total?.count ?? 0) : 0); +// +// final List chartData = [ +// ChartData('Completed', snapshot.completedRequests?.total?.count?.toDouble() ?? 0.0, AppColor.greenStatus(context)), +// ChartData('In Progress', snapshot.inProgressRequests?.total?.count?.toDouble() ?? 0.0, AppColor.yellowStatus(context)), +// ]; +// +// if (isCurrentUserNotEngineer) { +// chartData.insert(1, ChartData('Open', snapshot.openRequests?.total?.count?.toDouble() ?? 0.0, AppColor.blueStatus(context))); +// } +// +// return Column( +// children: [ +// AspectRatio( +// aspectRatio: 398 / 237, +// child: Stack( +// alignment: Alignment.center, +// children: [ +// SfCircularChart( +// tooltipBehavior: TooltipBehavior( +// enable: true, +// // elevation: 2, +// color: context.isDark ? Color(0xFF111427) : Color(0xffF7F9FB), +// textStyle: context.isDark ? null : TextStyle(color: Colors.black87, fontSize: 12), +// ), +// legend: Legend( +// //isVisible: true, +// ), +// series: [ +// DoughnutSeries( +// dataSource: chartData, +// radius: "110%", +// innerRadius: "60%", +// pointColorMapper: (ChartData data, _) => data.color, +// xValueMapper: (ChartData data, _) => data.x, +// yValueMapper: (ChartData data, _) => data.y, +// dataLabelMapper: (ChartData data, _) => data.x, +// dataLabelSettings: DataLabelSettings( +// isVisible: true, +// textStyle: TextStyle(color: context.isDark ? Colors.white : Colors.black87, fontSize: 12), +// labelPosition: ChartDataLabelPosition.outside, +// //useSeriesColor: true, +// ), +// ) +// ]).toShimmer(isShow: snapshot.isOpenLoading || snapshot.isInProgressLoading || snapshot.isCompleteLoading, radius: 300).paddingAll(12).toShadowContainer(context), +// Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// Text( +// context.translation.total, +// style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), +// ), +// Text( +// "$total", +// style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), +// ), +// ], +// ), +// ], +// ), +// ).paddingOnly(start: 16, end: 16, bottom: 16), +// DefaultTabController( +// length: isCurrentUserNotEngineer ? 3 : 2, +// child: Column( +// children: [ +// Container( +// margin: const EdgeInsets.only(left: 16, right: 16), +// decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, borderRadius: BorderRadius.circular(16)), +// child: TabBar( +// //controller: _tabController, +// padding: EdgeInsets.zero, +// labelColor: context.isDark ? AppColor.neutral30 : AppColor.neutral60, +// unselectedLabelColor: context.isDark ? AppColor.neutral10 : AppColor.neutral20, +// unselectedLabelStyle: AppTextStyles.bodyText, +// labelStyle: AppTextStyles.bodyText, +// indicatorPadding: const EdgeInsets.all(4), +// indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : Theme.of(context).cardColor, borderRadius: BorderRadius.circular(13)), +// onTap: (index) { +// // setState(() {}); +// }, +// tabs: [ +// if (isCurrentUserNotEngineer) Tab(text: context.translation.open, height: 57.toScreenHeight), +// Tab(text: context.translation.inProgress, height: 57.toScreenHeight), +// Tab(text: context.translation.completed, height: 57.toScreenHeight), +// ], +// ), +// ), +// 8.height, +// TabBarView( +// children: [ +// if (isCurrentUserNotEngineer) RequestItemViewList(snapshot.openRequests?.requestsDetails ?? [], snapshot.isOpenLoading), +// RequestItemViewList(snapshot.inProgressRequests?.requestsDetails ?? [], snapshot.isInProgressLoading), +// RequestItemViewList(snapshot.completedRequests?.requestsDetails ?? [], snapshot.isCompleteLoading), +// ], +// ).expanded, +// ], +// ), +// ).expanded, +// ], +// ); +// }, +// ); +// } +// } +// +// class ChartData { +// ChartData(this.x, this.y, this.color); +// +// final String x; +// final double y; +// final Color color; +// } +// +// + import 'package:flutter/material.dart'; -// import 'package:test_sa/pie_chart/pie_chart.dart'; import 'package:provider/provider.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/extensions/context_extension.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/pages/land_page/widgets/request_item_view_list.dart'; import '../../../../controllers/providers/api/user_provider.dart'; import '../../../../models/enums/user_types.dart'; @@ -26,19 +175,23 @@ class ProgressFragment extends StatelessWidget { bool isCurrentUserNotEngineer = (_userProvider.user.type != UsersTypes.engineer); return Consumer( builder: (context, snapshot, _) { - if (_provider == null) { - _provider = snapshot; - if (isCurrentUserNotEngineer) { - _provider.getOpenRequests(reset: true); - } - _provider.getInProgressRequests(reset:true); - _provider.getCompletedRequests(reset:true); - } + // WidgetsBinding.instance.addPostFrameCallback((_) { + // if (_provider == null) { + // _provider = snapshot; + // if (isCurrentUserNotEngineer) { + // _provider.getOpenRequests(reset: true); + // } + // _provider.getInProgressRequests(reset:true); + // _provider.getCompletedRequests(reset:true); + // } + // + // }); int total = (snapshot.completedRequests?.total?.count ?? 0) + (snapshot.inProgressRequests?.total?.count ?? 0) + (isCurrentUserNotEngineer ? (snapshot.openRequests?.total?.count ?? 0) : 0); final List chartData = [ ChartData('Completed', snapshot.completedRequests?.total?.count?.toDouble() ?? 0.0, AppColor.greenStatus(context)), + // snapshot.openRequests?.total?.count!=0? ChartData('Open', snapshot.openRequests?.total?.count?.toDouble() ?? 0.0, AppColor.blueStatus(context)), ChartData('In Progress', snapshot.inProgressRequests?.total?.count?.toDouble() ?? 0.0, AppColor.yellowStatus(context)), ]; @@ -57,12 +210,12 @@ class ProgressFragment extends StatelessWidget { tooltipBehavior: TooltipBehavior( enable: true, // elevation: 2, - color: context.isDark ? Color(0xFF111427) : Color(0xffF7F9FB), - textStyle: context.isDark ? null : TextStyle(color: Colors.black87, fontSize: 12), + color: context.isDark ? const Color(0xFF111427) : const Color(0xffF7F9FB), + textStyle: context.isDark ? null : const TextStyle(color: Colors.black87, fontSize: 12), ), legend: Legend( - //isVisible: true, - ), + //isVisible: true, + ), series: [ DoughnutSeries( dataSource: chartData, @@ -79,7 +232,7 @@ class ProgressFragment extends StatelessWidget { //useSeriesColor: true, ), ) - ]).toShimmer(isShow: snapshot.isOpenLoading || snapshot.isInProgressLoading || snapshot.isCompleteLoading, radius: 300).paddingAll(12).toShadowContainer(context), + ]).toShimmer(isShow: snapshot.isAllLoading, radius: 300).paddingAll(12).toShadowContainer(context), Column( mainAxisSize: MainAxisSize.min, children: [ @@ -95,44 +248,7 @@ class ProgressFragment extends StatelessWidget { ), ], ), - ).paddingOnly(start: 16, end: 16, bottom: 16), - DefaultTabController( - length: isCurrentUserNotEngineer ? 3 : 2, - child: Column( - children: [ - Container( - margin: const EdgeInsets.only(left: 16, right: 16), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, borderRadius: BorderRadius.circular(16)), - child: TabBar( - //controller: _tabController, - padding: EdgeInsets.zero, - labelColor: context.isDark ? AppColor.neutral30 : AppColor.neutral60, - unselectedLabelColor: context.isDark ? AppColor.neutral10 : AppColor.neutral20, - unselectedLabelStyle: AppTextStyles.bodyText, - labelStyle: AppTextStyles.bodyText, - indicatorPadding: const EdgeInsets.all(4), - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : Theme.of(context).cardColor, borderRadius: BorderRadius.circular(13)), - onTap: (index) { - // setState(() {}); - }, - tabs: [ - if (isCurrentUserNotEngineer) Tab(text: context.translation.open, height: 57.toScreenHeight), - Tab(text: context.translation.inProgress, height: 57.toScreenHeight), - Tab(text: context.translation.completed, height: 57.toScreenHeight), - ], - ), - ), - 8.height, - TabBarView( - children: [ - if (isCurrentUserNotEngineer) RequestItemViewList(snapshot.openRequests?.requestsDetails ?? [], snapshot.isOpenLoading), - RequestItemViewList(snapshot.inProgressRequests?.requestsDetails ?? [], snapshot.isInProgressLoading), - RequestItemViewList(snapshot.completedRequests?.requestsDetails ?? [], snapshot.isCompleteLoading), - ], - ).expanded, - ], - ), - ).expanded, + ), ], ); }, @@ -147,3 +263,4 @@ class ChartData { final double y; final Color color; } + diff --git a/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart b/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart index 1f6f857c..addb46a7 100644 --- a/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart +++ b/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart @@ -1,3 +1,75 @@ +//Older code +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +// import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +// import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +// import 'package:test_sa/controllers/providers/api/user_provider.dart'; +// import 'package:test_sa/extensions/context_extension.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/views/widgets/notifications/notification_item.dart'; +// +// class RecentActivitiesFragment extends StatelessWidget { +// RecentActivitiesFragment({Key key}) : super(key: key); +// +// //NotificationsProvider _notificationsProvider; +// +// @override +// Widget build(BuildContext context) { +// //_notificationsProvider ??= Provider.of(context, listen: false); +// return Consumer(builder: (context, _notificationsProvider, _) { +// return RefreshIndicator( +// onRefresh: () { +// Provider.of(context, listen: false).getRequests(); +// _notificationsProvider.getSystemNotifications(user: Provider.of(context, listen: false).user,resetProvider: true); +// return Future.delayed(const Duration(microseconds: 250)); +// }, +// child: SingleChildScrollView( +// padding: const EdgeInsets.all(16), +// child: Container( +// decoration: ShapeDecoration( +// color: AppColor.background(context), +// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), +// shadows: [boxShadowR14], +// ), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// context.translation.recentActivities +// .heading5(context) +// .toShimmer( +// isShow: _notificationsProvider.isLoading, +// ) +// .paddingOnly(top: 16, start: 16, end: 16), +// ListView.separated( +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// padding: const EdgeInsets.all(16), +// itemCount: _notificationsProvider.notifications.length, +// separatorBuilder: (context, itemIndex) => const Divider().defaultStyle(context).paddingOnly(top: 16, bottom: 16), +// itemBuilder: (context, itemIndex) { +// // todo add priority & progress tag to show chip +// return NotificationItem( +// isLoading: _notificationsProvider.isLoading, +// notification: _notificationsProvider.notifications[itemIndex], +// onPressed: (notification) { +// FirebaseNotificationManger.handleMessage(context, notification.toNotificationJson()); +// }, +// ); +// }, +// ), +// ], +// ), +// ), +// ), +// ); +// }); +// } +// } + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; @@ -5,8 +77,10 @@ import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.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/models/enums/user_types.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/notifications/notification_item.dart'; @@ -19,6 +93,8 @@ class RecentActivitiesFragment extends StatelessWidget { Widget build(BuildContext context) { //_notificationsProvider ??= Provider.of(context, listen: false); return Consumer(builder: (context, _notificationsProvider, _) { + UserProvider _userProvider = Provider.of(context); + bool isCurrentUserNotEngineer = (_userProvider.user.type != UsersTypes.engineer); return RefreshIndicator( onRefresh: () { Provider.of(context, listen: false).getRequests(); @@ -26,42 +102,37 @@ class RecentActivitiesFragment extends StatelessWidget { return Future.delayed(const Duration(microseconds: 250)); }, child: SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Container( - decoration: ShapeDecoration( - color: AppColor.background(context), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - shadows: [boxShadowR14], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - context.translation.recentActivities - .heading5(context) - .toShimmer( - isShow: _notificationsProvider.isLoading, - ) - .paddingOnly(top: 16, start: 16, end: 16), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: const EdgeInsets.all(16), - itemCount: _notificationsProvider.notifications.length, - separatorBuilder: (context, itemIndex) => const Divider().defaultStyle(context).paddingOnly(top: 16, bottom: 16), - itemBuilder: (context, itemIndex) { - // todo add priority & progress tag to show chip - return NotificationItem( + // padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _notificationsProvider.notifications.length, + // separatorBuilder: (context, itemIndex) => const Divider().defaultStyle(context).paddingOnly(top: 16, bottom: 16), + itemBuilder: (context, itemIndex) { + // todo add priority & progress tag to show chip + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16,vertical: 12), + margin:const EdgeInsets.symmetric(vertical: 8), + decoration: ShapeDecoration( + color: AppColor.background(context), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + shadows: [boxShadowR14], + ), + child: NotificationItem( isLoading: _notificationsProvider.isLoading, notification: _notificationsProvider.notifications[itemIndex], onPressed: (notification) { FirebaseNotificationManger.handleMessage(context, notification.toNotificationJson()); }, - ); - }, - ), - ], - ), + ), + ); + }, + ), + ], ), ), ); diff --git a/lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart b/lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart new file mode 100644 index 00000000..16e35b66 --- /dev/null +++ b/lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart @@ -0,0 +1,265 @@ +//Older code +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +// import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +// import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +// import 'package:test_sa/controllers/providers/api/user_provider.dart'; +// import 'package:test_sa/extensions/context_extension.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/views/widgets/notifications/notification_item.dart'; +// +// class RequestCategoryFragment extends StatelessWidget { +// RequestCategoryFragment({Key key}) : super(key: key); +// +// //NotificationsProvider _notificationsProvider; +// +// @override +// Widget build(BuildContext context) { +// //_notificationsProvider ??= Provider.of(context, listen: false); +// return Consumer(builder: (context, _notificationsProvider, _) { +// return RefreshIndicator( +// onRefresh: () { +// Provider.of(context, listen: false).getRequests(); +// _notificationsProvider.getSystemNotifications(user: Provider.of(context, listen: false).user,resetProvider: true); +// return Future.delayed(const Duration(microseconds: 250)); +// }, +// child: SingleChildScrollView( +// padding: const EdgeInsets.all(16), +// child: Container( +// decoration: ShapeDecoration( +// color: AppColor.background(context), +// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), +// shadows: [boxShadowR14], +// ), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// context.translation.recentActivities +// .heading5(context) +// .toShimmer( +// isShow: _notificationsProvider.isLoading, +// ) +// .paddingOnly(top: 16, start: 16, end: 16), +// ListView.separated( +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// padding: const EdgeInsets.all(16), +// itemCount: _notificationsProvider.notifications.length, +// separatorBuilder: (context, itemIndex) => const Divider().defaultStyle(context).paddingOnly(top: 16, bottom: 16), +// itemBuilder: (context, itemIndex) { +// // todo add priority & progress tag to show chip +// return NotificationItem( +// isLoading: _notificationsProvider.isLoading, +// notification: _notificationsProvider.notifications[itemIndex], +// onPressed: (notification) { +// FirebaseNotificationManger.handleMessage(context, notification.toNotificationJson()); +// }, +// ); +// }, +// ), +// ], +// ), +// ), +// ), +// ); +// }); +// } +// } + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.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/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/enums/user_types.dart'; +import 'package:test_sa/models/user.dart'; +import 'package:test_sa/new_views/common_widgets/tab_button.dart'; +import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/request_category_list.dart'; +import 'package:test_sa/utilities/request_utils.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; + +class RequestCategoryFragment extends StatefulWidget { + // final AllRequestsAndCount allRequestsAndCount; + + // const RequestCategoryFragment({Key key, this.allRequestsAndCount}) : super(key: key); + const RequestCategoryFragment({ + Key key, + }) : super(key: key); + + @override + State createState() => _RequestCategoryFragmentState(); +} + +class _RequestCategoryFragmentState extends State { + @override + void initState() { + // TODO: implement initState + // getInitialList(); + print('init state called...'); + super.initState(); + } + + // Future getInitialList() async { + // UserProvider userProvider = Provider.of(context, listen: false); + // + // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // UsersTypes usersType = userProvider.user.type; + // var tabs = RequestUtils.getTabs(userType: usersType, context: context); + // allRequestsProvider.currentListIndex = 0; + // allRequestsProvider.filterRequest = null; + // await allRequestsProvider.getFilterRequests(pagination: false, status: tabs[0]['status']); + // + // print('tabs lenght is ${tabs.length}'); + // } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (context, allRequestProvider, child) { + return Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ + context.translation.allRequests.heading4(context).paddingOnly(top: 16, bottom: 16), + getTabs( + requestsProvider: allRequestProvider, + context: context, + userType: Provider.of(context, listen: false).user.type, + ), + // Row( + // children: _buildTabButtons(isEngineer: Provider.of(context, listen: false).user.type == UsersTypes.engineer, allRequestsProvider: allRequestProvider), + // ), + 10.height, + allRequestProvider.isFilterRequestLoading||allRequestProvider.filterRequest==null?Column( + mainAxisSize: MainAxisSize.max, + children: List.generate( 3 , (index) { + return Padding( + padding: EdgeInsets.symmetric(vertical: 10.toScreenHeight,horizontal: 0), + child: const SizedBox().toRequestShimmer(context, allRequestProvider.isFilterRequestLoading), + ); + })): RequestCategoryList(allRequestProvider.filterRequest.requestsDetails ?? [], allRequestProvider.isFilterRequestLoading), + // if (allRequestProvider.isLoadingList) ...[ + // const Center(child: CircularProgressIndicator()), + // ] else ...[ + // RequestCategoryList(allRequestProvider.dashBoardFilterList?.requestsDetails ?? [], allRequestProvider.dashBoardFilterListLoading), + // ] + ]); + }); + } + + Widget getTabs({@required BuildContext context, @required AllRequestsProvider requestsProvider, @required UsersTypes userType}) { + List tabs = []; + switch (userType) { + case UsersTypes.engineer: + tabs = RequestUtils.getTabs(userType: UsersTypes.engineer, context: context); + return Row( + children: tabs.map((item) { + return tabWidget( + label: item['label'], + status: item['status'], + selectedTab: tabs.indexOf(item), + requestsProvider: requestsProvider, + ); + }).toList(), + ); + case UsersTypes.normal_user: + tabs = RequestUtils.getTabs(userType: UsersTypes.normal_user, context: context); + return Row( + children: tabs.map((item) { + return tabWidget( + label: item['label'], + status: item['status'], + selectedTab: tabs.indexOf(item), + requestsProvider: requestsProvider, + ); + }).toList(), + ); + default: + return const SizedBox(); + } + } + + Widget tabWidget({@required int selectedTab, @required String label, @required int status, double width, @required AllRequestsProvider requestsProvider}) { + return Padding( + padding: const EdgeInsets.only(right: 12), + child: TabButton( + label: label, + loading: requestsProvider.isFilterRequestLoading, + isSelected: requestsProvider.currentListIndex == selectedTab, + count: requestsProvider.filterRequest != null ? requestsProvider.filterRequest.total.count : 0, + onPressed: () async { + requestsProvider.currentListIndex = selectedTab; + requestsProvider.filterRequest = null; + await requestsProvider.getFilterRequests(status: status); + requestsProvider.isInProgressLoading = false; + requestsProvider.pageNum = 1; + // requestsProvider.dashBoardFilterList = requestsProvider.openRequests.requestsDetails; + }, + )); + } +} + +//tabs code... +// +// List _getTabButtonData({@required bool isEngineer, @required AllRequestsProvider allRequestsProvider, @required int totalCount}) { +// List tabList = []; +// List> tabs = []; +// print('dashboard filter list data is ${allRequestsProvider.dashBoardFilterList}'); +// +// if (!isEngineer && allRequestsProvider.dashBoardFilterList != null && allRequestsProvider.dashBoardFilterList.isNotEmpty) { +// tabList.add(TabButtonData( +// label: 'New Request', +// isSelected: allRequestsProvider.currentListIndex == 0, +// totalCount: totalCount, +// onPressed: () { +// allRequestsProvider.currentListIndex = 0; +// allRequestsProvider.dashBoardFilterList = allRequestsProvider.openRequests.requestsDetails; +// }, +// )); +// } +// tabList.add(TabButtonData( +// label: 'In Progress', +// isSelected: allRequestsProvider.currentListIndex == (isEngineer ? 0 : 1), +// totalCount: totalCount, +// onPressed: () { +// allRequestsProvider.currentListIndex = isEngineer ? 0 : 1; +// allRequestsProvider.dashBoardFilterList = allRequestsProvider.inProgressRequests.requestsDetails; +// }, +// )); +// tabList.add( +// TabButtonData( +// label: 'Completed', +// isSelected: allRequestsProvider.currentListIndex == (isEngineer ? 1 : 2), +// totalCount: totalCount, +// onPressed: () { +// allRequestsProvider.currentListIndex = isEngineer ? 1 : 2; +// allRequestsProvider.dashBoardFilterList = allRequestsProvider.completedRequests.requestsDetails; +// }, +// ), +// ); +// return tabList; +// } +// +// List _buildTabButtons({@required bool isEngineer, @required AllRequestsProvider allRequestsProvider}) { +// int totalCount = 0; +// print('build tab button called'); +// if (allRequestsProvider.dashBoardFilterList != null) { +// totalCount = allRequestsProvider.dashBoardFilterList.length; +// } +// return _getTabButtonData(isEngineer: isEngineer, allRequestsProvider: allRequestsProvider, totalCount: totalCount).map((tab) { +// return Padding( +// padding: const EdgeInsets.only(left: 10.0), +// child: TabButton( +// label: tab.label, +// isSelected: tab.isSelected, +// count: totalCount, +// onPressed: tab.onPressed, +// ), +// ); +// }).toList(); +// } diff --git a/lib/new_views/pages/land_page/dashboard_fragments/request_category_list.dart b/lib/new_views/pages/land_page/dashboard_fragments/request_category_list.dart new file mode 100644 index 00000000..099cc983 --- /dev/null +++ b/lib/new_views/pages/land_page/dashboard_fragments/request_category_list.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/new_views/pages/land_page/requests/asset_item_view.dart'; +import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; +import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart'; +import 'package:test_sa/new_views/pages/land_page/requests/service_request_item_view.dart'; + +class RequestCategoryList extends StatelessWidget { + final List list; + final bool isLoading; + + const RequestCategoryList(this.list, this.isLoading, {Key key}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: List.generate(isLoading ? 6 : list.length, (index) { + // if (isLoading) { + // return const SizedBox().toRequestShimmer(context, isLoading); + // } + // else { + return Padding( + padding: EdgeInsets.symmetric(vertical: 10.toScreenHeight), + child: _buildRequestItem(list[index])); + // } + })); + } + + Widget _buildRequestItem(RequestsDetails request) { + bool isServiceRequest = request.nameOfType == "ServiceRequest"; + bool isGasRefill = request.nameOfType == "GasRefill"; + bool isAssetTransfer = request.nameOfType == "AssetTransfer"; + bool isPPMs = request.nameOfType == "PPMs"; + + if (isServiceRequest) { + return ServiceRequestItemView(request); + } else if (isGasRefill) { + return GasRefillItemView(request); + } else if (isPPMs) { + return PpmItemView(request); + } else if (isAssetTransfer) { + return AssetItemView(request); + } else { + return Container( + height: 100, + width: double.infinity, + color: Colors.grey, + ); + } + } +} diff --git a/lib/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart b/lib/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart index 38588c18..c3d4ddac 100644 --- a/lib/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart +++ b/lib/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart @@ -1,3 +1,107 @@ +//older code.... +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/controllers/api_routes/api_manager.dart'; +// import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +// import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +// import 'package:test_sa/controllers/providers/api/user_provider.dart'; +// import 'package:test_sa/extensions/context_extension.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/models/enums/user_types.dart'; +// import 'package:test_sa/new_views/app_style/app_color.dart'; +// import 'package:test_sa/new_views/common_widgets/app_floating_action_button.dart'; +// import 'package:test_sa/new_views/pages/land_page/requests_list_page.dart'; +// +// class RequestsFragment extends StatelessWidget { +// const RequestsFragment({Key key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// // todo check here, nurse can add request not engineer +// floatingActionButton: const AppFloatingActionButton(), +// body: Consumer( +// builder: (context, snapshot, _) => RefreshIndicator( +// onRefresh: () { +// snapshot.getRequests(); +// Provider.of(context, listen: false).getSystemNotifications(user: Provider.of(context, listen: false).user, resetProvider: true); +// return Future.delayed(const Duration(microseconds: 250)); +// }, +// child: GridView( +// padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), +// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 191 / 237, crossAxisSpacing: 16, mainAxisSpacing: 16), +// children: [ +// listItem( +// snapshot.highPriorityRequests?.total?.count, +// "high_priority", +// context.translation.highPriority, +// context, +// snapshot.isHighPriorityLoading, +// 0, +// context.isDark ? AppColor.redStatus(context) : AppColor.red50, +// ), +// listItem(snapshot.overdueRequests?.total?.count, "overdue", context.translation.overdue, context, snapshot.isOverdueLoading, 1, AppColor.yellowStatus(context)), +// listItem(snapshot.openRequests?.total?.count, "new_request", ApiManager.instance.user.type == UsersTypes.engineer ? context.translation.inProgress : context.translation.newR, context, +// snapshot.isOpenLoading, 2, AppColor.primary40), +// listItem(snapshot.completedRequests?.total?.count, "complete_request", context.translation.completed, context, snapshot.isCompleteLoading, 3, AppColor.greenStatus(context)), +// ], +// ), +// ), +// ), +// ); +// } +// +// Widget listItem(int value, String icon, String title, BuildContext context, bool isLoading, int index, Color iconColor) { +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// value?.toString() ?? "-", +// style: AppTextStyles.heading1.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, height: 1), +// ).toShimmer(isShow: isLoading).expanded, +// 8.width, +// (icon ?? "").toSvgAsset(height: 48, width: 48, color: iconColor)?.toShimmer(isShow: isLoading), +// ], +// ).expanded, +// Text( +// "$title\n${context.translation.requests}", +// style: AppTextStyles.heading5.copyWith( +// color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, +// ), +// ).toShimmer(isShow: isLoading), +// 8.height, +// Row( +// mainAxisSize: MainAxisSize.min, +// children: [ +// Text( +// context.translation.viewDetails, +// style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary40 : AppColor.primary50), +// ), +// 4.width, +// Icon( +// Icons.arrow_forward, +// color: context.isDark ? AppColor.primary40 : AppColor.primary50, +// size: 14, +// ) +// ], +// ).toShimmer(isShow: isLoading), +// ], +// ).toShadowContainer(context).onPress(isLoading +// ? null +// : () async { +// await Navigator.push(context, MaterialPageRoute(builder: (context) => RequestsListPage(index))); +// Provider.of(context, listen: false).getRequests(); +// }); +// } +// } + + + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; @@ -8,6 +112,7 @@ import 'package:test_sa/extensions/context_extension.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:badges/badges.dart' as badges; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_floating_action_button.dart'; @@ -18,83 +123,380 @@ class RequestsFragment extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - // todo check here, nurse can add request not engineer - floatingActionButton: const AppFloatingActionButton(), - body: Consumer( - builder: (context, snapshot, _) => RefreshIndicator( - onRefresh: () { - snapshot.getRequests(); - Provider.of(context, listen: false).getSystemNotifications(user: Provider.of(context, listen: false).user, resetProvider: true); - return Future.delayed(const Duration(microseconds: 250)); - }, - child: GridView( - padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 191 / 237, crossAxisSpacing: 16, mainAxisSpacing: 16), - children: [ - gridItem( - snapshot.highPriorityRequests?.total?.count, - "high_priority", - context.translation.highPriority, - context, - snapshot.isHighPriorityLoading, - 0, - context.isDark ? AppColor.redStatus(context) : AppColor.red50, - ), - gridItem(snapshot.overdueRequests?.total?.count, "overdue", context.translation.overdue, context, snapshot.isOverdueLoading, 1, AppColor.yellowStatus(context)), - gridItem(snapshot.openRequests?.total?.count, "new_request", ApiManager.instance.user.type == UsersTypes.engineer ? context.translation.inProgress : context.translation.newR, context, - snapshot.isOpenLoading, 2, AppColor.primary40), - gridItem(snapshot.completedRequests?.total?.count, "complete_request", context.translation.completed, context, snapshot.isCompleteLoading, 3, AppColor.greenStatus(context)), - ], - ), + return Consumer( + builder: (context, snapshot, _) => RefreshIndicator( + onRefresh: () async { + snapshot.getRequests(); + await Provider.of(context, listen: false) + .getSystemNotifications( + user: Provider.of(context, listen: false).user, + resetProvider: true, + ); + return Future.delayed(const Duration(milliseconds: 250)); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _buildListItems(context, snapshot), ), ), ); } - Widget gridItem(int value, String icon, String title, BuildContext context, bool isLoading, int index, Color iconColor) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - value?.toString() ?? "-", - style: AppTextStyles.heading1.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, height: 1), - ).toShimmer(isShow: isLoading).expanded, - 8.width, - (icon ?? "").toSvgAsset(height: 48, width: 48, color: iconColor)?.toShimmer(isShow: isLoading), - ], - ).expanded, - Text( - "$title\n${context.translation.requests}", - style: AppTextStyles.heading5.copyWith( - color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + List _buildListItems(BuildContext context, AllRequestsProvider snapshot) { + final Map requestItems = { + 'high_priority': { + 'count': snapshot.highPriorityRequests?.total?.count, + 'translation': context.translation.highPriority, + 'isLoading': snapshot.isAllLoading, + 'color': context.isDark ? AppColor.redStatus(context) : AppColor.red50, + }, + 'overdue': { + 'count': snapshot.overdueRequests?.total?.count, + 'translation': context.translation.overdue, + 'isLoading': snapshot.isAllLoading, + 'color': AppColor.yellowStatus(context), + }, + 'new_request': { + 'count': snapshot.openRequests?.total?.count, + 'translation': ApiManager.instance.user.type == UsersTypes.engineer + ? context.translation.inProgress + : context.translation.newR, + 'isLoading': snapshot.isAllLoading, + 'color': AppColor.primary40, + }, + 'complete_request': { + 'count': snapshot.completedRequests?.total?.count, + 'translation': context.translation.completed, + 'isLoading': snapshot.isAllLoading, + 'color': AppColor.greenStatus(context), + }, + }; + + return requestItems.entries.map((entry) { + final key = entry.key; + final value = entry.value; + + return listItem( + value['count'], + key, + value['translation'], + context, + value['isLoading'], + requestItems.keys.toList().indexOf(key), + value['color'], + ); + }).toList(); + } + + Widget listItem( + int value, + String icon, + String title, + BuildContext context, + bool isLoading, + int index, + Color iconColor, + ) { + return GestureDetector( + onTap: isLoading + ? null + : () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RequestsListPage(index), ), - ).toShimmer(isShow: isLoading), - 8.height, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - context.translation.viewDetails, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary40 : AppColor.primary50), + ); + Provider.of(context, listen: false) + .getRequests(); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + value != null && value > 0&&!isLoading + ? badges.Badge( + badgeContent: Text( + value.toString(), + style: const TextStyle( + color: AppColor.white20, + fontWeight: FontWeight.normal, + ), + ), + badgeStyle: const badges.BadgeStyle( + padding: EdgeInsets.all(4), + badgeColor: AppColor.red50 ), - 4.width, - Icon( - Icons.arrow_forward, - color: context.isDark ? AppColor.primary40 : AppColor.primary50, - size: 14, - ) - ], - ).toShimmer(isShow: isLoading), - ], - ).toShadowContainer(context).onPress(isLoading - ? null - : () async { - await Navigator.push(context, MaterialPageRoute(builder: (context) => RequestsListPage(index))); - Provider.of(context, listen: false).getRequests(); - }); + child: Container( + child: (icon ?? "") + .toSvgAsset(height: 26, width: 26, color: iconColor) + ?.toShimmer(isShow: isLoading), + ).toShadowCircleContainer(context,padding: 18), + ) + : Container( + child: (icon ?? "") + .toSvgAsset(height: 26, width: 26, color: iconColor) + ?.toShimmer(isShow: isLoading), + ).toShadowCircleContainer(context,padding: 18), + 10.height, + Text( + title, + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + ), + ), + ], + ), + ); } } + + +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/controllers/api_routes/api_manager.dart'; +// import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +// import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +// import 'package:test_sa/controllers/providers/api/user_provider.dart'; +// import 'package:test_sa/extensions/context_extension.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:badges/badges.dart' as badges; +// import 'package:test_sa/models/enums/user_types.dart'; +// import 'package:test_sa/new_views/app_style/app_color.dart'; +// import 'package:test_sa/new_views/common_widgets/app_floating_action_button.dart'; +// import 'package:test_sa/new_views/pages/land_page/requests_list_page.dart'; +// +// class RequestsFragment extends StatelessWidget { +// const RequestsFragment({Key key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// // todo check here, nurse can add request not engineer +// floatingActionButton: const AppFloatingActionButton(), +// body: Consumer( +// builder: (context, snapshot, _) => RefreshIndicator( +// onRefresh: () { +// snapshot.getRequests(); +// Provider.of(context, listen: false) +// .getSystemNotifications( +// user: Provider.of(context, listen: false) +// .user, +// resetProvider: true); +// return Future.delayed(const Duration(microseconds: 250)); +// }, +// child: Container( +// height: 200.toScreenHeight, +// color: Colors.blue, +// child: Wrap( +// children: [ +// listItem( +// snapshot.highPriorityRequests?.total?.count, +// "high_priority", +// context.translation.highPriority, +// context, +// snapshot.isHighPriorityLoading, +// 0, +// context.isDark ? AppColor.redStatus(context) : AppColor.red50, +// ), +// ], +// ), +// // child: ListView( +// // // padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), +// // children: [ +// // listItem( +// // snapshot.highPriorityRequests?.total?.count, +// // "high_priority", +// // context.translation.highPriority, +// // context, +// // snapshot.isHighPriorityLoading, +// // 0, +// // context.isDark ? AppColor.redStatus(context) : AppColor.red50, +// // ), +// // listItem( +// // snapshot.overdueRequests?.total?.count, +// // "overdue", +// // context.translation.overdue, +// // context, +// // snapshot.isOverdueLoading, +// // 1, +// // AppColor.yellowStatus(context), +// // ), +// // listItem( +// // snapshot.openRequests?.total?.count, +// // "new_request", +// // ApiManager.instance.user.type == UsersTypes.engineer +// // ? context.translation.inProgress +// // : context.translation.newR, +// // context, +// // snapshot.isOpenLoading, +// // 2, +// // AppColor.primary40, +// // ), +// // listItem( +// // snapshot.completedRequests?.total?.count, +// // "complete_request", +// // context.translation.completed, +// // context, +// // snapshot.isCompleteLoading, +// // 3, +// // AppColor.greenStatus(context), +// // ), +// // ], +// // ), +// )), +// ), +// ); +// } +// +// Widget listItem( +// int value, +// String icon, +// String title, +// BuildContext context, +// bool isLoading, +// int index, +// Color iconColor, +// ) { +// value = 4; +// return GestureDetector( +// onTap: isLoading +// ? null +// : () async { +// await Navigator.push( +// context, +// MaterialPageRoute( +// builder: (context) => RequestsListPage(index))); +// Provider.of(context, listen: false) +// .getRequests(); +// }, +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// value!=null&&value > 0 +// ? badges.Badge( +// badgeContent: Text( +// value.toString(), +// style: const TextStyle( +// color: AppColor.white20, +// // fontSize: 1.3.h, +// fontWeight: FontWeight.normal), +// ), +// badgeStyle: badges.BadgeStyle( +// padding: EdgeInsets.all(9), +// ), +// child: Container( +// padding: const EdgeInsets.all(20), +// decoration: const BoxDecoration( +// shape: BoxShape.circle, +// //TODO add color according to theme... +// color: AppColor.white20, // Background color of the circle +// ), +// child: (icon ?? "") +// .toSvgAsset(height: 40, width: 40, color: iconColor) +// ?.toShimmer(isShow: isLoading), +// )) +// : Container( +// padding: const EdgeInsets.all(20), +// decoration: const BoxDecoration( +// shape: BoxShape.circle, +// //TODO add color according to theme... +// color: AppColor.white20, // Background color of the circle +// ), +// child: (icon ?? "") +// .toSvgAsset(height: 48, width: 48, color: iconColor) +// ?.toShimmer(isShow: isLoading), +// ), +// // Container( +// // padding: const EdgeInsets.all(20), +// // decoration: const BoxDecoration( +// // shape: BoxShape.circle, +// // //TODO add color according to theme... +// // color: AppColor.white20, // Background color of the circle +// // ), +// // child: (icon ?? "") +// // .toSvgAsset(height: 48, width: 48, color: iconColor) +// // ?.toShimmer(isShow: isLoading), +// // ), +// 20.height, +// Text( +// title, +// style: AppTextStyles.heading5.copyWith( +// color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, +// ), +// ), +// // Text( +// // "$title\n${context.translation.requests}", +// // style: AppTextStyles.heading5.copyWith( +// // color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, +// // ), +// // ).toShimmer(isShow: isLoading), +// // 8.height, +// // Row( +// // mainAxisSize: MainAxisSize.min, +// // children: [ +// // Text( +// // context.translation.viewDetails, +// // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary40 : AppColor.primary50), +// // ), +// // 4.width, +// // Icon( +// // Icons.arrow_forward, +// // color: context.isDark ? AppColor.primary40 : AppColor.primary50, +// // size: 14, +// // ) +// // ], +// // ).toShimmer(isShow: isLoading), +// ], +// ), +// ); +// } +// +// // Widget listItem(int value, String icon, String title, BuildContext context, bool isLoading, int index, Color iconColor) { +// // return Column( +// // crossAxisAlignment: CrossAxisAlignment.start, +// // children: [ +// // Row( +// // crossAxisAlignment: CrossAxisAlignment.start, +// // children: [ +// // //TODO add this to badges +// // // Text( +// // // value?.toString() ?? "-", +// // // style: AppTextStyles.heading1.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, height: 1), +// // // ).toShimmer(isShow: isLoading).expanded, +// // // 8.width, +// // (icon ?? "").toSvgAsset(height: 48, width: 48, color: iconColor)?.toShimmer(isShow: isLoading), +// // ], +// // ), +// // // Text( +// // // "$title\n${context.translation.requests}", +// // // style: AppTextStyles.heading5.copyWith( +// // // color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, +// // // ), +// // // ).toShimmer(isShow: isLoading), +// // // 8.height, +// // // Row( +// // // mainAxisSize: MainAxisSize.min, +// // // children: [ +// // // Text( +// // // context.translation.viewDetails, +// // // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.primary40 : AppColor.primary50), +// // // ), +// // // 4.width, +// // // Icon( +// // // Icons.arrow_forward, +// // // color: context.isDark ? AppColor.primary40 : AppColor.primary50, +// // // size: 14, +// // // ) +// // // ], +// // // ).toShimmer(isShow: isLoading), +// // ], +// // ).toShadowContainer(context).onPress(isLoading +// // ? null +// // : () async { +// // await Navigator.push(context, MaterialPageRoute(builder: (context) => RequestsListPage(index))); +// // Provider.of(context, listen: false).getRequests(); +// // }); +// // } +// } diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart index 8b3f37d8..0dbd7ed2 100644 --- a/lib/new_views/pages/land_page/land_page.dart +++ b/lib/new_views/pages/land_page/land_page.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/app_settings.dart'; +import 'package:test_sa/dashboard_latest/dashboard_view.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'; @@ -101,7 +102,7 @@ class _LandPageState extends State { if (_userProvider == null) { _userProvider = Provider.of(context, listen: false); _pages = [ - DashboardPage(onDrawerPress: (() { + DashboardView(onDrawerPress: (() { _scaffoldKey.currentState.isDrawerOpen ? _scaffoldKey.currentState.closeDrawer() : _scaffoldKey.currentState.openDrawer(); })), // const old_page.LandPage(), diff --git a/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart index 2d4d0a11..1a6d916e 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart @@ -1,3 +1,5 @@ +//All request page + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index ec8f6c4d..4cc643f0 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -1,3 +1,5 @@ +//request main page + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; @@ -12,6 +14,7 @@ import 'package:test_sa/new_views/pages/land_page/my_request/all_requests_search import 'package:test_sa/new_views/pages/land_page/widgets/request_item_view_list.dart'; import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; + class MyRequestsPage extends StatefulWidget { const MyRequestsPage({Key key}) : super(key: key); @@ -28,6 +31,7 @@ class _MyRequestsPageState extends State { @override Widget build(BuildContext context) { + if (_provider == null) { requestsList = [ context.translation.allRequests, diff --git a/lib/new_views/pages/land_page/requests/service_request_item_view.dart b/lib/new_views/pages/land_page/requests/service_request_item_view.dart index 0bc18630..28a5c5ff 100644 --- a/lib/new_views/pages/land_page/requests/service_request_item_view.dart +++ b/lib/new_views/pages/land_page/requests/service_request_item_view.dart @@ -1,3 +1,4 @@ +//service request item page import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -6,6 +7,8 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/service_request_latest/views/components/history_log_view.dart'; +import 'package:test_sa/service_request_latest/views/request_detail_view.dart'; import 'package:test_sa/views/pages/user/requests/service_request_details.dart'; import '../../../../views/widgets/requests/request_status.dart'; @@ -15,7 +18,7 @@ class ServiceRequestItemView extends StatelessWidget { final RequestsDetails request; final bool showShadow; - const ServiceRequestItemView(this.request, {Key key, this.showShadow = true}) : super(key: key); + ServiceRequestItemView(this.request, {Key key, this.showShadow = true}) : super(key: key); @override Widget build(BuildContext context) { @@ -65,10 +68,12 @@ class ServiceRequestItemView extends StatelessWidget { ), ], ).toShadowContainer(context, showShadow: showShadow).onPress(() { + //Older code... + Navigator.of(context).push(MaterialPageRoute( - builder: (_) => ServiceRequestDetailsPage( - serviceRequest: ServiceRequest(id: request.id.toString()), - ))); + builder: (_) => ServiceRequestDetailView( + serviceRequest: ServiceRequest(id: request.id.toString()), + ))); }); } } diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index d75e0af0..0f2a2e21 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -1,3 +1,4 @@ +//request tab page import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -21,6 +22,7 @@ class RequestItemViewList extends StatelessWidget { ? NoItemFound(message: context.translation.noDataFound) : ListView.separated( padding: const EdgeInsets.all(16), + shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); bool isServiceRequest = list[index].nameOfType == "ServiceRequest"; diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index 33cbaad8..0efe789f 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -1,7 +1,148 @@ +//older code... + +// import 'package:flutter/material.dart'; +// import 'package:fluttertoast/fluttertoast.dart'; +// import 'package:provider/provider.dart'; +// import 'package:shared_preferences/shared_preferences.dart'; +// import 'package:test_sa/controllers/providers/settings/app_settings.dart'; +// import 'package:test_sa/extensions/context_extension.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/pages/land_page/land_page.dart'; +// +// import '../../controllers/providers/api/user_provider.dart'; +// import '../../controllers/providers/settings/setting_provider.dart'; +// import '../../controllers/validator/validator.dart'; +// import '../../models/user.dart'; +// import '../common_widgets/app_filled_button.dart'; +// import '../common_widgets/app_text_form_field.dart'; +// +// class LoginPage extends StatefulWidget { +// static const String routeName = "/login_page"; +// +// const LoginPage({Key key}) : super(key: key); +// +// @override +// State createState() => _LoginPageState(); +// } +// +// class _LoginPageState extends State { +// final User _user = User(); +// UserProvider _userProvider; +// SettingProvider _settingProvider; +// final GlobalKey _formKey = GlobalKey(); +// +// bool rememberMe = false; +// +// @override +// Widget build(BuildContext context) { +// _userProvider = Provider.of(context); +// if (_settingProvider == null) { +// _settingProvider = Provider.of(context); +// rememberMe = _settingProvider.rememberMe; +// if (rememberMe) { +// _user.userName = _settingProvider.username; +// _user.password = _settingProvider.password; +// } +// } +// +// return Form( +// key: _formKey, +// child: Scaffold( +// body: Column( +// children: [ +// SingleChildScrollView( +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Hero(tag: "logo", child: "logo".toSvgAsset(height: 64)), +// 64.height, +// context.translation.login.heading2(context).custom(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.primary50 : AppColor.neutral50), +// context.translation.enterCredsToLogin.heading6(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), +// 32.height, +// AppTextFormField( +// initialValue: _user?.userName, +// validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField, +// labelText: context.translation.username, +// textInputType: TextInputType.text, +// onSaved: (value) { +// _user.userName = value; +// }, +// ), +// 16.height, +// AppTextFormField( +// initialValue: _user?.password, +// labelText: context.translation.password, +// obscureText: true, +// validator: (value) => Validator.isValidPassword(value) +// ? null +// : value.isEmpty +// ? context.translation.requiredField +// : context.translation.passwordLengthMessage, +// onSaved: (value) { +// _user.password = value; +// }, +// ), +// 8.height, +// Row( +// children: [ +// Checkbox( +// value: rememberMe, +// activeColor: AppColor.blueStatus(context), +// onChanged: (value) { +// setState(() { +// rememberMe = value; +// }); +// }), +// "Remember Me".bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral50).expanded, +// ], +// ), +// 16.height, +// Align( +// alignment: AlignmentDirectional.centerEnd, +// child: InkWell( +// onTap: () { +// /// TODO [zaid] : push to another screen +// }, +// child: context.translation.forgotPassword.bodyText(context).custom(color: AppColor.primary50, fontWeight: FontWeight.w500), +// ), +// ), +// ], +// ), +// ).center.expanded, +// AppFilledButton(label: context.translation.login, maxWidth: true, onPressed: _login), +// ], +// ).paddingOnly(start: 16, end: 16, bottom: 24, top: 24), +// ), +// ); +// } +// +// Future _login() async { +// if (!_formKey.currentState.validate()) return; +// _formKey.currentState.save(); +// int status = await _userProvider.login(context: context, user: _user); +// if (status >= 200 && status < 300 && _userProvider.user.isAuthenticated ?? false) { +// await _settingProvider.setUser(_userProvider.user); +// (await SharedPreferences.getInstance()).remove(ASettings.localAuth); +// await _settingProvider.setRememberMe(_user.userName, _user.password, rememberMe); +// +// /// The below line for the new design +// // Navigator.pushNamed(context, LandPage.routeName); +// Navigator.pushNamed(context, LandPage.routeName); +// } else { +// Fluttertoast.showToast(msg: _userProvider.user?.message ?? context.translation.failedToCompleteRequest); +// } +// } +// } + import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:test_sa/app_strings/app_asset.dart'; import 'package:test_sa/controllers/providers/settings/app_settings.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -9,6 +150,7 @@ 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/pages/land_page/land_page.dart'; +import 'package:test_sa/views/widgets/buttons/rounded_back_button.dart'; import '../../controllers/providers/api/user_provider.dart'; import '../../controllers/providers/settings/setting_provider.dart'; @@ -49,72 +191,119 @@ class _LoginPageState extends State { return Form( key: _formKey, child: Scaffold( - body: Column( - children: [ - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Hero(tag: "logo", child: "logo".toSvgAsset(height: 64)), - 64.height, - context.translation.login.heading2(context).custom(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.primary50 : AppColor.neutral50), - context.translation.enterCredsToLogin.heading6(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), - 32.height, - AppTextFormField( - initialValue: _user?.userName, - validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField, - labelText: context.translation.username, - textInputType: TextInputType.text, - onSaved: (value) { - _user.userName = value; - }, - ), - 16.height, - AppTextFormField( - initialValue: _user?.password, - labelText: context.translation.password, - obscureText: true, - validator: (value) => Validator.isValidPassword(value) - ? null - : value.isEmpty - ? context.translation.requiredField - : context.translation.passwordLengthMessage, - onSaved: (value) { - _user.password = value; - }, + backgroundColor: AppColor.background(context), + body: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: double.infinity, + height: 293.toScreenHeight, + padding: EdgeInsets.only(left: 16.toScreenWidth), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(AppAsset.loginTopBg), + fit: BoxFit.cover, // Adjusts the image to cover the entire container + ), ), - 8.height, - Row( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, children: [ - Checkbox( - value: rememberMe, - activeColor: AppColor.blueStatus(context), - onChanged: (value) { - setState(() { - rememberMe = value; - }); - }), - "Remember Me".bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral50).expanded, + SizedBox( + height: 146.toScreenHeight, + ), + // RoundedBackButton( + // icon: Icons.arrow_back_ios, + // onPressed: () { + // ///There is no previous screen + // }, + // backgroundColor: context.isDark ? AppColor.primary80 : AppColor.primary80), + + context.translation.signInToYour.customHeadingText(context).custom( + color: AppColor.white20, + ), + context.translation.account.customHeadingText(context).custom( + color: AppColor.white20, + ), + 25.height, + context.translation.letSignInToAccount.customHeadingText(context).custom( + color: AppColor.white20, + fontWeight: FontWeight.w500, + fontSize: 12, + ), ], ), - 16.height, - Align( - alignment: AlignmentDirectional.centerEnd, - child: InkWell( - onTap: () { - /// TODO [zaid] : push to another screen - }, - child: context.translation.forgotPassword.bodyText(context).custom(color: AppColor.primary50, fontWeight: FontWeight.w500), - ), + ), + SizedBox(height: 47.toScreenHeight,), + Padding( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppTextFormField( + initialValue: _user?.userName, + //TODO add the color according to theme.... + backgroundColor: AppColor.white20, + validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField, + labelText: context.translation.username, + textInputType: TextInputType.text, + showWithoutDecoration: true, + contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + onSaved: (value) { + _user.userName = value; + }, + ), + 18.height, + AppTextFormField( + initialValue: _user?.password, + showWithoutDecoration: true, + labelText: context.translation.password, + //TODO add the color according to theme.... + backgroundColor: AppColor.white20, + contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + obscureText: true, + validator: (value) => Validator.isValidPassword(value) + ? null + : value.isEmpty + ? context.translation.requiredField + : context.translation.passwordLengthMessage, + onSaved: (value) { + _user.password = value; + }, + ), + 16.height, + Align( + alignment: AlignmentDirectional.centerEnd, + child: InkWell( + onTap: () { + /// TODO [zaid] : push to another screen + }, + child: context.translation.forgotPassword.bodyText(context).custom(color: AppColor.primary10, fontWeight: FontWeight.w500), + ), + ), + Row( + children: [ + Checkbox( + value: rememberMe, + activeColor: AppColor.blueStatus(context), + onChanged: (value) { + setState(() { + rememberMe = value; + }); + }), + "Remember Me".bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral50).expanded, + ], + ), + 50.height, + AppFilledButton(label: context.translation.signIn,buttonColor: AppColor.primary10, maxWidth: true, onPressed: _login), + ], ), - ], - ), - ).center.expanded, - AppFilledButton(label: context.translation.login, maxWidth: true, onPressed: _login), - ], - ).paddingOnly(start: 16, end: 16, bottom: 24, top: 24), - ), + ), + ], + ), + )), ); } diff --git a/lib/service_request_latest/views/components/activities_list_view.dart b/lib/service_request_latest/views/components/activities_list_view.dart new file mode 100644 index 00000000..c654cf9e --- /dev/null +++ b/lib/service_request_latest/views/components/activities_list_view.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_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/models/enums/user_types.dart'; +import 'package:test_sa/models/service_request/search_work_order.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/common_widgets/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/create_service_report.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/update_service_report.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/work_order_details_page.dart'; +import 'package:test_sa/views/widgets/loaders/no_item_found.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class ActivitiesListView extends StatelessWidget { + static const String id = "/activities-list"; + + ActivitiesListView({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + // UserProvider _userProvider = Provider.of(context); + // SettingProvider _settingProvider = Provider.of(context); + List workOrders = []; + UserProvider _userProvider = Provider.of(context); + return Scaffold( + appBar: DefaultAppBar(title: context.translation.activities), + //backgroundColor: const Color(0xfff8f9fb), + body: Consumer(builder: (context, serviceRequestsProvider, child) { + return SafeArea( + child: FutureBuilder( + future: serviceRequestsProvider.searchWorkOrders(callId: serviceRequestsProvider.currentSelectedRequest?.requestCode), + builder: (context, snap) { + if (snap.connectionState == ConnectionState.waiting) return const Center(child: CircularProgressIndicator()); + workOrders = snap.data as List; + return Column( + children: [ + (workOrders.isEmpty) + ? NoItemFound(message: context.translation.noDataFound).expanded + : ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: workOrders.length, + separatorBuilder: (czt, index) => 8.height, + itemBuilder: (context, index) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: workOrders[index].currentSituation.name, + textColor: AppColor.getRequestStatusTextColorByName(context, workOrders[index].currentSituation.name), + backgroundColor: AppColor.getRequestStatusColorByName(context, workOrders[index].currentSituation.name), + ), + 8.height, + Text(serviceRequestsProvider.currentSelectedRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text( + '${context.translation.assetName}: ${workOrders[index].callRequest.asset.modelDefinition.assetName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.currentSituation}: ${workOrders[index].currentSituation.name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).onPress(() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: workOrders[index], serviceRequest: serviceRequestsProvider.currentSelectedRequest)), + ); + }).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (_userProvider.user.type == UsersTypes.engineer && + serviceRequestsProvider.currentSelectedRequest.statusValue != 5 && + serviceRequestsProvider.currentSelectedRequest.statusValue != 3) + "edit".toSvgAsset(height: 48, width: 48).onPress(() { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequestsProvider.currentSelectedRequest, workOrder: workOrders[index])), + ); + }), + if (_userProvider.user.type == UsersTypes.engineer && + serviceRequestsProvider.currentSelectedRequest.statusValue != 5 && + serviceRequestsProvider.currentSelectedRequest.statusValue != 3) + 8.height, + Text(workOrders[index].visitDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : const Color(0xFF3B3D4A))), + ], + ) + ], + ).toShadowContainer(context); + }, + ).expanded, + if (_userProvider.user.type == UsersTypes.engineer && (serviceRequestsProvider.currentSelectedRequest.statusValue != 5 && serviceRequestsProvider.currentSelectedRequest.statusValue != 3)) + AppFilledButton( + label: context.translation.createNewActivity, + maxWidth: true, + onPressed: () async{ + ServiceRequestBottomSheet.fixRemotelyBottomSheet(context: context); + // bool shouldReloadData = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // // builder: (context) => ActivityTypeBottomSheet(), + // builder: (context) => FixRemotlyBottomSheet(), + // )) as bool; + // if (shouldReloadData ?? false) { + // // getServiceRequest(); + // } + // Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequestsProvider.serviceRequest))); + }, + ).paddingOnly(start: 16, end: 16, bottom: 16) + ], + ); + }, + ), + ); + }), + ); + } +} diff --git a/lib/service_request_latest/views/components/activity_card_view.dart b/lib/service_request_latest/views/components/activity_card_view.dart new file mode 100644 index 00000000..1665ad0a --- /dev/null +++ b/lib/service_request_latest/views/components/activity_card_view.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_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/models/enums/user_types.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/update_service_report.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/work_order_details_page.dart'; + +import '../../../../views/widgets/requests/request_status.dart'; + +class ActivityCardView extends StatelessWidget { + final SearchWorkOrder workOrder; + final ServiceRequest serviceRequest; + final bool showShadow; + + ActivityCardView(this.workOrder, this.serviceRequest, {Key key, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + UserProvider _userProvider = Provider.of(context, listen: false); + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: workOrder.currentSituation.name, + textColor: AppColor.getRequestStatusTextColorByName(context, workOrder.currentSituation.name), + backgroundColor: AppColor.getRequestStatusColorByName(context, workOrder.currentSituation.name), + ), + 8.height, + Text(serviceRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text( + '${context.translation.assetName}: ${workOrder.callRequest.asset.modelDefinition.assetName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.currentSituation}: ${workOrder.currentSituation.name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.readCompleteThread, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context), decoration: TextDecoration.underline), + ), + // 4.width, + // Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).onPress(() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: workOrder, serviceRequest: serviceRequest)), + ); + }).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) + "edit_icon".toSvgAsset(height: 21, width: 21).onPress(() { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequest, workOrder: workOrder)), + ); + }), + if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) 8.height, + Text(workOrder.visitDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : const Color(0xFF3B3D4A))), + ], + ) + ], + ).toShadowContainer(context); + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart new file mode 100644 index 00000000..ffb56002 --- /dev/null +++ b/lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_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/service_request_latest/views/components/verify_arrival_view.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import '../../../../controllers/providers/api/service_requests_provider.dart'; +import '../../../../new_views/app_style/app_color.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/app_text_form_field.dart'; + +class ActionBottomSheet extends StatelessWidget { + final String title; + final String button1Text; + final String button2Text; + final VoidCallback button1Tap; + final VoidCallback button2Tap; + + ActionBottomSheet({Key key, @required this.title, this.button1Text, this.button2Text, this.button1Tap, this.button2Tap}) : super(key: key); + + final GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Consumer(builder: (context, serviceRequestProvider, child) { + return Wrap( + children: [ + Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: title.heading4(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 200.toScreenHeight, + child: AppFilledButton( + label: button1Text ?? context.translation.no, + loading: false, + buttonColor: AppColor.neutral40, + textColor: AppColor.balck10, + onPressed: button1Tap ?? + () async { + Navigator.pop(context); + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + }, + ), + ), + SizedBox( + width: 200.toScreenHeight, + child: AppFilledButton( + label: context.translation.yes, + buttonColor: AppColor.primary10, + loading: false, + onPressed:button2Tap, + ), + ), + ], + ) + ], + ), + ) + ], + ); + }); + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart new file mode 100644 index 00000000..ed66fe34 --- /dev/null +++ b/lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/app_strings/app_asset.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.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/models/service_request/service_request.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/spare_part_request.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/create_service_report.dart'; + +class ActivityTypeBottomSheet extends StatelessWidget { + ActivityTypeBottomSheet({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final List> items = [ + {'heading': context.translation.sparePartRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.sparePartIcon}, + {'heading': context.translation.maintenanceRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.maintenanceIcon}, + {'heading': context.translation.assetToBeRetired, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.retiredAssetIcon}, + ]; + return Wrap( + children: [ + Consumer(builder: (context, serviceRequestsProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + 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: 8.toScreenHeight), + child: SafeArea( + child: Column( + children: [ + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.selectActivityType.heading4(context).paddingOnly(top: 16, bottom: 16), + ), + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return listItem( + icon: item['icon'], + heading: item['heading'], + subHeading: item['subHeading'], + context: context, + onTap: () { + onItemTap(serviceRequest: serviceRequestsProvider.currentSelectedRequest, index: index, context: context); + }); + }, + ), + ], + ), + ), + ); + }), + ], + ); + } + + Widget listItem({@required BuildContext context, @required String icon, @required String heading, @required String subHeading, @required VoidCallback onTap}) { + return Padding( + padding: EdgeInsets.only(bottom: 8.toScreenHeight), + child: Card( + color: AppColor.neutral80, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + // Circular border radius + ), + // color: Colors.white, + child: ListTile( + minVerticalPadding: 8, + horizontalTitleGap: 10, + onTap: onTap, + contentPadding: const EdgeInsets.all(8), + leading: SvgPicture.asset(icon), + title: Text( + heading, + style: AppTextStyles.heading5, + ), + subtitle: Text( + subHeading, + style: AppTextStyles.bodyText, + ), + ), + ), + ); + } + + void onItemTap({@required int index, @required ServiceRequest serviceRequest, @required BuildContext context}) { + print('on item tap i got index is $index'); + switch (index) { + case 0: + Navigator.of(context).push(MaterialPageRoute(builder: (_) =>const SparePartRequest())); + + break; + case 1: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => ActivitiesListView()), + // ); + break; + case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break; + case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break; + } + // ScanQr + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart new file mode 100644 index 00000000..3c04ce0f --- /dev/null +++ b/lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart @@ -0,0 +1,217 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_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/service_request_latest/views/components/verify_arrival_view.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import '../../../../controllers/providers/api/service_requests_provider.dart'; +import '../../../../new_views/app_style/app_color.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/app_text_form_field.dart'; + +class InitialVisitBottomSheet extends StatelessWidget { + + InitialVisitBottomSheet({Key key,}) : super(key: key); + + final GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + final userProvider = Provider.of(context, listen: false); + return Consumer( + builder: (context, serviceRequestProvider,child) { + return Wrap( + children: [ + Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.setVisitDate.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + ), + + 8.height, + ADatePicker( + label: context.translation.visitDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.visitDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } + serviceRequestProvider.currentSelectedRequest.visitDate = selectedDateTime?.toIso8601String(); + } + } + }); + } + }, + ), + // ], + + if (serviceRequestProvider.currentSelectedRequest.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup.id == 1) ...[ + 8.height, + Row( + children: [ + ADatePicker( + label: context.translation.startDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + + } + } + }); + } + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.endDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.endDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + serviceRequestProvider.currentSelectedRequest.endDate = selectedDateTime?.toIso8601String(); + serviceRequestProvider.currentSelectedRequest.workingHours = + (((DateTime.parse(serviceRequestProvider.currentSelectedRequest.endDate).difference(DateTime.parse(serviceRequestProvider.currentSelectedRequest.startDate)).inSeconds ?? 0) / 60) / 60).toStringAsFixed(2); + } + } + }); + } + }, + ).expanded, + ], + ) + ], + + /// Loan availability not required + // 8.height, + // SingleItemDropDownMenu( + // context: context, + // title: context.translation.loanAvailability, + // initialValue: _serviceRequest.loanAvailability, + // onSelect: (status) { + // setState(() { + // _serviceRequest.loanAvailability = status; + // if (_serviceRequest.loanAvailability.value != 1) { + // asset = null; + // } + // }); + // }, + // ), + // if (_serviceRequest?.loanAvailability?.value == 1) 8.height, + // if (_serviceRequest?.loanAvailability?.value == 1) + // PickAsset( + // device: asset ?? _serviceRequest.device, + // onPickAsset: (asset) { + // setState(() { + // this.asset = asset; + // }); + // }, + // ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + Consumer( + builder: (context, snapshot, _) => AppFilledButton( + label: context.translation.save, + loading: snapshot.isLoading ?? false, + onPressed: () async { + _formKey.currentState.save(); + + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => VerifyArrivalView())); + }, + ), + ), + 16.height, + ], + ), + ), + ), + ) + ], + ); + } + ); + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart new file mode 100644 index 00000000..2566c764 --- /dev/null +++ b/lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart @@ -0,0 +1,236 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.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/models/device/asset.dart'; +import '../../../../controllers/providers/api/service_requests_provider.dart'; +import '../../../../models/lookup.dart'; +import '../../../../new_views/app_style/app_color.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../new_views/common_widgets/single_item_drop_down_menu.dart'; +import '../../../../providers/service_request_providers/first_action_provider.dart'; + +class RejectRequestBottomSheet extends StatelessWidget { + + RejectRequestBottomSheet({Key key,}) : super(key: key); + + final GlobalKey _formKey = GlobalKey(); + Asset asset; + + + @override + Widget build(BuildContext context) { + final userProvider = Provider.of(context, listen: false); + return Consumer( + builder: (context, requestDetailProvider,child) { + return Wrap( + children: [ + Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.rejectionReason.heading3(context).custom(fontWeight: FontWeight.w600).paddingOnly(top: 16, bottom: 16), + ), + SingleItemDropDownMenu( + context: context, + title: context.translation.rejectionReason, + initialValue: requestDetailProvider.currentSelectedRequest.firstAction, //_currentSelectedRequest.firstAction, + onSelect: (value) { + // setState(() { + //_currentSelectedRequest.firstAction = value; + requestDetailProvider.currentSelectedRequest.firstAction = value; + if (requestDetailProvider.currentSelectedRequest.firstAction.value != 2) { + requestDetailProvider.currentSelectedRequest.visitDate = null; + } + // }); + }, + ), + // if (requestDetailProvider.currentSelectedRequest.firstAction?.value == 2) ...[ + // 8.height, + // ADatePicker( + // label: context.translation.visitDate, + // date: DateTime.tryParse(requestDetailProvider.currentSelectedRequest.visitDate ?? ""), + // formatDateWithTime: true, + // onDatePicker: (selectedDate) { + // if (selectedDate != null) { + // showTimePicker( + // context: context, + // initialTime: TimeOfDay.now(), + // ).then((selectedTime) { + // // Handle the selected date and time here. + // if (selectedTime != null) { + // DateTime selectedDateTime = DateTime( + // selectedDate.year, + // selectedDate.month, + // selectedDate.day, + // selectedTime.hour, + // selectedTime.minute, + // ); + // if (selectedDateTime != null) { + // if (selectedDateTime.isBefore(DateTime.parse(requestDetailProvider.currentSelectedRequest.date))) { + // "Visit Date time must be greater then request date".showToast; + // return; + // } + // + // // setState(() { + // requestDetailProvider.currentSelectedRequest.visitDate = selectedDateTime?.toIso8601String(); + // // }); + // } + // } + // }); + // } + // }, + // ), + // ], + // + // if (requestDetailProvider.currentSelectedRequest.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup.id == 1) ...[ + // 8.height, + // Row( + // children: [ + // ADatePicker( + // label: context.translation.startDate, + // date: DateTime.tryParse(requestDetailProvider.currentSelectedRequest.startDate ?? ""), + // formatDateWithTime: true, + // onDatePicker: (selectedDate) { + // if (selectedDate != null) { + // showTimePicker( + // context: context, + // initialTime: TimeOfDay.now(), + // ).then((selectedTime) { + // // Handle the selected date and time here. + // if (selectedTime != null) { + // DateTime selectedDateTime = DateTime( + // selectedDate.year, + // selectedDate.month, + // selectedDate.day, + // selectedTime.hour, + // selectedTime.minute, + // ); + // if (selectedDateTime != null) { + // requestDetailProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + // } + // } + // }); + // } + // }, + // ).expanded, + // 8.width, + // ADatePicker( + // label: context.translation.endDate, + // date: DateTime.tryParse(requestDetailProvider.currentSelectedRequest.endDate ?? ""), + // formatDateWithTime: true, + // onDatePicker: (selectedDate) { + // if (selectedDate != null) { + // showTimePicker( + // context: context, + // initialTime: TimeOfDay.now(), + // ).then((selectedTime) { + // // Handle the selected date and time here. + // if (selectedTime != null) { + // DateTime selectedDateTime = DateTime( + // selectedDate.year, + // selectedDate.month, + // selectedDate.day, + // selectedTime.hour, + // selectedTime.minute, + // ); + // if (selectedDateTime != null) { + // requestDetailProvider.currentSelectedRequest.endDate = selectedDateTime?.toIso8601String(); + // requestDetailProvider.currentSelectedRequest.workingHours = + // (((DateTime.parse(requestDetailProvider.currentSelectedRequest.endDate).difference(DateTime.parse(requestDetailProvider.currentSelectedRequest.startDate)).inSeconds ?? 0) / 60) / 60).toStringAsFixed(2); + // } + // } + // }); + // } + // }, + // ).expanded, + // ], + // ) + // ], + + /// Loan availability not required + // 8.height, + // SingleItemDropDownMenu( + // context: context, + // title: context.translation.loanAvailability, + // initialValue: _currentSelectedRequest.loanAvailability, + // onSelect: (status) { + // setState(() { + // _currentSelectedRequest.loanAvailability = status; + // if (_currentSelectedRequest.loanAvailability.value != 1) { + // asset = null; + // } + // }); + // }, + // ), + // if (_currentSelectedRequest?.loanAvailability?.value == 1) 8.height, + // if (_currentSelectedRequest?.loanAvailability?.value == 1) + // PickAsset( + // device: asset ?? _currentSelectedRequest.device, + // onPickAsset: (asset) { + // setState(() { + // this.asset = asset; + // }); + // }, + // ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + onChange: (text) { + requestDetailProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + requestDetailProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + Consumer( + builder: (context, snapshot, _) => AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red50, + showBorder: true, + loading: snapshot.isLoading ?? false, + onPressed: () async { + _formKey.currentState.save(); + // requestDetailProvider.serviceRequest.device = asset; + await snapshot.updateRequest(user: userProvider.user, request: requestDetailProvider.currentSelectedRequest); + Navigator.pop(context, true); + }, + ), + ), + 16.height, + ], + ), + ), + ), + ) + ], + ); + } + ); + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart new file mode 100644 index 00000000..cb6ad769 --- /dev/null +++ b/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart @@ -0,0 +1,860 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/app_strings/app_asset.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_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/models/device/asset.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/first_action_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/spare_part_request.dart'; +import 'package:test_sa/service_request_latest/views/components/verify_arrival_view.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; +import '../../../../controllers/providers/api/service_requests_provider.dart'; +import '../../../../new_views/app_style/app_color.dart'; +import '../../../../new_views/common_widgets/app_filled_button.dart'; +import '../../../../new_views/common_widgets/app_text_form_field.dart'; + +// class FixRemotlyBottomSheet extends StatelessWidget { +// +// FixRemotlyBottomSheet({Key key,}) : super(key: key); +// +// final GlobalKey _formKey = GlobalKey(); +// +// @override +// Widget build(BuildContext context) { +// return Consumer( +// builder: (context, serviceRequestProvider,child) { +// return StatefulBuilder( +// builder: (BuildContext context, StateSetter setState) { +// return Container( +// clipBehavior: Clip.antiAlias, +// 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: 8.toScreenHeight), +// child: Form( +// key: _formKey, +// child: SingleChildScrollView( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Center( +// child: Container( +// width: 40.toScreenWidth, +// height: 5.toScreenHeight, +// decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), +// ), +// ), +// Align( +// alignment: AlignmentDirectional.centerStart, +// child: context.translation.fillDetails.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), +// ), +// +// 8.height, +// ADatePicker( +// label: context.translation.date, +// height: 80.toScreenHeight, +// backgroundColor: AppColor.neutral90, +// date: DateTime.tryParse(serviceRequestProvider.serviceRequest.startDate ?? ""), +// formatDateWithTime: true, +// onDatePicker: (selectedDate) { +// if (selectedDate != null) { +// showTimePicker( +// context: context, +// initialTime: TimeOfDay.now(), +// ).then((selectedTime) { +// // Handle the selected date and time here. +// if (selectedTime != null) { +// DateTime selectedDateTime = DateTime( +// selectedDate.year, +// selectedDate.month, +// selectedDate.day, +// selectedTime.hour, +// selectedTime.minute, +// ); +// if (selectedDateTime != null) { +// if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { +// "Visit Date time must be greater then request date".showToast; +// return; +// } +// +// setState(() { +// serviceRequestProvider.serviceRequest.startDate = selectedDateTime?.toIso8601String(); +// }); +// } +// } +// }); +// } +// }, +// ), +// 8.height, +// ATimePicker( +// label: context.translation.startTime, +// height: 80.toScreenHeight, +// backgroundColor: AppColor.neutral90, +// hint:context.translation.pickTime, +// time: serviceRequestProvider.selectedTime, +// onTimePicker: (selectedTime) { +// //TODO handle selected time here. +// if (selectedTime != null) { +// setState(() { +// serviceRequestProvider.selectedTime = selectedTime; +// }); +// // DateTime selectedDateTime = DateTime( +// // selectedDate.year, +// // selectedDate.month, +// // selectedDate.day, +// // selectedTime.hour, +// // selectedTime.minute, +// // ); +// // if (selectedDateTime != null) { +// // if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { +// // "Visit Date time must be greater then request date".showToast; +// // return; +// // } +// // +// +// // } +// } +// }, +// ), +// 8.height, +// ATimePicker( +// label: context.translation.endTime, +// height: 80.toScreenHeight, +// backgroundColor: AppColor.neutral90, +// hint:context.translation.pickTime, +// time: serviceRequestProvider.selectedTime, +// onTimePicker: (selectedTime) { +// //TODO handle selected time here. +// if (selectedTime != null) { +// setState(() { +// serviceRequestProvider.selectedTime = selectedTime; +// }); +// } +// }, +// ), +// 8.height, +// Container( +// width: double.infinity, +// height: 80.toScreenHeight, +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(10), +// color:AppColor.neutral90, +// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], +// ), +// padding: EdgeInsets.symmetric(horizontal: 20.toScreenWidth,vertical: 10.toScreenHeight), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.start, +// children: [ +// context.translation.workingHours.bodyText2(context), +// //TODo calculate the hours and write here. +// 'No of hours'.bodyText(context).custom(color:AppColor.balck10), +// ], +// ), +// +// ), +// 8.height, +// AppTextFormField( +// labelText: context.translation.comments, +// textInputType: TextInputType.multiline, +// alignLabelWithHint: true, +// backgroundColor: AppColor.neutral90, +// onChange: (text) { +// serviceRequestProvider.serviceRequest.comments = text; +// }, +// onSaved: (text) { +// serviceRequestProvider.serviceRequest.comments = text; +// }, +// ), +// 16.height, +// Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// SizedBox( +// width: 200.toScreenHeight, +// child: AppFilledButton( +// label: context.translation.cancel, +// loading: false, +// buttonColor: Colors.transparent, +// showBorder: true, +// textColor: AppColor.balck10, +// onPressed: +// () async { +// Navigator.pop(context); +// // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); +// // Navigator.pop(context, true); +// }, +// ), +// ), +// SizedBox( +// width: 200.toScreenHeight, +// child: AppFilledButton( +// label: context.translation.fixed, +// buttonColor: AppColor.green70, +// loading: false, +// onPressed:(){ +// +// }, +// ), +// ), +// ], +// ), +// 16.height, +// ], +// ), +// ), +// ), +// ); +// } +// ); +// } +// ); +// } +// } + +class ServiceRequestBottomSheet { + static Future fixRemotelyBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + 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: 8.toScreenHeight), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: StatefulBuilder( + builder: (context, setState) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.fillDetails.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + ), + 8.height, + ADatePicker( + label: context.translation.date, + hideShadow: true, + height: 80.toScreenHeight, + backgroundColor: AppColor.neutral90, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } + + setState(() { + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + }); + print('start date i got is ${serviceRequestProvider.currentSelectedRequest.startDate}'); + } + } + }); + } + }, + ), + + // ATimePicker( + // label: context.translation.startTime, + // height: 80.toScreenHeight, + // backgroundColor: AppColor.neutral90, + // hint: context.translation.pickTime, + // time: serviceRequestProvider.selectedTime, + // onTimePicker: (selectedTime) { + // //TODO handle selected time here. + // if (selectedTime != null) { + // // setState(() { + // serviceRequestProvider.selectedTime = selectedTime; + // // }); + // // DateTime selectedDateTime = DateTime( + // // selectedDate.year, + // // selectedDate.month, + // // selectedDate.day, + // // selectedTime.hour, + // // selectedTime.minute, + // // ); + // // if (selectedDateTime != null) { + // // if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { + // // "Visit Date time must be greater then request date".showToast; + // // return; + // // } + // // + // + // // } + // } + // }, + // ), + // 8.height, + // ATimePicker( + // label: context.translation.endTime, + // height: 80.toScreenHeight, + // backgroundColor: AppColor.neutral90, + // hint: context.translation.pickTime, + // time: serviceRequestProvider.selectedTime, + // onTimePicker: (selectedTime) { + // //TODO handle selected time here. + // if (selectedTime != null) { + // // setState(() { + // serviceRequestProvider.selectedTime = selectedTime; + // // }); + // } + // }, + // ), + 8.height, + SizedBox( + width: double.infinity, + height: 80.toScreenHeight, + // padding: EdgeInsets.symmetric(horizontal: 20.toScreenWidth, vertical: 10.toScreenHeight), + child: + AppTimer( + label: context.translation.workingHours, + timer: TimerModel(), + decoration: BoxDecoration( + color: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + borderRadius: BorderRadius.circular(10), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + // enabled: serviceRequestProvider.currentSelectedRequest.date == null, + enabled: true, + onChange: (timer) async { + print('timer i got is ${timer.toString()}'); + return true; + }, + ), + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // context.translation.workingHours.bodyText2(context), + // //TODo calculate the hours and write here. + // 'No of hours'.bodyText(context).custom(color: AppColor.balck10), + // ], + // ), + ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 200.toScreenHeight, + child: AppFilledButton( + label: context.translation.cancel, + loading: false, + buttonColor: Colors.transparent, + showBorder: true, + textColor: AppColor.balck10, + onPressed: () async { + Navigator.pop(context); + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + }, + ), + ), + SizedBox( + width: 200.toScreenHeight, + child: AppFilledButton( + label: context.translation.fixed, + buttonColor: AppColor.green70, + loading: false, + onPressed: () {}, + ), + ), + ], + ), + 16.height, + ], + ); + } + ), + ), + ), + ); + })); + } + + static Future initialVisitBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.setVisitDate.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + ), + + 8.height, + ADatePicker( + label: context.translation.visitDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.visitDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } + serviceRequestProvider.currentSelectedRequest.visitDate = selectedDateTime?.toIso8601String(); + } + } + }); + } + }, + ), + // ], + + if (serviceRequestProvider.currentSelectedRequest.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup.id == 1) ...[ + 8.height, + Row( + children: [ + ADatePicker( + label: context.translation.startDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + } + } + }); + } + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.endDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.endDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + serviceRequestProvider.currentSelectedRequest.endDate = selectedDateTime?.toIso8601String(); + serviceRequestProvider.currentSelectedRequest.workingHours = + (((DateTime.parse(serviceRequestProvider.currentSelectedRequest.endDate).difference(DateTime.parse(serviceRequestProvider.currentSelectedRequest.startDate)).inSeconds ?? + 0) / + 60) / + 60) + .toStringAsFixed(2); + } + } + }); + } + }, + ).expanded, + ], + ) + ], + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + Consumer( + builder: (context, snapshot, _) => AppFilledButton( + label: context.translation.save, + loading: snapshot.isLoading ?? false, + onPressed: () async { + _formKey.currentState.save(); + + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => VerifyArrivalView())); + }, + ), + ), + 16.height, + ], + ), + ), + ), + ); + })); + } + + static Future rejectRequestBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); + final userProvider = Provider.of(context, listen: false); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.rejectionReason.heading3(context).custom(fontWeight: FontWeight.w600).paddingOnly(top: 16, bottom: 16), + ), + SingleItemDropDownMenu( + context: context, + title: context.translation.rejectionReason, + initialValue: serviceRequestProvider.currentSelectedRequest.firstAction, //_serviceRequest.firstAction, + onSelect: (value) { + serviceRequestProvider.currentSelectedRequest.firstAction = value; + if (serviceRequestProvider.currentSelectedRequest.firstAction.value != 2) { + serviceRequestProvider.currentSelectedRequest.visitDate = null; + } + }, + ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + Consumer( + builder: (context, snapshot, _) => AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red50, + showBorder: true, + loading: snapshot.isLoading ?? false, + onPressed: () async { + _formKey.currentState.save(); + // serviceRequestProvider.serviceRequest.device = asset; + await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.currentSelectedRequest); + Navigator.pop(context, true); + }, + ), + ), + 16.height, + ], + ), + ), + ), + ); + })); + } + + static Future activityTypeBottomSheet({@required BuildContext context}) { + final List> items = [ + {'heading': context.translation.sparePartRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.sparePartIcon}, + {'heading': context.translation.maintenanceRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.maintenanceIcon}, + {'heading': context.translation.assetToBeRetired, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.retiredAssetIcon}, + ]; + Widget listItem({@required BuildContext context, @required String icon, @required String heading, @required String subHeading, @required VoidCallback onTap}) { + return Padding( + padding: EdgeInsets.only(bottom: 8.toScreenHeight), + child: Card( + color: AppColor.neutral80, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + // Circular border radius + ), + // color: Colors.white, + child: ListTile( + minVerticalPadding: 8, + horizontalTitleGap: 10, + onTap: onTap, + contentPadding: const EdgeInsets.all(8), + leading: SvgPicture.asset(icon), + title: Text( + heading, + style: AppTextStyles.heading5, + ), + subtitle: Text( + subHeading, + style: AppTextStyles.bodyText, + ), + ), + ), + ); + } + + void onItemTap({@required int index, @required ServiceRequest serviceRequest, @required BuildContext context}) { + print('on item tap i got index is $index'); + switch (index) { + case 0: + Navigator.of(context).push(MaterialPageRoute(builder: (_) => const SparePartRequest())); + + break; + case 1: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => ActivitiesListView()), + // ); + break; + case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break; + case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break; + } + // ScanQr + } + + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: false, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + 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: 8.toScreenHeight), + child: SafeArea( + child: Column( + children: [ + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.selectActivityType.heading4(context).paddingOnly(top: 16, bottom: 16), + ), + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return listItem( + icon: item['icon'], + heading: item['heading'], + subHeading: item['subHeading'], + context: context, + onTap: () { + onItemTap(serviceRequest: serviceRequestProvider.currentSelectedRequest, index: index, context: context); + }); + }, + ), + ], + ), + ), + ); + })); + } + + static Future actionBottomSheet({@required BuildContext context, @required String title, String button1Text, String button2Text, VoidCallback button1Tap, VoidCallback button2Tap}) { + final GlobalKey _formKey = GlobalKey(); + final userProvider = Provider.of(context, listen: false); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + Align( + alignment: AlignmentDirectional.centerStart, + child: title.heading4(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 200.toScreenHeight, + child: AppFilledButton( + label: button1Text ?? context.translation.no, + loading: false, + buttonColor: AppColor.neutral40, + textColor: AppColor.balck10, + onPressed: button1Tap ?? + () async { + Navigator.pop(context); + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + }, + ), + ), + SizedBox( + width: 200.toScreenHeight, + child: AppFilledButton( + label: context.translation.yes, + buttonColor: AppColor.primary10, + loading: false, + onPressed: button2Tap, + ), + ), + ], + ) + ], + ), + ); + })); + } +} diff --git a/lib/service_request_latest/views/components/history_log_view.dart b/lib/service_request_latest/views/components/history_log_view.dart new file mode 100644 index 00000000..188464fb --- /dev/null +++ b/lib/service_request_latest/views/components/history_log_view.dart @@ -0,0 +1,60 @@ +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/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'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class HistoryLogView extends StatelessWidget { + const HistoryLogView({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColor.neutral100, + body: Padding( + padding: EdgeInsets.symmetric(vertical: 50.toScreenHeight), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + historyLogCard(context: context,date: DateTime.now()), + historyLogCard(context: context,date: DateTime.now()), + historyLogCard(context: context,date: DateTime.now()), + historyLogCard(context: context,date: DateTime.now()), + ], + ), + ), + ); + } + + Widget historyLogCard({@required BuildContext context, @required DateTime date}) { + return SizedBox( + width: double.infinity, + child: Padding( + padding: EdgeInsets.only(left: 16.toScreenWidth, bottom: 16.toScreenHeight, top: 12.toScreenHeight), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + Text( + date.toString().toServiceRequestCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral20), + ), + ], + ), + 50.width, + Expanded( + child: 'Requester acknowledged adc dld a'.heading6(context), + ), + ], + ), + ), + ).toShadowContainer(context).paddingOnly(start: 16, end: 16); + } +} diff --git a/lib/service_request_latest/views/components/scan_qr_view.dart b/lib/service_request_latest/views/components/scan_qr_view.dart new file mode 100644 index 00000000..23740b79 --- /dev/null +++ b/lib/service_request_latest/views/components/scan_qr_view.dart @@ -0,0 +1,72 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:qr_code_scanner/qr_code_scanner.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + + +class ScanQrView extends StatefulWidget { + const ScanQrView({Key key}) : super(key: key); + + @override + _ScanQrViewState createState() => _ScanQrViewState(); +} + +class _ScanQrViewState extends State { + Barcode result; + QRViewController _controller; + bool _scanDone = false; + final GlobalKey qrKey = GlobalKey(debugLabel: 'QR_scanner'); + + // In order to get hot reload to work we need to pause the camera if the platform + // is android, or resume the camera if the platform is iOS. + @override + void reassemble() { + super.reassemble(); + if (Platform.isAndroid) { + _controller?.pauseCamera(); + } else if (Platform.isIOS) { + _controller?.resumeCamera(); + } + } + + @override + void dispose() { + super.dispose(); + _controller?.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + + body: Stack( + children: [ + QRView( + key: qrKey, + onQRViewCreated: (QRViewController controller) { + setState(() { + _controller = controller; + }); + controller.scannedDataStream.listen((scanData) { + if (!_scanDone) { + _scanDone = true; + Navigator.of(context).pop(scanData.code); + } + }); + }, + overlay: QrScannerOverlayShape(borderColor: Colors.red, borderRadius: 10, borderLength: 30, borderWidth: 10, cutOutSize: 280), + ), + Padding( + padding: EdgeInsets.all(12.0), + child: SizedBox( + height: 100.toScreenHeight, + child: DefaultAppBar(title: context.translation.scanQr)), + ) + ], + ), + ); + } +} diff --git a/lib/service_request_latest/views/components/spare_part_request.dart b/lib/service_request_latest/views/components/spare_part_request.dart new file mode 100644 index 00000000..68077dec --- /dev/null +++ b/lib/service_request_latest/views/components/spare_part_request.dart @@ -0,0 +1,250 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/attachment.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.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/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.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/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/part_no_button.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../models/lookup.dart'; +import '../../../../../models/service_request/spare_parts.dart'; +import '../../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../../new_views/common_widgets/default_app_bar.dart'; +import '../../../controllers/validator/validator.dart'; + +class SparePartRequest extends StatefulWidget { + static const String id = "/spare-part-request"; + + const SparePartRequest({Key key}) : super(key: key); + + @override + _SparePartRequestState createState() => _SparePartRequestState(); +} + +class _SparePartRequestState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + List _spareParts = []; + + final List _files = []; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + final TextEditingController _faultController = TextEditingController(); + final TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _partQtyController = TextEditingController(); + final TextEditingController _oracleNoController = TextEditingController(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _faultController.dispose(); + _workPreformedController.dispose(); + _partQtyController.dispose(); + super.dispose(); + } + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _spareParts = await _partsProvider.getPartsList(assetId: serviceRequestsProvider.currentSelectedRequest.deviceId); + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + _partsProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.sparePartRequest), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + context.translation.sparePartDetails.heading5(context), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.partNo, + staticData: _spareParts, + height: 80.toScreenHeight, + showShadow: false, + initialValue: serviceRequestProvider.initialSelectedSparePart.sparePart, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + onSelect: (part) { + serviceRequestProvider.initialSelectedSparePart = SparePartsWorkOrders(id: 0, sparePart: part, qty: 0); + }, + ), + 15.height, + AppTextFormField( + controller: _partQtyController, + labelText: context.translation.quantity, + textInputType: TextInputType.number, + contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onSaved: (text) { + serviceRequestProvider.initialSelectedSparePart.qty = num.tryParse(text ?? ""); + }, + ), + 15.height, + AppTextFormField( + controller: _oracleNoController, + labelText: context.translation.oracleNo, + textInputType: TextInputType.number, + contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onSaved: (text) { + //TODO set the values... + // serviceRequestProvider.initialSelectedSparePart. = num.tryParse(text ?? ""); + }, + ), + 15.height, + AppTextFormField( + initialValue: _serviceReport?.comment, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + labelText: context.translation.description, + alignLabelWithHint: true, + showWithoutDecoration: true, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.comment = value; + }, + ), + 15.height, + MultiFilesPicker(label: context.translation.attachQuotation, files: _files), + ], + ).paddingAll(16), + ), + 8.height, + ], + ), + ).expanded, + AppFilledButton( + label: context.translation.addSparePartActivity, + buttonColor: AppColor.green70, + onPressed: () async { + ServiceRequestBottomSheet.actionBottomSheet(context: context, title: context.translation.addSparePartActionHeading); + // bool shouldReloadData = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => ActionBottomSheet(title: context.translation.addSparePartActionHeading), + // )) as bool; + // if (shouldReloadData ?? false) {} + //TODO write add sparepart logic + + // if ((!_formKey.currentState.validate()) || (!(await _serviceReport.validate(context)))) { + // setState(() {}); + // return; + // } + // _formKey.currentState.save(); + // _serviceReport.attachmentsWorkOrder ??= []; + // if (_files.isEmpty) _serviceReport.attachmentsWorkOrder = []; + // for (var file in _files) { + // _serviceReport.attachmentsWorkOrder.add(Attachment(id: 0, name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}")); + // } + // final user = Provider.of(context, listen: false).user; + // await _serviceRequestsProvider.createServiceReport(context, report: _serviceReport, request: serviceRequestProvider.serviceRequest, user: user); + }, + ), + ], + ).paddingAll(16), + ), + ), + ); + }), + ); + } +} diff --git a/lib/service_request_latest/views/components/verify_arrival_view.dart b/lib/service_request_latest/views/components/verify_arrival_view.dart new file mode 100644 index 00000000..5aa9d97a --- /dev/null +++ b/lib/service_request_latest/views/components/verify_arrival_view.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/app_strings/app_asset.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.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/models/service_request/service_request.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/scan_qr_view.dart'; +import 'package:test_sa/views/widgets/qr/scan_qr.dart'; + +import 'activities_list_view.dart'; + +class VerifyArrivalView extends StatelessWidget { + VerifyArrivalView({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final List> items = [ + {'heading': context.translation.scanQr, 'subHeading': context.translation.scanQrDetail, 'icon': AppAsset.scanQrIcon}, + {'heading': context.translation.askRequester, 'subHeading': context.translation.askRequesterDetail, 'icon': AppAsset.askRequesterIcon}, + {'heading': context.translation.askOtp, 'subHeading': context.translation.askOtpDetail, 'icon': AppAsset.askOtpIcon}, + {'heading': context.translation.takeDevicePhoto, 'subHeading': context.translation.takeDevicePhotoDetail, 'icon': AppAsset.takeDevicePhotoIcon}, + ]; + return Scaffold( + appBar: DefaultAppBar(title: context.translation.verifyArrival), + //backgroundColor: const Color(0xfff8f9fb), + body: Consumer(builder: (context, serviceRequestsProvider, child) { + return SafeArea( + child: ListView.builder( + padding: EdgeInsets.symmetric(vertical: 12.toScreenHeight), + // padding: EdgeInsets.zero, + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return listItem( + icon: item['icon'], + heading: item['heading'], + subHeading: item['subHeading'], + context: context, + onTap: () { + + onItemTap(serviceRequest: serviceRequestsProvider.currentSelectedRequest, index: index,context: context); + }); + }, + ), + ); + }), + ); + } + + Widget listItem({@required BuildContext context, @required String icon, @required String heading, @required String subHeading, @required VoidCallback onTap}) { + return Padding( + padding: EdgeInsets.only(left: 16.toScreenWidth,right: 16.toScreenWidth,bottom: 12.toScreenHeight), + + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14), // Circular border radius + ), + color: Colors.white, + child: + ListTile( + minVerticalPadding: 12, + horizontalTitleGap: 10, + onTap: onTap, + // contentPadding: const EdgeInsets.all(12), + leading: SvgPicture.asset(icon), + title: Text( + heading, + style: AppTextStyles.heading5, + ), + subtitle: Text( + subHeading, + style: AppTextStyles.bodyText, + ), + ), + ), + ); + } + + void onItemTap({@required int index, @required ServiceRequest serviceRequest,@required BuildContext context}) { + print('on item tap i got index is $index'); + switch(index){ + case 0: + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const ScanQrView()), + ); + break;case 1: + //push to specific screen... + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ActivitiesListView()), + ); + break;case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break;case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break; + } + // ScanQr + } +} diff --git a/lib/service_request_latest/views/components/verify_otp_view.dart b/lib/service_request_latest/views/components/verify_otp_view.dart new file mode 100644 index 00000000..fff00916 --- /dev/null +++ b/lib/service_request_latest/views/components/verify_otp_view.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:pinput/pinput.dart'; +import 'package:test_sa/extensions/context_extension.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/models/timer_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; + +class VerifyOtpView extends StatelessWidget { + const VerifyOtpView({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final defaultPinTheme = PinTheme( + width: 51.toScreenWidth, + height: 63.toScreenHeight, + textStyle: const TextStyle( + fontSize: 22, + color: Colors.black, + ), + decoration: BoxDecoration( + color: AppColor.neutral100, + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Colors.transparent), + ), + ); + return Scaffold( + backgroundColor: AppColor.neutral100, + appBar: DefaultAppBar(title: context.translation.askOtpFromRequester), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + SizedBox( + width: double.infinity, + child: Padding( + padding: EdgeInsets.only(left: 16.toScreenWidth, bottom: 16.toScreenHeight, top: 12.toScreenHeight), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + context.translation.verify.heading5(context), + 12.height, + context.translation.otpSentToNumber.bodyText(context), + Padding( + padding: EdgeInsets.symmetric( + vertical: 50.toScreenHeight, + ), + child: Center( + child: Pinput( + length: 4, + defaultPinTheme: defaultPinTheme, + focusedPinTheme: defaultPinTheme.copyWith( + decoration: defaultPinTheme.decoration?.copyWith( + border: Border.all(color: AppColor.neutral100), + ), + ), + onCompleted: (pin) => debugPrint(pin), + ), + ), + ), + Row( + children: [ + context.translation.resendIn.bodyText(context), + 7.width, + ValueListenableBuilder( + //add actual timer value... + valueListenable: ValueNotifier("0:00"), + builder: (context, value, _) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + value.bodyText(context).custom( + color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, + ), + ], + ); + }, + ), + 7.width, + InkWell( + onTap: (){ + //other method check.. + }, + child: Text(context.translation.resend,style: const TextStyle( + color: AppColor.primary10, + decoration: TextDecoration.underline, + ),), + ), + ], + ), + ], + ), + ), + ).toShadowContainer(context).paddingOnly(start: 16, end: 16), + Padding( + padding: EdgeInsets.only(left: 17.toScreenWidth, top: 24.toScreenHeight), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + context.translation.havingTroubleReceivingOtp.heading6(context), + 3.height, + InkWell( + onTap: (){ + //other method check.. + }, + child: Text(context.translation.checkOutOtherMethods,style: const TextStyle( + color: AppColor.primary10, + decoration: TextDecoration.underline, + ),), + ), + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/service_request_latest/views/request_detail_view.dart b/lib/service_request_latest/views/request_detail_view.dart new file mode 100644 index 00000000..dd0f041d --- /dev/null +++ b/lib/service_request_latest/views/request_detail_view.dart @@ -0,0 +1,393 @@ +import 'package:another_flushbar/flushbar.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/comments_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_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/models/enums/user_types.dart'; +import 'package:test_sa/models/service_request/service_request.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/common_widgets/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart'; +import 'package:test_sa/service_request_latest/views/components/verify_otp_view.dart'; +import 'package:test_sa/utilities/general_utils.dart'; +import 'package:test_sa/views/pages/user/requests/comments_bottom_sheet.dart'; +import 'package:test_sa/views/pages/user/requests/first_action_bottom_sheet.dart'; +import 'package:test_sa/views/pages/user/requests/update_service_request_page.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/work_orders_list_page.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; +import 'package:test_sa/views/widgets/sound/sound_player.dart'; + +import 'components/bottom_sheets/initial_visit_bottomsheet.dart'; + +class ServiceRequestDetailView extends StatefulWidget { + static const String id = "/call-details"; + ServiceRequest serviceRequest; + + ServiceRequestDetailView({Key key, this.serviceRequest}) : super(key: key); + + @override + State createState() => _ServiceRequestDetailViewState(); +} + +class _ServiceRequestDetailViewState extends State { + bool loading = false; + + // ServiceRequest serviceRequest; + + @override + void initState() { + super.initState(); + getServiceRequest(requestId: widget.serviceRequest.id); + } + + void getServiceRequest({@required dynamic requestId}) { + // setState(() {}); + WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((timeStamp) async { + Provider.of(context, listen: false).reset(); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + serviceRequestsProvider.currentSelectedRequest = await serviceRequestsProvider.getServiceRequestObjectById(requestId: requestId); + // setState(() {}); + }); + } + + @override + Widget build(BuildContext context) { + UserProvider _userProvider = Provider.of(context, listen: false); + + Widget informationCard(ServiceRequest serviceRequest) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + StatusLabel( + label: serviceRequest.priority.name, + id: serviceRequest.priority.id, + textColor: AppColor.getPriorityStatusTextColor(context, serviceRequest.priority.id), + backgroundColor: AppColor.getPriorityStatusColor(context, serviceRequest.priority.id), + ), + 8.width, + StatusLabel( + label: serviceRequest.statusLabel, + textColor: AppColor.getRequestStatusTextColor(context, serviceRequest.statusValue), + backgroundColor: AppColor.getRequestStatusColor(context, serviceRequest.statusValue), + ), + 1.width.expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + if (_userProvider.user.type == UsersTypes.normal_user) + context.translation.code.toSvgAsset(width: 48).onPress(() { + Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateServiceRequestPage(serviceRequest: serviceRequest))); + }), + if (_userProvider.user.type == UsersTypes.engineer) 16.height, + Text( + serviceRequest.date.toServiceRequestCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + ], + ) + ], + ), + Text( + context.translation.assetDetails, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + '${context.translation.assetName}: ${serviceRequest.deviceEnName?.cleanupWhitespace?.capitalizeFirstOfEach}'.bodyText(context), + // 8.height, + Text( + '${context.translation.assetNumber}: ${serviceRequest.device?.assetNumber}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + + Text( + '${context.translation.equipmentStatus}: ${serviceRequest.defectType?.name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.manufacture}: ${serviceRequest.device.modelDefinition.manufacturerName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.model}: ${serviceRequest.device.modelDefinition.modelName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.site}: ${serviceRequest.device.site?.custName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.building}: ${serviceRequest.device.building?.name?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.floor}: ${serviceRequest.device.floor?.name?.cleanupWhitespace?.capitalizeFirstOfEach ?? ""}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.department}: ${serviceRequest.device.department?.departmentName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.room}: ${(serviceRequest.device.room?.name ?? "").cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + ], + ).expanded, + ], + ), + 8.height, + const Divider().defaultStyle(context), + + //... request details starts here.... + Text( + context.translation.requestDetail, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + Text( + '${context.translation.requestType}: ${serviceRequest.type.name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.requestNo}: ${serviceRequest.requestCode}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.requesterName}: ${serviceRequest.callCreatedBy?.name ?? "-"}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + + 8.height, + if ((serviceRequest.callComments ?? "").isNotEmpty) ...[ + const Divider().defaultStyle(context), + 8.height, + Text( + serviceRequest.callComments, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + ], + if (serviceRequest.devicePhotos.isNotEmpty) ...[ + 8.height, + const Divider().defaultStyle(context), + FilesList(images: serviceRequest.devicePhotos), + ], + if (serviceRequest.audio?.isNotEmpty ?? false) ...[ + const Divider().defaultStyle(context), + 16.height, + ASoundPlayer(audio: serviceRequest.audio), + 8.height, + ], + ], + ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8), + (_userProvider.user.type == UsersTypes.normal_user + ? Container( + height: 50, + padding: const EdgeInsets.only(left: 16, right: 16), + alignment: Alignment.center, + width: double.infinity, + decoration: ShapeDecoration( + color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + ), + ), + ), + child: Row( + children: [ + Text( + '${context.translation.commentHere}...', + style: AppTextStyles.heading6.copyWith( + color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50).withOpacity(.6), + ), + ).expanded, + "comment_send".toSvgAsset(width: 24, color: context.isDark ? AppColor.primary50 : AppColor.primary70), + ], + ), + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewComments, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).paddingOnly(bottom: 16, start: 16, end: 16)) + .onPress(() { + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + useRootNavigator: true, + backgroundColor: Colors.transparent, + builder: (context) => CommentsBottomSheet(requestId: serviceRequest.id), + ); + }), + ], + ).toShadowContainer(context, padding: 0); + } + + return Scaffold( + appBar: DefaultAppBar(title: context.translation.serviceDetails), + //backgroundColor: const Color(0xfff8f9fb), + body: Consumer(builder: (context, serviceRequestsProvider, child) { + return SafeArea( + child: serviceRequestsProvider.isDetialLoading + ? const ALoading().center + : serviceRequestsProvider.currentSelectedRequest == null + ? Text( + context.translation.noDataFound, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ).center + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: informationCard(serviceRequestsProvider.currentSelectedRequest), + ).expanded, + Center( + child: InkWell( + onTap: () async { + AllRequestsProvider allRequestProvider = Provider.of(context, listen: false); + int index = allRequestProvider.filterRequest.requestsDetails.indexWhere((element) => element.id.toString() == serviceRequestsProvider.currentSelectedRequest.id); + print('index i got is $index'); + if (index != -1 && index != allRequestProvider.filterRequest.requestsDetails.length) { + print('loading value is $loading'); + getServiceRequest(requestId: allRequestProvider.filterRequest.requestsDetails[index + 1].id.toString()); + print('call the api with next id ...${allRequestProvider.filterRequest.requestsDetails[index + 1].id.toString()}'); + } + }, + child: Text( + context.translation.skipForLater, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, decoration: TextDecoration.underline, fontSize: 16), + ), + ), + ), + 20.height, + if (_userProvider.user.type == UsersTypes.engineer || + (serviceRequestsProvider.currentSelectedRequest.statusValue == 5 || serviceRequestsProvider.currentSelectedRequest.statusValue == 3)) + (serviceRequestsProvider.currentSelectedRequest?.firstAction == null + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red50, + showBorder: true, + onPressed: () async { + print('service request value is ${serviceRequestsProvider.currentSelectedRequest.type}'); + ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); + // bool shouldReloadData = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => RejectRequestBottomSheet(), + // )) as bool; + // if (shouldReloadData ?? false) { + // getServiceRequest(); + // } + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.accept, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + // GeneralUtils.showFlushBar(context: context); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => const VerifyOtpView())); + + // ServiceRequestBottomSheet.fixRemotelyBottomSheet(context: context); + // bool shouldReloadData = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => InitialVisitBottomSheet(), + // )) as bool; + // if (shouldReloadData ?? false) { + // getServiceRequest(); + // } + }, + ).expanded, + ], + ) + // ? AppFilledButton( + // label: context.translation.firstAction, + // maxWidth: true, + // onPressed: () async { + // bool shouldReloadData = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => FirstActionBottomSheet(request: serviceRequestsProvider.serviceRequest), + // )) as bool; + // if (shouldReloadData ?? false) { + // getServiceRequest(); + // } + // }, + // ) + : AppFilledButton( + label: context.translation.viewWorkOrder, + maxWidth: true, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => WorkOrderListPage(serviceRequest: serviceRequestsProvider.currentSelectedRequest)), + ); + // Navigator.of(context).pushNamed(WorkOrderListPage.id, arguments: serviceRequest); + }, + )) + .paddingOnly(start: 16, end: 16, bottom: 24), + ], + ), + ); + }), + ); + } +} diff --git a/lib/utilities/general_utils.dart b/lib/utilities/general_utils.dart new file mode 100644 index 00000000..43633bc4 --- /dev/null +++ b/lib/utilities/general_utils.dart @@ -0,0 +1,48 @@ +import 'package:another_flushbar/flushbar.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class GeneralUtils{ + + static Duration parseTimeString(String timeString) { + try { + print('time string i got is ${timeString}'); + List timeParts = timeString.split(':'); + + int hours = int.parse(timeParts[0]); + int minutes = int.parse(timeParts[1]); + int seconds = int.parse(timeParts[2]); + + print(''); + + return Duration(hours: hours, minutes: minutes, seconds: seconds); + } catch (e) { + if (kDebugMode) { + print("Error parsing time string: $e"); + } + return Duration.zero; // Return zero duration in case of an error + } + } + static Widget showFlushBar({@required BuildContext context,String title,String message,double duration}){ + return Flushbar( + flushbarPosition: FlushbarPosition.TOP, + backgroundColor: AppColor.green70, + title:title?? "Hey Ninja", + message:message?? "Lorem Ipsum is simply dummy text of the printing and typesetting industry", + duration: Duration(seconds:duration?? 3), + flushbarStyle: FlushbarStyle.GROUNDED, + reverseAnimationCurve: Curves.easeInOut, + mainButton: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + color: AppColor.white20, + ), + ), + )..show(context); + } +} \ No newline at end of file diff --git a/lib/utilities/request_utils.dart b/lib/utilities/request_utils.dart new file mode 100644 index 00000000..81c441cc --- /dev/null +++ b/lib/utilities/request_utils.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/models/enums/user_types.dart'; + +class RequestUtils{ + static List> getTabs({@required UsersTypes userType,@required BuildContext context}) { + List> tabs = []; + if(userType==UsersTypes.engineer){ + tabs.add({'label':'In Progress','status':2}); + tabs.add({'label':'Completed','status':4}); + return tabs; + } + tabs.add({'label':'New Request','status':1}); + tabs.add({'label':'In Progress','status':2}); + tabs.add({'label':'Completed','status':4}); + return tabs; + + } +} \ No newline at end of file diff --git a/lib/views/app_style/colors.dart b/lib/views/app_style/colors.dart index 0c4f5e3b..82a7302c 100644 --- a/lib/views/app_style/colors.dart +++ b/lib/views/app_style/colors.dart @@ -132,7 +132,7 @@ // } // } // -// static Color getPriorityStatusColor(int id) { +// static Color getPriorityStatusColor(int id) {l // switch (id) { // case 81: // return AColors.statusGreenLight; diff --git a/lib/views/pages/user/requests/requests_page.dart b/lib/views/pages/user/requests/requests_page.dart index bb69111a..9f020ca3 100644 --- a/lib/views/pages/user/requests/requests_page.dart +++ b/lib/views/pages/user/requests/requests_page.dart @@ -44,7 +44,8 @@ class _ServiceRequestsPageState extends State with TickerPr _serviceRequestsProvider.reset(); await _serviceRequestsProvider.getRequests(hospitalId: _userProvider.user.clientId); }, - child: ServiceRequestsList( + child: + ServiceRequestsList( nextPage: _serviceRequestsProvider.nextPage, onLazyLoad: () async { await _serviceRequestsProvider.getRequests(hospitalId: _userProvider.user.clientId); diff --git a/lib/views/pages/user/requests/work_order/work_order_details_page.dart b/lib/views/pages/user/requests/work_order/work_order_details_page.dart index 7c99f4bc..d711c931 100644 --- a/lib/views/pages/user/requests/work_order/work_order_details_page.dart +++ b/lib/views/pages/user/requests/work_order/work_order_details_page.dart @@ -32,7 +32,7 @@ class WorkOrderDetailsPage extends StatelessWidget { Widget build(BuildContext context) { UserProvider userProvider = Provider.of(context); return Scaffold( - appBar: DefaultAppBar(title: context.translation.workOrder), + appBar: DefaultAppBar(title: context.translation.activities), body: FutureBuilder( future: Provider.of(context).getSingleServiceReport(context, reportId: workOrder.id), builder: (context, snapshot) { @@ -98,7 +98,7 @@ class WorkOrderDetailsPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ if (userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) - Align(alignment: AlignmentDirectional.centerEnd, child: "edit".toSvgAsset(height: 48, width: 48)).onPress(() { + Align(alignment: AlignmentDirectional.centerEnd, child: "edit_icon".toSvgAsset(height: 21, width: 21)).onPress(() { Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateServiceReport(workOrder: workOrder, request: serviceRequest))); }), // if (userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) 8.height, diff --git a/lib/views/pages/user/requests/work_order/work_orders_list_page.dart b/lib/views/pages/user/requests/work_order/work_orders_list_page.dart index 37fabe53..b29e2383 100644 --- a/lib/views/pages/user/requests/work_order/work_orders_list_page.dart +++ b/lib/views/pages/user/requests/work_order/work_orders_list_page.dart @@ -13,6 +13,7 @@ import 'package:test_sa/models/service_request/service_request.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/common_widgets/default_app_bar.dart'; +import 'package:test_sa/service_request_latest/views/components/activity_card_view.dart'; import 'package:test_sa/views/pages/user/requests/work_order/create_service_report.dart'; import 'package:test_sa/views/pages/user/requests/work_order/update_service_report.dart'; import 'package:test_sa/views/pages/user/requests/work_order/work_order_details_page.dart'; @@ -34,7 +35,7 @@ class WorkOrderListPage extends StatelessWidget { UserProvider _userProvider = Provider.of(context); serviceRequestsProvider ??= Provider.of(context); return Scaffold( - appBar: DefaultAppBar(title: context.translation.workOrders), + appBar: DefaultAppBar(title: context.translation.activities), //backgroundColor: const Color(0xfff8f9fb), body: SafeArea( child: FutureBuilder( @@ -51,64 +52,67 @@ class WorkOrderListPage extends StatelessWidget { itemCount: workOrders.length, separatorBuilder: (czt, index) => 8.height, itemBuilder: (context, index) { - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - StatusLabel( - label: workOrders[index].currentSituation.name, - textColor: AppColor.getRequestStatusTextColorByName(context, workOrders[index].currentSituation.name), - backgroundColor: AppColor.getRequestStatusColorByName(context, workOrders[index].currentSituation.name), - ), - 8.height, - Text(serviceRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), - Text( - '${context.translation.assetName}: ${workOrders[index].callRequest.asset.modelDefinition.assetName?.cleanupWhitespace?.capitalizeFirstOfEach}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), - ), - Text( - '${context.translation.currentSituation}: ${workOrders[index].currentSituation.name}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), - ), - 16.height, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - context.translation.viewDetails, - style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), - ), - 4.width, - Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) - ], - ), - ], - ).onPress(() { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: workOrders[index], serviceRequest: serviceRequest)), - ); - }).expanded, - Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) - "edit".toSvgAsset(height: 48, width: 48).onPress(() { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequest, workOrder: workOrders[index])), - ); - }), - if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) 8.height, - Text(workOrders[index].visitDate?.toServiceRequestCardFormat ?? "", - textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : const Color(0xFF3B3D4A))), - ], - ) - ], - ).toShadowContainer(context); + return ActivityCardView(workOrders[index], serviceRequest); + + //older code.... + // Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Column( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // StatusLabel( + // label: workOrders[index].currentSituation.name, + // textColor: AppColor.getRequestStatusTextColorByName(context, workOrders[index].currentSituation.name), + // backgroundColor: AppColor.getRequestStatusColorByName(context, workOrders[index].currentSituation.name), + // ), + // 8.height, + // Text(serviceRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + // Text( + // '${context.translation.assetName}: ${workOrders[index].callRequest.asset.modelDefinition.assetName?.cleanupWhitespace?.capitalizeFirstOfEach}', + // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + // ), + // Text( + // '${context.translation.currentSituation}: ${workOrders[index].currentSituation.name}', + // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + // ), + // 16.height, + // Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // context.translation.viewDetails, + // style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + // ), + // 4.width, + // Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + // ], + // ), + // ], + // ).onPress(() { + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: workOrders[index], serviceRequest: serviceRequest)), + // ); + // }).expanded, + // Column( + // crossAxisAlignment: CrossAxisAlignment.end, + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) + // "edit".toSvgAsset(height: 48, width: 48).onPress(() { + // Navigator.of(context).push( + // MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequest, workOrder: workOrders[index])), + // ); + // }), + // if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) 8.height, + // Text(workOrders[index].visitDate?.toServiceRequestCardFormat ?? "", + // textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : const Color(0xFF3B3D4A))), + // ], + // ) + // ], + // ).toShadowContainer(context); }, ).expanded, if (_userProvider.user.type == UsersTypes.engineer && (serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3)) diff --git a/lib/views/widgets/buttons/rounded_back_button.dart b/lib/views/widgets/buttons/rounded_back_button.dart new file mode 100644 index 00000000..4a5d9755 --- /dev/null +++ b/lib/views/widgets/buttons/rounded_back_button.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class RoundedBackButton extends StatelessWidget { + final VoidCallback onPressed; + final IconData icon; + final Color backgroundColor; + final Color iconColor; + + const RoundedBackButton({Key key, this.onPressed,@required this.icon,this.backgroundColor,this.iconColor}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(left: 8), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: backgroundColor??Colors.blue, // Background color of the circle + ), + child: Padding( + padding: const EdgeInsets.all(8), + child: Icon( + icon, + color: iconColor??Colors.white, + size: 22, // Adjust the icon size as needed + ), + ), + ); + } +} diff --git a/lib/views/widgets/date_and_time/date_picker.dart b/lib/views/widgets/date_and_time/date_picker.dart index 983163bc..8fa843b8 100644 --- a/lib/views/widgets/date_and_time/date_picker.dart +++ b/lib/views/widgets/date_and_time/date_picker.dart @@ -11,16 +11,22 @@ class ADatePicker extends StatelessWidget { final DateTime from; final DateTime to; final String label; + final bool hideShadow; + final String hint; final Function(DateTime) onDatePicker; final bool enable, withBorder; final Color backgroundColor; final bool formatDateWithTime; + final double height; const ADatePicker({ Key key, @required this.label, this.withBorder = true, + this.height, this.backgroundColor, + this.hideShadow=false, + this.hint, this.date, this.formatDateWithTime = false, this.onDatePicker, @@ -32,6 +38,7 @@ class ADatePicker extends StatelessWidget { @override Widget build(BuildContext context) { return Container( + height:height, decoration: BoxDecoration( color: backgroundColor ?? (context.isDark && (enable == false) @@ -41,7 +48,7 @@ class ADatePicker extends StatelessWidget { : AppColor.background(context)), borderRadius: BorderRadius.circular(10), border: withBorder ? Border.all(width: 1, color: Theme.of(context).scaffoldBackgroundColor) : const Border(), - boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + boxShadow: hideShadow?null: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], ), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), child: Row( @@ -54,7 +61,7 @@ class ADatePicker extends StatelessWidget { children: [ label.tinyFont(context), (date?.toIso8601String == null - ? context.translation.pickADate + ?hint?? context.translation.pickADate : (formatDateWithTime ? date?.toIso8601String()?.toFirstActionFormat : (date?.toIso8601String()?.split("T")?.first ?? context.translation.pickADate))) .bodyText(context) .custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), diff --git a/lib/views/widgets/date_and_time/time_picker.dart b/lib/views/widgets/date_and_time/time_picker.dart index 135083fb..2752d455 100644 --- a/lib/views/widgets/date_and_time/time_picker.dart +++ b/lib/views/widgets/date_and_time/time_picker.dart @@ -1,73 +1,87 @@ -///todo deleted -// import 'package:flutter/material.dart'; -// import 'package:test_sa/views/app_style/sizing.dart'; -// -// class ADateTimePicker extends StatelessWidget { -// final DateTime date; -// final DateTime from; -// final DateTime to; -// final Function(DateTime) onDateTimePicker; -// final bool enable; -// -// const ADateTimePicker({Key key, this.date, this.onDateTimePicker, this.from, this.to, this.enable}) : super(key: key); -// -// @override -// Widget build(BuildContext context) { -// return ElevatedButton( -// style: ElevatedButton.styleFrom( -// foregroundColor: Colors.white, -// textStyle: Theme.of(context).textTheme.subtitle2, -// shape: RoundedRectangleBorder( -// borderRadius: BorderRadius.circular(12 * AppStyle.getScaleFactor(context)), -// ), -// ), -// child: Text( -// date == null ? "Pick Time" : date.toString().substring(0, date.toString().lastIndexOf(":")), -// textScaleFactor: AppStyle.getScaleFactor(context), -// ), -// onPressed: enable -// ? () async { -// // TimeOfDay picked = await showTimePicker(context: context, initialTime: TimeOfDay.now()); -// onDateTimePicker(await showDateTimePicker(context: context, initialDate: date, firstDate: from, lastDate: to)); -// } -// : null, -// ); -// } -// } -// -// Future showDateTimePicker({ -// BuildContext context, -// DateTime initialDate, -// DateTime firstDate, -// DateTime lastDate, -// }) async { -// initialDate ??= DateTime.now(); -// firstDate ??= initialDate.subtract(const Duration(days: 365 * 100)); -// lastDate ??= firstDate.add(const Duration(days: 365 * 200)); -// -// final DateTime selectedDate = await showDatePicker( -// context: context, -// initialDate: initialDate, -// firstDate: firstDate, -// lastDate: lastDate, -// ); -// -// if (selectedDate == null) return null; -// -// if (!context.mounted) return selectedDate; -// -// final TimeOfDay selectedTime = await showTimePicker( -// context: context, -// initialTime: TimeOfDay.fromDateTime(selectedDate), -// ); -// -// return selectedTime == null -// ? selectedDate -// : DateTime( -// selectedDate.year, -// selectedDate.month, -// selectedDate.day, -// selectedTime.hour, -// selectedTime.minute, -// ); -// } +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/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'; + +class ATimePicker extends StatelessWidget { + final TimeOfDay time; + final String label; + final String hint; + final Function(TimeOfDay) onTimePicker; + final bool enable, withBorder; + final Color backgroundColor; + final double height; + + const ATimePicker({ + Key key, + @required this.label, + this.withBorder = true, + this.height, + this.backgroundColor, + this.hint, + this.time, + this.onTimePicker, + this.enable = true, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + print('initial time in picker is $time'); + return Container( + height:height, + decoration: BoxDecoration( + color: backgroundColor ?? + (context.isDark && (enable == false) + ? AppColor.neutral50 + : (enable == false) + ? AppColor.neutral40 + : AppColor.background(context)), + borderRadius: BorderRadius.circular(10), + border: withBorder ? Border.all(width: 1, color: Theme.of(context).scaffoldBackgroundColor) : const Border(), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: Row( + children: [ + // enable + // ? + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + label.tinyFont(context), + (time == null + ?hint?? context.translation.pickTime + : (time.format(context)?? context.translation.pickADate)) + .bodyText(context) + .custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ], + ).expanded, + //: label.bodyText(context).paddingOnly(top: 8, bottom: 8), + enable ? 16.width : const Spacer(), + "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null), + ], + ), + ).onPress(enable + ? () async { + // Define the initial time + TimeOfDay initialTime = TimeOfDay.now(); + + // Show the time picker with the initial time set + TimeOfDay pickedTime = await showTimePicker( + context: context, + initialTime: initialTime, + ); + + // Handle the selected time (if user didn't cancel) + if (pickedTime != null) { + if (onTimePicker != null) onTimePicker(pickedTime); + print("Selected time: ${pickedTime.format(context)}"); + } + } + : null); + } +} diff --git a/lib/views/widgets/requests/service_request_list.dart b/lib/views/widgets/requests/service_request_list.dart index 782769e8..9827338f 100644 --- a/lib/views/widgets/requests/service_request_list.dart +++ b/lib/views/widgets/requests/service_request_list.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -16,6 +18,7 @@ class ServiceRequestsList extends StatelessWidget { @override Widget build(BuildContext context) { + print('servies request page'); if (requests.length == 0) { return NoItemFound( message: context.translation.noServiceRequestFound, diff --git a/lib/views/widgets/timer/app_timer.dart b/lib/views/widgets/timer/app_timer.dart index 920e552f..55bf230c 100644 --- a/lib/views/widgets/timer/app_timer.dart +++ b/lib/views/widgets/timer/app_timer.dart @@ -14,6 +14,7 @@ class AppTimer extends StatefulWidget { final TimerModel timer; final Future Function(TimerModel) onChange; final TextStyle style; + final BoxDecoration decoration; final bool enabled; final String label; @@ -25,6 +26,7 @@ class AppTimer extends StatefulWidget { this.timer, this.onChange, this.style, + this.decoration, this.timerProgress, this.enabled = true, }) : super(key: key); @@ -111,7 +113,7 @@ class _AppTimerState extends State { width: 100 * AppStyle.getScaleFactor(context), height: 56.toScreenHeight, padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - decoration: BoxDecoration( + decoration:widget.decoration?? BoxDecoration( color: context.isDark && (widget.enabled == false) ? AppColor.neutral60 : (widget.enabled == false) diff --git a/localization_error.txt b/localization_error.txt new file mode 100644 index 00000000..b7a7b76f --- /dev/null +++ b/localization_error.txt @@ -0,0 +1,9 @@ +{ + "ar": [ + "returnToService", + "signInToYour", + "overdue", + "newR", + "noDataFound" + ] +} diff --git a/pubspec.lock b/pubspec.lock index 1fcfc4de..0fdf4ad9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.10" + another_flushbar: + dependency: "direct main" + description: + name: another_flushbar + sha256: "19bf9520230ec40b300aaf9dd2a8fefcb277b25ecd1c4838f530566965befc2a" + url: "https://pub.dev" + source: hosted + version: "1.12.30" archive: dependency: transitive description: @@ -89,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + badges: + dependency: "direct main" + description: + name: badges + sha256: "6e7f3ec561ec08f47f912cfe349d4a1707afdc8dda271e17b046aa6d42c89e77" + url: "https://pub.dev" + source: hosted + version: "3.1.1" boolean_selector: dependency: transitive description: @@ -949,6 +965,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" + pinput: + dependency: "direct main" + description: + name: pinput + sha256: "7bf9aa7d0eeb3da9f7d49d2087c7bc7d36cd277d2e94cc31c6da52e1ebb048d0" + url: "https://pub.dev" + source: hosted + version: "5.0.0" platform: dependency: transitive description: @@ -1274,6 +1298,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + universal_platform: + dependency: transitive + description: + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" + url: "https://pub.dev" + source: hosted + version: "1.1.0" url_launcher: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index c8ea53d4..f79dc6ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: flutter_sound: ^9.2.13 permission_handler: ^10.2.0 rive: ^0.9.1 + another_flushbar: + pinput: audioplayers: ^1.1.1 flare_flutter: ^3.0.2 signature: ^5.3.0 @@ -75,6 +77,8 @@ dependencies: table_calendar: ^3.0.8 image_cropper: ^3.0.3 touchable: ^0.2.1 + badges: ^3.1.1 +# buttons_tabbar: ^1.1.2 flutter_month_picker: ^0.0.2 syncfusion_flutter_charts: ^21.2.3 local_auth: ^2.1.6