diff --git a/android/app/build.gradle b/android/app/build.gradle index 4f0659df..d8e93da8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -49,30 +49,30 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. minSdkVersion 21 targetSdkVersion 33 - versionCode 1 - versionName '1.0.0' + versionCode 3 + versionName '1.0.3' } signingConfigs { -// release { -// keyAlias keystoreProperties['keyAlias'] -// keyPassword keystoreProperties['keyPassword'] -// storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null -// storePassword keystoreProperties['storePassword'] -// } + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } } buildTypes { debug { signingConfig signingConfigs.debug } - release { - signingConfig signingConfigs.debug - } // release { -// minifyEnabled true -// shrinkResources true -// signingConfig signingConfigs.release +// signingConfig signingConfigs.debug // } + release { + minifyEnabled true + shrinkResources true + signingConfig signingConfigs.release + } } } diff --git a/android/build.gradle b/android/build.gradle index 93d82389..419b3fd3 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.8.20' repositories { google() mavenCentral() diff --git a/assets/images/cloud_logo.png b/assets/images/cloud_logo.png new file mode 100644 index 00000000..a1f1aaed Binary files /dev/null and b/assets/images/cloud_logo.png differ diff --git a/assets/images/doc.png b/assets/images/doc.png new file mode 100644 index 00000000..e7418db8 Binary files /dev/null and b/assets/images/doc.png differ diff --git a/assets/images/excel.png b/assets/images/excel.png new file mode 100644 index 00000000..470e1be5 Binary files /dev/null and b/assets/images/excel.png differ diff --git a/assets/images/pdf.png b/assets/images/pdf.png new file mode 100644 index 00000000..3102284f Binary files /dev/null and b/assets/images/pdf.png differ diff --git a/assets/subtitles/ar_subtitle.json b/assets/subtitles/ar_subtitle.json index 16cad068..c8f3b057 100644 --- a/assets/subtitles/ar_subtitle.json +++ b/assets/subtitles/ar_subtitle.json @@ -167,7 +167,7 @@ "newServiceReport": "تقرير خدمة جديد", "number": "رقم", "operatingHours": "ساعات العمل", - "partNumber": "رقم القطعة", + "partNumberName": "رقم/اسم القطعة", "quantity": "كمية", "reasons": "الاسباب", "reportStatus": "حالة التقرير", @@ -201,5 +201,9 @@ "floor": "طابق", "department": "قسم", "room": "غرفه", - "actions": "اجراءات" + "actions": "اجراءات", + "deviceFiles": "ملفات الجهاز", + "pickFromFiles" : "اختر من الملفات", + "requiredFile" : "الملف مطلوب", + "pickFile" : "اختر ملف" } \ No newline at end of file diff --git a/assets/subtitles/en_subtitle.json b/assets/subtitles/en_subtitle.json index d1412bf5..a30908c9 100644 --- a/assets/subtitles/en_subtitle.json +++ b/assets/subtitles/en_subtitle.json @@ -73,7 +73,7 @@ "deviceImages": "Asset Images", "deviceModel": "Asset Model", "deviceRequired": "Asset Required", - "deviceSN": "Asset SN", + "deviceSN": "Asset Serial Number", "engineerName": "Engineer Name", "engineerPhone": "Engineer Phone", "facebook": "facebook", @@ -167,7 +167,7 @@ "newServiceReport": "New Work Order", "number": "Number", "operatingHours": "Operating Hours", - "partNumber": "Part Number", + "partNumberName": "Part Number/Name", "quantity": "Quantity", "reasons": "Reasons", "reportStatus": "Report Status", @@ -201,5 +201,9 @@ "floor": "Floor", "department": "Department", "room": "Room", - "actions": "Actions" + "actions": "Actions", + "deviceFiles": "Asset Files", + "pickFromFiles" : "Pick From Files", + "requiredFile" : "File Required", + "pickFile" : "Pick File" } \ No newline at end of file diff --git a/ios/Podfile b/ios/Podfile index 0646ebd4..c0216e16 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -41,4 +41,16 @@ post_install do |installer| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' end end + installer.generated_projects.each do |project| + project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + ## dart: PermissionGroup.microphone + 'PERMISSION_MICROPHONE=1', + ] + end + end + end end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 00000000..82bdbf8e --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,268 @@ +PODS: + - audioplayers_darwin (0.0.1): + - Flutter + - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.4) + - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.4) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Firebase/CoreOnly (10.12.0): + - FirebaseCore (= 10.12.0) + - Firebase/Messaging (10.12.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 10.12.0) + - firebase_core (2.15.0): + - Firebase/CoreOnly (= 10.12.0) + - Flutter + - firebase_messaging (14.6.5): + - Firebase/Messaging (= 10.12.0) + - firebase_core + - Flutter + - FirebaseCore (10.12.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Logger (~> 7.8) + - FirebaseCoreInternal (10.12.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseInstallations (10.12.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - FirebaseMessaging (10.12.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Reachability (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - nanopb (< 2.30910.0, >= 2.30908.0) + - Flutter (1.0.0) + - flutter_keyboard_visibility (0.0.1): + - Flutter + - flutter_local_notifications (0.0.1): + - Flutter + - flutter_sound (9.2.13): + - Flutter + - flutter_sound_core (= 9.2.13) + - flutter_sound_core (9.2.13) + - fluttertoast (0.0.2): + - Flutter + - Toast + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - GoogleDataTransport (9.2.3): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.11.4): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.11.4): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.11.4): + - GoogleUtilities/Environment + - GoogleUtilities/Network (7.11.4): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.11.4)" + - GoogleUtilities/Reachability (7.11.4): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.11.4): + - GoogleUtilities/Logger + - image_picker_ios (0.0.1): + - Flutter + - MTBBarcodeScanner (5.0.11) + - nanopb (2.30909.0): + - nanopb/decode (= 2.30909.0) + - nanopb/encode (= 2.30909.0) + - nanopb/decode (2.30909.0) + - nanopb/encode (2.30909.0) + - package_info (0.0.1): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - permission_handler_apple (9.1.1): + - Flutter + - PromisesObjC (2.3.1) + - qr_code_scanner (0.2.0): + - Flutter + - MTBBarcodeScanner + - SDWebImage (5.17.0): + - SDWebImage/Core (= 5.17.0) + - SDWebImage/Core (5.17.0) + - share (0.0.1): + - Flutter + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - speech_to_text (0.0.1): + - Flutter + - Try + - sqflite (0.0.3): + - Flutter + - FMDB (>= 2.7.5) + - SwiftyGif (5.4.4) + - Toast (4.0.0) + - Try (2.1.1) + - url_launcher_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) + - Flutter (from `Flutter`) + - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - package_info (from `.symlinks/plugins/package_info/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) + - share (from `.symlinks/plugins/share/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) + - speech_to_text (from `.symlinks/plugins/speech_to_text/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - Firebase + - FirebaseCore + - FirebaseCoreInternal + - FirebaseInstallations + - FirebaseMessaging + - flutter_sound_core + - FMDB + - GoogleDataTransport + - GoogleUtilities + - MTBBarcodeScanner + - nanopb + - PromisesObjC + - SDWebImage + - SwiftyGif + - Toast + - Try + +EXTERNAL SOURCES: + audioplayers_darwin: + :path: ".symlinks/plugins/audioplayers_darwin/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_messaging: + :path: ".symlinks/plugins/firebase_messaging/ios" + Flutter: + :path: Flutter + flutter_keyboard_visibility: + :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" + flutter_sound: + :path: ".symlinks/plugins/flutter_sound/ios" + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + package_info: + :path: ".symlinks/plugins/package_info/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/ios" + permission_handler_apple: + :path: ".symlinks/plugins/permission_handler_apple/ios" + qr_code_scanner: + :path: ".symlinks/plugins/qr_code_scanner/ios" + share: + :path: ".symlinks/plugins/share/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/ios" + speech_to_text: + :path: ".symlinks/plugins/speech_to_text/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + +SPEC CHECKSUMS: + audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 + DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: ce3938a0df3cc1ef404671531facef740d03f920 + Firebase: 07150e75d142fb9399f6777fa56a187b17f833a0 + firebase_core: e477125798fc37cd4ab43ca6a8536bf7e0929c00 + firebase_messaging: 334d68c3a36b6d4d5cd91e4f42509e0d4ae49828 + FirebaseCore: f86a1394906b97ac445ae49c92552a9425831bed + FirebaseCoreInternal: 950500ad8a08963657f6d8c67b579740c06d6aa1 + FirebaseInstallations: 7b99ef103f013624444c614397038219c45f8e63 + FirebaseMessaging: bb2c4f6422a753038fe137d90ae7c1af57251316 + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 + flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 + flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 + flutter_sound_core: 26c10e5832e76aaacfae252d8925232281c486ae + fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd + GoogleUtilities: c63691989bf362ba0505507da00eeb326192e83e + image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb + nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 + package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 + qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e + SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9 + share: 0b2c3e82132f5888bccca3351c504d0003b3b410 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe + sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a + SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f + Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 + Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 + url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 + +PODFILE CHECKSUM: 9addd1ae6176ca7bfe24f8bac9acf6aeb76cd8f5 + +COCOAPODS: 1.12.1 diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 86b0405c..3f4e3439 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -7,7 +7,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Atoms SA + Atoms CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - Atoms SA + Atoms CFBundlePackageType APPL CFBundleShortVersionString @@ -28,6 +28,8 @@ LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + NSCameraUsageDescription This app requires permission to access Camera to allow user to attach images NSMicrophoneUsageDescription @@ -36,6 +38,8 @@ This app requires permission to access photo gallery to allow user to attach images NSSpeechRecognitionUsageDescription This app requires permission for Speech Recognition for speech to text functionality. + UIApplicationSupportsIndirectInputEvents + UIBackgroundModes fetch @@ -58,9 +62,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UISupportsDocumentBrowser + UIViewControllerBasedStatusBarAppearance - UIApplicationSupportsIndirectInputEvents - diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements index 903def2a..b3fdc75e 100644 --- a/ios/Runner/Runner.entitlements +++ b/ios/Runner/Runner.entitlements @@ -4,5 +4,7 @@ aps-environment development + inter-app-audio + diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart index 3bbfed51..77adc8b5 100644 --- a/lib/controllers/api_routes/api_manager.dart +++ b/lib/controllers/api_routes/api_manager.dart @@ -1,7 +1,5 @@ import 'dart:convert'; -import 'dart:developer'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart' as http; @@ -23,6 +21,7 @@ class ApiManager { Future get( String url, { Map headers, + enableToastMessage = true, }) async { headers ??= {}; @@ -34,7 +33,7 @@ class ApiManager { http.Response response = await http.get(_url, headers: headers); if (jsonDecode(response.body) is Map) { final message = jsonDecode(response.body)["message"]; - if (message != null && message.toString().isNotEmpty) { + if (message != null && message.toString().isNotEmpty && enableToastMessage) { Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG); } } diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index b4cb7226..64815ebc 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,8 +1,12 @@ class URLs { URLs._(); - static const host2 = "http://194.163.164.213/atoms/api"; - static const host1 = "https://atomsuat.hmg.com"; // uat url + static const host2 = "http://194.163.164.213/atoms/api"; // todo @sikander will remove after confirmation + + //static const host1 = "https://atomsuat.hmg.com"; // old uat url + //static const host1 = "https://atomsm.hmg.com"; // production url + + static const host1 = "https://atomsmdev.hmg.com"; // local UAT url // static const host1 = "http://109.123.243.118:9000"; @@ -12,7 +16,9 @@ class URLs { set host(String value) => _host = value; - static String getFileUrl(String file) => (file == null || file.isEmpty) ? null : (file.contains("/") ? file : "$_host/attachment/$file"); + static String getFileUrl(String file) => (file == null || file.isEmpty) ? null : (file.contains("/") ? file : "$_baseUrl/Files/DownloadFile?fileName=$file"); + + // static String getFileUrl(String file) => (file == null || file.isEmpty) ? null :1 (file.contains("/") ? file : "$_host/attachment/$file"); // API Routes static get login => "$_baseUrl/MobileAuth/LoginIntegration"; // post @@ -50,6 +56,8 @@ class URLs { static get updateRegularVisits => "$_baseUrl/Visit/UpdateVisits"; // get static get getSingleServiceRequest => "$_baseUrl/return/call/information"; // get + static get getSuppliersAutoComplete => "$_baseUrl/Supplier/GetSuppliersAutoComplete"; + static get getNotifications => "$_baseUrl/return/user/notification"; // get static get getRecentNotifications => "$_baseUrl/return/user/recent/notification"; // get static get createRequest => "$_baseUrl/CallRequest/AddCallRequest"; // get @@ -63,13 +71,15 @@ class URLs { static get createDuplicatedReport => "$_baseUrl/handle/duplicate/request"; // get static get searchWorkOrders => "$_baseUrl/WorkOrder/SearchWorkOrders"; + static get getSubWorkerInfoAccordingToPreviousStep => "$_baseUrl/WorkOrder/GetDataPreviousStep"; + static get getServiceReportReasons => "$_baseUrl/Lookups/GetLookup?lookupEnum=522"; // get static get getServiceReportTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=501"; // get static get getServiceReportStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=521"; // get static get getServiceReportLastCalls => "$_baseUrl/WorkOrder/GetLookupCallLastSituationBasedOnCase"; // get static get getAssetTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=500"; // get static get getPartNumber => "$_baseUrl/PartCatalog/GetPartAutoComplete"; // get - static get getServiceReportPriority => "$_baseUrl/Lookups/GetLookup?lookupEnum=602"; // get + static get getServiceReportPriority => "$_baseUrl/Lookups/GetLookup?lookupEnum=4"; // get static get getServiceReportDefectTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=601"; // get static get getCallRequestForWorkOrder => "$_baseUrl/CallRequest/GetCallRequestForWorkOrder"; // get @@ -87,6 +97,8 @@ class URLs { static get requestDeviceTransfer => "$_baseUrl/AssetTransfer/AddAssetTransfer"; // get static get updateDeviceTransfer => "$_baseUrl/AssetTransfer/UpdateAssetTransfer"; // get static get getDeviceTransfer => "$_baseUrl/AssetTransfer/GetAssetTransfers"; // get + static get getAssetTransferById => "$_baseUrl/AssetTransfer/GetAssetTransferById"; // get + static get getAssetTransferStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=406"; // get // employee static get getEmployees => "$_baseUrl/Lookups/GetLookup?lookupEnum=33"; // get diff --git a/lib/controllers/providers/api/device_transfer_provider.dart b/lib/controllers/providers/api/device_transfer_provider.dart index ca5234ce..52434818 100644 --- a/lib/controllers/providers/api/device_transfer_provider.dart +++ b/lib/controllers/providers/api/device_transfer_provider.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/cupertino.dart'; import 'package:http/http.dart'; @@ -6,6 +7,7 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/models/device/device_transfer_info.dart'; +import 'package:test_sa/models/device/device_transfer_search.dart'; import 'package:test_sa/models/user.dart'; import '../../../models/hospital.dart'; @@ -14,6 +16,8 @@ class DeviceTransferProvider extends ChangeNotifier { // number of items call in each request final pageItemNumber = 12; + DeviceTransferSearch deviceTransferSearch = DeviceTransferSearch(); + //reset provider data void reset() { items = null; @@ -63,16 +67,15 @@ class DeviceTransferProvider extends ChangeNotifier { }) async { if (isLoading == true) return -2; isLoading = true; + if (items?.isEmpty ?? true) notifyListeners(); Response response; try { Map body = {}; body["pageNumber"] = (items?.length ?? 0) ~/ pageItemNumber + 1; body["pageSize"] = pageItemNumber; + body.addAll(deviceTransferSearch.toMap()); - response = await ApiManager.instance.post( - URLs.getDeviceTransfer, - body: body, - ); + response = await ApiManager.instance.post(URLs.getDeviceTransfer, body: body); stateCode = response.statusCode; if (stateCode >= 200 && stateCode < 300) { @@ -80,8 +83,8 @@ class DeviceTransferProvider extends ChangeNotifier { List listJson = json.decode(response.body)["data"]; List itemsPage = listJson.map((request) => DeviceTransfer.fromJson(request)).toList(); items ??= []; - items.addAll(itemsPage); - print(listJson); + items.addAll(itemsPage.toSet().toList()); + notifyListeners(); if (itemsPage.length == pageItemNumber) { nextPage = true; } else { @@ -99,6 +102,23 @@ class DeviceTransferProvider extends ChangeNotifier { } } + Future getRequestById({int assetTransferId}) async { + Response response; + try { + response = await ApiManager.instance.get( + URLs.getAssetTransferById + "?assetTransferId=$assetTransferId", + enableToastMessage: false, + ); + if (response.statusCode >= 200 && response.statusCode < 300) { + return DeviceTransfer.fromJson(json.decode(response.body)["data"]); + } + return null; + } catch (error) { + print(error); + return null; + } + } + Future createRequest({ @required String host, @required User user, @@ -107,18 +127,22 @@ class DeviceTransferProvider extends ChangeNotifier { Map body = { "id": 0, "assetId": model.device.id ?? "", - "destSiteId": model.receiver.client.id ?? "", - "destDepartmentId": model.receiver.department.id ?? "", - "senderSiteId": model.receiver.client.id ?? "", + "destSiteId": hospital.id ?? "", + "destDepartmentId": department.id ?? "", + "senderSiteId": model.sender.client.id ?? "", // "transferNo": 0, // "transferCode": "string", "destBuildingId": building?.id, "destFloorId": floor.id, "destRoom": room, - // "senderBuildingId": 0, - // "senderFloorId": 0, - // "senderDepartmentId": 0, - // "senderRoom": "string", + ///// + "senderBuildingId": model.device.destBuildingId, + "senderFloorId": model.device.destFloorId, + "senderDepartmentId": model.device.destDepartmentId, + "senderRoom": model.device.destRoom, + if (model?.sender?.attachments?.isNotEmpty ?? false) + "senderAttachments": + model?.sender?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(), // "senderAssignedEmployeeId": "string", // "senderMachineStatusId": 0, // "senderComment": "string", @@ -181,17 +205,27 @@ class DeviceTransferProvider extends ChangeNotifier { "senderStartDate": newModel.timer?.startAt?.toIso8601String(), "senderEndDate": newModel.timer?.endAt?.toIso8601String(), "senderTravelingHours": newModel.travelingHours, - "senderAttachmentName": newModel?.signature ?? "", - "destSiteId": oldModel.receiver.client.id, - "destDepartmentId": oldModel.receiver.department.id, + "senderEngSignature": newModel.engSignature, + if (newModel?.attachments?.isNotEmpty ?? false) + "senderAttachments": + newModel?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(), + "destSiteId": oldModel.receiver.client?.id, + "destDepartmentId": oldModel.receiver.department?.id, + "destBuildingId": oldModel.device?.destBuildingId, + "destFloorId": oldModel.device?.destFloorId, + "destRoom": oldModel.device?.destRoom, "receiverAssignedEmployeeId": oldModel.receiver.userId, "receiverMachineStatusId": oldModel.receiver.status.id ?? "", "receiverComment": oldModel.receiver.comment, "receiverWorkingHours": oldModel.receiver.workingHours, "receiverStartDate": oldModel.receiver.timer?.startAt?.toIso8601String(), "receiverEndDate": oldModel.receiver.timer?.endAt?.toIso8601String(), - "receiverTravelingHours": oldModel.receiver.travelingHours, - "receiverAttachmentName": oldModel.receiver?.signature ?? "", + "receiverTravelingHours": oldModel.receiver?.travelingHours, + "receiverEngSignature": oldModel.receiver?.engSignature, + if (oldModel.receiver?.attachments?.isNotEmpty ?? false) + "receiverAttachments": oldModel.receiver?.attachments + ?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path}) + ?.toList(), }); } else { body.addAll({ @@ -203,10 +237,16 @@ class DeviceTransferProvider extends ChangeNotifier { "senderWorkingHours": oldModel.sender.workingHours, "senderStartDate": oldModel.sender.timer?.startAt?.toIso8601String(), "senderEndDate": oldModel.sender.timer?.endAt?.toIso8601String(), - "senderTravelingHours": oldModel.sender.travelingHours, - "senderAttachmentName": oldModel.sender?.signature ?? "", - "destSiteId": newModel.client.id, - "destDepartmentId": newModel.department.id, + "senderTravelingHours": oldModel.sender?.travelingHours, + "senderEngSignature": oldModel.sender?.engSignature, + if (oldModel.sender?.attachments?.isNotEmpty ?? false) + "senderAttachments": + oldModel.sender?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(), + "destSiteId": newModel.client?.id, + "destDepartmentId": newModel.department?.id, + "destBuildingId": oldModel.device?.destBuildingId, + "destFloorId": oldModel.device?.destFloorId, + "destRoom": oldModel.device?.destRoom, "receiverAssignedEmployeeId": newModel.userId, "receiverMachineStatusId": newModel.status?.id ?? "", "receiverComment": newModel.comment, @@ -214,18 +254,20 @@ class DeviceTransferProvider extends ChangeNotifier { "receiverStartDate": newModel.timer?.startAt?.toIso8601String(), "receiverEndDate": newModel.timer?.endAt?.toIso8601String(), "receiverTravelingHours": newModel.travelingHours, - "receiverAttachmentName": newModel?.signature ?? "", + "receiverEngSignature": newModel.engSignature, + if (newModel?.attachments?.isNotEmpty ?? false) + "receiverAttachments": + newModel?.attachments?.map((file) => {"attachmentName": _isLocalUrl(file.path) ? ("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}") : file.path})?.toList(), }); } - //body.addAll(newModel.toJson(isSender)); - print(body); + log(body?.toString()); Response response; try { response = await ApiManager.instance.put(URLs.updateDeviceTransfer, body: body); print(response.body); - print("${newModel.signature}.png"); + print("${newModel.engSignature}.png"); // response = await post( // Uri.parse("$host${URLs.updateDeviceTransfer}/$requestId"), // body: body, @@ -246,4 +288,9 @@ class DeviceTransferProvider extends ChangeNotifier { return -1; } } + + bool _isLocalUrl(String url) { + if (url?.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } } diff --git a/lib/controllers/providers/api/devices_provider.dart b/lib/controllers/providers/api/devices_provider.dart index 2d55a2a7..03a8228f 100644 --- a/lib/controllers/providers/api/devices_provider.dart +++ b/lib/controllers/providers/api/devices_provider.dart @@ -17,20 +17,25 @@ class DevicesProvider extends ChangeNotifier { final pageItemNumber = 10; bool nextPage = true; + // state code of current request to defied error message // like 400 customer request failed // 500 service not available int _stateCode; + int get stateCode => _stateCode; List _devices = []; + List get devices => _devices; // when categories in-process _loading = true // done _loading = true // failed _loading = false bool _loading; + bool get isLoading => _loading; + set isLoading(bool isLoading) { _loading = isLoading; notifyListeners(); @@ -47,6 +52,7 @@ class DevicesProvider extends ChangeNotifier { @required int hospitalId, String serialNumber, String number, + bool isQr = false, }) async { if (_loading == true) return -2; _loading = true; @@ -70,7 +76,15 @@ class DevicesProvider extends ChangeNotifier { if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List equipmentListJson = json.decode(response.body)["data"]; - _devices.addAll(equipmentListJson.map((device) => Device.fromJson(device)).toList()); + var dList = equipmentListJson.map((device) => Device.fromJson(device, startKeyWithDest: false)).toList(); + try { + if (isQr) { + dList = dList.where((element) => number?.toLowerCase() == element?.number?.toLowerCase())?.toList() ?? []; + } + } catch (e) { + print(e); + } + _devices.addAll(dList); nextPage = true; } else { nextPage = false; @@ -111,8 +125,8 @@ class DevicesProvider extends ChangeNotifier { if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List equipmentListJson = json.decode(response.body)["data"]; - page = equipmentListJson.map((device) => Device.fromJson(device)).toList(); - _devices.addAll(equipmentListJson.map((device) => Device.fromJson(device)).toList()); + page = equipmentListJson.map((device) => Device.fromJson(device, startKeyWithDest: false)).toList(); + _devices.addAll(equipmentListJson.map((device) => Device.fromJson(device, startKeyWithDest: false)).toList()); notifyListeners(); } return page; @@ -147,31 +161,31 @@ class DevicesProvider extends ChangeNotifier { } } - // /// return -2 if request in progress - // /// return -1 if error happen when sending request - // /// return state code if request complete may be 200, 404 or 403 - // /// for more details check http state manager - // /// lib\controllers\http_status_manger\http_status_manger.dart - // Future> getDevicesListBySN({@required String host, @required User user, @required int hospitalId, @required String sn}) async { - // Response response; - // try { - // response = await get( - // Uri.parse(URLs.getEquipment + "?client=$hospitalId" + (sn == null || sn.isEmpty ? "" : "&serial_qr=$sn")), - // ); - // - // _stateCode = response.statusCode; - // List _page = []; - // if (response.statusCode >= 200 && response.statusCode < 300) { - // // client's request was successfully received - // List categoriesListJson = json.decode(utf8.decode(response.bodyBytes)); - // _page = categoriesListJson.map((device) => Device.fromJson(device)).toList(); - // } - // return _page; - // } catch (error) { - // _loading = false; - // _stateCode = -1; - // notifyListeners(); - // return []; - // } - // } +// /// return -2 if request in progress +// /// return -1 if error happen when sending request +// /// return state code if request complete may be 200, 404 or 403 +// /// for more details check http state manager +// /// lib\controllers\http_status_manger\http_status_manger.dart +// Future> getDevicesListBySN({@required String host, @required User user, @required int hospitalId, @required String sn}) async { +// Response response; +// try { +// response = await get( +// Uri.parse(URLs.getEquipment + "?client=$hospitalId" + (sn == null || sn.isEmpty ? "" : "&serial_qr=$sn")), +// ); +// +// _stateCode = response.statusCode; +// List _page = []; +// if (response.statusCode >= 200 && response.statusCode < 300) { +// // client's request was successfully received +// List categoriesListJson = json.decode(utf8.decode(response.bodyBytes)); +// _page = categoriesListJson.map((device) => Device.fromJson(device)).toList(); +// } +// return _page; +// } catch (error) { +// _loading = false; +// _stateCode = -1; +// notifyListeners(); +// return []; +// } +// } } diff --git a/lib/controllers/providers/api/gas_refill_provider.dart b/lib/controllers/providers/api/gas_refill_provider.dart index faf84d66..9e24fcb6 100644 --- a/lib/controllers/providers/api/gas_refill_provider.dart +++ b/lib/controllers/providers/api/gas_refill_provider.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/cupertino.dart'; import 'package:http/http.dart'; @@ -6,6 +7,7 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/gas_refill/gas_refill_model.dart'; import 'package:test_sa/models/hospital.dart'; +import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/models/user.dart'; class GasRefillProvider extends ChangeNotifier { @@ -47,20 +49,19 @@ class GasRefillProvider extends ChangeNotifier { Future getRequests({ @required String host, @required User user, + @required bool mostRecent, }) async { if (isLoading == true) return -2; isLoading = true; + if (items?.isEmpty ?? true) notifyListeners(); Response response; Map body = {}; body["pageNumber"] = (items?.length ?? 0) ~/ pageItemNumber + 1; body["pageSize"] = pageItemNumber; - print("url:${URLs.getGasRefill}:body:$body"); + body["mostRecent"] = mostRecent; - response = await ApiManager.instance.post( - URLs.getGasRefill, - body: body, - ); + response = await ApiManager.instance.post(URLs.getGasRefill, body: body); stateCode = response.statusCode; if (stateCode >= 200 && stateCode < 300) { // client's request was successfully received @@ -68,6 +69,7 @@ class GasRefillProvider extends ChangeNotifier { List itemsPage = requestsListJson.map((request) => GasRefillModel.fromJson(request)).toList(); items ??= []; items.addAll(itemsPage); + notifyListeners(); if (itemsPage.length == pageItemNumber) { nextPage = true; } else { @@ -91,24 +93,22 @@ class GasRefillProvider extends ChangeNotifier { @required User user, @required GasRefillModel model, }) async { - print("ss"); Map body = { "uid": user.id.toString(), "token": user.token ?? "", "site": hospital?.toMap(), "building": {"id": building?.id, "name": building?.name, "value": building?.value}, "floor": {"id": floor?.id, "name": floor?.name, "value": floor?.value}, - if (expectedDateTime != null) "expectedDate": expectedDateTime?.toIso8601String(), + //if (expectedDateTime != null) "expectedDate": expectedDateTime?.toIso8601String(), if (expectedDateTime != null) "expectedTime": expectedDateTime?.toIso8601String(), - if (startDate != null) "startDate": startDate?.toIso8601String(), - if (startDate != null) "startTime": startDate?.toIso8601String(), - if (endDate != null) "endDate": endDate?.toIso8601String(), - if (endDate != null) "endTime": endDate?.toIso8601String(), + if (timer?.startAt != null) "startDate": timer.startAt.toIso8601String(), + if (timer?.startAt != null) "startTime": timer.startAt.toIso8601String(), + if (timer?.endAt != null) "endDate": timer.endAt.toIso8601String(), + if (timer?.endAt != null) "endTime": timer.endAt.toIso8601String(), "department": {"id": department?.id, "departmentName": department?.name, "departmentCode": "", "ntCode": ""}, "GazRefillNo": "GR-${DateTime.now().toString().split(" ").first}", "status": model.status.toMap(), }; - print("ss1"); body["gazRefillDetails"] = model.details .map((model) => { "gasType": model.type.toMap(), @@ -121,7 +121,6 @@ class GasRefillProvider extends ChangeNotifier { Response response; try { response = await ApiManager.instance.post(URLs.requestGasRefill, body: body); - print("ss2"); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { if (items != null) { @@ -146,13 +145,14 @@ class GasRefillProvider extends ChangeNotifier { "id": newModel.id, "gazRefillNo": newModel.title ?? "", "status": newModel.status.toMap(), - "expectedDate": oldModel.expectedDate?.toIso8601String(), - "expectedTime": oldModel.expectedDate?.toIso8601String(), - "startDate": startDate?.toIso8601String(), - "startTime": startDate?.toIso8601String(), - "endDate": endDate?.toIso8601String(), - "endTime": endDate?.toIso8601String(), - "workingHours": ((endDate?.difference(startDate)?.inMinutes ?? 0) / 60), + //"expectedDate": newModel.expectedDate?.toIso8601String(), + "expectedTime": newModel.expectedDate?.toIso8601String(), + if (timer?.startAt != null) "startDate": timer.startAt.toIso8601String(), + if (timer?.startAt != null) "startTime": timer.startAt.toIso8601String(), + if (timer?.endAt != null) "endDate": timer.endAt.toIso8601String(), + if (timer?.endAt != null) "endTime": timer.endAt.toIso8601String(), + // "workingHours": ((endDate?.difference(startDate)?.inMinutes ?? 0) / 60), + 'workingHours': timer.durationInSecond != null ? timer.durationInSecond / 60 / 60 : newModel.workingHours, "assignedEmployee": oldModel?.assignedEmployee?.id == null ? null : oldModel?.assignedEmployee?.toJson(), "site": hospital?.toMap(), "building": building?.toJson(includeFloors: false), @@ -171,7 +171,7 @@ class GasRefillProvider extends ChangeNotifier { "deliverdQty": model.deliveredQuantity, }) .toList(); - + log(body.toString()); Response response; try { response = await ApiManager.instance.put(URLs.updateGasRefill, body: body); @@ -196,6 +196,5 @@ class GasRefillProvider extends ChangeNotifier { Floors floor; Departments department; DateTime expectedDateTime; - DateTime startDate; - DateTime endDate; + TimerModel timer; } diff --git a/lib/controllers/providers/api/hospitals_provider.dart b/lib/controllers/providers/api/hospitals_provider.dart index a52a750e..da0e2cd7 100644 --- a/lib/controllers/providers/api/hospitals_provider.dart +++ b/lib/controllers/providers/api/hospitals_provider.dart @@ -22,22 +22,27 @@ class HospitalsProvider extends ChangeNotifier { // like 400 customer request failed // 500 service not available int _stateCode; + int get stateCode => _stateCode; // true if there is next page in product list and false if not bool _nextPage = true; + bool get nextPage => _nextPage; // contain user data // when user not login or register _user = null List _hospitals; + List get hospitals => _hospitals; // when categories in-process _loading = true // done _loading = true // failed _loading = false bool _loading; + bool get isLoading => _loading; + set isLoading(bool isLoading) { _loading = isLoading; notifyListeners(); diff --git a/lib/controllers/providers/api/parts_provider.dart b/lib/controllers/providers/api/parts_provider.dart index c0ae098c..de14ce42 100644 --- a/lib/controllers/providers/api/parts_provider.dart +++ b/lib/controllers/providers/api/parts_provider.dart @@ -22,22 +22,27 @@ class PartsProvider extends ChangeNotifier { // like 400 customer request failed // 500 service not available int _stateCode; + int get stateCode => _stateCode; // true if there is next page in product list and false if not bool _nextPage = true; + bool get nextPage => _nextPage; // contain user data // when user not login or register _user = null List _parts; + List get parts => _parts; // when categories in-process _loading = true // done _loading = true // failed _loading = false bool _loading; + bool get isLoading => _loading; + set isLoading(bool isLoading) { _loading = isLoading; notifyListeners(); @@ -85,17 +90,21 @@ class PartsProvider extends ChangeNotifier { /// return state code if request complete may be 200, 404 or 403 /// for more details check http state manager /// lib\controllers\http_status_manger\http_status_manger.dart - Future> getPartsList({String host, User user, String title}) async { + Future> getPartsList({String host, User user, num assetId, String title}) async { Response response; try { - response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partName": title}); - List _page = []; + if (int.tryParse(title) != null) { + response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partNo": title, "assetId": assetId}); + } else { + response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partName": title, "assetId": assetId}); + } + List page = []; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List categoriesListJson = json.decode(response.body)["data"]; - _page = categoriesListJson.map((part) => Part.fromJson(part)).toList(); + page = categoriesListJson.map((part) => Part.fromJson(part)).toList(); } - return _page; + return page; } catch (error) { return []; } diff --git a/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart b/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart index 59bf347a..53c3756d 100644 --- a/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart +++ b/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart @@ -69,7 +69,7 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier { // client's request was successfully received List requestsListJson = json.decode(utf8.decode(response.bodyBytes)); List _visits = requestsListJson.map((request) => Visit.fromJson(request)).toList(); - if (visits == null) visits = []; + visits ??= []; visits.addAll(_visits); if (_visits.length == pageItemNumber) { nextPage = true; diff --git a/lib/controllers/providers/api/regular_visits_provider.dart b/lib/controllers/providers/api/regular_visits_provider.dart index 42fb1dd9..7209c08a 100644 --- a/lib/controllers/providers/api/regular_visits_provider.dart +++ b/lib/controllers/providers/api/regular_visits_provider.dart @@ -13,7 +13,7 @@ import 'package:test_sa/models/visits/visits_search.dart'; class RegularVisitsProvider extends ChangeNotifier { // number of items call in each request - final pageItemNumber = 20; + final pageItemNumber = 12; //reset provider data void reset() { @@ -52,7 +52,7 @@ class RegularVisitsProvider extends ChangeNotifier { }) async { if (isLoading == true) return -2; isLoading = true; - if (visits == null) notifyListeners(); + if (visits?.isEmpty ?? true) notifyListeners(); Response response; //userId = 397.toString(); // testing id to view data @@ -77,10 +77,11 @@ class RegularVisitsProvider extends ChangeNotifier { // client's request was successfully received try { List requestsListJson = json.decode(response.body)["data"]; - List _visits = requestsListJson.map((request) => Visit.fromJson(request)).toList(); - visits ??= []; - visits.addAll(_visits); - if (_visits.length == pageItemNumber) { + List visits = requestsListJson.map((request) => Visit.fromJson(request)).toList(); + this.visits ??= []; + this.visits.addAll(visits); + notifyListeners(); + if (visits.length == pageItemNumber) { nextPage = true; } else { nextPage = false; diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 8b014f83..5aee9c12 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/subtitle.dart'; import 'package:test_sa/models/timer_model.dart'; import '../../../models/service_request/search_work_order.dart'; +import '../../../models/service_request/sub_work_order_details.dart'; import '../../../models/user.dart'; class ServiceRequestsProvider extends ChangeNotifier { @@ -57,7 +58,7 @@ class ServiceRequestsProvider extends ChangeNotifier { Future getRequests({@required int hospitalId}) async { if (isLoading == true) return -2; isLoading = true; - if (serviceRequests == null) notifyListeners(); + if (serviceRequests?.isEmpty ?? false) notifyListeners(); Response response; try { Map body = {}; @@ -77,6 +78,7 @@ class ServiceRequestsProvider extends ChangeNotifier { List serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList(); serviceRequests ??= []; serviceRequests.addAll(serviceRequestsPage); + notifyListeners(); if (serviceRequestsPage.length == pageItemNumber) { nextPage = true; } else { @@ -144,10 +146,10 @@ class ServiceRequestsProvider extends ChangeNotifier { "client": user.clientId, "callComments": serviceRequest.callComments, if (serviceRequest.devicePhotos.isNotEmpty) "attachmentsCallRequest": serviceRequest.devicePhotos.map((e) => {"name": e}).toList(), - "priority": serviceRequest.priority.toMap(), - "defectType": serviceRequest.defectType.toMap(), - "typeofRequest": serviceRequest.type.toMap(), - "requestedThrough": serviceRequest.requestedThrough.toMap(), + "priority": serviceRequest.priority?.toMap(), + "defectType": serviceRequest.defectType?.toMap(), + "typeofRequest": serviceRequest.type?.toMap(), + "requestedThrough": serviceRequest.requestedThrough?.toMap(), "reviewComment": null, if (serviceRequest.audio != null) "voiceNote": serviceRequest.audio, "callSiteContactPerson": [ @@ -176,17 +178,26 @@ class ServiceRequestsProvider extends ChangeNotifier { body["voiceNote"] = serviceRequest.audio; } Response response; - try { - response = await ApiManager.instance.post(URLs.createRequest, body: body); - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - if (serviceRequests != null) serviceRequests.insert(0, ServiceRequest.fromJson(json.decode(utf8.decode(response.bodyBytes))[0])); - notifyListeners(); + //try { + response = await ApiManager.instance.post(URLs.createRequest, body: body); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + if (serviceRequests != null) { + var data = json.decode(utf8.decode(response.bodyBytes)); + if (data is List) { + serviceRequests.insert(0, ServiceRequest.fromJson(data[0])); + } else { + if (data["data"] != null && data["data"] == true) { + // serviceRequests.insert(0, ServiceRequest.fromJson(data[0])); + } + } } - return response.statusCode; - } catch (error) { - return -1; + notifyListeners(); } + return response.statusCode; + // } catch (error) { + // return -1; + // } } Future createIssueReport({ @@ -221,7 +232,6 @@ class ServiceRequestsProvider extends ChangeNotifier { Map serviceRequest = await getServiceRequestById(requestId: request.id) ?? ""; final List callSiteContacts = (serviceRequest['callSiteContactPerson'] as List); final Map callSiteContactPerson = callSiteContacts.isEmpty ? {} : callSiteContacts[0]; - print(callSiteContactPerson); Response response; var body = { "id": request.id, @@ -305,7 +315,7 @@ class ServiceRequestsProvider extends ChangeNotifier { }, "assetType": report.assetType?.toMap(), "assignedEmployee": {"id": report.engineer?.id, "name": report.engineer?.name ?? ""}, - "visitDate": report.visitDate?.toIso8601String() ?? "", + "visitDate": report.returnToService?.toIso8601String() ?? "", // "assistantEmployees": [ // {"id": report.engineer.id, "name": report.engineer.name}, // ], @@ -337,7 +347,7 @@ class ServiceRequestsProvider extends ChangeNotifier { ?.map( (p) => { "id": p.reportPartID ?? 0, - "sparePart": {"id": p.id, "partNo": p.code, "partName": p.name}, + "sparePart": {"id": p.id, "partNo": p.partNo, "partName": p.partName}, "qty": p.quantity }, ) @@ -354,7 +364,6 @@ class ServiceRequestsProvider extends ChangeNotifier { // body["uid"] = user.id; // body["token"] = user.token; response = await ApiManager.instance.post(URLs.createServiceReport, body: body); - print(response.body); // response = await post( // Uri.parse( // host+URLs.createServiceReport), @@ -380,8 +389,6 @@ class ServiceRequestsProvider extends ChangeNotifier { try { Map body = workOrder.toJson(); response = await ApiManager.instance.post(URLs.createServiceReport, body: body); - print(response.body); - stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { reset(); @@ -432,7 +439,6 @@ class ServiceRequestsProvider extends ChangeNotifier { if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List workOrdersJson = json.decode(response.body)["data"]; - print(workOrdersJson); workOrders = workOrdersJson.map((request) => SearchWorkOrder.fromJson(request)).toList(); if (workOrders.length == pageItemNumber) { nextPage = true; @@ -446,6 +452,23 @@ class ServiceRequestsProvider extends ChangeNotifier { } } + Future getSubWorkOrderDetails({@required String parentId}) async { + Response response; + try { + response = await ApiManager.instance.get(URLs.getSubWorkerInfoAccordingToPreviousStep + "?parentId=$parentId"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + final workOrderJson = json.decode(response.body)["data"]; + return SubWorkOrderDetails.fromJson(workOrderJson); + } + return null; + } catch (e) { + print("getSubWorkOrderDetails [error] : $e"); + return null; + } + } + Future createDuplicatedReport({ @required String host, @required User user, @@ -595,6 +618,19 @@ class ServiceRequestsProvider extends ChangeNotifier { } } + Future getServiceRequestObjectById({@required String requestId}) async { + try { + Response response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId"); + if (response.statusCode >= 200 && response.statusCode < 300) { + return ServiceRequest.fromJson(json.decode(response.body)["data"]); + } else { + return null; + } + } catch (error) { + return null; + } + } + Future> getServiceRequestById({@required String requestId}) async { Response response; try { @@ -651,7 +687,6 @@ class ServiceRequestsProvider extends ChangeNotifier { if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List workOrdersJson = json.decode(response.body)["data"]; - print(workOrdersJson); workOrders ??= []; workOrders.addAll(workOrdersJson.map((request) => SearchWorkOrder.fromJson(request)).toList()); if (workOrders.length == pageItemNumber) { diff --git a/lib/controllers/providers/api/status_drop_down/asset_transfer_status_provider.dart b/lib/controllers/providers/api/status_drop_down/asset_transfer_status_provider.dart new file mode 100644 index 00000000..8b578176 --- /dev/null +++ b/lib/controllers/providers/api/status_drop_down/asset_transfer_status_provider.dart @@ -0,0 +1,75 @@ +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/user.dart'; + +class AssetTransferStatusProvider extends ChangeNotifier { + //reset provider data + void reset() { + _items = null; + _loading = null; + _stateCode = null; + } + + // state code of current request to defied error message + // like 400 customer request failed + // 500 service not available + int _stateCode; + + int get stateCode => _stateCode; + + // contain user data + // when user not login or register _user = null + List _items; + + List get items => _items; + + // when categories in-process _loading = true + // done _loading = true + // failed _loading = false + bool _loading; + + bool get isLoading => _loading; + + set isLoading(bool isLoading) { + _loading = isLoading; + notifyListeners(); + } + + /// return -2 if request in progress + /// return -1 if error happen when sending request + /// return state code if request complete may be 200, 404 or 403 + /// for more details check http state manager + /// lib\controllers\http_status_manger\http_status_manger.dart + Future getData({ + String host, + User user, + }) async { + if (_loading == true) return -2; + _loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getAssetTransferStatus); + _stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List categoriesListJson = json.decode(response.body)["data"]; + _items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + _loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + _loading = false; + _stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/controllers/providers/api/status_drop_down/employee/engineers_provider.dart b/lib/controllers/providers/api/status_drop_down/employee/engineers_provider.dart index d6fe0011..c075faa5 100644 --- a/lib/controllers/providers/api/status_drop_down/employee/engineers_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/employee/engineers_provider.dart @@ -1,13 +1,12 @@ import 'dart:convert'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/engineer.dart'; -import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/user.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:http/http.dart'; class EngineersProvider extends ChangeNotifier { //reset provider data diff --git a/lib/controllers/providers/api/status_drop_down/gas_refill/gas_status_provider.dart b/lib/controllers/providers/api/status_drop_down/gas_refill/gas_status_provider.dart index ce7332a7..7dc22e8d 100644 --- a/lib/controllers/providers/api/status_drop_down/gas_refill/gas_status_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/gas_refill/gas_status_provider.dart @@ -1,8 +1,5 @@ import 'dart:convert'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/models/user.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; diff --git a/lib/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart b/lib/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart index e9b3836f..0050c4f5 100644 --- a/lib/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart @@ -1,8 +1,5 @@ import 'dart:convert'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/models/user.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; diff --git a/lib/controllers/providers/api/status_drop_down/report/service_report_equipment_status_provider.dart b/lib/controllers/providers/api/status_drop_down/report/service_report_equipment_status_provider.dart index 82ac1f49..1931d54c 100644 --- a/lib/controllers/providers/api/status_drop_down/report/service_report_equipment_status_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/report/service_report_equipment_status_provider.dart @@ -1,12 +1,9 @@ import 'dart:convert'; -import 'package:test_sa/controllers/api_routes/api_manager.dart'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/models/user.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/user.dart'; diff --git a/lib/controllers/providers/api/status_drop_down/report/service_report_status_provider.dart b/lib/controllers/providers/api/status_drop_down/report/service_report_status_provider.dart index fed9a24f..af3c9f86 100644 --- a/lib/controllers/providers/api/status_drop_down/report/service_report_status_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/report/service_report_status_provider.dart @@ -1,12 +1,9 @@ import 'dart:convert'; -import 'package:test_sa/controllers/api_routes/api_manager.dart'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/models/lookup.dart'; -import 'package:test_sa/models/user.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/user.dart'; diff --git a/lib/controllers/providers/api/status_drop_down/report/vendor_provider.dart b/lib/controllers/providers/api/status_drop_down/report/vendor_provider.dart new file mode 100644 index 00000000..4271e001 --- /dev/null +++ b/lib/controllers/providers/api/status_drop_down/report/vendor_provider.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; + +class VendorProvider extends ChangeNotifier { + void reset() { + _vendors = null; + _loading = null; + _stateCode = null; + } + + int _stateCode; + int get stateCode => _stateCode; + + List _vendors; + List get vendors => _vendors; + + bool _loading; + bool get isLoading => _loading; + set isLoading(bool isLoading) { + _loading = isLoading; + notifyListeners(); + } + + Future getVendors(String text) async { + if (_loading == true) return -2; + _loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get("${URLs.getSuppliersAutoComplete}?searchText=$text"); + _stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List suppliersJson = json.decode(response.body)["data"]; + _vendors = suppliersJson.map((type) => Supplier.fromJson(type)).toList(); + } + _loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + _loading = false; + _stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart b/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart index cfc49f74..64106b31 100644 --- a/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart @@ -66,4 +66,8 @@ class ServiceRequestedThroughProvider extends ChangeNotifier { return -1; } } + + Lookup getDefaultItem() { + return items?.firstWhere((element) => element.name.toLowerCase().contains("app")); + } } diff --git a/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart b/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart index a0c6cad2..e38d3e78 100644 --- a/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart +++ b/lib/controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart @@ -66,4 +66,8 @@ class ServiceRequestTypeProvider extends ChangeNotifier { return -1; } } + + Lookup getDefaultItem() { + return items?.firstWhere((element) => element.name.toLowerCase().contains("maintenance")); + } } diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index bce2ce22..5f539f05 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -63,6 +63,7 @@ class UserProvider extends ChangeNotifier { notifyListeners(); return response.statusCode; } catch (error) { + print(error); _loading = false; notifyListeners(); return -1; @@ -112,45 +113,45 @@ class UserProvider extends ChangeNotifier { /// return state code if request complete may be 200, 404 or 403 /// for more details about state codes check http state manager /// lib\controllers\http_status_manger\http_status_manger.dart - Future updateProfile({ - @required String host, - @required User user, - }) async { - if (_loading == true) return -2; - _loading = true; - notifyListeners(); - Response response; - - Map jsonObject = {}; - jsonObject["uid"] = user.id; - jsonObject["token"] = user.token; - if (user.departmentId != _user.departmentId) jsonObject["department"] = user.departmentId; - // if (user.whatsApp != _user.whatsApp) jsonObject["whatsapp"] = user.whatsApp; - if (user.phoneNumber != _user.phoneNumber) jsonObject["phone"] = user.phoneNumber; - try { - response = response = await ApiManager.instance.post( - URLs.login, - body: jsonObject, - ); - } catch (error) { - _loading = false; - notifyListeners(); - return -1; - } - - _loading = false; - notifyListeners(); - - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - _user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]); - _user.clientId = user.clientId; - _user.clientName = user.clientName; - _user.departmentName = user.departmentName; - _user.departmentId = user.departmentId; - notifyListeners(); - return response.statusCode; - } - return response.statusCode; - } + // Future updateProfile({ + // @required String host, + // @required User user, + // }) async { + // if (_loading == true) return -2; + // _loading = true; + // notifyListeners(); + // Response response; + // + // Map jsonObject = {}; + // jsonObject["uid"] = user.id; + // jsonObject["token"] = user.token; + // if (user.departmentId != _user.departmentId) jsonObject["department"] = user.departmentId; + // // if (user.whatsApp != _user.whatsApp) jsonObject["whatsapp"] = user.whatsApp; + // if (user.phoneNumber != _user.phoneNumber) jsonObject["phone"] = user.phoneNumber; + // try { + // response = response = await ApiManager.instance.post( + // URLs.login, + // body: jsonObject, + // ); + // } catch (error) { + // _loading = false; + // notifyListeners(); + // return -1; + // } + // + // _loading = false; + // notifyListeners(); + // + // if (response.statusCode >= 200 && response.statusCode < 300) { + // // client's request was successfully received + // _user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]); + // _user.clientId = user.clientId; + // _user.clientName = user.clientName; + // _user.departmentName = user.departmentName; + // _user.departmentId = user.departmentId; + // notifyListeners(); + // return response.statusCode; + // } + // return response.statusCode; + // } } diff --git a/lib/controllers/providers/settings/setting_provider.dart b/lib/controllers/providers/settings/setting_provider.dart index 0e8db564..a38b20c1 100644 --- a/lib/controllers/providers/settings/setting_provider.dart +++ b/lib/controllers/providers/settings/setting_provider.dart @@ -1,10 +1,11 @@ import 'dart:async'; import 'dart:convert'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/models/user.dart'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/user.dart'; + import '../settings/app_settings.dart'; class SettingProvider extends ChangeNotifier { diff --git a/lib/extensions/int_extensions.dart b/lib/extensions/int_extensions.dart index 5f1e672e..d4d867ad 100644 --- a/lib/extensions/int_extensions.dart +++ b/lib/extensions/int_extensions.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:test_sa/views/app_style/colors.dart'; diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 5a8f3ce5..f88f8c08 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; extension WidgetExtensions on Widget { Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this); diff --git a/lib/main.dart b/lib/main.dart index 466e0528..3d7241b5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,6 +13,7 @@ import 'package:test_sa/controllers/providers/api/hospitals_provider.dart'; import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; import 'package:test_sa/controllers/providers/api/regular_visits_provider.dart'; import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/status_drop_down/asset_transfer_status_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/employee/assigned_to_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/employee/engineers_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_cylinder_size_provider.dart'; @@ -63,6 +64,7 @@ import 'controllers/providers/api/status_drop_down/report/service_report_repair_ import 'controllers/providers/api/status_drop_down/report/service_report_status_provider.dart'; import 'controllers/providers/api/status_drop_down/report/service_report_types_provider.dart'; import 'controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import 'controllers/providers/api/status_drop_down/report/vendor_provider.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; import 'views/pages/device_transfer/request_device_transfer.dart'; @@ -81,20 +83,23 @@ void main() async { } runApp(ChangeNotifierProvider( create: (_) => SettingProvider(), - child: MyApp(), + child: const MyApp(), )); } class MyApp extends StatelessWidget { + const MyApp({Key key}) : super(key: key); + // This widget is the root of your application. @override Widget build(BuildContext context) { - final _settingProvider = Provider.of(context); + final settingProvider = Provider.of(context); return MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => UserProvider()), ChangeNotifierProvider(create: (_) => HospitalsProvider()), ChangeNotifierProvider(create: (_) => DevicesProvider()), + ChangeNotifierProvider(create: (_) => AssetTransferStatusProvider()), ChangeNotifierProvider(create: (_) => ServiceRequestsProvider()), ChangeNotifierProvider(create: (_) => DepartmentsProvider()), ChangeNotifierProvider(create: (_) => NotificationsProvider()), @@ -131,6 +136,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()), ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()), ChangeNotifierProvider(create: (_) => ServiceReportAssistantsEmployeeProvider()), + ChangeNotifierProvider(create: (_) => VendorProvider()), ], child: GestureDetector( onTap: () { @@ -160,7 +166,7 @@ class MyApp extends StatelessWidget { Locale('en'), Locale('ar'), ], - locale: Locale(_settingProvider.language ?? 'en'), + locale: Locale(settingProvider.language ?? 'en'), initialRoute: SplashScreen.id, routes: { SplashScreen.id: (_) => const SplashScreen(), diff --git a/lib/models/call_request_for_work_order_model.dart b/lib/models/call_request_for_work_order_model.dart index 188edce4..35b34551 100644 --- a/lib/models/call_request_for_work_order_model.dart +++ b/lib/models/call_request_for_work_order_model.dart @@ -1,3 +1,5 @@ +import 'package:test_sa/models/lookup.dart'; + class CallRequestForWorkOrder { int id; String callNo; @@ -71,11 +73,11 @@ class Asset { String ipAddress; String macAddress; String portNumber; - String assetReplace; + Lookup assetReplace; String oldAsset; - bool isParent; + Lookup isParent; String parentAsset; - int assetType; + Lookup assetType; Site site; Building building; String floor; @@ -171,11 +173,11 @@ class Asset { ipAddress = json['ipAddress']; macAddress = json['macAddress']; portNumber = json['portNumber']; - assetReplace = json['assetReplace']; + assetReplace = json['assetReplace'] != null ? Lookup.fromJson(json['assetReplace']) : null; oldAsset = json['oldAsset']; - isParent = json['isParent']; + isParent = json['isParent'] != null ? Lookup.fromJson(json['isParent']) : null; parentAsset = json['parentAsset']; - assetType = json['assetType']; + assetType = json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null; site = json['site'] != null ? new Site.fromJson(json['site']) : null; building = json['building']; floor = json['floor']; @@ -457,12 +459,12 @@ class AssignedEmployee { class CallSiteContactPerson { int id; - Null employeeCode; + String employeeCode; String name; String telephone; String job; String email; - Null land; + String land; String contactUserId; CallSiteContactPerson({this.id, this.employeeCode, this.name, this.telephone, this.job, this.email, this.land, this.contactUserId}); diff --git a/lib/models/device/device.dart b/lib/models/device/device.dart index 40d2f92b..fe6a8409 100644 --- a/lib/models/device/device.dart +++ b/lib/models/device/device.dart @@ -9,10 +9,14 @@ class Device { String number; String assetName; String destBuildingName; + int destBuildingId; String destDepartmentName; + int destDepartmentId; String destRoom; String destFloor; + int destFloorId; String destSiteName; + // String brand; // String model; ModelDefinition modelDefinition; @@ -32,10 +36,12 @@ class Device { // this.brand, // this.model, this.modelDefinition, + this.destFloorId, + this.destDepartmentId, + this.destBuildingId, }); - factory Device.fromJson(Map parsedJson) { - print("parsedJson:$parsedJson"); + factory Device.fromJson(Map parsedJson, {bool startKeyWithDest = true}) { return Device( id: parsedJson["id"], serialNumber: parsedJson["assetSerialNo"], @@ -43,10 +49,13 @@ class Device { assetName: parsedJson["assetName"], modelDefinition: ModelDefinition.fromJson(parsedJson["modelDefinition"]), hospital: Hospital.fromJson(parsedJson["site"]), - destBuildingName: parsedJson["destBuildingName"], - destDepartmentName: parsedJson["destDepartmentName"], - destRoom: parsedJson["destRoom"], - destFloor: parsedJson["destFloor"], + destBuildingName: startKeyWithDest ? parsedJson["destBuildingName"] : parsedJson['building']['name'], + destBuildingId: startKeyWithDest ? parsedJson["destBuildingName"] : parsedJson['building']['id'], + destDepartmentName: startKeyWithDest ? parsedJson["destDepartmentName"] : parsedJson['department']['departmentName'], + destDepartmentId: startKeyWithDest ? parsedJson["destDepartmentName"] : parsedJson['department']['id'], + destRoom: startKeyWithDest ? parsedJson["destRoom"] : parsedJson['room'], + destFloor: startKeyWithDest ? parsedJson["destFloor"] : parsedJson['floor']['name'], + destFloorId: startKeyWithDest ? null : parsedJson['floor']['id'], destSiteName: parsedJson['destSiteName'] // parsedJson["modelDefinition"] == null ? "" : // parsedJson["modelDefinition"]["manufacturerName"], diff --git a/lib/models/device/device_transfer.dart b/lib/models/device/device_transfer.dart index 84ab75c2..75e9ef75 100644 --- a/lib/models/device/device_transfer.dart +++ b/lib/models/device/device_transfer.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/department.dart'; import 'package:test_sa/models/device/device.dart'; @@ -14,6 +16,7 @@ class DeviceTransfer { Device device; DeviceTransferInfo sender; DeviceTransferInfo receiver; + String createdOn; DeviceTransfer({ this.id, @@ -22,6 +25,7 @@ class DeviceTransfer { this.userId, this.sender, this.receiver, + this.createdOn, }); bool validate() { @@ -40,20 +44,35 @@ class DeviceTransfer { final receiver = DeviceTransferInfo(); receiver.fromDetails(old.receiver); this.receiver = receiver; + createdOn = old.createdOn; } factory DeviceTransfer.fromJson(Map parsedJson) { + List senderFiles = []; + if (parsedJson["senderAttachments"] != null && parsedJson["senderAttachments"] is List) { + List list = parsedJson["senderAttachments"]; + senderFiles = list.map((e) => (URLs.getFileUrl(e["attachmentName"]))).toList(); + } + List receiverFiles = []; + if (parsedJson["receiverAttachments"] != null && parsedJson["receiverAttachments"] is List) { + List list = parsedJson["receiverAttachments"]; + receiverFiles = list.map((e) => (URLs.getFileUrl(e["attachmentName"]))).toList(); + } return DeviceTransfer( id: parsedJson["id"], title: parsedJson["transferCode"], userId: parsedJson["uid"], + createdOn: parsedJson['createdOn'], device: Device( id: parsedJson["assetId"], number: parsedJson["assetNumber"], assetName: parsedJson["assetName"], serialNumber: parsedJson["assetSerialNo"], + destBuildingId: parsedJson["destBuildingId"], destBuildingName: parsedJson["destBuildingName"], + destDepartmentId: parsedJson["destDepartmentId"], destDepartmentName: parsedJson["destDepartmentName"], + destFloorId: parsedJson["destFloorId"], destFloor: parsedJson["destFloorName"], destRoom: parsedJson["destRoom"], destSiteName: parsedJson["destSiteName"], @@ -62,6 +81,7 @@ class DeviceTransfer { travelingHours: parsedJson["senderTravelingHours"], comment: parsedJson["senderComment"], workingHours: parsedJson["senderWorkingHours"], + attachments: senderFiles?.map((e) => File(e))?.toList(), timer: TimerModel( startAt: DateTime.tryParse(parsedJson["senderStartDate"] ?? ""), endAt: DateTime.tryParse(parsedJson["senderEndDate"] ?? ""), @@ -77,8 +97,7 @@ class DeviceTransfer { id: parsedJson["senderDepartmentId"], name: parsedJson["senderDepartmentName"], ), - // todo add segnature - signature: URLs.getFileUrl(parsedJson["senderAttachmentName"]), + engSignature: URLs.getFileUrl(parsedJson["senderEngSignature"]), status: Lookup( id: parsedJson["senderMachineStatusId"], name: parsedJson["senderMachineStatusName"], @@ -88,6 +107,7 @@ class DeviceTransfer { travelingHours: parsedJson["receiverTravelingHours"], comment: parsedJson["receiverComment"], workingHours: parsedJson["receiverWorkingHours"], + attachments: receiverFiles?.map((e) => File(e))?.toList(), timer: parsedJson["receiverStartDate"] != null || parsedJson["receiverEndDate"] != null ? TimerModel(startAt: DateTime.tryParse(parsedJson["receiverStartDate"] ?? ""), endAt: DateTime.tryParse(parsedJson["receiverEndDate"] ?? "")) : null, @@ -101,8 +121,7 @@ class DeviceTransfer { id: parsedJson["destDepartmentId"], name: parsedJson["destDepartmentName"], ), - // todo add segnature - signature: URLs.getFileUrl(parsedJson["receiverAttachmentName"]), + engSignature: URLs.getFileUrl(parsedJson["receiverEngSignature"]), status: Lookup( id: parsedJson["receiverMachineStatusId"], name: parsedJson["receiverMachineStatusName"], diff --git a/lib/models/device/device_transfer_info.dart b/lib/models/device/device_transfer_info.dart index 093beb46..ef03cd1b 100644 --- a/lib/models/device/device_transfer_info.dart +++ b/lib/models/device/device_transfer_info.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:test_sa/models/department.dart'; import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/lookup.dart'; @@ -10,11 +12,13 @@ class DeviceTransferInfo { Hospital client; Department department; String workingHours; + // DateTime startDate; // DateTime endDate; String travelingHours; String userName; - String signature; + String engSignature; + List attachments; String assignedEmployeeName; Lookup status; TimerModel timer; @@ -29,10 +33,11 @@ class DeviceTransferInfo { // this.startDate, // this.endDate, this.workingHours, - this.signature, + this.engSignature, this.status, this.assignedEmployeeName, this.timer, + this.attachments, }); Map toJson(bool isSender) { @@ -47,7 +52,7 @@ class DeviceTransferInfo { if (timer?.endAt != null) body["${baseKey}end_date"] = timer?.endAt?.toIso8601String(); if (travelingHours != null && travelingHours.isNotEmpty) body["${baseKey}travel_hours"] = travelingHours; if (status != null) body["${baseKey}status"] = status.id.toString(); - if (signature != null && signature.isNotEmpty) body["${baseKey}image"] = signature; + if (engSignature != null && engSignature.isNotEmpty) body["${baseKey}image"] = engSignature; return body; } @@ -63,40 +68,37 @@ class DeviceTransferInfo { client = Hospital.fromHospital(old.client); department = Department.fromDepartment(old.department); workingHours = old.workingHours; + attachments = old.attachments ?? []; // startDate = old.startDate; // endDate = old.endDate; timer = old.timer; travelingHours = old.travelingHours; comment = old.comment; - if (withSignature) signature = old.signature; + if (withSignature) engSignature = old.engSignature; status = old.status; } - factory DeviceTransferInfo.fromJson(Map parsedJson, String key) { - return DeviceTransferInfo( - workingHours: parsedJson["${key}working_hours"], - // startDate: parsedJson["${key}start_date"], - // endDate: parsedJson["${key}end_date"], - timer: TimerModel( - startAt: DateTime.tryParse(parsedJson["${key}start_date"] ?? ""), - endAt: DateTime.tryParse(parsedJson["${key}end_date"] ?? ""), - durationInSecond: ((parsedJson["${key}working_hours"] ?? 0) * 60 * 60).toInt(), - ), - travelingHours: parsedJson["${key}travel_hours"], - userName: parsedJson["${key}name"], - signature: parsedJson["${key}image"], - userId: parsedJson["${key}id"], - comment: parsedJson["${key}comment"], - assignedEmployeeName: parsedJson["${key}AssignedEmployeeName"], - client: Hospital(id: parsedJson["${key}SiteId"], name: parsedJson["${key}SiteName"]), - department: Department( - id: parsedJson["${key}DepartmentId"], - name: parsedJson["${key}DepartmentName"], - ), - status: Lookup( - id: parsedJson["${key}status"], - name: parsedJson["${key}status"], - ), - ); - } + // factory DeviceTransferInfo.fromJson(Map parsedJson, String key) { + // return DeviceTransferInfo( + // workingHours: parsedJson["${key}working_hours"], + // // startDate: parsedJson["${key}start_date"], + // // endDate: parsedJson["${key}end_date"], + // timer: TimerModel( + // startAt: DateTime.tryParse(parsedJson["${key}start_date"] ?? ""), + // endAt: DateTime.tryParse(parsedJson["${key}end_date"] ?? ""), + // durationInSecond: ((parsedJson["${key}working_hours"] ?? 0) * 60 * 60).toInt(), + // ), + // travelingHours: parsedJson["${key}travel_hours"], + // userName: parsedJson["${key}name"], + // signature: parsedJson["${key}image"], + // userId: parsedJson["${key}id"], + // comment: parsedJson["${key}comment"], + // assignedEmployeeName: parsedJson["${key}AssignedEmployeeName"], + // client: Hospital(id: parsedJson["${key}SiteId"], name: parsedJson["${key}SiteName"]), + // department: Department( + // id: parsedJson["${key}DepartmentId"], + // name: parsedJson["${key}DepartmentName"], + // ), + // ); + // } } diff --git a/lib/models/device/device_transfer_search.dart b/lib/models/device/device_transfer_search.dart new file mode 100644 index 00000000..218e838d --- /dev/null +++ b/lib/models/device/device_transfer_search.dart @@ -0,0 +1,67 @@ +import 'package:test_sa/models/device/device.dart'; + +import '../hospital.dart'; + +class DeviceTransferSearch { + Device device; + String title, room; + bool mostRecent; + Hospital hospital; + Buildings building; + List buildingsList; + Floors floor; + List floorsList; + Departments department; + List departmentsList; + + DeviceTransferSearch({ + this.device, + this.hospital, + this.building, + this.floor, + this.department, + this.room, + this.title, + this.mostRecent = true, + }); + + Map toMap() { + Map search = {}; + if (title != null && title.isNotEmpty) { + search["transferCode"] = title; + } + if (device != null) { + search["assetId"] = device.id; + } + if (mostRecent != null) { + search["mostRecent"] = mostRecent; + } + if (hospital?.id != null) { + search["destSiteId"] = hospital.id; + } + if (building?.id != null) { + search["destBuildingId"] = building.id; + } + if (floor?.id != null) { + search["destFloorId"] = floor.id; + } + if (department?.id != null) { + search["destDepartmentId"] = department.id; + } + if (room != null && room.isNotEmpty) { + search["destRoom"] = department.id; + } + return search; + } + + void fromSearch(DeviceTransferSearch newSearch) { + title = newSearch.title; + room = newSearch.room; + mostRecent = newSearch.mostRecent; + device = newSearch.device; + hospital = newSearch.hospital; + building = newSearch.building; + floor = newSearch.floor; + department = newSearch.department; + } +} diff --git a/lib/models/gas_refill/gas_refill_model.dart b/lib/models/gas_refill/gas_refill_model.dart index 291ee5ad..aeed1b85 100644 --- a/lib/models/gas_refill/gas_refill_model.dart +++ b/lib/models/gas_refill/gas_refill_model.dart @@ -8,6 +8,7 @@ import '../call_request_for_work_order_model.dart'; class GasRefillModel { int id; + //String userId; String clientName; String title; @@ -21,8 +22,9 @@ class GasRefillModel { String signatureEngineer; Uint8List localNurseSignature; Uint8List localEngineerSignature; - + num workingHours; DateTime startDate, endDate, expectedDate; + GasRefillModel({ this.id, //this.userId, @@ -41,6 +43,7 @@ class GasRefillModel { this.signatureEngineer, this.localEngineerSignature, this.localNurseSignature, + this.workingHours, }); bool validate() { @@ -73,6 +76,7 @@ class GasRefillModel { localNurseSignature = model.localNurseSignature; signatureEngineer = model.signatureEngineer; signatureNurse = model.signatureNurse; + workingHours = model.workingHours; } factory GasRefillModel.fromJson(Map parsedJson) { @@ -97,6 +101,7 @@ class GasRefillModel { assignedEmployee: AssignedEmployee.fromJson(parsedJson['assignedEmployee'] ?? {}), signatureEngineer: URLs.getFileUrl(parsedJson["engSignature"]), signatureNurse: URLs.getFileUrl(parsedJson["nurseSignature"]), + workingHours: parsedJson["workingHours"], ); } } diff --git a/lib/models/pantry/calibration_tools.dart b/lib/models/pantry/calibration_tools.dart index 324be41a..29c90e27 100644 --- a/lib/models/pantry/calibration_tools.dart +++ b/lib/models/pantry/calibration_tools.dart @@ -22,7 +22,7 @@ class CalibrationTool { factory CalibrationTool.fromMap(Map map) { return CalibrationTool( - assetsNumber: Lookup(id: map["assetId"], name: map['assetSerialNo']), + assetsNumber: Lookup(id: map["assetId"], name: map['assetNumber']), dataOfTesting: DateTime.tryParse(map['calibrationDateOfTesters'] ?? ""), ); } diff --git a/lib/models/pantry/pentry.dart b/lib/models/pantry/pentry.dart index 28f1d8e6..c59e651f 100644 --- a/lib/models/pantry/pentry.dart +++ b/lib/models/pantry/pentry.dart @@ -18,7 +18,8 @@ class Pentry { DateTime expectedVisitDate; String travelingHours; String image; - File imageFile; + List files = []; + // List contacts; List ppmCheckLists; List calibrationTools; @@ -36,7 +37,7 @@ class Pentry { this.actualVisitDate, this.expectedVisitDate, this.image, - this.imageFile, + this.files, // this.contacts, this.ppmCheckLists, this.calibrationTools, @@ -74,8 +75,8 @@ class Pentry { Map toMap(int visitId) { Map map = {}; - map["visitStatusId"] = ppmVisitStatus?.id.toString(); - if (status != null) map["deviceStatusId"] = status?.id.toString(); + map["visitStatusId"] = ppmVisitStatus?.id?.toString(); + if (status != null) map["deviceStatusId"] = status?.id?.toString(); if (travelingHours != null) map["travelingHours"] = travelingHours; //if(imageFile != null) map["file_attachement"] = base64Encode(imageFile.readAsBytesSync()); map["actualDate"] = actualVisitDate.toIso8601String(); @@ -85,10 +86,8 @@ class Pentry { map["endDate"] = timer.endAt?.toIso8601String() ?? DateTime.now().toIso8601String(); map["workingHours"] = (timer.durationInSecond / 60 / 60).toStringAsFixed(5); } - if (imageFile != null) { - map["vAttachments"] = [ - {"attachmentName": (imageFile.path.split("/").last + base64Encode(imageFile.readAsBytesSync()))} - ]; + if (files?.isNotEmpty ?? false) { + map["vAttachments"] = files.map((file) => {"attachmentName": _isLocalUrl(file.path) ? (file.path.split("/").last + "|" + base64Encode(file.readAsBytesSync())) : file.path}).toList(); } map["travelingHours"] = travelingHours; // if(contacts?.isNotEmpty == true) { @@ -101,11 +100,16 @@ class Pentry { map["vChecklists"] = ppmCheckLists.map((e) => e.toMap(visitId)).toList(); map["vCalibrationTools"] = calibrationTools.map((e) => e.toMap(visitId)).toList(); map["vKits"] = pmKits.map((e) => e.toMap(visitId)).toList(); - map["nurseSignature"] = signatureNurse;//"${DateTime.now().toIso8601String()}.png|$signatureNurse"; - map["engSignature"] = signatureEngineer;//"${DateTime.now().toIso8601String()}.png|$signatureEngineer"; + map["nurseSignature"] = signatureNurse; //"${DateTime.now().toIso8601String()}.png|$signatureNurse"; + map["engSignature"] = signatureEngineer; //"${DateTime.now().toIso8601String()}.png|$signatureEngineer"; return map; } + bool _isLocalUrl(String url) { + if (url?.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } + factory Pentry.fromMap(Map map) { // List contacts = []; // if(map['contacts'] != null){ @@ -118,7 +122,12 @@ class Pentry { if (map['vKits'] != null) { pmKits = (map['vKits'] as List).map((e) => PMKit.fromMap(e as Map)).toList(); } - + List files = []; + if (map["vAttachments"] != null) if (map["vAttachments"] is List) { + List list = map["vAttachments"]; + list.removeWhere((element) => (element["attachmentURL"]?.toString() ?? "").isEmpty); + files = list.map((e) => URLs.getFileUrl(e["attachmentName"])).toList(); + } List ppmCheckLists = []; if (map['vChecklists'] != null) { ppmCheckLists = (map['vChecklists'] as List).map((e) => PPMCheckList.fromMap(e as Map)).toList(); @@ -129,7 +138,7 @@ class Pentry { calibrationTools = (map['vCalibrationTools'] as List).map((e) => CalibrationTool.fromMap(e as Map)).toList(); } return Pentry( - status: Lookup(id: map["taskStatusId"], name: map["taskStatusName"]), + status: Lookup(id: map["deviceStatusId"], name: map["deviceStatusName"]), ppmVisitStatus: Lookup(id: map["visitStatusId"], name: map["visitStatusName"]), actualVisitDate: DateTime.tryParse(map["actualDate"] ?? ""), expectedVisitDate: DateTime.tryParse(map["expectedDate"] ?? ""), @@ -143,6 +152,10 @@ class Pentry { ppmCheckLists: ppmCheckLists, calibrationTools: calibrationTools, pmKits: pmKits, + files: files?.map((e) { + return File(e); + })?.toList() ?? + [], signatureNurse: URLs.getFileUrl(map["nurseSignature"]), signatureEngineer: URLs.getFileUrl(map["engSignature"]), ); @@ -156,7 +169,7 @@ class Pentry { DateTime expectedVisitDate, String travelingHours, String image, - File imageFile, + List files, List ppmCheckLists, List calibrationTools, List pmKits, @@ -171,11 +184,17 @@ class Pentry { expectedVisitDate: expectedVisitDate ?? this.expectedVisitDate, travelingHours: travelingHours ?? this.travelingHours, image: image ?? this.image, - imageFile: imageFile ?? this.imageFile, + files: files ?? this.files, ppmCheckLists: ppmCheckLists ?? this.ppmCheckLists?.map((e) => e.copyWith())?.toList(), calibrationTools: calibrationTools ?? this.calibrationTools?.map((e) => e.copyWith())?.toList(), pmKits: pmKits ?? this.pmKits.map((e) => e.copyWith()).toList(), signatureNurse: signatureNurse ?? this.signatureNurse, signatureEngineer: signatureEngineer ?? this.signatureEngineer); } + + void clearEmptyObjects() { + ppmCheckLists.removeWhere((element) => (element?.title?.isEmpty ?? true) && (element?.comment?.isEmpty ?? true) && (element?.measuredValue?.isEmpty ?? true) && element.status == null); + calibrationTools.removeWhere((element) => (element?.assetsNumber == null) && (element?.dataOfTesting == null)); + pmKits.removeWhere((element) => (element?.itemCode == null)); + } } diff --git a/lib/models/part.dart b/lib/models/part.dart index 176811cc..9f8b0cad 100644 --- a/lib/models/part.dart +++ b/lib/models/part.dart @@ -1,23 +1,28 @@ class Part { int id; int reportPartID; - String code; - String name; + String partNo; + String partName; int quantity; + double returnQty, installQty; Part({ this.id, this.reportPartID, - this.code, - this.name, + this.partNo, + this.partName, this.quantity = 1, + this.installQty, + this.returnQty, }); Map toJson() { return { "id": reportPartID ?? 0, - "sparePart": {"id": id, "partNo": code, "partName": name}, - "qty": quantity + "sparePart": {"id": id, "partNo": partNo, "partName": partName}, + "qty": quantity, + if (returnQty != null) "returnQty": returnQty, + if (installQty != null) "installQty": installQty, }; } @@ -25,9 +30,11 @@ class Part { return Part( id: parsedJson["id"], reportPartID: reportJson != null ? reportJson["id"] : null, - code: parsedJson["partNo"], - name: parsedJson["partName"], + partNo: parsedJson["partNo"], + partName: parsedJson["partName"], quantity: reportJson != null ? (reportJson["qty"] ?? 1).toInt() : 1, + returnQty: parsedJson["returnQty"], + installQty: parsedJson["installQty"], ); } } diff --git a/lib/models/service_report.dart b/lib/models/service_report.dart index 7abb59cb..7575bce3 100644 --- a/lib/models/service_report.dart +++ b/lib/models/service_report.dart @@ -14,6 +14,8 @@ class ServiceReport { int id; double operatingHours; DateTime visitDate; + DateTime returnToService; + // DateTime endDate; // DateTime startDate; Lookup assetType; @@ -32,7 +34,7 @@ class ServiceReport { String invoiceNumber; String invoiceCode; List parts; - String image; + List files; Device device; String quantity; String jobSheetNumber; @@ -46,46 +48,48 @@ class ServiceReport { String reviewComment; FaultDescription faultDescription; - ServiceReport({ - this.id, - this.visitDate, - // this.endDate, - this.assetType, - this.equipmentStatus, - this.type, - this.faultDescriptionId, - this.workingHours, - this.travelingHours, - this.parts, - this.engineer, - this.workPreformed, - this.reason, - this.operatingHours, - this.callLastSituation, - this.currentSituation, - this.jobSheetNumber, - this.image, - this.device, - this.invoiceCode, - this.invoiceNumber, - this.quantity = "1", - this.timer, - this.signatureNurse, - this.signatureEngineer, - this.localNurseSignature, - this.localEngineerSignature, - this.comment, - this.repairLocation, - this.travelingExpense, - // this.startDate, - this.reviewComment, - this.faultDescription, - }); + ServiceReport( + {this.id, + this.visitDate, + // this.endDate, + this.assetType, + this.equipmentStatus, + this.type, + this.faultDescriptionId, + this.workingHours, + this.travelingHours, + this.parts, + this.engineer, + this.workPreformed, + this.reason, + this.operatingHours, + this.callLastSituation, + this.currentSituation, + this.jobSheetNumber, + this.files, + this.device, + this.invoiceCode, + this.invoiceNumber, + this.quantity = "1", + this.timer, + this.signatureNurse, + this.signatureEngineer, + this.localNurseSignature, + this.localEngineerSignature, + this.comment, + this.repairLocation, + this.travelingExpense, + // this.startDate, + this.reviewComment, + this.faultDescription, + this.returnToService}); Map toMap(ServiceRequest request) { Map _map = {}; if (id != null) _map["id"] = id; if (visitDate != null) _map["visitDate"] = visitDate.toIso8601String(); + if (returnToService != null) _map["replacementDate"] = returnToService.toIso8601String(); + //if(serviceType != null) _map["service_type"] = serviceType.id.toString(); if (equipmentStatus != null) _map["equipmentStatus"] = equipmentStatus?.toMap(); if (type != null) _map["typeOfWO"] = type?.toMap(); @@ -132,10 +136,8 @@ class ServiceReport { //if(image != null) _map["image"] = image; //if(invoiceCode != null) _map["invoice_no"] = invoiceCode; //if(invoiceNumber != null) _map["invoice_code"] = invoiceNumber; - if (image != null) { - _map["attachmentsWorkOrder"] = [ - {"name": image} - ]; + if (files != null) { + _map["attachmentsWorkOrder"] = files.map((e) => {"name": e}).toList(); } _map["nurseSignature"] = signatureNurse; _map["engSignature"] = signatureEngineer; @@ -152,15 +154,14 @@ class ServiceReport { } Future validate() async { - print("visitDate:$visitDate"); - print("equipmentStatus:${equipmentStatus?.toMap()}"); - print("callLastSituation:${callLastSituation?.toMap()}"); - print("parts:$parts"); - print("reason:${reason?.toMap()}"); - if (visitDate == null) { - await Fluttertoast.showToast(msg: "Visit Date Required"); - return false; - } + // if (visitDate == null) { + // await Fluttertoast.showToast(msg: "Visit Date Required"); + // return false; + // } + // if (returnToService == null) { + // await Fluttertoast.showToast(msg: "Return To Service Date Required"); + // return false; + // } if (timer?.startAt == null) { await Fluttertoast.showToast(msg: "Working Hours Required"); return false; @@ -196,6 +197,11 @@ class ServiceReport { _parts = partsList.map((e) => Part.fromJson(e["sparePart"], reportJson: e)).toList(); } } + List _files = []; + if (parsedJson["attachmentsWorkOrder"] != null && parsedJson["attachmentsWorkOrder"] is List) { + List list = parsedJson["attachmentsWorkOrder"]; + _files = list.map((e) => (URLs.getFileUrl(e["name"]))).toList(); + } return ServiceReport( id: id, assetType: Lookup.fromJson(parsedJson["assetType"]), @@ -206,7 +212,7 @@ class ServiceReport { equipmentStatus: Lookup.fromJson(parsedJson["equipmentStatus"]), type: Lookup.fromJson(parsedJson["typeOfWO"]), faultDescription: parsedJson['faultDescription'] != null ? FaultDescription.fromJson(parsedJson['faultDescription']) : null, - + files: _files, // faultDescription: parsedJson["faultDescription"], // startDate: DateTime.tryParse(parsedJson["startofWorkTime"] ?? ""), // endDate: DateTime.tryParse(parsedJson["endofWorkTime"] ?? ""), @@ -219,7 +225,8 @@ class ServiceReport { //quantity: parsedJson["nid"], travelingHours: parsedJson["travelingHours"], travelingExpense: parsedJson["travelingExpenses"], - visitDate: DateTime.tryParse(parsedJson["visitDate"]), + visitDate: DateTime.tryParse(parsedJson["visitDate"] ?? ""), + returnToService: DateTime.tryParse(parsedJson["replacementDate"] ?? ""), workingHours: parsedJson["workingHours"], timer: TimerModel( startAt: DateTime.tryParse(parsedJson["startofWorkTime"] ?? ""), diff --git a/lib/models/service_request/search_work_order.dart b/lib/models/service_request/search_work_order.dart index 898fa0e9..cd2cda55 100644 --- a/lib/models/service_request/search_work_order.dart +++ b/lib/models/service_request/search_work_order.dart @@ -1,4 +1,5 @@ import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/service_request/sub_work_order_details.dart'; import 'package:test_sa/models/timer_model.dart'; import '../fault_description.dart'; @@ -38,6 +39,7 @@ class SearchWorkOrder { this.nurseSignature, this.woParentDto, this.timer, + this.mrNumber, }); SearchWorkOrder.fromJson(dynamic json) { @@ -50,6 +52,7 @@ class SearchWorkOrder { assetType = json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null; assignedEmployee = json['assignedEmployee'] != null ? AssignedEmployee.fromJson(json['assignedEmployee']) : null; visitDate = json['visitDate']; + mrNumber = json['mrNumber']; if (json['assistantEmployees'] != null) { assistantEmployees = []; json['assistantEmployees'].forEach((v) { @@ -144,6 +147,7 @@ class SearchWorkOrder { engSignature = wo.engSignature ?? engSignature; nurseSignature = wo.nurseSignature ?? nurseSignature; woParentDto = wo.woParentDto ?? woParentDto; + mrNumber = wo.mrNumber ?? mrNumber; } num id; @@ -179,6 +183,7 @@ class SearchWorkOrder { String nurseSignature; WoParentDto woParentDto; TimerModel timer; + String mrNumber; SearchWorkOrder copyWith({ num id, @@ -214,6 +219,7 @@ class SearchWorkOrder { String nurseSignature, WoParentDto woParentDto, TimerModel timer, + String mrNumber, }) => SearchWorkOrder( id: id ?? this.id, @@ -249,7 +255,9 @@ class SearchWorkOrder { nurseSignature: nurseSignature ?? this.nurseSignature, woParentDto: woParentDto ?? this.woParentDto, timer: timer ?? this.timer, + mrNumber: mrNumber ?? this.mrNumber, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -284,7 +292,7 @@ class SearchWorkOrder { if (repairLocation?.id != null) { map['repairLocation'] = repairLocation.toMap(); } - if (reason != null) { + if (reason != null && reason.id != null) { map['reason'] = reason.toMap(); } // map['startofWorkTime'] = startofWorkTime; @@ -306,7 +314,7 @@ class SearchWorkOrder { if (attachmentsWorkOrder != null) { map['attachmentsWorkOrder'] = attachmentsWorkOrder.map((v) => v.toJson()).toList(); } - if (equipmentStatus != null) { + if (equipmentStatus != null && equipmentStatus.id != null) { map['equipmentStatus'] = equipmentStatus.toMap(); } if (suppEngineerWorkOrders != null) { @@ -317,8 +325,20 @@ class SearchWorkOrder { if (woParentDto != null) { map['woParentDto'] = woParentDto.toJson(); } + if (mrNumber != null) { + map['mrNumber'] = mrNumber; + } return map; } + + void copyDetails(SubWorkOrderDetails subWoDetails) { + equipmentStatus = subWoDetails.equipmentStatus; + reason = subWoDetails.reason; + faultDescription = subWoDetails.faultDescription; + sparePartsWorkOrders = subWoDetails.sparePartsWorkOrders; + suppEngineerWorkOrders = subWoDetails.suppEngineerWorkOrders; + supplier = subWoDetails.supplier; + } } class WoParentDto { @@ -352,6 +372,7 @@ class WoParentDto { equipmentStatus = json['equipmentStatus'] != null ? Lookup.fromJson(json['equipmentStatus']) : null; currentSituation = json['currentSituation'] != null ? Lookup.fromJson(json['currentSituation']) : null; } + Lookup callLastSituation; SupplierModel supplier; Lookup assetType; @@ -362,6 +383,7 @@ class WoParentDto { List suppEngineerWorkOrders; Lookup equipmentStatus; Lookup currentSituation; + WoParentDto copyWith({ Lookup callLastSituation, SupplierModel supplier, @@ -386,6 +408,7 @@ class WoParentDto { equipmentStatus: equipmentStatus ?? this.equipmentStatus, currentSituation: currentSituation ?? this.currentSituation, ); + Map toJson() { final map = {}; if (callLastSituation != null) { @@ -436,6 +459,7 @@ class SuppEngineerWorkOrders { externalEngCode = json['externalEngCode']; email = json['email']; } + num id; num supplierContactId; String personName; @@ -443,6 +467,7 @@ class SuppEngineerWorkOrders { String contact; String externalEngCode; String email; + SuppEngineerWorkOrders copyWith({ num id, num supplierContactId, @@ -461,6 +486,7 @@ class SuppEngineerWorkOrders { externalEngCode: externalEngCode ?? this.externalEngCode, email: email ?? this.email, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -496,6 +522,7 @@ class StepsWorkOrderDto { parentWOId = json['parentWOId']; callId = json['callId']; } + num sequence; num id; String name; @@ -504,6 +531,7 @@ class StepsWorkOrderDto { bool processed; num parentWOId; num callId; + StepsWorkOrderDto copyWith({ num sequence, num id, @@ -524,6 +552,7 @@ class StepsWorkOrderDto { parentWOId: parentWOId ?? this.parentWOId, callId: callId ?? this.callId, ); + Map toJson() { final map = {}; map['sequence'] = sequence; @@ -612,6 +641,7 @@ class SupplierModel { }); } } + num id; String suppliername; String name; @@ -631,6 +661,7 @@ class SupplierModel { List attachments; List suppPersons; List suppTCodes; + SupplierModel copyWith({ num id, String suppliername, @@ -673,6 +704,7 @@ class SupplierModel { suppPersons: suppPersons ?? this.suppPersons, suppTCodes: suppTCodes ?? this.suppTCodes, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -724,10 +756,12 @@ class SuppTCodes { codeTypeId = json['codeTypeId']; codeValue = json['codeValue']; } + num id; num supplierId; num codeTypeId; String codeValue; + SuppTCodes copyWith({ num id, num supplierId, @@ -740,6 +774,7 @@ class SuppTCodes { codeTypeId: codeTypeId ?? this.codeTypeId, codeValue: codeValue ?? this.codeValue, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -770,6 +805,7 @@ class SuppPersons { externalEngCode = json['externalEngCode']; email = json['email']; } + num id; num supplierId; String personName; @@ -777,6 +813,7 @@ class SuppPersons { String contact; String externalEngCode; String email; + SuppPersons copyWith({ num id, num supplierId, @@ -795,6 +832,7 @@ class SuppPersons { externalEngCode: externalEngCode ?? this.externalEngCode, email: email ?? this.email, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -822,10 +860,12 @@ class Attachments { attachmentName = json['attachmentName']; attachmentURL = json['attachmentURL']; } + num id; num supplierId; String attachmentName; String attachmentURL; + Attachments copyWith({ num id, num supplierId, @@ -838,6 +878,7 @@ class Attachments { attachmentName: attachmentName ?? this.attachmentName, attachmentURL: attachmentURL ?? this.attachmentURL, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -860,9 +901,11 @@ class Addresses { supplierId = json['supplierId']; address = json['address']; } + num id; num supplierId; String address; + Addresses copyWith({ num id, num supplierId, @@ -873,6 +916,7 @@ class Addresses { supplierId: supplierId ?? this.supplierId, address: address ?? this.address, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -894,9 +938,11 @@ class Faxes { supplierId = json['supplierId']; fax = json['fax']; } + num id; num supplierId; String fax; + Faxes copyWith({ num id, num supplierId, @@ -907,6 +953,7 @@ class Faxes { supplierId: supplierId ?? this.supplierId, fax: fax ?? this.fax, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -928,9 +975,11 @@ class Telephones { supplierId = json['supplierId']; telephone = json['telephone']; } + num id; num supplierId; String telephone; + Telephones copyWith({ num id, num supplierId, @@ -941,6 +990,7 @@ class Telephones { supplierId: supplierId ?? this.supplierId, telephone: telephone ?? this.telephone, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -960,8 +1010,10 @@ class AttachmentsWorkOrder { id = json['id']; name = json['name']; } + num id; String name; + AttachmentsWorkOrder copyWith({ num id, String name, @@ -970,6 +1022,7 @@ class AttachmentsWorkOrder { id: id ?? this.id, name: name ?? this.name, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -994,11 +1047,13 @@ class SparePartsWorkOrders { returnQty = json['returnQty']; installQty = json['installQty']; } + num id; SparePart sparePart; num qty; num returnQty; num installQty; + SparePartsWorkOrders copyWith({ num id, SparePart sparePart, @@ -1013,6 +1068,7 @@ class SparePartsWorkOrders { returnQty: returnQty ?? this.returnQty, installQty: installQty ?? this.installQty, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1038,9 +1094,11 @@ class SparePart { partNo = json['partNo']; partName = json['partName']; } + num id; String partNo; String partName; + SparePart copyWith({ num id, String partNo, @@ -1051,6 +1109,7 @@ class SparePart { partNo: partNo ?? this.partNo, partName: partName ?? this.partName, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1082,6 +1141,7 @@ class ContactPersonWorkOrders { land = json['land']; contactUserId = json['contactUserId']; } + num id; String employeeCode; String name; @@ -1090,6 +1150,7 @@ class ContactPersonWorkOrders { String email; String land; String contactUserId; + ContactPersonWorkOrders copyWith({ num id, String employeeCode, @@ -1110,6 +1171,7 @@ class ContactPersonWorkOrders { land: land ?? this.land, contactUserId: contactUserId ?? this.contactUserId, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1134,8 +1196,10 @@ class AssistantEmployees { id = json['id']; user = json['user'] != null ? UserModel.fromJson(json['user']) : UserModel(name: json['userName'], id: json['userId']); } + num id; UserModel user; + AssistantEmployees copyWith({ num id, UserModel user, @@ -1144,6 +1208,7 @@ class AssistantEmployees { id: id ?? this.id, user: user ?? this.user, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1164,8 +1229,10 @@ class UserModel { id = json['id']; name = json['name']; } + String id; String name; + UserModel copyWith({ String id, String name, @@ -1174,6 +1241,7 @@ class UserModel { id: id ?? this.id, name: name ?? this.name, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1192,8 +1260,10 @@ class AssignedEmployee { id = json['id']; name = json['name']; } + String id; String name; + AssignedEmployee copyWith({ String id, String name, @@ -1202,6 +1272,7 @@ class AssignedEmployee { id: id ?? this.id, name: name ?? this.name, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1243,6 +1314,7 @@ class CallRequest { firstAction = json['firstAction'] != null ? FirstAction.fromJson(json['firstAction']) : null; assetType = json['assetType']; } + num id; String callNo; String callComments; @@ -1254,6 +1326,7 @@ class CallRequest { DefectType defectType; FirstAction firstAction; num assetType; + CallRequest copyWith({ num id, String callNo, @@ -1280,6 +1353,7 @@ class CallRequest { firstAction: firstAction ?? this.firstAction, assetType: assetType ?? this.assetType, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1323,9 +1397,11 @@ class FirstAction { name = json['name']; value = json['value']; } + num id; String name; num value; + FirstAction copyWith({ num id, String name, @@ -1336,6 +1412,7 @@ class FirstAction { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1357,9 +1434,11 @@ class DefectType { name = json['name']; value = json['value']; } + num id; String name; num value; + DefectType copyWith({ num id, String name, @@ -1370,6 +1449,7 @@ class DefectType { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1391,9 +1471,11 @@ class Status { name = json['name']; value = json['value']; } + num id; String name; num value; + Status copyWith({ num id, String name, @@ -1404,6 +1486,7 @@ class Status { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1435,6 +1518,7 @@ class CallSiteContactPerson { land = json['land']; contactUserId = json['contactUserId']; } + num id; String employeeCode; String name; @@ -1443,6 +1527,7 @@ class CallSiteContactPerson { String email; String land; String contactUserId; + CallSiteContactPerson copyWith({ num id, String employeeCode, @@ -1463,6 +1548,7 @@ class CallSiteContactPerson { land: land ?? this.land, contactUserId: contactUserId ?? this.contactUserId, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1584,6 +1670,7 @@ class Asset { comment = json['comment']; tagCode = json['tagCode']; } + num id; String assetSerialNo; String systemID; @@ -1632,6 +1719,7 @@ class Asset { List technicalGuidanceBooks; String comment; String tagCode; + Asset copyWith({ num id, String assetSerialNo, @@ -1732,6 +1820,7 @@ class Asset { comment: comment ?? this.comment, tagCode: tagCode ?? this.tagCode, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1760,10 +1849,6 @@ class Asset { } map['assetType'] = assetType?.toMap(); - print("supplier : ${supplier?.toJson()}"); - print("supplier 2 : ${map['supplier']}"); - print("asset type : ${assetType?.toMap()}"); - print("asset type 2: ${map['assetType']}"); if (site != null) { map['site'] = site.toJson(); } @@ -1836,8 +1921,10 @@ class TechnicalGuidanceBooks { id = json['id']; guidanceBook = json['guidanceBook'] != null ? GuidanceBook.fromJson(json['guidanceBook']) : null; } + num id; GuidanceBook guidanceBook; + TechnicalGuidanceBooks copyWith({ num id, GuidanceBook guidanceBook, @@ -1846,6 +1933,7 @@ class TechnicalGuidanceBooks { id: id ?? this.id, guidanceBook: guidanceBook ?? this.guidanceBook, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1868,9 +1956,11 @@ class GuidanceBook { name = json['name']; value = json['value']; } + num id; String name; num value; + GuidanceBook copyWith({ num id, String name, @@ -1881,6 +1971,7 @@ class GuidanceBook { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1902,9 +1993,11 @@ class RemainderWarrantyMonths { name = json['name']; value = json['value']; } + num id; String name; num value; + RemainderWarrantyMonths copyWith({ num id, String name, @@ -1915,6 +2008,7 @@ class RemainderWarrantyMonths { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1936,9 +2030,11 @@ class ExtendedWarrantyMonths { name = json['name']; value = json['value']; } + num id; String name; num value; + ExtendedWarrantyMonths copyWith({ num id, String name, @@ -1949,6 +2045,7 @@ class ExtendedWarrantyMonths { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -1970,9 +2067,11 @@ class SiteWarrantyMonths { name = json['name']; value = json['value']; } + num id; String name; num value; + SiteWarrantyMonths copyWith({ num id, String name, @@ -1983,6 +2082,7 @@ class SiteWarrantyMonths { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2004,9 +2104,11 @@ class CommissioningStatus { name = json['name']; value = json['value']; } + num id; String name; num value; + CommissioningStatus copyWith({ num id, String name, @@ -2017,6 +2119,7 @@ class CommissioningStatus { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2045,10 +2148,12 @@ class OriginSite { }); } } + num id; num customerCode; String custName; List buildings; + OriginSite copyWith({ num id, num customerCode, @@ -2061,6 +2166,7 @@ class OriginSite { custName: custName ?? this.custName, buildings: buildings ?? this.buildings, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2092,10 +2198,12 @@ class Buildings { }); } } + num id; String name; num value; List floors; + Buildings copyWith({ num id, String name, @@ -2108,6 +2216,7 @@ class Buildings { value: value ?? this.value, floors: floors ?? this.floors, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2139,10 +2248,12 @@ class Floors { }); } } + num id; String name; num value; List departments; + Floors copyWith({ num id, String name, @@ -2155,6 +2266,7 @@ class Floors { value: value ?? this.value, departments: departments ?? this.departments, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2177,8 +2289,10 @@ class Departments { id = json['id']; name = json['name']; } + num id; String name; + Departments copyWith({ num id, String name, @@ -2187,6 +2301,7 @@ class Departments { id: id ?? this.id, name: name ?? this.name, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2209,10 +2324,12 @@ class OriginDepartment { departmentCode = json['departmentCode']; ntCode = json['ntCode']; } + num id; String departmentName; String departmentCode; String ntCode; + OriginDepartment copyWith({ num id, String departmentName, @@ -2225,6 +2342,7 @@ class OriginDepartment { departmentCode: departmentCode ?? this.departmentCode, ntCode: ntCode ?? this.ntCode, ); + Map toJson() { final map = {}; map['id'] = id; @@ -2247,9 +2365,11 @@ class Currency { name = json['name']; value = json['value']; } + num id; String name; num value; + Currency copyWith({ num id, String name, @@ -2260,6 +2380,7 @@ class Currency { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2283,10 +2404,12 @@ class Department { departmentCode = json['departmentCode']; ntCode = json['ntCode']; } + num id; String departmentName; String departmentCode; String ntCode; + Department copyWith({ num id, String departmentName, @@ -2299,6 +2422,7 @@ class Department { departmentCode: departmentCode ?? this.departmentCode, ntCode: ntCode ?? this.ntCode, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2321,9 +2445,11 @@ class Floor { name = json['name']; value = json['value']; } + num id; String name; num value; + Floor copyWith({ num id, String name, @@ -2334,6 +2460,7 @@ class Floor { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2355,9 +2482,11 @@ class Building { name = json['name']; value = json['value']; } + num id; String name; num value; + Building copyWith({ num id, String name, @@ -2368,6 +2497,7 @@ class Building { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2396,10 +2526,12 @@ class Site { }); } } + num id; num customerCode; String custName; List buildings; + Site copyWith({ num id, num customerCode, @@ -2412,6 +2544,7 @@ class Site { custName: custName ?? this.custName, buildings: buildings ?? this.buildings, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2440,11 +2573,13 @@ class ParentAsset { tagCode = json['tagCode']; systemId = json['systemId']; } + num id; String assetSerialNo; String assetNumber; String tagCode; String systemId; + ParentAsset copyWith({ num id, String assetSerialNo, @@ -2459,6 +2594,7 @@ class ParentAsset { tagCode: tagCode ?? this.tagCode, systemId: systemId ?? this.systemId, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2482,9 +2618,11 @@ class IsParent { name = json['name']; value = json['value']; } + num id; String name; num value; + IsParent copyWith({ num id, String name, @@ -2495,6 +2633,7 @@ class IsParent { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2520,11 +2659,13 @@ class OldAsset { tagCode = json['tagCode']; systemId = json['systemId']; } + num id; String assetSerialNo; String assetNumber; String tagCode; String systemId; + OldAsset copyWith({ num id, String assetSerialNo, @@ -2539,6 +2680,7 @@ class OldAsset { tagCode: tagCode ?? this.tagCode, systemId: systemId ?? this.systemId, ); + Map toJson() { final map = {}; map['id'] = id; @@ -2562,9 +2704,11 @@ class AssetReplace { name = json['name']; value = json['value']; } + num id; String name; num value; + AssetReplace copyWith({ num id, String name, @@ -2575,6 +2719,7 @@ class AssetReplace { name: name ?? this.name, value: value ?? this.value, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2588,26 +2733,42 @@ class Supplier { Supplier({ this.id, this.suppliername, + this.suppPersons, }); Supplier.fromJson(dynamic json) { id = json['id']; suppliername = json['suppliername']; + if (json['suppPersons'] != null) { + suppPersons = []; + json['suppPersons'].forEach((v) { + suppPersons.add(SuppPersons.fromJson(v)); + }); + } } + num id; String suppliername; + List suppPersons; + SupplierModel copyWith({ num id, String suppliername, + List suppPersons, }) => SupplierModel( id: id ?? this.id, suppliername: suppliername ?? this.suppliername, + suppPersons: suppPersons ?? this.suppPersons, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; map['suppliername'] = suppliername; + if (suppPersons != null) { + map['suppPersons'] = suppPersons.map((v) => v.toJson()).toList(); + } return map; } } @@ -2654,6 +2815,7 @@ class ModelDefinition { }); } } + num id; String assetName; String modelDefCode; @@ -2667,6 +2829,7 @@ class ModelDefinition { num lifeSpan; List modelDefRelatedDefects; List suppliers; + ModelDefinition copyWith({ num id, String assetName, @@ -2697,6 +2860,7 @@ class ModelDefinition { modelDefRelatedDefects: modelDefRelatedDefects ?? this.modelDefRelatedDefects, suppliers: suppliers ?? this.suppliers, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2730,8 +2894,10 @@ class Suppliers { id = json['id']; suppliername = json['suppliername']; } + num id; String suppliername; + Suppliers copyWith({ num id, String suppliername, @@ -2740,6 +2906,7 @@ class Suppliers { id: id ?? this.id, suppliername: suppliername ?? this.suppliername, ); + Map toJson() { final map = {}; map['id'] = id ?? 0; @@ -2762,10 +2929,12 @@ class ModelDefRelatedDefects { workPerformed = json['workPerformed']; estimatedTime = json['estimatedTime']; } + num id; String defectName; String workPerformed; String estimatedTime; + ModelDefRelatedDefects copyWith({ num id, String defectName, @@ -2778,6 +2947,7 @@ class ModelDefRelatedDefects { workPerformed: workPerformed ?? this.workPerformed, estimatedTime: estimatedTime ?? this.estimatedTime, ); + Map toJson() { final map = {}; map['id'] = id; diff --git a/lib/models/service_request/service_request.dart b/lib/models/service_request/service_request.dart index 68a55eb8..836112c3 100644 --- a/lib/models/service_request/service_request.dart +++ b/lib/models/service_request/service_request.dart @@ -1,5 +1,6 @@ import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/device/device.dart'; +import 'package:test_sa/models/fault_description.dart'; import 'package:test_sa/models/lookup.dart'; class ServiceRequest { @@ -27,8 +28,9 @@ class ServiceRequest { bool viewReport; String engineerMobile; String deviceModel; - String faultDescription; - String workPerformed; + FaultDescription faultDescription; + + //String workPerformed; String visitDate; DateTime nextVisitDate; String jobSheetNumber; @@ -68,7 +70,7 @@ class ServiceRequest { this.jobSheetNumber, this.visitDate, this.nextVisitDate, - this.workPerformed, + //this.workPerformed, this.reportID, this.defectType, this.priority, @@ -86,7 +88,7 @@ class ServiceRequest { List images = []; if (parsedJson["attachmentsCallRequest"] != null) if (parsedJson["attachmentsCallRequest"] is List) { List list = parsedJson["attachmentsCallRequest"]; - images = list.map((e) => URLs.getFileUrl(e["attachmentsCallRequest"])).toList(); + images = list.map((e) => URLs.getFileUrl(e["name"])).toList(); } return ServiceRequest( id: parsedJson["id"].toString(), @@ -114,16 +116,21 @@ class ServiceRequest { viewReport: parsedJson["workOrder"] != null, deviceModel: parsedJson["asset"]["modelDefinition"]["modelName"], engineerMobile: parsedJson["assignedEmployee"] == null ? null : parsedJson["assignedEmployee"]["phone"], - faultDescription: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["faultDescription"] : null, + faultDescription: parsedJson["workOrder"] != null + ? parsedJson["workOrder"]["faultDescription"] != null + ? FaultDescription.fromJson(parsedJson["workOrder"]["faultDescription"]) + : null + : null, + jobSheetNumber: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["jobSheetNumber"] : null, visitDate: DateTime.tryParse(parsedJson["visitDate"] ?? "").toString().split(" ").first, nextVisitDate: DateTime.tryParse(parsedJson["nextVisitDate"] ?? ""), - workPerformed: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["workPerformed"] : null, + //workPerformed: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["workPerformed"] : null, device: Device.fromJson(parsedJson["asset"]), reviewComment: parsedJson["reviewComment"], type: Lookup.fromJson(parsedJson['typeofRequest']), defectType: Lookup.fromJson(parsedJson['defectType']), - loanAvailability: Lookup.fromJson(parsedJson['loanAvailability']), + loanAvailability: Lookup.fromJson(parsedJson['loanAvailablity']), firstAction: Lookup.fromJson(parsedJson['firstAction']), requestedThrough: Lookup.fromJson(parsedJson['requestedThrough']), priority: Lookup.fromJson(parsedJson['priority']), diff --git a/lib/models/service_request/service_request_search.dart b/lib/models/service_request/service_request_search.dart index 53fca4ab..f6628672 100644 --- a/lib/models/service_request/service_request_search.dart +++ b/lib/models/service_request/service_request_search.dart @@ -1,13 +1,20 @@ import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/lookup.dart'; +import '../call_request_for_work_order_model.dart'; + class ServiceRequestSearch { + String callId; String deviceSerialNumber; String deviceNumber; String deviceName; Hospital hospital; String model; Lookup statusValue; + bool mostRecent; + String from, to; + Lookup dateOperator; + AssignedEmployee assignedEmployee; ServiceRequestSearch({ this.deviceSerialNumber, @@ -16,6 +23,12 @@ class ServiceRequestSearch { this.deviceName, this.model, this.hospital, + this.callId, + this.from, + this.to, + this.assignedEmployee, + this.dateOperator, + this.mostRecent = true, }); fromSearch(ServiceRequestSearch newSearch) { @@ -24,6 +37,12 @@ class ServiceRequestSearch { statusValue = newSearch.statusValue; hospital = newSearch.hospital; model = newSearch.model; + mostRecent = newSearch.mostRecent; + callId = newSearch.callId; + from = newSearch.from; + to = newSearch.to; + assignedEmployee = newSearch.assignedEmployee; + dateOperator = newSearch.dateOperator; } Map toMap() { @@ -32,6 +51,10 @@ class ServiceRequestSearch { search["assetSerialNumber"] = deviceSerialNumber; } + if (mostRecent != null) { + search["mostRecent"] = mostRecent; + } + if (deviceNumber != null && deviceNumber.isNotEmpty) { search["assetNo"] = deviceNumber; } @@ -48,9 +71,24 @@ class ServiceRequestSearch { search["site"] = hospital.name; } - if (model != null) { + if (model != null && model.isNotEmpty) { search["modelDefinition"] = model; } + + if (callId != null && callId.isNotEmpty) { + search["callId"] = callId; + } + + if (dateOperator != null && from != null) { + search["requestedDateSymbol"] = dateOperator.toMap(); + search["requestedDateFrom"] = from; + } + if (dateOperator != null && to != null) { + search["requestedDateTo"] = to; + } + if (assignedEmployee != null) { + search["assignedEmployee"] = assignedEmployee.toJson(); + } return search; } } diff --git a/lib/models/service_request/sub_work_order_details.dart b/lib/models/service_request/sub_work_order_details.dart new file mode 100644 index 00000000..6e58d34c --- /dev/null +++ b/lib/models/service_request/sub_work_order_details.dart @@ -0,0 +1,73 @@ +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; + +import '../fault_description.dart'; + +class SubWorkOrderDetails { + Lookup equipmentStatus; + Lookup reason; + FaultDescription faultDescription; + List sparePartsWorkOrders; + List suppEngineerWorkOrders; + SupplierModel supplier; + + SubWorkOrderDetails({ + this.equipmentStatus, + this.reason, + this.faultDescription, + this.sparePartsWorkOrders, + this.supplier, + this.suppEngineerWorkOrders, + }); + + SubWorkOrderDetails.fromJson(dynamic json) { + if (json['equipmentStatus'] != null) equipmentStatus = Lookup.fromJson(json['equipmentStatus']); + if (json['reason'] != null) reason = Lookup.fromJson(json['reason']); + if (json['faultDescription'] != null) faultDescription = FaultDescription.fromJson(json['faultDescription']); + if (json['supplier'] != null) supplier = SupplierModel.fromJson(json['supplier']); + if (json['sparePartsWorkOrders'] != null) { + sparePartsWorkOrders = []; + json['sparePartsWorkOrders'].forEach((v) { + sparePartsWorkOrders.add(SparePartsWorkOrders.fromJson(v)); + }); + } + if (json['suppEngineerWorkOrders'] != null) { + suppEngineerWorkOrders = []; + json['suppEngineerWorkOrders'].forEach((v) { + suppEngineerWorkOrders.add(SuppEngineerWorkOrders.fromJson(v)); + }); + } + } + + SubWorkOrderDetails copyWith({ + Lookup equipmentStatus, + Lookup reason, + FaultDescription faultDescription, + List sparePartsWorkOrders, + SupplierModel supplier, + SuppEngineerWorkOrders suppEngineerWorkOrders, + }) => + SubWorkOrderDetails( + equipmentStatus: equipmentStatus ?? this.equipmentStatus, + reason: reason ?? this.reason, + faultDescription: faultDescription ?? this.faultDescription, + sparePartsWorkOrders: sparePartsWorkOrders ?? this.sparePartsWorkOrders, + supplier: supplier ?? this.supplier, + suppEngineerWorkOrders: suppEngineerWorkOrders ?? this.suppEngineerWorkOrders, + ); + + Map toJson() { + final map = {}; + map['equipmentStatus'] = equipmentStatus?.toMap(); + map['reason'] = reason?.toMap(); + map['faultDescription'] = faultDescription?.toJson(); + if (sparePartsWorkOrders?.isNotEmpty ?? false) { + map['sparePartsWorkOrders'] = sparePartsWorkOrders?.map((e) => e.toJson())?.toList(); + } + if (suppEngineerWorkOrders?.isNotEmpty ?? false) { + map['suppEngineerWorkOrders'] = suppEngineerWorkOrders?.map((e) => e.toJson())?.toList(); + } + map['supplier'] = supplier?.toJson(); + return map; + } +} diff --git a/lib/models/subtitle.dart b/lib/models/subtitle.dart index 4007a7cb..e2c8df61 100644 --- a/lib/models/subtitle.dart +++ b/lib/models/subtitle.dart @@ -84,6 +84,7 @@ class Subtitle { String hospital; String device; String deviceImages; + String deviceFiles; String pickDevice; String maintenanceIssue; String create; @@ -186,6 +187,7 @@ class Subtitle { String image; String pickImage; String requiredImage; + String requiredFile; String taskStatus; String activationAlert; @@ -205,7 +207,7 @@ class Subtitle { String reasons; String attachImage; String operatingHours; - String partNumber; + String partNumberName; String number; String quantity; String orderWorkNumber; @@ -236,6 +238,8 @@ class Subtitle { String department; String room; String actions; + String pickFromFiles; + String pickFile; void setIssues(List issues) { issues.clear(); @@ -359,6 +363,7 @@ class Subtitle { @required this.createServiceRequest, @required this.delete, @required this.deviceImages, + @required this.deviceFiles, @required this.deviceRequired, @required this.general, @required this.maintenanceIssueRequired, @@ -404,6 +409,7 @@ class Subtitle { @required this.image, @required this.pickImage, @required this.requiredImage, + @required this.requiredFile, @required this.activationAlert, @required this.callId, @required this.requiredWord, @@ -417,7 +423,7 @@ class Subtitle { @required this.newServiceReport, @required this.number, @required this.operatingHours, - @required this.partNumber, + @required this.partNumberName, @required this.reasons, @required this.reportStatus, @required this.reportType, @@ -447,6 +453,8 @@ class Subtitle { @required this.department, @required this.room, @required this.actions, + @required this.pickFromFiles, + @required this.pickFile, }); factory Subtitle.fromJson(Map parsedJson) { @@ -520,6 +528,7 @@ class Subtitle { device: parsedJson["device"], deviceArName: parsedJson["deviceArName"], deviceImages: parsedJson["deviceImages"], + deviceFiles: parsedJson["deviceFiles"], deviceModel: parsedJson["deviceModel"], deviceName: parsedJson["deviceName"], deviceRequired: parsedJson["deviceRequired"], @@ -607,6 +616,7 @@ class Subtitle { image: parsedJson["image"], pickImage: parsedJson["pickImage"], requiredImage: parsedJson["requiredImage"], + requiredFile: parsedJson["requiredFile"], taskStatus: parsedJson["taskStatus"], activationAlert: parsedJson["activationAlert"], attachImage: parsedJson["attachImage"], @@ -618,7 +628,7 @@ class Subtitle { newServiceReport: parsedJson["newServiceReport"], number: parsedJson["number"], operatingHours: parsedJson["operatingHours"], - partNumber: parsedJson["partNumber"], + partNumberName: parsedJson["partNumberName"], quantity: parsedJson["quantity"], reasons: parsedJson["reasons"], reportStatus: parsedJson["reportStatus"], @@ -651,6 +661,8 @@ class Subtitle { department: parsedJson["department"], room: parsedJson["room"], actions: parsedJson["actions"], + pickFromFiles: parsedJson["pickFromFiles"], + pickFile: parsedJson["pickFile"], ); } } diff --git a/lib/models/timer_model.dart b/lib/models/timer_model.dart index 1e68767d..a0854b47 100644 --- a/lib/models/timer_model.dart +++ b/lib/models/timer_model.dart @@ -2,6 +2,7 @@ class TimerModel { DateTime startAt; DateTime endAt; int durationInSecond; + // bool stopped; TimerModel({this.startAt, this.endAt, this.durationInSecond}); diff --git a/lib/models/user.dart b/lib/models/user.dart index c64c471f..4daa7964 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -4,8 +4,8 @@ import 'package:test_sa/models/enums/user_types.dart'; class User { int clientId; String clientName; - int departmentId; - String departmentName; + List departmentId; + List departmentName; String message; String username; String userID; @@ -76,10 +76,10 @@ class User { } UsersTypes get type { - switch (userRoles?.first?.name) { - case "Engineer": + switch (userRoles?.first?.value) { + case "R-6": return UsersTypes.engineer; - case "Hospital": + case "R-7": return UsersTypes.normal_user; default: return null; @@ -148,8 +148,18 @@ class User { User.fromJson(dynamic json) { clientId = json['client_id']; clientName = json['client_name']; - departmentId = json['department_id']; - departmentName = json['department_name']; + if (json['department_id'] != null) { + departmentId = []; + json['department_id'].forEach((v) { + departmentId.add(v); + }); + } + if (json['department_name'] != null) { + departmentId = []; + json['department_name'].forEach((v) { + departmentId.add(v); + }); + } message = json['message']; username = json['username']; userID = json['userID']; diff --git a/lib/models/visits/visit.dart b/lib/models/visits/visit.dart index 2ad5a3d6..994df35e 100644 --- a/lib/models/visits/visit.dart +++ b/lib/models/visits/visit.dart @@ -1,3 +1,4 @@ +import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/pantry/pentry.dart'; @@ -6,6 +7,7 @@ class Visit { String serialNumber; String expectDate; String actualDate; + String createdOn; int hospitalId; String hospitalName; int deviceId; @@ -42,37 +44,42 @@ class Visit { this.images, this.assignTo, this.deviceNumber, + this.createdOn, }); factory Visit.fromJson(Map parsedJson) { List images = []; if (parsedJson["vAttachments"] is List) { List list = parsedJson["vAttachments"]; - images = list.map((e) => e["attachmentURL"].toString()).toList(); + images = list.map((e) { + return URLs.getFileUrl(e["attachmentURL"].toString()); + }).toList(); } return Visit( - id: parsedJson["id"], - serialNumber: parsedJson["visitCode"], - ppmScheduleId: parsedJson["ppmScheduleId"], - hospitalId: parsedJson["siteId"], - deviceNumber: parsedJson["assetNumber"], - hospitalName: parsedJson["siteName"], - deviceId: parsedJson["assetId"], - deviceSerialNumber: parsedJson["assetSerialNo"], - deviceEnglishName: parsedJson["assetName"], - deviceArabicName: parsedJson["assetName"], - employId: parsedJson["assignedEmployeeId"].toString(), - employName: parsedJson["assignedEmployeeName"], - expectDate: parsedJson["expectedDate"].toString().split("T").first, - actualDate: parsedJson["actualDate"].toString().split("T").first, - modelAndBrand: "${parsedJson["modelName"]} / ${parsedJson["manufacturerName"]}", - // contactStatus: parsedJson["contactStatus"], - images: images, - status: Lookup( - id: parsedJson["visitStatusId"], // actual value (0,1,2) - name: parsedJson["visitStatusName"] // text value - ), - assignTo: parsedJson["assignedToName"], - pentry: Pentry.fromMap(parsedJson)); + id: parsedJson["id"], + serialNumber: parsedJson["visitCode"], + ppmScheduleId: parsedJson["ppmScheduleId"], + hospitalId: parsedJson["siteId"], + deviceNumber: parsedJson["assetNumber"], + hospitalName: parsedJson["siteName"], + deviceId: parsedJson["assetId"], + deviceSerialNumber: parsedJson["assetSerialNo"], + deviceEnglishName: parsedJson["assetName"], + deviceArabicName: parsedJson["assetName"], + employId: parsedJson["assignedEmployeeId"].toString(), + employName: parsedJson["assignedEmployeeName"], + expectDate: parsedJson["expectedDate"].toString().split("T").first, + actualDate: parsedJson["actualDate"].toString().split("T").first, + modelAndBrand: "${parsedJson["modelName"]} / ${parsedJson["manufacturerName"]}", + // contactStatus: parsedJson["contactStatus"], + images: images, + status: Lookup( + id: parsedJson["visitStatusId"], // actual value (0,1,2) + name: parsedJson["visitStatusName"] // text value + ), + assignTo: parsedJson["assignedToName"], + pentry: Pentry.fromMap(parsedJson), + createdOn: parsedJson['createdOn'], + ); } } diff --git a/lib/models/visits/visits_search.dart b/lib/models/visits/visits_search.dart index 5c3692bd..aa91d444 100644 --- a/lib/models/visits/visits_search.dart +++ b/lib/models/visits/visits_search.dart @@ -3,6 +3,8 @@ import 'package:test_sa/models/lookup.dart'; class VisitsSearch { String deviceSerialNumber; + String deviceName; + String deviceNumber; Hospital hospital; String brand; Lookup model; @@ -12,6 +14,7 @@ class VisitsSearch { DateTime actualDateFrom; DateTime actualDateTo; Lookup statusValue; + bool mostRecent; VisitsSearch({ this.deviceSerialNumber, @@ -24,6 +27,9 @@ class VisitsSearch { this.contactStatus, this.expectedDateFrom, this.expectedDateTo, + this.deviceNumber, + this.deviceName, + this.mostRecent = true, }); fromSearch(VisitsSearch newSearch) { @@ -37,6 +43,9 @@ class VisitsSearch { expectedDateFrom = newSearch.expectedDateFrom; expectedDateTo = newSearch.expectedDateTo; statusValue = newSearch.statusValue; + mostRecent = newSearch.mostRecent; + deviceNumber = newSearch.deviceNumber; + deviceName = newSearch.deviceName; } Map toMap() { @@ -49,6 +58,10 @@ class VisitsSearch { _search["siteId"] = hospital.id; } + if (mostRecent != null) { + _search["mostRecent"] = mostRecent; + } + if (brand != null && brand.isNotEmpty) { // todo get new key _search[""] = brand; diff --git a/lib/views/app_style/colors.dart b/lib/views/app_style/colors.dart index 3d247952..fb1aa4b2 100644 --- a/lib/views/app_style/colors.dart +++ b/lib/views/app_style/colors.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; class AColors { AColors._(); + static const Color white = Color(0xffffffff); static const Color black = Color(0xff000000); static const Color grey3A = Color(0xff2e303a); diff --git a/lib/views/pages/device_transfer/device_transfer_details.dart b/lib/views/pages/device_transfer/device_transfer_details.dart index 4d6e7e24..5fdfdb93 100644 --- a/lib/views/pages/device_transfer/device_transfer_details.dart +++ b/lib/views/pages/device_transfer/device_transfer_details.dart @@ -3,9 +3,7 @@ import 'package:provider/provider.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/controllers/providers/api/device_transfer_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/models/device/device_transfer.dart'; -import 'package:test_sa/models/device/device_transfer_info.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; @@ -13,6 +11,7 @@ import 'package:test_sa/views/pages/device_transfer/update_device_transfer.dart' import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_small_button.dart'; import 'package:test_sa/views/widgets/device_trancfer/device_transfer_info_section.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/requests/info_row.dart'; @@ -28,12 +27,10 @@ class DeviceTransferDetails extends StatefulWidget { } class _DeviceTransferDetailsState extends State { - final DeviceTransferInfo _model = DeviceTransferInfo(); + DeviceTransfer _model; bool _isSender = false; bool _isReceiver = false; UserProvider _userProvider; - SettingProvider _settingProvider; - DeviceTransferProvider _deviceTransferProvider; bool _isLoading = false; Subtitle _subtitle; final GlobalKey _formKey = GlobalKey(); @@ -41,150 +38,168 @@ class _DeviceTransferDetailsState extends State { @override void initState() { + _model = widget.model; super.initState(); } + Future _getDeviceTransfer() async { + _model = await Provider.of(context).getRequestById(assetTransferId: widget.model.id); + } + @override Widget build(BuildContext context) { - _subtitle = AppLocalization.of(context).subtitle; - _userProvider = Provider.of(context); - _settingProvider = Provider.of(context); - _deviceTransferProvider = Provider.of(context); - _isSender = _userProvider.user.userID == widget.model.sender?.userId; - _isReceiver = _userProvider.user.userID == widget.model.receiver?.userId; return Scaffold( key: _scaffoldKey, body: SafeArea( - child: Form( - key: _formKey, - child: LoadingManager( - isLoading: _isLoading, - isFailedLoading: false, - stateCode: 200, - onRefresh: () async {}, - child: Column( - children: [ - Container( - color: Theme.of(context).colorScheme.primary, - padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), - child: Row( + child: FutureBuilder( + future: _getDeviceTransfer(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const ALoading(); + } else { + _subtitle = AppLocalization.of(context).subtitle; + _userProvider = Provider.of(context); + _isSender = _userProvider.user.userID == _model.sender?.userId; + _isReceiver = _userProvider.user.userID == _model.receiver?.userId; + return Form( + key: _formKey, + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Column( children: [ - const ABackButton(), - Expanded( - child: Center( - child: Text( - _subtitle.details, - style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), - ), - ), - ), - const SizedBox(width: 58), - ], - ), - ), - Expanded( - child: SingleChildScrollView( - padding: EdgeInsets.all(16 * AppStyle.getScaleFactor(context)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RequestInfoRow( - title: "Transfer Id", - info: widget.model.title?.toString(), - ), - RequestInfoRow( - title: _subtitle.assetName, - info: widget.model.device.assetName, - ), - RequestInfoRow( - title: _subtitle.assetSN, - info: widget.model.device.serialNumber, - ), - RequestInfoRow( - title: _subtitle.assetNumber, - info: widget.model.device.number, - ), - RequestInfoRow( - title: _subtitle.destinationSite, - info: widget.model.device.destSiteName, - ), - RequestInfoRow( - title: _subtitle.building, - info: widget.model.device.destBuildingName, - ), - RequestInfoRow( - title: _subtitle.floor, - info: widget.model.device.destFloor, - ), - RequestInfoRow( - title: _subtitle.department, - info: widget.model.device.destDepartmentName, - ), - RequestInfoRow( - title: _subtitle.room, - info: widget.model.device.destRoom, - ), - RequestInfoRow( - title: _subtitle.actions, - info: "", - ), - const SizedBox(height: 8), - Row( + Container( + color: Theme.of(context).colorScheme.primary, + padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), + child: Row( children: [ + const ABackButton(), Expanded( - child: Text("Sender", style: Theme.of(context).textTheme.headline6), - ), - if (_userProvider.user?.type == UsersTypes.engineer) - ASmallButton( - text: _subtitle.edit, - onPressed: (_isSender || false) - ? () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => UpdateDeviceTransfer( - model: widget.model, - isSender: true, - ))); - } - : null, + child: Center( + child: Text( + _subtitle.details, + style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), + ), ), - ], - ), - const SizedBox(height: 12), - DeviceTransferInfoSection( - info: widget.model.sender, - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: Text("Receiver", style: Theme.of(context).textTheme.headline6), ), - if (_userProvider.user?.type == UsersTypes.engineer) - ASmallButton( - text: _subtitle.edit, - onPressed: (_isReceiver || false) - ? () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => UpdateDeviceTransfer( - model: widget.model, - isSender: false, - ))); - } - : null, - ), + const SizedBox(width: 58), ], ), - const SizedBox(height: 12), - DeviceTransferInfoSection( - info: widget.model.receiver, + ), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.all(16 * AppStyle.getScaleFactor(context)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RequestInfoRow( + title: "Transfer Id", + info: _model.title?.toString(), + ), + RequestInfoRow( + title: _subtitle.assetName, + info: _model.device.assetName, + ), + RequestInfoRow( + title: _subtitle.assetSN, + info: _model.device.serialNumber, + ), + RequestInfoRow( + title: _subtitle.assetNumber, + info: _model.device.number, + ), + RequestInfoRow( + title: _subtitle.destinationSite, + info: _model.device.destSiteName, + ), + RequestInfoRow( + title: _subtitle.building, + info: _model.device.destBuildingName, + ), + RequestInfoRow( + title: _subtitle.floor, + info: _model.device.destFloor, + ), + RequestInfoRow( + title: _subtitle.department, + info: _model.device.destDepartmentName, + ), + RequestInfoRow( + title: _subtitle.room, + info: _model.device.destRoom, + ), + RequestInfoRow( + title: _subtitle.actions, + info: "", + ), + const SizedBox(height: 8), + Row( + children: [ + Expanded( + child: Text("Sender", style: Theme.of(context).textTheme.headline6), + ), + if (_userProvider.user?.type == UsersTypes.engineer) + ASmallButton( + text: _subtitle.edit, + onPressed: (_isSender) + ? (_model.sender.status?.name == "Closed" + ? null + : () { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => UpdateDeviceTransfer( + model: _model, + isSender: true, + ))); + }) + : null, + ), + ], + ), + const SizedBox(height: 12), + DeviceTransferInfoSection( + info: _model.sender, + isSender: true, + ), + const SizedBox(height: 8), + Row( + children: [ + Expanded( + child: Text("Receiver", style: Theme.of(context).textTheme.headline6), + ), + if (_userProvider.user?.type == UsersTypes.engineer) + ASmallButton( + text: _subtitle.edit, + onPressed: (_isReceiver) + ? (_model.receiver.status?.name == "Closed" + ? null + : () { + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => UpdateDeviceTransfer( + model: _model, + isSender: false, + ))); + }) + : null, + ), + ], + ), + const SizedBox(height: 12), + DeviceTransferInfoSection( + info: _model.receiver, + isSender: false, + ), + ], + ), ), - ], - ), + ), + ], ), ), - ], - ), - ), + ); + } + }, ), ), ); diff --git a/lib/views/pages/device_transfer/request_device_transfer.dart b/lib/views/pages/device_transfer/request_device_transfer.dart index 5ec58012..5f6ad2a3 100644 --- a/lib/views/pages/device_transfer/request_device_transfer.dart +++ b/lib/views/pages/device_transfer/request_device_transfer.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/api_routes/http_status_manger.dart'; import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; @@ -12,14 +10,13 @@ import 'package:test_sa/models/device/device_transfer_info.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; -import 'package:test_sa/views/widgets/departments/department_button.dart'; import 'package:test_sa/views/widgets/equipment/device_button.dart'; -import 'package:test_sa/views/widgets/hospitals/hospital_button.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../../../../controllers/localization/localization.dart'; import '../../../controllers/validator/validator.dart'; +import '../../app_style/colors.dart'; import '../../widgets/app_text_form_field.dart'; import '../../widgets/gas_refill/building_type_menu.dart'; import '../../widgets/gas_refill/department_type_menu.dart'; @@ -28,6 +25,7 @@ import '../../widgets/hospitals/hospital_auto_complete_field_new.dart'; class RequestDeviceTransfer extends StatefulWidget { static const String id = "/request-device-transfer"; + const RequestDeviceTransfer({Key key}) : super(key: key); @override @@ -66,7 +64,7 @@ class _RequestDeviceTransferState extends State { _isLoading = true; setState(() {}); - _formModel.sender?.client?.id = _userProvider.user?.clientId; + // _formModel.sender?.client?.id = _userProvider.user?.clientId; int status = await _deviceTransferProvider.createRequest( user: _userProvider.user, host: _settingProvider.host, @@ -120,7 +118,7 @@ class _RequestDeviceTransferState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Text( - "Transfer Device", + "Transfer Asset", style: Theme.of(context).textTheme.headline5.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold), ), ), @@ -140,7 +138,7 @@ class _RequestDeviceTransferState extends State { // }, // ), 12.height, - const ASubTitle("Device"), + const ASubTitle("Asset"), if (_validate && _formModel.device == null) ASubTitle( _subtitle.requiredWord, @@ -151,9 +149,19 @@ class _RequestDeviceTransferState extends State { device: _formModel.device, onDevicePick: (device) { _formModel.device = device; + _formModel.sender.client = device.hospital; setState(() {}); }, ), + if (_formModel.device != null) 8.height, + if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Site", value: _formModel.device.hospital?.name), + if (_formModel.device != null) 4.height, + if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Department", value: _formModel.device.destDepartmentName), + if (_formModel.device != null) 4.height, + if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Floor", value: _formModel.device.destFloor), + if (_formModel.device != null) 4.height, + if (_formModel.device != null) AdditionalAssetInfo(title: "Asset Room", value: _formModel.device.destRoom), + if (_formModel.device != null) 8.height, // const SizedBox(height: 8,), // const ASubTitle("Sender Department"), // if(_validate && _formModel.senderDepartment == null) @@ -202,6 +210,8 @@ class _RequestDeviceTransferState extends State { Divider( color: Theme.of(context).colorScheme.primary, ), + const SizedBox(height: 8), + const ASubTitle("Destination"), const SizedBox( height: 4, ), @@ -250,8 +260,8 @@ class _RequestDeviceTransferState extends State { }, ), const SizedBox(height: 8), - ASubTitle("Room"), - SizedBox( + const ASubTitle("Room"), + const SizedBox( height: 4, ), ATextFormField( @@ -281,3 +291,31 @@ class _RequestDeviceTransferState extends State { ); } } + +class AdditionalAssetInfo extends StatelessWidget { + final String title, value; + const AdditionalAssetInfo({@required this.title, @required this.value, Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ASubTitle(title ?? ""), + Container( + width: double.infinity, + alignment: Alignment.center, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), + decoration: BoxDecoration( + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: const Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: ASubTitle(value ?? ""), + ), + ], + ); + } +} diff --git a/lib/views/pages/device_transfer/track_device_transfer.dart b/lib/views/pages/device_transfer/track_device_transfer.dart index d62943ef..34e81688 100644 --- a/lib/views/pages/device_transfer/track_device_transfer.dart +++ b/lib/views/pages/device_transfer/track_device_transfer.dart @@ -1,14 +1,16 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/controllers/providers/api/device_transfer_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/models/subtitle.dart'; +import 'package:test_sa/models/device/device_transfer_search.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/device_trancfer/device_transfer_list.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/search/asset_transfer_search_dialog.dart'; + +import '../../widgets/buttons/app_icon_button.dart'; class TrackDeviceTransferPage extends StatefulWidget { static const String id = "/track-device-transfer"; @@ -23,12 +25,12 @@ class _TrackDeviceTransferPageState extends State with DeviceTransferProvider _deviceTransferProvider; UserProvider _userProvider; SettingProvider _settingProvider; + @override Widget build(BuildContext context) { _deviceTransferProvider = Provider.of(context); _userProvider = Provider.of(context); _settingProvider = Provider.of(context); - Subtitle _subtitle = AppLocalization.of(context).subtitle; return Scaffold( body: SafeArea( @@ -54,18 +56,40 @@ class _TrackDeviceTransferPageState extends State with children: [ Row( children: [ - ABackButton(), + const ABackButton(), Expanded( child: Center( child: Text( - "Device Transfer", + "Asset Transfer", style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), ), - const SizedBox( - width: 48, - ) + AIconButton( + iconData: Icons.search, + color: AColors.secondaryColor, + buttonSize: 42, + backgroundColor: AColors.white, + onPressed: () async { + DeviceTransferSearch temp = await showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return AssetTransferSearchDialog(initialSearchValue: _deviceTransferProvider.deviceTransferSearch); + }, + ); + if (temp != null) { + _deviceTransferProvider.deviceTransferSearch = temp; + _deviceTransferProvider.reset(); + setState(() {}); + await _deviceTransferProvider.getRequests( + user: _userProvider.user, + host: _settingProvider.host, + ); + } + }, + ), + const SizedBox(width: 16), ], ), ], diff --git a/lib/views/pages/device_transfer/update_device_transfer.dart b/lib/views/pages/device_transfer/update_device_transfer.dart index 9a870ad9..29844f8a 100644 --- a/lib/views/pages/device_transfer/update_device_transfer.dart +++ b/lib/views/pages/device_transfer/update_device_transfer.dart @@ -14,8 +14,9 @@ import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; -import 'package:test_sa/views/widgets/status/gas_refill/gas_status.dart'; +import 'package:test_sa/views/widgets/status/asset_status.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../../../../controllers/localization/localization.dart'; @@ -40,7 +41,7 @@ class _UpdateDeviceTransferState extends State { Uint8List _signature; DeviceTransferProvider _deviceTransferProvider; final TextEditingController _requestedQuantityController = TextEditingController(); - final DeviceTransferInfo _formModel = DeviceTransferInfo(); + final DeviceTransferInfo _formModel = DeviceTransferInfo(attachments: []); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); @@ -72,7 +73,6 @@ class _UpdateDeviceTransferState extends State { ); _validate = false; Navigator.of(context).pop(); - Navigator.of(context).pop(); } } @@ -118,7 +118,7 @@ class _UpdateDeviceTransferState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Text( - "Edit Transfer Device", + "Edit Transfer Asset", style: Theme.of(context).textTheme.headline5.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold), ), ), @@ -180,7 +180,7 @@ class _UpdateDeviceTransferState extends State { const SizedBox( height: 4, ), - GasStatusMenu( + AssetStatusMenu( initialValue: _formModel.status, onSelect: (status) { if (status == null) return; @@ -189,7 +189,14 @@ class _UpdateDeviceTransferState extends State { }, ), const SizedBox( - height: 8, + height: 16, + ), + MultiFilesPicker( + label: "Attachments", + files: _formModel.attachments, + ), + const SizedBox( + height: 16, ), const ASubTitle("Signature"), // if(_validate && _formModel.signature == null) @@ -198,12 +205,12 @@ class _UpdateDeviceTransferState extends State { height: 4, ), ESignature( - oldSignature: widget.isSender ? widget.model.sender.signature : widget.model.receiver.signature, + oldSignature: widget.isSender ? widget.model.sender.engSignature : widget.model.receiver.engSignature, newSignature: _signature, onSaved: (signature) { _signature = signature; if (signature == null || signature.isEmpty) return; - _formModel.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + _formModel.engSignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; // base64Encode(signature); }, ), diff --git a/lib/views/pages/register.dart b/lib/views/pages/register.dart index ab370de9..1246fff3 100644 --- a/lib/views/pages/register.dart +++ b/lib/views/pages/register.dart @@ -6,14 +6,12 @@ import 'package:test_sa/controllers/localization/localization.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/controllers/validator/validator.dart'; -import 'package:test_sa/models/department.dart'; import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/models/user.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; -import 'package:test_sa/views/widgets/departments/department_button.dart'; import 'package:test_sa/views/widgets/hospitals/hospital_button.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; @@ -131,15 +129,15 @@ class _RegisterState extends State { setState(() {}); }, ), - const SizedBox(height: 12), - DepartmentButton( - department: Department(id: _user.departmentId, name: _user.departmentName), - onDepartmentPick: (department) { - _user.departmentId = department.id; - _user.departmentName = department.name; - setState(() {}); - }, - ), + // const SizedBox(height: 12), + // DepartmentButton( + // department: Department(id: _user.departmentId, name: _user.departmentName), + // onDepartmentPick: (department) { + // _user.departmentId = department.id; + // _user.departmentName = department.name; + // setState(() {}); + // }, + // ), const SizedBox(height: 12), ATextFormField( initialValue: _user.phoneNumber, diff --git a/lib/views/pages/sub_workorder/auto_generated_vendor_name.dart b/lib/views/pages/sub_workorder/auto_generated_vendor_name.dart new file mode 100644 index 00000000..41244de8 --- /dev/null +++ b/lib/views/pages/sub_workorder/auto_generated_vendor_name.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; + +import '../../../controllers/providers/api/status_drop_down/report/vendor_provider.dart'; +import '../../app_style/colors.dart'; +import '../../app_style/sizing.dart'; + +class AutoGeneratedVendorName extends StatefulWidget { + final String initialValue; + final Function(Supplier) onSearch; + const AutoGeneratedVendorName({Key key, this.initialValue, this.onSearch}) : super(key: key); + + @override + State createState() => _AutoGeneratedVendorNameState(); +} + +class _AutoGeneratedVendorNameState extends State { + TextEditingController _controller; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(text: widget.initialValue ?? ""); + } + + @override + void didUpdateWidget(covariant AutoGeneratedVendorName oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.initialValue != widget.initialValue) { + _controller = TextEditingController(text: widget.initialValue ?? ""); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final vendorProvider = Provider.of(context, listen: false); + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: const Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: [ + // AppStyle.boxShadow + // ] + ), + child: TypeAheadField( + textFieldConfiguration: TextFieldConfiguration( + style: Theme.of(context).textTheme.titleLarge, + controller: _controller, + textAlign: TextAlign.center, + decoration: const InputDecoration( + hintText: "Vendor Name", + border: InputBorder.none, + disabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + textInputAction: TextInputAction.search, + ), + suggestionsCallback: (vale) async { + await vendorProvider.getVendors(_controller.text.trim()); + return vendorProvider.vendors; + }, + itemBuilder: (context, vendor) { + return ListTile(title: Text(vendor.suppliername)); + }, + onSuggestionSelected: (hospital) { + widget.onSearch(hospital); + }, + ), + ); + } +} diff --git a/lib/views/pages/sub_workorder/create_sub_workorder_page.dart b/lib/views/pages/sub_workorder/create_sub_workorder_page.dart index fdfd67e5..6e4df099 100644 --- a/lib/views/pages/sub_workorder/create_sub_workorder_page.dart +++ b/lib/views/pages/sub_workorder/create_sub_workorder_page.dart @@ -16,6 +16,7 @@ import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart'; import 'package:test_sa/views/pages/sub_workorder/work_order_details_bottom_sheet.dart'; import 'package:test_sa/views/pages/sub_workorder/workorder_details.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/status/service_request/service_request_defect_types_mune.dart'; @@ -27,7 +28,6 @@ import '../../widgets/app_text_form_field.dart'; import '../../widgets/buttons/app_back_button.dart'; import '../../widgets/buttons/app_button.dart'; import '../../widgets/date_and_time/date_picker.dart'; -import '../../widgets/images/mini_one_image_picker.dart'; import '../../widgets/status/report/service_report_fault_description.dart'; import '../../widgets/status/report/service_report_reasons.dart'; import '../../widgets/titles/app_sub_title.dart'; @@ -47,7 +47,7 @@ class _CreateSubWorkOrderPageState extends State { SearchWorkOrder _subWorkOrders; Lookup _serviceReportReason = const Lookup(); ServiceReport _serviceReport; - File _image; + final List _files = []; bool _isLoading = false; bool _validate = false; @@ -58,6 +58,7 @@ class _CreateSubWorkOrderPageState extends State { callRequest: CallRequest(id: widget?.workOrder?.callRequest?.id), currentSituation: null, supplier: null, + parentWOId: widget.workOrder.id, ); _serviceReport = ServiceReport(id: widget.workOrder.id, type: widget.workOrder.assetType, equipmentStatus: widget.workOrder.equipmentStatus); _isLoading = true; @@ -69,9 +70,19 @@ class _CreateSubWorkOrderPageState extends State { Future getAssetType() async { //if (assetTypesProvider == null) { + final serviceRequestProvider = Provider.of(context); Provider.of(context, listen: false).reset(); assetTypesProvider = Provider.of(context, listen: false); - _callRequestForWorkOrder = await Provider.of(context).getCallRequestForWorkOrder(callId: widget.workOrder.callRequest.id.toString()); + _callRequestForWorkOrder = await serviceRequestProvider.getCallRequestForWorkOrder(callId: widget.workOrder.callRequest.id.toString()); + if (_subWorkOrders?.parentWOId != null) { + print(_subWorkOrders?.parentWOId.toString()); + final subWoDetails = await serviceRequestProvider.getSubWorkOrderDetails(parentId: _subWorkOrders?.parentWOId.toString()); + _subWorkOrders.copyDetails(subWoDetails); + _serviceReport.equipmentStatus = subWoDetails.equipmentStatus; + _serviceReport.reason = subWoDetails.reason; + _serviceReport.faultDescription = subWoDetails.faultDescription; + _serviceReportReason = _subWorkOrders.reason; + } await assetTypesProvider.getTypes(); _subWorkOrders?.assetType = assetTypesProvider.statuses?.firstWhere( (element) => element.value == _callRequestForWorkOrder?.assetType, @@ -112,7 +123,7 @@ class _CreateSubWorkOrderPageState extends State { Expanded( child: Center( child: Text( - "New Work Order", + "New Sub Work Order", style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), @@ -158,11 +169,11 @@ class _CreateSubWorkOrderPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const ASubTitle("Return to Service"), - if (_validate && _subWorkOrders.visitDate == null) - ASubTitle( - subtitle.requiredWord, - color: Colors.red, - ), + // if (_validate && _subWorkOrders.visitDate == null) + // ASubTitle( + // subtitle.requiredWord, + // color: Colors.red, + // ), const SizedBox( height: 4, ), @@ -200,7 +211,7 @@ class _CreateSubWorkOrderPageState extends State { onSelect: (status) { _serviceReportReason = status; _subWorkOrders.reason = status; - setState(() {}); + // setState(() {}); }, ), ], @@ -238,6 +249,8 @@ class _CreateSubWorkOrderPageState extends State { ], ), const SizedBox(height: 8), + MultiFilesPicker(label: "Attachments", files: _files), + const SizedBox(height: 8), InkWell( onTap: () async { await showModalBottomSheet( @@ -247,7 +260,7 @@ class _CreateSubWorkOrderPageState extends State { backgroundColor: Colors.transparent, builder: (context) => WorkOrderDetailsBottomSheet(subWorkOrder: _subWorkOrders), ); - log(_subWorkOrders?.toJson()?.toString()); + //log(_subWorkOrders?.toJson()?.toString()); }, child: Card( child: ListTile( @@ -272,7 +285,10 @@ class _CreateSubWorkOrderPageState extends State { useSafeArea: true, isScrollControlled: true, backgroundColor: Colors.transparent, - builder: (context) => SparePartsBottomSheet(subWorkOrder: _subWorkOrders), + builder: (context) => SparePartsBottomSheet( + subWorkOrder: _subWorkOrders, + assetId: widget.workOrder?.callRequest?.asset?.id, + ), ); log(_subWorkOrders?.toJson()?.toString()); }, @@ -291,15 +307,14 @@ class _CreateSubWorkOrderPageState extends State { ), ), ), - const SizedBox(height: 8), - AMiniOneImagePicker( - image: _image, - onPick: (image) { - _image = image; - _subWorkOrders.attachmentsWorkOrder ??= []; - _subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}")); - }, - ), + // AMiniOneFilePicker( + // file: _file, + // onPick: (file) { + // _file = file; + // _subWorkOrders.attachmentsWorkOrder ??= []; + // _subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}")); + // }, + // ), const SizedBox(height: 50), ], ), @@ -313,10 +328,17 @@ class _CreateSubWorkOrderPageState extends State { child: AButton( text: subtitle.create, onPressed: () async { - _subWorkOrders.parentWOId = widget.workOrder.id; _validate = true; setState(() {}); if (validate()) { + if (_subWorkOrders.calllastSituation.value == 12 && (_subWorkOrders.sparePartsWorkOrders == null || _subWorkOrders.sparePartsWorkOrders.isEmpty)) { + await Fluttertoast.showToast(msg: "You have to add parts"); + return; + } + _subWorkOrders.attachmentsWorkOrder ??= []; + for (var file in _files) { + _subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}")); + } if (_subWorkOrders.timer?.startAt == null || _subWorkOrders.timer?.endAt == null) { Fluttertoast.showToast(msg: "Working hours required"); return; @@ -330,6 +352,11 @@ class _CreateSubWorkOrderPageState extends State { if (_formKey.currentState?.validate() ?? false) {} _formKey.currentState?.save(); final serviceRequestsProvider = Provider.of(context, listen: false); + for (var element in (_subWorkOrders?.suppEngineerWorkOrders ?? [])) { + if (element != null) { + element.id = 0; + } + } final status = await serviceRequestsProvider.createSubWorkOrder(workOrder: _subWorkOrders); _isLoading = false; setState(() {}); @@ -354,7 +381,7 @@ class _CreateSubWorkOrderPageState extends State { } bool validate() { - if (_subWorkOrders.faultDescription == null || _subWorkOrders.reason == null || _subWorkOrders.equipmentStatus == null || _subWorkOrders.visitDate == null) { + if (_subWorkOrders.faultDescription == null || _subWorkOrders.reason == null || _subWorkOrders.equipmentStatus == null) { return false; } else { return true; diff --git a/lib/views/pages/sub_workorder/search_sub_workorder_page.dart b/lib/views/pages/sub_workorder/search_sub_workorder_page.dart index 32fcec04..35817468 100644 --- a/lib/views/pages/sub_workorder/search_sub_workorder_page.dart +++ b/lib/views/pages/sub_workorder/search_sub_workorder_page.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; import 'package:test_sa/models/engineer.dart'; @@ -24,6 +23,7 @@ import '../../widgets/titles/app_sub_title.dart'; class SearchSubWorkOrderPage extends StatefulWidget { static String id = "/SubWorkOrderPage"; + const SearchSubWorkOrderPage({Key key}) : super(key: key); @override diff --git a/lib/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart b/lib/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart index e7d5fc93..6829e63b 100644 --- a/lib/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart +++ b/lib/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart @@ -6,6 +6,7 @@ import 'package:test_sa/views/app_style/colors.dart'; import '../../../controllers/localization/localization.dart'; import '../../../models/subtitle.dart'; import '../../app_style/sizing.dart'; +import '../../widgets/app_text_form_field.dart'; import '../../widgets/buttons/app_button.dart'; import '../../widgets/parts/auto_complete_parts_field.dart'; import '../../widgets/parts/part_item.dart'; @@ -13,7 +14,9 @@ import '../../widgets/titles/app_sub_title.dart'; class SparePartsBottomSheet extends StatefulWidget { final SearchWorkOrder subWorkOrder; - const SparePartsBottomSheet({this.subWorkOrder, Key key}) : super(key: key); + final num assetId; + + const SparePartsBottomSheet({this.subWorkOrder, this.assetId, Key key}) : super(key: key); @override State createState() => _SparePartsBottomSheetState(); @@ -86,7 +89,7 @@ class _SparePartsBottomSheetState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ASubTitle(subtitle.partNumber), + ASubTitle(subtitle.partNumberName), _validate && _workOrder.sparePartsWorkOrders == null ? ASubTitle( subtitle.requiredWord, @@ -95,12 +98,15 @@ class _SparePartsBottomSheetState extends State { : const SizedBox.shrink(), const SizedBox(height: 4), AutoCompletePartsField( + assetId: widget.assetId, onPick: (part) { _workOrder.sparePartsWorkOrders ??= []; _workOrder.sparePartsWorkOrders.add(SparePartsWorkOrders( id: part.reportPartID, qty: part.quantity, - sparePart: SparePart(id: part.id, partName: part.name, partNo: part.code), + sparePart: SparePart(id: part.id, partName: part.partName, partNo: part.partNo), + installQty: part.installQty, + returnQty: part.returnQty, )); }, ), @@ -128,19 +134,55 @@ class _SparePartsBottomSheetState extends State { Part part = Part( id: spare.sparePart?.id, reportPartID: spare.id, - code: spare.sparePart?.partNo, - name: spare.sparePart?.partName, - quantity: spare.qty, + partNo: spare.sparePart?.partNo, + partName: spare.sparePart?.partName, + quantity: spare.qty?.toInt(), + installQty: spare.installQty, + returnQty: spare.returnQty, ); - return PartItem( - part: part, - onEdit: (qty) { - spare.qty = qty; - }, - onDelete: (part) { - _workOrder.sparePartsWorkOrders.remove(spare); - setState(() {}); - }, + return Column( + children: [ + PartItem( + part: part, + onEdit: (qty) { + spare.qty = qty; + }, + onDelete: (part) { + _workOrder.sparePartsWorkOrders.remove(spare); + setState(() {}); + }, + ), + if (_workOrder.calllastSituation?.name?.toLowerCase()?.contains("part installation") ?? false) + Row( + children: [ + Expanded( + child: ATextFormField( + initialValue: part?.returnQty?.toString(), + labelText: "Return Quantity", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.number, + onSaved: (value) { + spare.returnQty = num.tryParse(value)?.toDouble(); + }, + ), + ), + const SizedBox(width: 8), + Expanded( + child: ATextFormField( + initialValue: part?.installQty?.toString(), + labelText: "Install Quantity", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.number, + onSaved: (value) { + spare.installQty = num.tryParse(value)?.toDouble(); + }, + ), + ), + ], + ), + ], ); }, ), diff --git a/lib/views/pages/sub_workorder/work_order_details_bottom_sheet.dart b/lib/views/pages/sub_workorder/work_order_details_bottom_sheet.dart index e91de02e..5ed1e253 100644 --- a/lib/views/pages/sub_workorder/work_order_details_bottom_sheet.dart +++ b/lib/views/pages/sub_workorder/work_order_details_bottom_sheet.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/search_work_order.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; @@ -8,11 +9,13 @@ import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; import 'package:test_sa/views/widgets/status/report/service_report_maintenance_situation.dart'; import 'package:test_sa/views/widgets/status/report/service_report_repair_location.dart'; +import 'package:test_sa/views/widgets/status/service_request/supplier_engineers_menu.dart'; import '../../../controllers/localization/localization.dart'; import '../../../controllers/providers/api/status_drop_down/report/service_report_maintenance_situation_provider.dart'; import '../../widgets/timer/app_timer.dart'; import '../../widgets/titles/app_sub_title.dart'; +import 'auto_generated_vendor_name.dart'; class WorkOrderDetailsBottomSheet extends StatefulWidget { final SearchWorkOrder subWorkOrder; @@ -25,17 +28,33 @@ class WorkOrderDetailsBottomSheet extends StatefulWidget { class _WorkOrderDetailsBottomSheetState extends State { final GlobalKey _formKey = GlobalKey(); final SearchWorkOrder _workOrder = SearchWorkOrder(); + bool _showVendorFields = false; + SuppEngineerWorkOrders engineer; @override void initState() { super.initState(); - _workOrder.copyFrom(widget.subWorkOrder); + if (checkVendorFieldsVisibility(_workOrder.calllastSituation)) { + if (_workOrder.suppEngineerWorkOrders?.isNotEmpty ?? false) { + engineer = _workOrder.suppEngineerWorkOrders?.last; + engineer?.id = engineer?.supplierContactId; + } + _workOrder.supplier ??= SupplierModel(id: _workOrder?.supplier?.id); + } if (context.mounted) { Provider.of(context, listen: false).reset(); } } + bool checkVendorFieldsVisibility(Lookup callsLastSituation) { + bool result = (_workOrder.supplier?.suppliername?.isNotEmpty ?? false) || + (callsLastSituation?.name?.toLowerCase()?.contains("under repair-vendor") ?? false) || + (callsLastSituation?.name?.toLowerCase()?.contains("waiting for vendor") ?? false); + _showVendorFields = result; + return result; + } + @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; @@ -118,15 +137,53 @@ class _WorkOrderDetailsBottomSheetState extends State items; final Future> Function() onLazyLoading; + WorkOrderList({Key key, this.items, this.onLazyLoading}) : super(key: key); @override @@ -25,6 +26,7 @@ class WorkOrderList extends StatefulWidget { class _WorkOrderListState extends State { List _items; + @override void initState() { super.initState(); @@ -81,7 +83,6 @@ class _WorkOrderListState extends State { onPressed: (model) { // Navigator.of(context).push(MaterialPageRoute( // builder: (_) => WorkOrderUpdate(item: model,))); - log(model?.toJson()?.toString()); Navigator.push( context, MaterialPageRoute(builder: (context) => CreateSubWorkOrderPage(workOrder: model)), diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index c9d9a65d..39422b24 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -25,15 +25,16 @@ import '../../../../models/enums/user_types.dart'; import '../../../app_style/colors.dart'; class GasRefillDetails extends StatefulWidget { - final GasRefillModel model; - const GasRefillDetails({Key key, this.model}) : super(key: key); + GasRefillModel model; + + GasRefillDetails({Key key, this.model}) : super(key: key); @override State createState() => _GasRefillDetailsState(); } class _GasRefillDetailsState extends State { - final GasRefillModel _model = GasRefillModel(); + GasRefillModel _model = GasRefillModel(); bool _enableEdit = false; bool _validate = false; UserProvider _userProvider; @@ -43,6 +44,7 @@ class _GasRefillDetailsState extends State { Subtitle _subtitle; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); + _update() async { _validate = true; if (!_formKey.currentState.validate()) { @@ -73,7 +75,7 @@ class _GasRefillDetailsState extends State { @override void initState() { - _model.fromGasRefillModel(widget.model); + _model?.fromGasRefillModel(widget.model); super.initState(); } @@ -100,11 +102,15 @@ class _GasRefillDetailsState extends State { padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), child: Row( children: [ - const ABackButton(), + ABackButton( + onPressed: () { + Navigator.of(context).pop(_model); + }, + ), Expanded( child: Center( child: Text( - _subtitle.details, + "Gas Refill Request", style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), @@ -115,21 +121,26 @@ class _GasRefillDetailsState extends State { color: Theme.of(context).colorScheme.onPrimary, buttonSize: 42, backgroundColor: AColors.green, - onPressed: () async { - // _enableEdit = !_enableEdit; - print(widget.model.startDate); - _model.fromGasRefillModel(widget.model); - print(widget.model.startDate); - // setState(() {}); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => RequestGasRefill( - gasRefillModel: widget.model, - ), - ), - ); - }, + onPressed: (widget.model.status?.value ?? 0) == 2 + ? null + : () async { + // _enableEdit = !_enableEdit; + _model?.fromGasRefillModel(widget.model); + // setState(() {}); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RequestGasRefill( + gasRefillModel: widget.model, + ), + ), + ).then((value) { + if (value != null) { + _model = value; + } + }); + setState(() {}); + }, ), const SizedBox( width: 16, @@ -144,7 +155,7 @@ class _GasRefillDetailsState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ RequestInfoRow( - title: _subtitle.title, + title: "Gas Refill No", info: _model.title, ), RequestInfoRow( @@ -159,13 +170,17 @@ class _GasRefillDetailsState extends State { title: "Floor", info: _model.floor?.name, ), + RequestInfoRow( + title: "Department", + info: _model.department?.departmentName, + ), RequestInfoRow( title: _subtitle.startDate, - info: _model.startDate == null ? null : DateFormat.yMd().format(_model.startDate), + info: _model.startDate == null ? null : "${DateFormat.yMd().format(_model.startDate)} ${DateFormat.Hms().format(_model.startDate)}", ), RequestInfoRow( title: _subtitle.endDate, - info: _model.endDate == null ? null : DateFormat.yMd().format(_model.endDate), + info: _model.endDate == null ? null : "${DateFormat.yMd().format(_model.endDate)} ${DateFormat.Hms().format(_model.endDate)}", ), _enableEdit ? Column( diff --git a/lib/views/pages/user/gas_refill/request_gas_refill.dart b/lib/views/pages/user/gas_refill/request_gas_refill.dart index cb186466..8228da29 100644 --- a/lib/views/pages/user/gas_refill/request_gas_refill.dart +++ b/lib/views/pages/user/gas_refill/request_gas_refill.dart @@ -12,10 +12,10 @@ import 'package:test_sa/models/gas_refill/gas_refill_details.dart'; import 'package:test_sa/models/gas_refill/gas_refill_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/subtitle.dart'; +import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; -import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; import 'package:test_sa/views/widgets/gas_refill/building_type_menu.dart'; import 'package:test_sa/views/widgets/gas_refill/department_type_menu.dart'; import 'package:test_sa/views/widgets/gas_refill/floor_type_menu.dart'; @@ -30,12 +30,13 @@ import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/providers/api/hospitals_provider.dart'; -import '../../../../models/enums/user_types.dart'; import '../../../widgets/e_signature/e_signature.dart'; +import '../../../widgets/timer/app_timer.dart'; class RequestGasRefill extends StatefulWidget { static const String id = "/request-gas-refill"; final GasRefillModel gasRefillModel; + const RequestGasRefill({this.gasRefillModel, Key key}) : super(key: key); @override @@ -85,6 +86,12 @@ class _RequestGasRefillState extends State { return; } } + if (_gasRefillProvider.department?.name == null) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Select department"))); + _isLoading = false; + setState(() {}); + return; + } int status = widget.gasRefillModel == null ? await _gasRefillProvider.createModel( @@ -104,7 +111,8 @@ class _RequestGasRefillState extends State { Fluttertoast.showToast( msg: _subtitle.requestCompleteSuccessfully, ); - Navigator.of(context).pop(); + Navigator.of(context).pop(_formModel); + setState(() {}); } else { String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); ScaffoldMessenger.of(context).showSnackBar(SnackBar( @@ -149,20 +157,25 @@ class _RequestGasRefillState extends State { _settingProvider = Provider.of(context); if (_gasRefillProvider == null) { _gasRefillProvider = Provider.of(context, listen: false); - _gasRefillProvider.reset(); + //_gasRefillProvider.reset(); } - if (widget.gasRefillModel != null && _firstTime) { - _formModel = widget.gasRefillModel; - _formModel.status = const Lookup(value: 0); - HospitalsProvider().getHospitalsListByVal(searchVal: widget.gasRefillModel.clientName).then((value) { - _gasRefillProvider.hospital = value?.firstWhere((element) => element.name == widget.gasRefillModel.clientName, orElse: () => null); - print(_gasRefillProvider.hospital?.buildings?.length); - print(widget.gasRefillModel?.building?.name); + if (_firstTime) { + String _clientName; + if (widget.gasRefillModel != null) { + _formModel.status = widget.gasRefillModel?.status ?? const Lookup(value: 0); + _gasRefillProvider.expectedDateTime = _formModel.expectedDate; + _gasRefillProvider.timer = TimerModel(startAt: widget.gasRefillModel?.startDate, endAt: widget.gasRefillModel?.endDate); + _clientName = _formModel.clientName; + } else { + _gasRefillProvider.timer = null; + _clientName = _userProvider.user?.clientName; + } + + HospitalsProvider().getHospitalsListByVal(searchVal: _clientName).then((value) { + _gasRefillProvider.hospital = value?.firstWhere((element) => element.name == _clientName, orElse: () => null); _gasRefillProvider.building = _gasRefillProvider.hospital?.buildings?.firstWhere((element) => element.name == widget.gasRefillModel?.building?.name, orElse: () => null); _gasRefillProvider.floor = _gasRefillProvider.building?.floors?.firstWhere((element) => element.name == widget.gasRefillModel?.floor?.name, orElse: () => null); _gasRefillProvider.department = _gasRefillProvider.floor?.departments?.firstWhere((element) => element.name == widget.gasRefillModel?.department?.departmentName, orElse: () => null); - _gasRefillProvider.startDate = widget.gasRefillModel?.startDate; - _gasRefillProvider.endDate = widget.gasRefillModel?.endDate; _firstTime = false; setState(() {}); }); @@ -217,7 +230,7 @@ class _RequestGasRefillState extends State { ), GasStatusMenu( initialValue: _formModel.status ?? const Lookup(value: 0), - enabled: false, + enabled: widget.gasRefillModel != null, onSelect: (status) { _formModel.status = status; }, @@ -232,6 +245,7 @@ class _RequestGasRefillState extends State { height: 4, ), HospitalAutoCompleteField( + enabled: false, initialValue: _gasRefillProvider.hospital?.name, // onSave: (value){ // _search.hospital = value; @@ -250,6 +264,8 @@ class _RequestGasRefillState extends State { BuildingTypeMenu( initialValue: _gasRefillProvider?.building, building: _gasRefillProvider?.hospital?.buildings, + loading: _firstTime, + enabled: widget.gasRefillModel == null, onSelect: (status) { _gasRefillProvider.building = status; setState(() {}); @@ -259,6 +275,8 @@ class _RequestGasRefillState extends State { FloorTypeMenu( initialValue: _gasRefillProvider?.floor, floors: _gasRefillProvider?.building?.floors, + enabled: widget.gasRefillModel == null, + loading: _firstTime, onSelect: (status) { _gasRefillProvider.floor = status; setState(() {}); @@ -268,31 +286,54 @@ class _RequestGasRefillState extends State { DepartmentTypeMenu( initialValue: _gasRefillProvider?.department, departments: _gasRefillProvider?.floor?.departments, + loading: _firstTime, + enabled: widget.gasRefillModel == null, onSelect: (status) { _gasRefillProvider.department = status; setState(() {}); }, ), const SizedBox(height: 8), - if (_userProvider.user?.type == UsersTypes.normal_user) - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + if (widget.gasRefillModel != null) ASubTitle(_subtitle.workingHours), + if (widget.gasRefillModel != null) const SizedBox(height: 8), + if (widget.gasRefillModel != null) + Row( children: [ - const ASubTitle("Expected Date Time"), - SizedBox( - height: 8 * AppStyle.getScaleFactor(context), - ), - ADateTimePicker( - date: _gasRefillProvider.expectedDateTime, - from: DateTime.now().subtract(const Duration(days: 365)), - to: DateTime.now().add(const Duration(days: 365)), - onDateTimePicker: (date) { - _gasRefillProvider.expectedDateTime = date; - setState(() {}); - }, + Expanded( + child: AppTimer( + timer: _gasRefillProvider.timer, + onChange: (timer) async { + _gasRefillProvider.timer = timer; + _formModel.workingHours = num.tryParse((((timer?.durationInSecond ?? 0) / 60) / 60)?.toStringAsFixed(2) ?? "0"); + _formModel.startDate = timer.startAt; + _formModel.endDate = timer.endAt; + return true; + }, + ), ), ], ), + //const SizedBox(height: 8), + // if (_userProvider.user?.type == UsersTypes.normal_user || widget.gasRefillModel != null) + // Column( + // crossAxisAlignment: CrossAxisAlignment.stretch, + // children: [ + // const ASubTitle("Expected Date"), + // SizedBox( + // height: 8 * AppStyle.getScaleFactor(context), + // ), + // ADateTimePicker( + // date: _gasRefillProvider.expectedDateTime, + // from: DateTime.now().subtract(const Duration(days: 365)), + // to: DateTime.now().add(const Duration(days: 365)), + // onDateTimePicker: (date) { + // _gasRefillProvider.expectedDateTime = date; + // _formModel.expectedDate = _gasRefillProvider.expectedDateTime; + // setState(() {}); + // }, + // ), + // ], + // ), // if (_userProvider.user?.type == UsersTypes.engineer) // Column( // children: [ @@ -367,7 +408,7 @@ class _RequestGasRefillState extends State { const SizedBox(height: 8), Divider(color: Theme.of(context).colorScheme.primary), const SizedBox(height: 4), - const ASubTitle("Type"), + const ASubTitle("Gas Type"), if (_validate && _currentDetails.type == null) ASubTitle(_subtitle.requiredWord, color: Colors.red), const SizedBox(height: 4), GasTypeMenu( @@ -395,9 +436,6 @@ class _RequestGasRefillState extends State { const SizedBox( height: 8, ), - const SizedBox( - height: 8, - ), const ASubTitle("Cylinder Type"), if (_validate && _currentDetails.cylinderSize == null) ASubTitle( @@ -508,12 +546,12 @@ class _RequestGasRefillState extends State { if (widget.gasRefillModel != null) ESignature( oldSignature: _formModel.signatureEngineer, - newSignature: _formModel.localNurseSignature, + newSignature: _formModel.localEngineerSignature, onChange: (signature) { if (signature == null || signature.isEmpty) { return; } - _formModel.localNurseSignature = signature; + _formModel.localEngineerSignature = signature; _formModel.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; }, ), diff --git a/lib/views/pages/user/gas_refill/track_gas_refill.dart b/lib/views/pages/user/gas_refill/track_gas_refill.dart index 6dd1ca6d..9eb9bc79 100644 --- a/lib/views/pages/user/gas_refill/track_gas_refill.dart +++ b/lib/views/pages/user/gas_refill/track_gas_refill.dart @@ -10,6 +10,8 @@ import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/gas_refill/gas_refill_list.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../widgets/switch_button.dart'; + class TrackGasRefillPage extends StatefulWidget { static const String id = "/track-gas-refill"; @@ -23,6 +25,7 @@ class _TrackGasRefillPageState extends State with TickerProv GasRefillProvider _gasRefillProvider; UserProvider _userProvider; SettingProvider _settingProvider; + bool mostRecent = true; @override Widget build(BuildContext context) { @@ -46,6 +49,7 @@ class _TrackGasRefillPageState extends State with TickerProv await _gasRefillProvider.getRequests( user: _userProvider.user, host: _settingProvider.host, + mostRecent: mostRecent, ); }, child: Stack( @@ -59,11 +63,11 @@ class _TrackGasRefillPageState extends State with TickerProv children: [ Row( children: [ - ABackButton(), + const ABackButton(), Expanded( child: Center( child: Text( - _subtitle.serviceRequests, + "Gas Refill Requests", style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.grey3A, fontStyle: FontStyle.italic), ), ), @@ -76,6 +80,22 @@ class _TrackGasRefillPageState extends State with TickerProv ], ), ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: ASwitchButton( + title: "Most Recent", + value: mostRecent, + onChange: (value) async { + mostRecent = value; + _gasRefillProvider.reset(); + await _gasRefillProvider.getRequests( + user: _userProvider.user, + host: _settingProvider.host, + mostRecent: mostRecent, + ); + }, + ), + ), Expanded( child: GasRefillList( nextPage: _gasRefillProvider.nextPage, @@ -83,6 +103,7 @@ class _TrackGasRefillPageState extends State with TickerProv await _gasRefillProvider.getRequests( user: _userProvider.user, host: _settingProvider.host, + mostRecent: mostRecent, ); }, items: _gasRefillProvider.items, diff --git a/lib/views/pages/user/land_page.dart b/lib/views/pages/user/land_page.dart index 3aa625e1..e249206d 100644 --- a/lib/views/pages/user/land_page.dart +++ b/lib/views/pages/user/land_page.dart @@ -199,14 +199,14 @@ class _LandPageState extends State { }, ), LandPageItem( - text: "transfer Device", + text: "Transfer Asset", icon: FontAwesomeIcons.rightLeft, onPressed: () { Navigator.of(context).pushNamed(RequestDeviceTransfer.id); }, ), LandPageItem( - text: "Track Device Transfer", + text: "Track Asset Transfer", icon: FontAwesomeIcons.peopleCarryBox, onPressed: () { Navigator.of(context).pushNamed(TrackDeviceTransferPage.id); @@ -214,7 +214,7 @@ class _LandPageState extends State { ), if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.normal_user) LandPageItem( - text: "Search Work Order", + text: "Create Sub Work Order", svgPath: "assets/images/sub_workorder_icon.svg", onPressed: () { Navigator.of(context).pushNamed(SearchSubWorkOrderPage.id); @@ -392,12 +392,12 @@ class _LandPageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - "Powered By NewTrack", + "Powered By Cloud Solutions", style: Theme.of(context).textTheme.headline6.copyWith(fontWeight: FontWeight.w500, color: AColors.grey3A, fontSize: 12), textScaleFactor: AppStyle.getScaleFactor(context), ), 6.width, - Image.asset("assets/images/qr.jpeg", width: 32, height: 32, color: AColors.grey3A) + Image.asset("assets/images/cloud_logo.png", width: 32, height: 32) ], ).paddingOnly(left: 20, right: 20, top: 8, bottom: 8), ], diff --git a/lib/views/pages/user/notifications/notifications_page.dart b/lib/views/pages/user/notifications/notifications_page.dart index bab082e3..614855d4 100644 --- a/lib/views/pages/user/notifications/notifications_page.dart +++ b/lib/views/pages/user/notifications/notifications_page.dart @@ -12,6 +12,7 @@ import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; class NotificationsPage extends StatefulWidget { static final String id = "/notifications"; + @override _NotificationsPageState createState() => _NotificationsPageState(); } @@ -21,6 +22,7 @@ class _NotificationsPageState extends State with TickerProvid UserProvider _userProvider; SettingProvider _settingProvider; Subtitle _subtitle; + @override Widget build(BuildContext context) { _notificationsProvider = Provider.of(context); diff --git a/lib/views/pages/user/profile_page.dart b/lib/views/pages/user/profile_page.dart index f5bb5c2c..a5b88dae 100644 --- a/lib/views/pages/user/profile_page.dart +++ b/lib/views/pages/user/profile_page.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/api_routes/http_status_manger.dart'; import 'package:test_sa/controllers/localization/localization.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/controllers/validator/validator.dart'; -import 'package:test_sa/models/department.dart'; import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/models/user.dart'; @@ -14,12 +12,12 @@ import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; -import 'package:test_sa/views/widgets/departments/department_button.dart'; import 'package:test_sa/views/widgets/hospitals/hospital_button.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; class ProfilePage extends StatefulWidget { static final String id = "/user/profile"; + @override _ProfilePageState createState() => _ProfilePageState(); } @@ -33,6 +31,7 @@ class _ProfilePageState extends State { bool _firstTime = true; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); + @override Widget build(BuildContext context) { _userProvider = Provider.of(context); @@ -119,14 +118,14 @@ class _ProfilePageState extends State { SizedBox( height: 8, ), - DepartmentButton( - department: Department(name: _user.departmentName, id: _user.departmentId), - onDepartmentPick: (department) { - _user.departmentName = department.name; - _user.departmentId = department.id; - setState(() {}); - }, - ), + // DepartmentButton( + // department: Department(name: _user.departmentName, id: _user.departmentId), + // onDepartmentPick: (department) { + // _user.departmentName = department.name; + // _user.departmentId = department.id; + // setState(() {}); + // }, + // ), SizedBox( height: 8, ), @@ -170,29 +169,29 @@ class _ProfilePageState extends State { child: AButton( text: _subtitle.update, onPressed: () async { - if (!_formKey.currentState.validate()) return; - _formKey.currentState.save(); - if (_user.departmentId == null) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(_subtitle.unitRequired), - )); - return; - } - int status = await _userProvider.updateProfile( - user: _user, - host: _settingProvider.host, - ); - if (status >= 200 && status < 300) { - _settingProvider.setUser(_userProvider.user); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(_subtitle.requestCompleteSuccessfully), - )); - } else { - String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(errorMessage), - )); - } + // if (!_formKey.currentState.validate()) return; + // _formKey.currentState.save(); + // if (_user.departmentId == null) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text(_subtitle.unitRequired), + // )); + // return; + // } + // int status = await _userProvider.updateProfile( + // user: _user, + // host: _settingProvider.host, + // ); + // if (status >= 200 && status < 300) { + // _settingProvider.setUser(_userProvider.user); + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text(_subtitle.requestCompleteSuccessfully), + // )); + // } else { + // String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text(errorMessage), + // )); + // } }, ), ), diff --git a/lib/views/pages/user/report_issues_page.dart b/lib/views/pages/user/report_issues_page.dart index 3a2f3f3e..0da3b23c 100644 --- a/lib/views/pages/user/report_issues_page.dart +++ b/lib/views/pages/user/report_issues_page.dart @@ -22,6 +22,7 @@ class ReportIssuesPage extends StatefulWidget { final ServiceRequest serviceRequest; const ReportIssuesPage({Key key, this.serviceRequest}) : super(key: key); + @override _ReportIssuesPageState createState() => _ReportIssuesPageState(); } @@ -35,6 +36,7 @@ class _ReportIssuesPageState extends State { UserProvider _userProvider; SettingProvider _settingProvider; final GlobalKey _formKey = GlobalKey(); + @override Widget build(BuildContext context) { Subtitle _subtitle = AppLocalization.of(context).subtitle; diff --git a/lib/views/pages/user/requests/create_request.dart b/lib/views/pages/user/requests/create_request.dart index 14d7eb36..c6c05bab 100644 --- a/lib/views/pages/user/requests/create_request.dart +++ b/lib/views/pages/user/requests/create_request.dart @@ -20,10 +20,12 @@ import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; import 'package:test_sa/views/widgets/equipment/device_button.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/sound/record_sound.dart'; +import 'package:test_sa/views/widgets/sound/sound_player.dart'; import 'package:test_sa/views/widgets/speech_to_text/speech_to_text.dart'; import 'package:test_sa/views/widgets/status/service_request/service_request_defect_types_mune.dart'; import 'package:test_sa/views/widgets/status/service_request/service_request_priority_mune.dart'; @@ -31,6 +33,9 @@ import 'package:test_sa/views/widgets/status/service_request/service_request_thr import 'package:test_sa/views/widgets/status/service_request/service_request_types_mune.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; +import '../../../../controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart'; +import '../../../../controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart'; +import '../../../app_style/sizing.dart'; import '../../../widgets/date_and_time/date_picker.dart'; import '../../../widgets/status/service_request/service_request_first_action.dart'; import '../../../widgets/status/service_request/service_request_loan_availability.dart'; @@ -38,6 +43,7 @@ import '../../../widgets/status/service_request/service_request_loan_availabilit class CreateRequestPage extends StatefulWidget { static const String id = "/create-request"; final ServiceRequest serviceRequest; + const CreateRequestPage({this.serviceRequest, Key key}) : super(key: key); @override @@ -57,9 +63,11 @@ class CreateRequestPageState extends State { Subtitle _subtitle; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - TextEditingController _maintenanceController, _commentController; + TextEditingController _maintenanceController, _commentController, _reviewCommentController; DateTime _dateTime; + bool isFirstActionSubmitted = false; + @override void initState() { _maintenanceController = TextEditingController(); @@ -69,12 +77,36 @@ class CreateRequestPageState extends State { _device = _serviceRequest.device; _deviceImages.addAll(_serviceRequest.devicePhotos.map((e) => File(e)).toList()); _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit"; + if (_showDatePicker && _serviceRequest.visitDate != null) { + _dateTime = DateTime.tryParse(_serviceRequest.visitDate); + } } else { _serviceRequest = ServiceRequest(); } + isFirstActionSubmitted = _serviceRequest?.firstAction != null; super.initState(); } + // + // getServiceRequestById(String id) async { + // try { + // ServiceRequest request = await _serviceRequestsProvider.getServiceRequestObjectById(requestId: id) ?? ""; + // _serviceRequest = request; + // _device = _serviceRequest.device; + // _deviceImages.addAll(_serviceRequest.devicePhotos.map((e) { + // return File(e); + // }).toList()); + // _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit"; + // if (_showDatePicker && _serviceRequest.visitDate != null) { + // _dateTime = DateTime.tryParse(_serviceRequest.visitDate); + // } + // _isLoading = false; + // } catch (ex) { + // _isLoading = false; + // } + // setState(() {}); + // } + @override void dispose() { _maintenanceController.dispose(); @@ -82,13 +114,19 @@ class CreateRequestPageState extends State { super.dispose(); } + bool _isLocalUrl(String url) { + if (url?.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } + @override Widget build(BuildContext context) { _height = MediaQuery.of(context).size.height; _userProvider = Provider.of(context); _settingProvider = Provider.of(context); - _serviceRequestsProvider = Provider.of(context); _subtitle = AppLocalization.of(context).subtitle; + _serviceRequestsProvider = Provider.of(context); + return Scaffold( key: _scaffoldKey, body: SafeArea( @@ -135,14 +173,39 @@ class CreateRequestPageState extends State { style: Theme.of(context).textTheme.subtitle1, ), 12.height, - _userProvider.user.departmentId == null + _userProvider.user.departmentId == null || (_userProvider.user?.departmentId?.isEmpty ?? false) ? const SizedBox.shrink() - : ATextFormField( - enable: false, - initialValue: _userProvider.user.departmentName ?? _subtitle.noUniteFound, - hintText: _subtitle.unite, - prefixIconData: FontAwesomeIcons.hospitalUser, - style: Theme.of(context).textTheme.subtitle1, + : Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xfff5f5f5), + border: Border.all( + color: const Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _userProvider.user.departmentName + ?.map( + (e) => Text( + e?.trim() ?? "", + style: Theme.of(context).textTheme.titleMedium.copyWith(color: AColors.black), + ), + ) + ?.toList() ?? + [], + ), + Icon( + FontAwesomeIcons.hospitalUser, + size: 20 * AppStyle.getScaleFactor(context), + color: const Color(0xff2e303a), + ), + ], + ), ), 12.height, DeviceButton( @@ -160,15 +223,16 @@ class CreateRequestPageState extends State { height: 4, ), ServiceRequestPriorityMenu( - initialValue: _serviceRequest.priority, + initialValue: widget.serviceRequest?.priority, onSelect: (status) { _serviceRequest.priority = status; }, + enabled: widget.serviceRequest == null ? true : false, ), const SizedBox( height: 8, ), - const ASubTitle("Defect Type"), + const ASubTitle("Equipment Status"), const SizedBox( height: 4, ), @@ -177,12 +241,13 @@ class CreateRequestPageState extends State { onSelect: (status) { _serviceRequest.defectType = status; }, + enabled: widget.serviceRequest == null ? true : false, ), 12.height, const SizedBox( height: 8, ), - const ASubTitle("Type"), + const ASubTitle("Type of Request"), const SizedBox( height: 4, ), @@ -191,6 +256,8 @@ class CreateRequestPageState extends State { onSelect: (status) { _serviceRequest.type = status; }, + enabled: false, + withDefaultItem: widget.serviceRequest == null, ), const SizedBox( height: 8, @@ -201,9 +268,7 @@ class CreateRequestPageState extends State { ), ServiceRequestedThroughMenu( initialValue: _serviceRequest.requestedThrough, - onSelect: (status) { - _serviceRequest.requestedThrough = status; - }, + enabled: false, ), if (widget.serviceRequest != null) 12.height, if (widget.serviceRequest != null) const ASubTitle("First Action"), @@ -213,6 +278,7 @@ class CreateRequestPageState extends State { if (widget.serviceRequest != null) ServiceRequestedFirstAction( initialValue: _serviceRequest.firstAction, + enabled: !isFirstActionSubmitted, onSelect: (status) { _dateTime = null; _serviceRequest.firstAction = status; @@ -222,10 +288,11 @@ class CreateRequestPageState extends State { ), if (_showDatePicker) 12.height, if (_showDatePicker) - ADatePicker( + ADateTimePicker( date: _dateTime, + enable: !isFirstActionSubmitted, from: DateTime.now(), - onDatePicker: (date) { + onDateTimePicker: (date) { _dateTime = date; setState(() {}); }, @@ -249,7 +316,7 @@ class CreateRequestPageState extends State { ), if (widget.serviceRequest != null) ATextFormField( - controller: _commentController, + controller: _reviewCommentController, initialValue: _serviceRequest.reviewComment, hintText: _subtitle.comment, style: Theme.of(context).textTheme.titleMedium, @@ -257,14 +324,19 @@ class CreateRequestPageState extends State { onSaved: (value) { _serviceRequest.reviewComment = value; }, + enable: widget.serviceRequest != null ? false : true, ), 12.height, - MultiImagesPicker( - label: _subtitle.deviceImages, - images: _deviceImages, + MultiFilesPicker( + label: _subtitle.deviceFiles, + files: _deviceImages, + enabled: widget.serviceRequest == null ? true : false, ), 12.height, - SpeechToTextButton(controller: _maintenanceController), + SpeechToTextButton( + controller: _maintenanceController, + enabled: widget.serviceRequest == null ? true : false, + ), 12.height, ATextFormField( controller: _maintenanceController, @@ -273,15 +345,24 @@ class CreateRequestPageState extends State { prefixIconData: FontAwesomeIcons.triangleExclamation, style: Theme.of(context).textTheme.titleLarge, textInputType: TextInputType.multiline, - validator: (value) => Validator.hasValue(value) ? null : _subtitle.maintenanceIssueRequired, + validator: (value) => widget.serviceRequest != null || Validator.hasValue(value) ? null : _subtitle.maintenanceIssueRequired, onSaved: (value) { _serviceRequest.callComments = value; }, + enable: widget.serviceRequest == null ? true : false, ), 12.height, - RecordSound(onRecord: (audio) { - _serviceRequest.audio = audio; - }), + if (_serviceRequest.audio?.isNotEmpty == true) + ASoundPlayer( + audio: _serviceRequest.audio, + ) + else + RecordSound( + onRecord: (audio) { + _serviceRequest.audio = audio; + }, + enabled: widget.serviceRequest == null ? true : false, + ), 12.height, if (widget.serviceRequest != null) ATextFormField( @@ -307,7 +388,7 @@ class CreateRequestPageState extends State { return; } if (_serviceRequest.firstAction?.name == "Need a visit" && _dateTime == null) { - Fluttertoast.showToast(msg: _subtitle.noDateFound); + Fluttertoast.showToast(msg: "first action is required"); return; } if (widget.serviceRequest != null && (_serviceRequest?.engineerId == null || (_serviceRequest?.engineerId?.isEmpty ?? false))) { @@ -316,12 +397,18 @@ class CreateRequestPageState extends State { } _formKey.currentState.save(); _serviceRequest.deviceId = _device?.id; + if (widget.serviceRequest == null) { + _serviceRequest.type = Provider.of(context, listen: false).getDefaultItem(); + } + _serviceRequest.requestedThrough = Provider.of(context, listen: false).getDefaultItem(); _isLoading = true; setState(() {}); - _serviceRequest.devicePhotos = _deviceImages.map((e) => "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}").toList(); + _serviceRequest.devicePhotos = _deviceImages.map((e) => _isLocalUrl(e.path) ? "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}" : e.path).toList(); if (_serviceRequest.audio != null) { - final file = File(_serviceRequest.audio); - _serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; + if (_isLocalUrl(_serviceRequest.audio)) { + final File file = File(_serviceRequest.audio); + _serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; + } } int status = 0; if (widget.serviceRequest == null) { diff --git a/lib/views/pages/user/requests/future_request_service_details.dart b/lib/views/pages/user/requests/future_request_service_details.dart index 3ece8e61..6a09ae35 100644 --- a/lib/views/pages/user/requests/future_request_service_details.dart +++ b/lib/views/pages/user/requests/future_request_service_details.dart @@ -20,6 +20,7 @@ class FutureRequestServiceDetails extends StatefulWidget { class _FutureRequestServiceDetailsState extends State { UserProvider _userProvider; SettingProvider _settingProvider; + @override Widget build(BuildContext context) { _userProvider = Provider.of(context); diff --git a/lib/views/pages/user/requests/report/create_service_report.dart b/lib/views/pages/user/requests/report/create_service_report.dart index 4eac7042..0e7d35d8 100644 --- a/lib/views/pages/user/requests/report/create_service_report.dart +++ b/lib/views/pages/user/requests/report/create_service_report.dart @@ -22,10 +22,8 @@ import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; import 'package:test_sa/views/widgets/equipment/auto_complete_devices_field.dart'; -import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; import 'package:test_sa/views/widgets/parts/part_item.dart'; @@ -35,6 +33,8 @@ import 'package:test_sa/views/widgets/status/report/service_report_reasons.dart' import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../widgets/date_and_time/date_picker.dart'; +import '../../../../widgets/images/multi_image_picker.dart'; import '../../../../widgets/status/report/service_report_fault_description.dart'; import '../../../../widgets/status/report/service_report_repair_location.dart'; import '../../../../widgets/timer/app_timer.dart'; @@ -60,7 +60,7 @@ class _CreateServiceReportState extends State with TickerPr bool _showCommentField = false; Subtitle _subtitle; - File _image; + final List _files = []; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); final TextEditingController _faultController = TextEditingController(); @@ -69,7 +69,7 @@ class _CreateServiceReportState extends State with TickerPr @override void initState() { _serviceReport = ServiceReport( - visitDate: DateTime.now(), + returnToService: DateTime.now(), //type: const Lookup(value: 2), device: widget.request.device, parts: [], @@ -155,12 +155,17 @@ class _CreateServiceReportState extends State with TickerPr ) ]), child: Wrap( + direction: Axis.vertical, spacing: 10, children: [ ASubTitle( "${_subtitle.callId}: ${widget.request.requestCode}", font: 14, ), + ASubTitle( + "${_subtitle.assetNumber}: ${widget.request.deviceNumber}", + font: 14, + ), widget.request.deviceSerialNumber == null ? const SizedBox() : ASubTitle( @@ -195,63 +200,6 @@ class _CreateServiceReportState extends State with TickerPr crossAxisAlignment: CrossAxisAlignment.start, children: [ // Report type and Reasons - Row( - children: [ - // Report Status - // Expanded( - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // ASubTitle(_subtitle.reportType), - // _validate && _serviceReport.type == null ? - // ASubTitle(_subtitle.requiredWord,color: Colors.red,): - // const SizedBox.shrink(), - // const SizedBox(height: 4,), - // ServiceReportTypeMenu( - // initialValue: _serviceReport.type, - // onSelect: (status){ - // _serviceReport.type = status; - // }, - // ), - // ], - // ), - // ), - // const SizedBox(width: 8,), - // visit date - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ASubTitle(_subtitle.visitDate), - _validate && _serviceReport.visitDate == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - Row( - children: [ - Expanded( - child: ADatePicker( - date: _serviceReport.visitDate, - from: DateTime.now().subtract(const Duration(days: 365)), - to: DateTime.now().add(const Duration(days: 365)), - onDatePicker: (date) { - _serviceReport.visitDate = date; - setState(() {}); - }, - ), - ), - ], - ), - ], - ), - ), - ], - ), - const SizedBox( - height: 8, - ), // device sn Visibility( visible: widget.request.deviceSerialNumber == null, @@ -281,7 +229,7 @@ class _CreateServiceReportState extends State with TickerPr const SizedBox( height: 8, ), - ASubTitle(_subtitle.assetType ??""), + ASubTitle(_subtitle.assetType ?? ""), _validate && _serviceReport.assetType == null ? ASubTitle( _subtitle.requiredWord, @@ -415,6 +363,63 @@ class _CreateServiceReportState extends State with TickerPr SizedBox( height: 8 * AppStyle.getScaleFactor(context), ), + Row( + children: [ + // Report Status + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // ASubTitle(_subtitle.reportType), + // _validate && _serviceReport.type == null ? + // ASubTitle(_subtitle.requiredWord,color: Colors.red,): + // const SizedBox.shrink(), + // const SizedBox(height: 4,), + // ServiceReportTypeMenu( + // initialValue: _serviceReport.type, + // onSelect: (status){ + // _serviceReport.type = status; + // }, + // ), + // ], + // ), + // ), + // const SizedBox(width: 8,), + // visit date + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const ASubTitle("Return to Service"), + // _validate && _serviceReport.returnToService == null + // ? ASubTitle( + // _subtitle.requiredWord, + // color: Colors.red, + // ) + // : const SizedBox.shrink(), + Row( + children: [ + Expanded( + child: ADatePicker( + date: _serviceReport.returnToService, + from: DateTime.now().subtract(const Duration(days: 365)), + to: DateTime.now().add(const Duration(days: 365)), + onDatePicker: (date) { + _serviceReport.returnToService = date; + setState(() {}); + }, + ), + ), + ], + ), + ], + ), + ), + ], + ), + const SizedBox( + height: 8, + ), ASubTitle(_subtitle.workingHours), const SizedBox(height: 8), Row( @@ -541,8 +546,10 @@ class _CreateServiceReportState extends State with TickerPr requestId: widget.request?.id, initialValue: _serviceReport.faultDescription, onSelect: (status) { - _serviceReport.faultDescription = status; - setState(() {}); + if (status != null) { + _serviceReport.faultDescription = status; + setState(() {}); + } }, ), const SizedBox( @@ -564,7 +571,7 @@ class _CreateServiceReportState extends State with TickerPr ), Row( children: [ - ASubTitle(_subtitle.workPreformed), + const ASubTitle("Solutions"), // Expanded( // child: SizedBox( // height: 32 * AppStyle.getScaleFactor(context), @@ -604,7 +611,7 @@ class _CreateServiceReportState extends State with TickerPr child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ASubTitle(_subtitle.reasons), + const ASubTitle("Failure Reason"), _validate && _serviceReport.reason?.id == null ? ASubTitle( _subtitle.requiredWord, @@ -622,25 +629,27 @@ class _CreateServiceReportState extends State with TickerPr ), ), const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ASubTitle(_subtitle.attachImage), - AMiniOneImagePicker( - //error: _validate && _serviceReport.image == null, - image: _image, - onPick: (image) { - _image = image; - _serviceReport.image = "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}"; - }, - ), - ], - ), - ), + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // const ASubTitle("Attachments"), + // AMiniOneFilePicker( + // //error: _validate && _serviceReport.image == null, + // file: _file, + // onPick: (file) { + // _file = file; + // _serviceReport.files[0] = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; + // }, + // ), + // ], + // ), + // ), ], ), const SizedBox(height: 8), + MultiFilesPicker(label: "Attachments", files: _files), + const SizedBox(height: 8), ASubTitle(_subtitle.repairLocation), const SizedBox(height: 4), ServiceReportRepairLocation( @@ -650,7 +659,7 @@ class _CreateServiceReportState extends State with TickerPr }, ), const SizedBox(height: 16), - ASubTitle(_subtitle.travelingExpense), + const ASubTitle("Travel Expenses"), const SizedBox( height: 4, ), @@ -786,7 +795,7 @@ class _CreateServiceReportState extends State with TickerPr // ), const SizedBox(height: 8), - ASubTitle(_subtitle.comment), + const ASubTitle("Technical comment"), const SizedBox(height: 4), ATextFormField( initialValue: _serviceReport?.comment, @@ -853,7 +862,7 @@ class _CreateServiceReportState extends State with TickerPr child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ASubTitle(_subtitle.partNumber), + ASubTitle(_subtitle.partNumberName), _validate && _serviceReport.parts == null ? ASubTitle( _subtitle.requiredWord, @@ -864,6 +873,7 @@ class _CreateServiceReportState extends State with TickerPr height: 4, ), AutoCompletePartsField( + assetId: _serviceReport?.device?.id, onPick: (part) { _serviceReport.parts.add(part); }, @@ -918,15 +928,16 @@ class _CreateServiceReportState extends State with TickerPr _isLoading = true; setState(() {}); - + _serviceReport.files ??= []; + for (var file in _files) { + _serviceReport.files.add("${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"); + } int status = await _serviceRequestsProvider.createServiceReport( user: _userProvider.user, host: _settingProvider.host, report: _serviceReport, request: widget.request, ); - print(6); - print(status); _isLoading = false; setState(() {}); if (status >= 200 && status < 300) { diff --git a/lib/views/pages/user/requests/report/edit_service_report.dart b/lib/views/pages/user/requests/report/edit_service_report.dart index 8ca73c90..ae74092f 100644 --- a/lib/views/pages/user/requests/report/edit_service_report.dart +++ b/lib/views/pages/user/requests/report/edit_service_report.dart @@ -26,7 +26,6 @@ import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; import 'package:test_sa/views/widgets/equipment/auto_complete_devices_field.dart'; -import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; import 'package:test_sa/views/widgets/parts/part_item.dart'; @@ -38,6 +37,8 @@ import 'package:test_sa/views/widgets/status/report/service_report_repair_locati import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; +import '../../../../widgets/images/multi_image_picker.dart'; + class EditServiceReport extends StatefulWidget { static final String id = "/edit-service-report"; final ServiceRequest request; @@ -60,7 +61,7 @@ class _EditServiceReportState extends State with TickerProvid bool _showCommentField = false; Subtitle _subtitle; - File _image; + List _images = []; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); TextEditingController _faultController = TextEditingController(); @@ -73,6 +74,7 @@ class _EditServiceReportState extends State with TickerProvid @override void initState() { _serviceReport = widget.report; + _images = widget.report?.files?.map((e) => File(e))?.toList(); super.initState(); } @@ -149,12 +151,17 @@ class _EditServiceReportState extends State with TickerProvid ) ]), child: Wrap( + direction: Axis.vertical, spacing: 10, children: [ ASubTitle( "${_subtitle.callId}: ${widget.request.requestCode}", font: 14, ), + ASubTitle( + "${_subtitle.assetNumber}: ${widget.request.deviceNumber}", + font: 14, + ), widget.request.deviceSerialNumber == null ? const SizedBox() : ASubTitle( @@ -179,8 +186,8 @@ class _EditServiceReportState extends State with TickerProvid width: double.infinity, padding: const EdgeInsets.all(16), margin: const EdgeInsets.symmetric(vertical: 16), - decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [ - const BoxShadow( + decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: const [ + BoxShadow( color: AColors.grey, offset: Offset(0, -1), ) @@ -189,70 +196,70 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ // Report type and Reasons - Row( - children: [ - // Report Status - // Expanded( - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // ASubTitle(_subtitle.reportType), - // _validate && _serviceReport.type == null - // ? ASubTitle( - // _subtitle.requiredWord, - // color: Colors.red, - // ) - // : const SizedBox.shrink(), - // const SizedBox( - // height: 4, - // ), - // ServiceReportTypeMenu( - // initialValue: _serviceReport.type, - // onSelect: (status) { - // _serviceReport.type = status; - // }, - // ), - // ], - // ), - // ), - // const SizedBox( - // width: 8, - // ), - // visit date - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ASubTitle(_subtitle.visitDate), - _validate && _serviceReport.visitDate == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - Row( - children: [ - Expanded( - child: ADatePicker( - date: _serviceReport.visitDate, - from: DateTime.now().subtract(const Duration(days: 365)), - to: DateTime.now().add(const Duration(days: 365)), - onDatePicker: (date) { - _serviceReport.visitDate = date; - setState(() {}); - }, - ), - ), - ], - ), - ], - ), - ), - ], - ), - const SizedBox( - height: 8, - ), + // Row( + // children: [ + // // Report Status + // // Expanded( + // // child: Column( + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // ASubTitle(_subtitle.reportType), + // // _validate && _serviceReport.type == null + // // ? ASubTitle( + // // _subtitle.requiredWord, + // // color: Colors.red, + // // ) + // // : const SizedBox.shrink(), + // // const SizedBox( + // // height: 4, + // // ), + // // ServiceReportTypeMenu( + // // initialValue: _serviceReport.type, + // // onSelect: (status) { + // // _serviceReport.type = status; + // // }, + // // ), + // // ], + // // ), + // // ), + // // const SizedBox( + // // width: 8, + // // ), + // // visit date + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // ASubTitle(_subtitle.visitDate), + // _validate && _serviceReport.visitDate == null + // ? ASubTitle( + // _subtitle.requiredWord, + // color: Colors.red, + // ) + // : const SizedBox.shrink(), + // Row( + // children: [ + // Expanded( + // child: ADatePicker( + // date: _serviceReport.visitDate, + // from: DateTime.now().subtract(const Duration(days: 365)), + // to: DateTime.now().add(const Duration(days: 365)), + // onDatePicker: (date) { + // _serviceReport.visitDate = date; + // setState(() {}); + // }, + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // ], + // ), + // const SizedBox( + // height: 8, + // ), // device sn Visibility( visible: widget.request.deviceSerialNumber == null, @@ -380,6 +387,7 @@ class _EditServiceReportState extends State with TickerProvid setState(() {}); } else { _serviceReport.callLastSituation = status; + setState(() {}); } }, ), @@ -390,6 +398,56 @@ class _EditServiceReportState extends State with TickerProvid ), ], ), + const SizedBox( + height: 8, + ), + const ASubTitle("Return to Service"), + Row( + children: [ + Expanded( + child: ADatePicker( + date: _serviceReport.returnToService, + from: DateTime.now().subtract(const Duration(days: 365)), + to: DateTime.now().add(const Duration(days: 365)), + onDatePicker: (date) { + _serviceReport.returnToService = date; + setState(() {}); + }, + ), + ), + ], + ), + if (_serviceReport?.callLastSituation?.value == 2) + Column( + children: [ + const SizedBox( + height: 8, + ), + ATextFormField( + initialValue: _serviceReport?.reviewComment, + hintText: "Vendor Name", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.reviewComment = value; + }, + ), + const SizedBox( + height: 8, + ), + ATextFormField( + initialValue: _serviceReport?.reviewComment, + hintText: "Vendor Engineer", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.reviewComment = value; + }, + ), + ], + ), if (_showCommentField) const SizedBox( height: 8, @@ -658,13 +716,14 @@ class _EditServiceReportState extends State with TickerProvid requestId: widget.request?.id, initialValue: _serviceReport.faultDescription, onSelect: (status) { - print("faluttt:${status?.toJson()}"); _serviceReport.faultDescription = status; - if (mounted) setState(() {}); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + if (mounted) setState(() {}); + }); }, ), const SizedBox(height: 8), - ASubTitle(_subtitle.workPreformed), + const ASubTitle("Solutions"), const SizedBox(height: 4), ATextFormField( initialValue: _serviceReport?.workPreformed, @@ -680,50 +739,38 @@ class _EditServiceReportState extends State with TickerProvid }, ), const SizedBox(height: 4), - Row( - children: [ - // reasons - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ASubTitle(_subtitle.reasons), - const SizedBox( - height: 4, - ), - ServiceReportReasonsMenu( - initialValue: _serviceReport.reason, - onSelect: (status) { - _serviceReport.reason = status; - }, - ), - ], - ), - ), - const SizedBox( - width: 8, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ASubTitle(_subtitle.attachImage), - AMiniOneImagePicker( - //error: _validate && _serviceReport.image == null, - image: _image, - onPick: (image) { - _image = image; - _serviceReport.image = base64Encode(image.readAsBytesSync()); - }, - ), - ], - ), - ), - ], + ASubTitle("Failure Reason"), + const SizedBox( + height: 4, + ), + ServiceReportReasonsMenu( + initialValue: _serviceReport.reason, + onSelect: (status) { + _serviceReport.reason = status; + }, ), const SizedBox( height: 8, ), + ASubTitle(_subtitle.attachImage), + const SizedBox( + height: 4, + ), + MultiFilesPicker( + label: "", + files: _images, + ), + // AMiniOneImagePicker( + // //error: _validate && _serviceReport.image == null, + // image: _image, + // onPick: (image) { + // _image = image; + // _serviceReport.image = base64Encode(image.readAsBytesSync()); + // }, + // ), + const SizedBox( + height: 8, + ), const SizedBox(height: 8), ASubTitle(_subtitle.repairLocation), const SizedBox(height: 4), @@ -734,7 +781,7 @@ class _EditServiceReportState extends State with TickerProvid }, ), const SizedBox(height: 16), - ASubTitle(_subtitle.travelingExpense), + ASubTitle("Travel Expenses"), const SizedBox( height: 4, ), @@ -746,9 +793,9 @@ class _EditServiceReportState extends State with TickerProvid textInputType: TextInputType.number, onSaved: (value) { if (value != null && value.isEmpty) { - _serviceReport.travelingExpense = int.tryParse(_serviceReport?.travelingExpense?.toString() ?? "") ?? 0; + _serviceReport.travelingExpense = num.tryParse(_serviceReport?.travelingExpense?.toString() ?? "") ?? 0; } else - _serviceReport.travelingExpense = int.tryParse(value) ?? 0; + _serviceReport.travelingExpense = num.tryParse(value) ?? 0; }, ), @@ -885,7 +932,7 @@ class _EditServiceReportState extends State with TickerProvid //const SizedBox(height: 8,), const SizedBox(height: 8), - ASubTitle(_subtitle.comment), + const ASubTitle("Technical comment"), const SizedBox(height: 4), ATextFormField( initialValue: _serviceReport?.comment, @@ -955,7 +1002,7 @@ class _EditServiceReportState extends State with TickerProvid child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ASubTitle(_subtitle.partNumber), + ASubTitle(_subtitle.partNumberName), _validate && _serviceReport.parts == null ? ASubTitle( _subtitle.requiredWord, @@ -966,6 +1013,7 @@ class _EditServiceReportState extends State with TickerProvid height: 4, ), AutoCompletePartsField( + assetId: _serviceReport?.device?.id, onPick: (part) { _serviceReport.parts.add(part); setState(() {}); @@ -1011,7 +1059,6 @@ class _EditServiceReportState extends State with TickerProvid return; } _validate = true; - print("jere1245"); // if (!_formKey.currentState.validate()) { // setState(() {}); // return; @@ -1026,7 +1073,7 @@ class _EditServiceReportState extends State with TickerProvid _isLoading = true; setState(() {}); - + _serviceReport.files = _images.map((e) => _isLocalUrl(e.path) ? "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}" : e.path).toList(); int status = await _serviceRequestsProvider.updateServiceReport(user: _userProvider.user, host: _settingProvider.host, report: _serviceReport, request: widget.request); _isLoading = false; setState(() {}); @@ -1054,4 +1101,9 @@ class _EditServiceReportState extends State with TickerProvid ), ); } + + bool _isLocalUrl(String url) { + if (url?.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } } diff --git a/lib/views/pages/user/requests/report/future_service_report.dart b/lib/views/pages/user/requests/report/future_service_report.dart index cb39a6e3..a54e3566 100644 --- a/lib/views/pages/user/requests/report/future_service_report.dart +++ b/lib/views/pages/user/requests/report/future_service_report.dart @@ -26,30 +26,32 @@ class FutureServiceReport extends StatefulWidget { class _FutureServiceReportState extends State { UserProvider _userProvider; SettingProvider _settingProvider; + @override Widget build(BuildContext context) { _userProvider = Provider.of(context); _settingProvider = Provider.of(context); - Subtitle _subtitle = AppLocalization.of(context).subtitle; - ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: _subtitle); + Subtitle subtitle = AppLocalization.of(context).subtitle; + ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: subtitle); return Scaffold( body: FutureBuilder( - future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: _subtitle), + future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: subtitle), builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasError) + if (snapshot.hasError) { return FailedLoading( message: snapshot.error.toString(), onReload: () { setState(() {}); }, ); - if (snapshot.hasData) { + } + if (snapshot.connectionState == ConnectionState.done) { return EditServiceReport( report: snapshot.data, request: widget.request, ); } - return Center(child: ALoading()); + return const Center(child: ALoading()); }, ), ); diff --git a/lib/views/pages/user/requests/request_details.dart b/lib/views/pages/user/requests/request_details.dart index 23bd5792..35b78099 100644 --- a/lib/views/pages/user/requests/request_details.dart +++ b/lib/views/pages/user/requests/request_details.dart @@ -6,6 +6,7 @@ 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/int_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/models/subtitle.dart'; @@ -16,7 +17,9 @@ import 'package:test_sa/views/pages/user/requests/report/create_service_report.d import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/buttons/app_icon_button.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/images_list.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/image_loader.dart'; import 'package:test_sa/views/widgets/requests/info_row.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; @@ -27,10 +30,10 @@ import '../../../../models/service_request/search_work_order.dart'; import 'report/future_service_report.dart'; class RequestDetailsPage extends StatelessWidget { - static final String id = "/call-details"; - final ServiceRequest serviceRequest; + static const String id = "/call-details"; + ServiceRequest serviceRequest; - const RequestDetailsPage({Key key, this.serviceRequest}) : super(key: key); + RequestDetailsPage({Key key, this.serviceRequest}) : super(key: key); @override Widget build(BuildContext context) { @@ -39,404 +42,431 @@ class RequestDetailsPage extends StatelessWidget { SettingProvider _settingProvider = Provider.of(context); List workOrders = []; ServiceRequestsProvider _serviceRequestsProvider = Provider.of(context); + _serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id); + return DefaultTabController( length: 2, child: Scaffold( body: SafeArea( - child: Column( - children: [ - Container( - color: AColors.primaryColor, - padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), - child: Row( - children: [ - ABackButton(), - Expanded( - child: Center( - child: Text( - _subtitle.details, - style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), - ), - ), - ), - _userProvider.user.type == UsersTypes.normal_user - ? - // AIconButton( - // iconData: Icons.warning_amber_rounded, - // color: AColors.white, - // buttonSize: 42, - // backgroundColor: AColors.deepOrange, - // onPressed: (){ - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest,) - // ) - // ); - // }, - // ) - const SizedBox( - width: 48, - ) - : AIconButton( - iconData: Icons.edit, - color: AColors.white, - buttonSize: 42, - backgroundColor: AColors.green, - onPressed: () async { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => CreateRequestPage(serviceRequest: serviceRequest)), - ); - // showModalBottomSheet( - // context: context, - // builder: (context) { - // return ServiceRequestsUpdateDialog( - // request: serviceRequest, - // ); - // }); - // DateTime picked = await showDatePicker( - // context: context, - // initialDate: DateTime.now(), - // firstDate: DateTime.now(), - // lastDate: DateTime.now().add(Duration(days: 182)) - // ); - // if(picked == null){return;} - // showDialog( - // context: context, - // barrierDismissible: false, - // builder: (BuildContext context) { - // return CupertinoAlertDialog( - // title: Text(_subtitle.updatingDots), - // content: Center(child: CircularProgressIndicator()), - // ); - // }, - // ); - // int status = await _serviceRequestsProvider.updateDate( - // user: _userProvider.user, - // host: _settingProvider.host, - // request: serviceRequest, - // newDate: picked.toString().split(" ").first - // ); - // Navigator.of(context).pop(); - // Fluttertoast.showToast( - // msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle), - // ); - }, - ), - SizedBox( - width: 16, - ) - ], - ), - ), - serviceRequest.devicePhotos.isEmpty - ? SizedBox.shrink() - : Column( - children: [ - SizedBox( - height: 8, - ), - MaterialButton( - padding: EdgeInsets.zero, - onPressed: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => Scaffold( - body: InteractiveViewer( - child: Center( - child: ImageLoader( - url: serviceRequest.devicePhotos.first, - boxFit: BoxFit.contain, - ), - ), - ), - ))); - }, - child: SizedBox( - height: 140 * AppStyle.getScaleFactor(context), - width: MediaQuery.of(context).size.width, - child: ImageLoader( - url: serviceRequest.devicePhotos.first, - boxFit: BoxFit.cover, - ), - ), - ), - SizedBox(height: 8), - SizedBox( - height: 60 * AppStyle.getScaleFactor(context), - child: ImagesList( - images: serviceRequest.devicePhotos, - ), - ), - ], - ), - TabBar(labelColor: AColors.primaryColor, tabs: [ - Tab( - text: _subtitle.general, - ), - Tab( - text: _subtitle.serviceRequestInformation, - ), - ]), - SizedBox( - height: 8, - ), - Expanded( - child: TabBarView( - children: [ - ListView( - padding: EdgeInsets.symmetric(horizontal: 16), - children: [ - RequestInfoRow( - title: _subtitle.code, - info: serviceRequest.requestCode, - ), - RequestInfoRow( - title: "Asset Number", - info: serviceRequest.deviceNumber, - ), - RequestInfoRow( - title: _subtitle.assetName, - info: serviceRequest.deviceEnName, - ), - RequestInfoRow( - title: _subtitle.deviceModel, - info: serviceRequest.deviceModel, - ), - RequestInfoRow( - title: _subtitle.engineerName, - info: serviceRequest.engineerName, - ), - RequestInfoRow( - title: _subtitle.engineerPhone, - info: serviceRequest.engineerMobile, - ), - RequestInfoRow( - title: _subtitle.date, - info: serviceRequest.date, - ), - serviceRequest.nextVisitDate == null - ? SizedBox.shrink() - : RequestInfoRow( - title: _subtitle.nextVisitDate, - info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate), - ), - Row( + child: FutureBuilder( + future: _serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id), + builder: (context, snap) { + if (snap.connectionState == ConnectionState.waiting) { + return const ALoading(); + } else if (snap.hasData) { + serviceRequest = snap.data; + return Column( + children: [ + Container( + color: AColors.primaryColor, + padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), + child: Row( children: [ + ABackButton(), Expanded( - child: Text( - "${_subtitle.status} : ", - style: Theme.of(context).textTheme.subtitle1, - textScaleFactor: AppStyle.getScaleFactor(context), + child: Center( + child: Text( + _subtitle.details, + style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), + ), ), ), - StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue)), + _userProvider.user.type == UsersTypes.normal_user + ? + // AIconButton( + // iconData: Icons.warning_amber_rounded, + // color: AColors.white, + // buttonSize: 42, + // backgroundColor: AColors.deepOrange, + // onPressed: (){ + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest,) + // ) + // ); + // }, + // ) + const SizedBox( + width: 48, + ) + : AIconButton( + iconData: Icons.edit, + color: AColors.white, + buttonSize: 42, + backgroundColor: AColors.green, + onPressed: (serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3) + ? null + : () async { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => CreateRequestPage(serviceRequest: serviceRequest)), + ); + // showModalBottomSheet( + // context: context, + // builder: (context) { + // return ServiceRequestsUpdateDialog( + // request: serviceRequest, + // ); + // }); + // DateTime picked = await showDatePicker( + // context: context, + // initialDate: DateTime.now(), + // firstDate: DateTime.now(), + // lastDate: DateTime.now().add(Duration(days: 182)) + // ); + // if(picked == null){return;} + // showDialog( + // context: context, + // barrierDismissible: false, + // builder: (BuildContext context) { + // return CupertinoAlertDialog( + // title: Text(_subtitle.updatingDots), + // content: Center(child: CircularProgressIndicator()), + // ); + // }, + // ); + // int status = await _serviceRequestsProvider.updateDate( + // user: _userProvider.user, + // host: _settingProvider.host, + // request: serviceRequest, + // newDate: picked.toString().split(" ").first + // ); + // Navigator.of(context).pop(); + // Fluttertoast.showToast( + // msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle), + // ); + }, + ), + SizedBox( + width: 16, + ) ], ), - Divider( - color: Theme.of(context).primaryColor, - ), - RequestInfoRow( - title: _subtitle.hospital, - info: serviceRequest.hospitalName, - ), - RequestInfoRow( - title: _subtitle.unite, - info: serviceRequest.departmentName, - ), - // RequestInfoRow( - // title: _subtitle.deviceArName, - // content: serviceRequest.deviceArName, - // ), - RequestInfoRow( - title: _subtitle.deviceName, - content: serviceRequest.deviceEnName, + ), + serviceRequest.devicePhotos.isEmpty + ? const SizedBox.shrink() + : SizedBox( + height: 60 * AppStyle.getScaleFactor(context), + child: FilesList( + images: serviceRequest.devicePhotos, + ), + ).paddingOnly(top: 4, bottom: 4), + + // Column( + // children: [ + // SizedBox( + // height: 8, + // ), + // MaterialButton( + // padding: EdgeInsets.zero, + // onPressed: () { + // Navigator.of(context).push(MaterialPageRoute( + // builder: (_) => Scaffold( + // body: InteractiveViewer( + // child: Center( + // child: ImageLoader( + // url: serviceRequest.devicePhotos.first, + // boxFit: BoxFit.contain, + // ), + // ), + // ), + // ))); + // }, + // child: SizedBox( + // height: 140 * AppStyle.getScaleFactor(context), + // width: MediaQuery.of(context).size.width, + // child: ImageLoader( + // url: serviceRequest.devicePhotos.first, + // boxFit: BoxFit.cover, + // ), + // ), + // ), + // SizedBox(height: 8), + // SizedBox( + // height: 60 * AppStyle.getScaleFactor(context), + // child: FilesList( + // images: serviceRequest.devicePhotos, + // ), + // ), + // ], + // ), + TabBar(labelColor: AColors.primaryColor, tabs: [ + Tab( + text: _subtitle.general, ), - RequestInfoRow( - title: _subtitle.maintenanceIssue, - content: serviceRequest.callComments, + Tab( + text: _subtitle.serviceRequestInformation, ), - if (serviceRequest.audio?.isNotEmpty == true) - ASoundPlayer( - audio: serviceRequest.audio, - ), - // - // Center( - // child: Padding( - // padding: EdgeInsets.all(32), - // child: AButton( - // text: _subtitle.duplicateRequest, - // onPressed: () async { - // bool result = await showDialog( - // context: context, - // builder: (_) => AAlertDialog( - // title: _subtitle.duplicateAlert, - // content: _subtitle.duplicateAlertMessage, - // ) - // ); - // if(result == true){ - // showDialog( - // context: context, - // builder: (context){ - // return Center(child: CircularProgressIndicator()); - // } - // ); - // int status = await _serviceRequestsProvider.createDuplicatedReport( - // host: _settingProvider.host, - // user: _userProvider.user, - // request: serviceRequest - // ); - // Navigator.of(context).pop(); - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Text( - // HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle) - // ) - // ) - // ); - // } - // }, - // ), - // ), - // ) - ], - ), - // workOrders.isEmpty ? - FutureBuilder( - future: _serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode), - builder: (context, snap) { - workOrders = snap.data as List; - if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator()); - if (snap.connectionState == ConnectionState.done && (snap.data?.length ?? 0) != 0) { - return SingleChildScrollView( - child: Column( + ]), + SizedBox( + height: 8, + ), + Expanded( + child: TabBarView( + children: [ + ListView( + padding: EdgeInsets.symmetric(horizontal: 16), children: [ - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: EdgeInsets.all(21), - itemCount: workOrders.length, - separatorBuilder: (czt, index) => 21.height, - itemBuilder: (context, index) { - Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; - Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; - - return ElevatedButton( - style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), - primary: itemColor.withOpacity(.7), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), - ), - ), - //padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8), - onPressed: () { - // onPressed(request); - }, - child: Column( - children: [ - RequestInfoRow( - title: _subtitle.callId, - content: serviceRequest.requestCode, - ), - RequestInfoRow( - title: _subtitle.orderWorkNumber, - info: workOrders[index].workOrderNo.toString(), - ), - RequestInfoRow( - title: _subtitle.visitDate, - info: workOrders[index].visitDate, - ), - RequestInfoRow(title: _subtitle.assignedEmployee, info: workOrders[index].assignedEmployee?.name ?? ""), - RequestInfoRow( - title: _subtitle.assetSN, - info: workOrders[index].callRequest.asset.assetSerialNo, - ), - RequestInfoRow( - title: _subtitle.assetName, - info: workOrders[index].callRequest.asset.modelDefinition.assetName, - ), - RequestInfoRow( - title: _subtitle.model, - info: workOrders[index].callRequest.asset.modelDefinition.modelName, - ), - RequestInfoRow( - title: _subtitle.site, - info: workOrders[index].callRequest.asset.site.custName, - ), - RequestInfoRow( - title: _subtitle.maintenanceSituation, - info: workOrders[index].calllastSituation.name ?? '', - ), - RequestInfoRow( - title: _subtitle.currentSituation, - info: workOrders[index].currentSituation.name ?? '', - ), - _userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null - ? Padding( - padding: EdgeInsets.all(32), - child: AButton( - text: _subtitle.editServiceReport, - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => FutureServiceReport( - request: serviceRequest, - workOrder: workOrders[index], - )), - ); - }, - ), - ) - : SizedBox.shrink(), - ], - ), - ); - }, + RequestInfoRow( + title: _subtitle.callId, + info: serviceRequest.requestCode, + ), + RequestInfoRow( + title: "Asset Number", + info: serviceRequest.deviceNumber, + ), + RequestInfoRow( + title: _subtitle.assetName, + info: serviceRequest.deviceEnName, + ), + RequestInfoRow( + title: _subtitle.deviceModel, + info: serviceRequest.deviceModel, ), - if (_userProvider.user.type == UsersTypes.engineer) - Center( - child: Padding( - padding: const EdgeInsets.all(32), - child: AButton( - text: "Create Work Order", - onPressed: () { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest))); - }, + RequestInfoRow( + title: _subtitle.engineerName, + info: serviceRequest.engineerName, + ), + RequestInfoRow( + title: _subtitle.engineerPhone, + info: serviceRequest.engineerMobile, + ), + RequestInfoRow( + title: _subtitle.date, + info: serviceRequest.date, + ), + serviceRequest.nextVisitDate == null + ? SizedBox.shrink() + : RequestInfoRow( + title: _subtitle.nextVisitDate, + info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate), + ), + Row( + children: [ + Expanded( + child: Text( + "${_subtitle.status} : ", + style: Theme.of(context).textTheme.subtitle1, + textScaleFactor: AppStyle.getScaleFactor(context), ), ), + StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue)), + ], + ), + Divider( + color: Theme.of(context).primaryColor, + ), + RequestInfoRow( + title: _subtitle.hospital, + info: serviceRequest.hospitalName, + ), + RequestInfoRow( + title: _subtitle.unite, + info: serviceRequest.departmentName, + ), + // RequestInfoRow( + // title: _subtitle.deviceArName, + // content: serviceRequest.deviceArName, + // ), + // RequestInfoRow( + // title: _subtitle.deviceName, + // content: serviceRequest.deviceEnName, + // ), + RequestInfoRow( + title: _subtitle.maintenanceIssue, + content: serviceRequest.callComments, + ), + if (serviceRequest.audio?.isNotEmpty == true) + ASoundPlayer( + audio: serviceRequest.audio, ), + // + // Center( + // child: Padding( + // padding: EdgeInsets.all(32), + // child: AButton( + // text: _subtitle.duplicateRequest, + // onPressed: () async { + // bool result = await showDialog( + // context: context, + // builder: (_) => AAlertDialog( + // title: _subtitle.duplicateAlert, + // content: _subtitle.duplicateAlertMessage, + // ) + // ); + // if(result == true){ + // showDialog( + // context: context, + // builder: (context){ + // return Center(child: CircularProgressIndicator()); + // } + // ); + // int status = await _serviceRequestsProvider.createDuplicatedReport( + // host: _settingProvider.host, + // user: _userProvider.user, + // request: serviceRequest + // ); + // Navigator.of(context).pop(); + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // content: Text( + // HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle) + // ) + // ) + // ); + // } + // }, + // ), + // ), + // ) ], ), - ); - } else { - return Column( - children: [ - Expanded( - child: Center( - child: ASubTitle(_subtitle.dataNotFound), - ), - ), - if (_userProvider.user.type == UsersTypes.engineer) - Center( - child: Padding( - padding: const EdgeInsets.all(32), - child: AButton( - text: "Create Work Order", - onPressed: () { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest))); - }, + // workOrders.isEmpty ? + FutureBuilder( + future: _serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode), + builder: (context, snap) { + workOrders = snap.data as List; + if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator()); + if (snap.connectionState == ConnectionState.done && (snap.data?.length ?? 0) != 0) { + return SingleChildScrollView( + child: Column( + children: [ + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(21), + itemCount: workOrders.length, + separatorBuilder: (czt, index) => 21.height, + itemBuilder: (context, index) { + Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; + Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; + + return ElevatedButton( + style: ElevatedButton.styleFrom( + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), + primary: itemColor.withOpacity(.7), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), + ), + ), + //padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8), + onPressed: () { + // onPressed(request); + }, + child: Column( + children: [ + RequestInfoRow( + title: _subtitle.callId, + content: serviceRequest.requestCode, + ), + RequestInfoRow( + title: _subtitle.orderWorkNumber, + info: workOrders[index].workOrderNo.toString(), + ), + RequestInfoRow( + title: _subtitle.visitDate, + info: workOrders[index].visitDate, + ), + RequestInfoRow(title: _subtitle.assignedEmployee, info: workOrders[index].assignedEmployee?.name ?? ""), + RequestInfoRow( + title: _subtitle.assetSN, + info: workOrders[index].callRequest.asset.assetSerialNo, + ), + RequestInfoRow( + title: _subtitle.assetName, + info: workOrders[index].callRequest.asset.modelDefinition.assetName, + ), + RequestInfoRow( + title: _subtitle.assetNumber, + info: workOrders[index].callRequest.asset.assetNumber, + ), + RequestInfoRow( + title: _subtitle.model, + info: workOrders[index].callRequest.asset.modelDefinition.modelName, + ), + RequestInfoRow( + title: _subtitle.site, + info: workOrders[index].callRequest.asset.site.custName, + ), + RequestInfoRow( + title: "Call last Situation", + info: workOrders[index].currentSituation.name ?? '', + ), + _userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null + ? Padding( + padding: EdgeInsets.all(32), + child: AButton( + text: _subtitle.editServiceReport, + onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3 + ? null + : () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => FutureServiceReport( + request: serviceRequest, + workOrder: workOrders[index], + )), + ); + }, + ), + ) + : SizedBox.shrink(), + ], + ), + ); + }, + ), + if (_userProvider.user.type == UsersTypes.engineer) + Center( + child: Padding( + padding: const EdgeInsets.all(32), + child: AButton( + text: "Create Work Order", + onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3 + ? null + : () { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest))); + }, + ), + ), + ), + ], ), - ), - ), - ], - ); - } - }, - ), - ], - ), - ), - ], - ), + ); + } else { + return Column( + children: [ + Expanded( + child: Center( + child: ASubTitle(_subtitle.dataNotFound), + ), + ), + if (_userProvider.user.type == UsersTypes.engineer) + Center( + child: Padding( + padding: const EdgeInsets.all(32), + child: AButton( + text: "Create Work Order", + onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3 + ? null + : () { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest))); + }, + ), + ), + ), + ], + ); + } + }, + ), + ], + ), + ), + ], + ); + } + return const SizedBox(); + }), ), ), ); diff --git a/lib/views/pages/user/requests/requests_page.dart b/lib/views/pages/user/requests/requests_page.dart index a21debef..65f00cdb 100644 --- a/lib/views/pages/user/requests/requests_page.dart +++ b/lib/views/pages/user/requests/requests_page.dart @@ -15,6 +15,7 @@ import 'package:test_sa/views/widgets/search/service_request_search_bar.dart'; class ServiceRequestsPage extends StatefulWidget { static final String id = "/service-requests"; + @override _ServiceRequestsPageState createState() => _ServiceRequestsPageState(); } @@ -25,6 +26,7 @@ class _ServiceRequestsPageState extends State with TickerPr SettingProvider _settingProvider; bool _expandedSearch = false; bool _firstTime = true; + @override Widget build(BuildContext context) { _serviceRequestsProvider = Provider.of(context); diff --git a/lib/views/pages/user/visits/pantry/edit_pentry.dart b/lib/views/pages/user/visits/pantry/edit_pentry.dart index 744c0a20..a27b8308 100644 --- a/lib/views/pages/user/visits/pantry/edit_pentry.dart +++ b/lib/views/pages/user/visits/pantry/edit_pentry.dart @@ -22,6 +22,7 @@ import '../../../../widgets/pentry/pentry_info_form.dart'; class EditPentry extends StatefulWidget { final Pentry pentry; final Visit visit; + const EditPentry({Key key, this.pentry, this.visit}) : super(key: key); @override @@ -39,6 +40,7 @@ class _EditPentryState extends State with SingleTickerProviderStateM final GlobalKey _scaffoldKey = GlobalKey(); TabController _tabController; + _onSubmit() async { _validate = true; @@ -46,10 +48,9 @@ class _EditPentryState extends State with SingleTickerProviderStateM setState(() {}); return; } - _isLoading = true; setState(() {}); - + _pentry.clearEmptyObjects(); int status = await _regularVisitsProvider.updatePentry(user: _userProvider.user, host: _settingProvider.host, pentry: _pentry, visit: widget.visit); _isLoading = false; setState(() {}); @@ -145,6 +146,7 @@ class _EditPentryState extends State with SingleTickerProviderStateM PentryPMKitForm( models: _pentry.pmKits, enableValidate: _validate, + assetId: widget.visit?.deviceId, ), PentryInfoForm( model: _pentry, diff --git a/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart b/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart index 9dccd448..c841bbf3 100644 --- a/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart +++ b/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart @@ -21,6 +21,7 @@ import 'package:test_sa/views/widgets/visits/visits_list.dart'; class PreventiveMaintenanceVisitsPage extends StatefulWidget { static final String id = "/preventive-maintenance-visits"; + @override _PreventiveMaintenanceVisitsPageState createState() => _PreventiveMaintenanceVisitsPageState(); } diff --git a/lib/views/pages/user/visits/regular_visits_page.dart b/lib/views/pages/user/visits/regular_visits_page.dart index c6421bd9..c2ded666 100644 --- a/lib/views/pages/user/visits/regular_visits_page.dart +++ b/lib/views/pages/user/visits/regular_visits_page.dart @@ -21,6 +21,7 @@ import 'package:test_sa/views/widgets/visits/visits_list.dart'; class RegularVisitsPage extends StatefulWidget { static final String id = "/Regular-visits"; + @override _RegularVisitsPageState createState() => _RegularVisitsPageState(); } @@ -31,6 +32,7 @@ class _RegularVisitsPageState extends State with TickerProvid SettingProvider _settingProvider; bool _expandedSearch = false; Subtitle _subtitle; + @override Widget build(BuildContext context) { _visitsProvider = Provider.of(context); @@ -105,7 +107,7 @@ class _RegularVisitsPageState extends State with TickerProvid ), ), Visibility( - visible: _visitsProvider.visitsSearch.toMap().isNotEmpty, + visible: (_visitsProvider.visitsSearch.toMap()..remove("mostRecent")).isNotEmpty, child: Padding( padding: const EdgeInsets.all(8.0), child: AButton( diff --git a/lib/views/pages/user/visits/update_visits_group_sheet.dart b/lib/views/pages/user/visits/update_visits_group_sheet.dart index 7068b2aa..35e3e81a 100644 --- a/lib/views/pages/user/visits/update_visits_group_sheet.dart +++ b/lib/views/pages/user/visits/update_visits_group_sheet.dart @@ -1,10 +1,5 @@ -import 'package:flutter/material.dart'; -import 'dart:convert'; -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:test_sa/controllers/localization/localization.dart'; -import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/models/visits/visit.dart'; import 'package:test_sa/models/visits/visits_group.dart'; @@ -18,6 +13,7 @@ import 'package:test_sa/views/widgets/visits/visit_status.dart'; class UpdateVisitsGroupSheet extends StatefulWidget { final List visits; final String title; + const UpdateVisitsGroupSheet({Key key, this.visits, this.title}) : super(key: key); @override @@ -36,6 +32,7 @@ class _UpdateVisitsGroupSheetState extends State { // Lookup(name: "Failed", id: 1), // ]; VisitsGroup _group = VisitsGroup(); + // File _image; Subtitle _subtitle; diff --git a/lib/views/pages/user/visits/visit_details.dart b/lib/views/pages/user/visits/visit_details.dart index d6635358..e75e826d 100644 --- a/lib/views/pages/user/visits/visit_details.dart +++ b/lib/views/pages/user/visits/visit_details.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/localization/localization.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/models/visits/visit.dart'; import 'package:test_sa/views/app_style/colors.dart'; @@ -8,25 +9,25 @@ import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/pages/user/visits/pantry/edit_pentry.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_icon_button.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/images_list.dart'; -import 'package:test_sa/views/widgets/loaders/image_loader.dart'; import 'package:test_sa/views/widgets/requests/info_row.dart'; import 'package:test_sa/views/widgets/visits/visit_status.dart'; -import '../../../../controllers/providers/api/regular_visits_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart'; import '../../../../models/enums/user_types.dart'; +import '../../../widgets/loaders/image_loader.dart'; class VisitDetailsPage extends StatelessWidget { - static final String id = "/visit-details"; + static const String id = "/visit-details"; final Visit visit; const VisitDetailsPage({Key key, this.visit}) : super(key: key); + @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context).subtitle; - final regularVisitsProvider = Provider.of(context); - UserProvider _userProvider = Provider.of(context); + Subtitle subtitle = AppLocalization.of(context).subtitle; + UserProvider userProvider = Provider.of(context); return Scaffold( body: SafeArea( @@ -37,80 +38,87 @@ class VisitDetailsPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), child: Row( children: [ - ABackButton(), + const ABackButton(), Expanded( child: Center( child: Text( - _subtitle.visitInformation, - style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic), + subtitle.visitInformation, + style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), ), - if (_userProvider?.user?.type == UsersTypes.engineer) + if (userProvider?.user?.type == UsersTypes.engineer) AIconButton( iconData: Icons.edit, color: AColors.white, buttonSize: 42, backgroundColor: AColors.green, - onPressed: () async { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => EditPentry( - visit: visit, - pentry: visit.pentry, - ))); - }, + onPressed: visit?.status?.name == "Closed" || visit?.status?.name == "Complete" + ? null + : () async { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => EditPentry( + visit: visit, + pentry: visit.pentry, + ), + ), + ); + }, ), - SizedBox(width: 42) + const SizedBox(width: 42) ], ), ), Expanded( child: ListView( - padding: EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 16), children: [ - SizedBox( - height: 8, - ), - MaterialButton( - padding: EdgeInsets.zero, - onPressed: visit.images.isEmpty || (visit.images?.first?.isEmpty ?? false) - ? () {} - : () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => Scaffold( - body: InteractiveViewer( - child: Center( - child: ImageLoader( - url: visit.images.first, - boxFit: BoxFit.contain, - ), - ), - ), - ))); - }, - child: SizedBox( - height: 140 * AppStyle.getScaleFactor(context), - width: MediaQuery.of(context).size.width, - child: ImageLoader( - url: visit.images.isEmpty ? " " : visit.images.first, - boxFit: BoxFit.cover, + const SizedBox(height: 8), + // MaterialButton( + // padding: EdgeInsets.zero, + // onPressed: () { + // if ((visit.images?.isNotEmpty ?? false) && (visit.images?.first?.isNotEmpty ?? false)) { + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (_) => Scaffold( + // body: InteractiveViewer( + // child: Center( + // child: ImageLoader( + // url: visit.images.first, + // boxFit: BoxFit.contain, + // ), + // ), + // ), + // ), + // ), + // ); + // } + // }, + // child: SizedBox( + // height: 140 * AppStyle.getScaleFactor(context), + // width: MediaQuery.of(context).size.width, + // child: ImageLoader( + // url: visit.images.isEmpty ? " " : visit.images.first, + // boxFit: BoxFit.cover, + // ), + // ), + // ), + // const SizedBox( + // height: 8, + // ), + if (visit?.images?.isNotEmpty ?? false) + SizedBox( + height: 60 * AppStyle.getScaleFactor(context), + child: FilesList( + images: visit.images, ), - ), - ), - SizedBox( - height: 8, - ), - SizedBox( - height: 60 * AppStyle.getScaleFactor(context), - child: ImagesList( - images: visit.images, - ), - ), - SizedBox( + ).paddingOnly(top: 4, bottom: 4), + const SizedBox( height: 8, ), RequestInfoRow( - title: _subtitle.code, + title: subtitle.code, info: visit.serialNumber, ), RequestInfoRow( @@ -118,23 +126,27 @@ class VisitDetailsPage extends StatelessWidget { info: visit.deviceNumber, ), RequestInfoRow( - title: _subtitle.deviceSN, + title: subtitle.deviceName, + content: visit.deviceEnglishName, + ), + RequestInfoRow( + title: subtitle.deviceSN, info: visit.deviceSerialNumber, ), RequestInfoRow( - title: _subtitle.expectDate, + title: subtitle.expectDate, info: visit.expectDate, ), RequestInfoRow( - title: _subtitle.actualDate, + title: subtitle.actualDate, info: visit.actualDate, ), Row( children: [ Expanded( child: Text( - "${_subtitle.status} : ", - style: Theme.of(context).textTheme.subtitle1.copyWith(fontWeight: FontWeight.bold), + "${subtitle.status} : ", + style: Theme.of(context).textTheme.titleMedium.copyWith(fontWeight: FontWeight.bold), textScaleFactor: AppStyle.getScaleFactor(context), ), ), @@ -147,21 +159,17 @@ class VisitDetailsPage extends StatelessWidget { color: Theme.of(context).primaryColor, ), RequestInfoRow( - title: _subtitle.contactStatus, + title: subtitle.contactStatus, info: visit.assignTo, ), RequestInfoRow( - title: _subtitle.engineerName, + title: subtitle.engineerName, info: visit.employName, ), RequestInfoRow( - title: _subtitle.hospital, + title: subtitle.hospital, content: visit.hospitalName, ), - RequestInfoRow( - title: _subtitle.deviceName, - content: visit.deviceEnglishName, - ), ], ), ), diff --git a/lib/views/widgets/buttons/app_flat_button.dart b/lib/views/widgets/buttons/app_flat_button.dart index b154ac4d..946a167f 100644 --- a/lib/views/widgets/buttons/app_flat_button.dart +++ b/lib/views/widgets/buttons/app_flat_button.dart @@ -9,6 +9,7 @@ class AFlatButton extends StatelessWidget { final VoidCallback onPressed; const AFlatButton({Key key, this.text, this.textColor, this.style, this.onPressed, this.padding}) : super(key: key); + @override Widget build(BuildContext context) { return TextButton( diff --git a/lib/views/widgets/buttons/app_small_button.dart b/lib/views/widgets/buttons/app_small_button.dart index 44073d64..15ad3cfd 100644 --- a/lib/views/widgets/buttons/app_small_button.dart +++ b/lib/views/widgets/buttons/app_small_button.dart @@ -9,6 +9,7 @@ class ASmallButton extends StatelessWidget { final VoidCallback onPressed; const ASmallButton({Key key, this.text, this.style, this.onPressed, this.padding, this.color}) : super(key: key); + @override Widget build(BuildContext context) { return ElevatedButton( diff --git a/lib/views/widgets/date_and_time/date_picker.dart b/lib/views/widgets/date_and_time/date_picker.dart index 54c4ef8c..09f66465 100644 --- a/lib/views/widgets/date_and_time/date_picker.dart +++ b/lib/views/widgets/date_and_time/date_picker.dart @@ -6,8 +6,9 @@ class ADatePicker extends StatelessWidget { final DateTime from; final DateTime to; final Function(DateTime) onDatePicker; + final bool enable; - const ADatePicker({Key key, this.date, this.onDatePicker, this.from, this.to}) : super(key: key); + const ADatePicker({Key key, this.date, this.onDatePicker, this.from, this.to, this.enable = true}) : super(key: key); @override Widget build(BuildContext context) { @@ -19,14 +20,16 @@ class ADatePicker extends StatelessWidget { borderRadius: BorderRadius.circular(12 * AppStyle.getScaleFactor(context)), ), ), + onPressed: enable + ? () async { + DateTime picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: from ?? DateTime.now(), lastDate: to ?? DateTime.now().add(Duration(days: 365))); + onDatePicker(picked); + } + : null, child: Text( date == null ? "Pick Date" : date.toString().split(" ").first, textScaleFactor: AppStyle.getScaleFactor(context), ), - onPressed: () async { - DateTime picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: from ?? DateTime.now(), lastDate: to ?? DateTime.now().add(Duration(days: 365))); - onDatePicker(picked); - }, ); } } diff --git a/lib/views/widgets/date_and_time/from_to_date_bar.dart b/lib/views/widgets/date_and_time/from_to_date_bar.dart index 1288c743..fb222b68 100644 --- a/lib/views/widgets/date_and_time/from_to_date_bar.dart +++ b/lib/views/widgets/date_and_time/from_to_date_bar.dart @@ -12,6 +12,7 @@ class FromToDateBar extends StatefulWidget { final Function(DateTime) onPickTo; const FromToDateBar({Key key, this.from, this.to, this.onPickFrom, this.onPickTo}) : super(key: key); + @override _FromToDateBarState createState() => _FromToDateBarState(); } diff --git a/lib/views/widgets/date_and_time/time_picker.dart b/lib/views/widgets/date_and_time/time_picker.dart index 63648225..ea079428 100644 --- a/lib/views/widgets/date_and_time/time_picker.dart +++ b/lib/views/widgets/date_and_time/time_picker.dart @@ -6,8 +6,10 @@ class ADateTimePicker extends StatelessWidget { 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}) : super(key: key); + + const ADateTimePicker({Key key, this.date, this.onDateTimePicker, this.from, this.to, this.enable}) : super(key: key); @override Widget build(BuildContext context) { @@ -23,10 +25,10 @@ class ADateTimePicker extends StatelessWidget { date == null ? "Pick Time" : date.toString().substring(0, date.toString().lastIndexOf(":")), textScaleFactor: AppStyle.getScaleFactor(context), ), - onPressed: () async { + onPressed: enable? () async { // TimeOfDay picked = await showTimePicker(context: context, initialTime: TimeOfDay.now()); onDateTimePicker(await showDateTimePicker(context: context, initialDate: date, firstDate: from, lastDate: to)); - }, + }: null, ); } } diff --git a/lib/views/widgets/departments/department_button.dart b/lib/views/widgets/departments/department_button.dart index 47bc81ce..5aa8b0e4 100644 --- a/lib/views/widgets/departments/department_button.dart +++ b/lib/views/widgets/departments/department_button.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/models/department.dart'; import 'package:test_sa/models/subtitle.dart'; diff --git a/lib/views/widgets/departments/department_item.dart b/lib/views/widgets/departments/department_item.dart index 4474af62..c578ba17 100644 --- a/lib/views/widgets/departments/department_item.dart +++ b/lib/views/widgets/departments/department_item.dart @@ -8,6 +8,7 @@ class DepartmentItem extends StatelessWidget { final Function(Department) onPressed; const DepartmentItem({Key key, this.department, this.onPressed}) : super(key: key); + @override Widget build(BuildContext context) { return Padding( diff --git a/lib/views/widgets/departments/single_department_picker.dart b/lib/views/widgets/departments/single_department_picker.dart index d055a873..c1d56fdd 100644 --- a/lib/views/widgets/departments/single_department_picker.dart +++ b/lib/views/widgets/departments/single_department_picker.dart @@ -13,6 +13,7 @@ import '../app_text_form_field.dart'; class SingleDepartmentPicker extends StatefulWidget { static final String id = "/single-Department-Picker"; + @override _SingleDepartmentPickerState createState() => _SingleDepartmentPickerState(); } @@ -22,6 +23,7 @@ class _SingleDepartmentPickerState extends State { SettingProvider _settingProvider; List _searchableList = []; bool _firstTime = true; + @override Widget build(BuildContext context) { _departmentsProvider = Provider.of(context); diff --git a/lib/views/widgets/device_trancfer/device_transfer_info_section.dart b/lib/views/widgets/device_trancfer/device_transfer_info_section.dart index ea699121..29f519f3 100644 --- a/lib/views/widgets/device_trancfer/device_transfer_info_section.dart +++ b/lib/views/widgets/device_trancfer/device_transfer_info_section.dart @@ -8,17 +8,19 @@ import 'package:test_sa/views/widgets/requests/info_row.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; import '../../../controllers/providers/api/user_provider.dart'; +import '../images/multi_image_picker.dart'; class DeviceTransferInfoSection extends StatelessWidget { final DeviceTransferInfo info; + final bool isSender; final VoidCallback onEdit; - const DeviceTransferInfoSection({Key key, this.info, this.onEdit}) : super(key: key); + const DeviceTransferInfoSection({Key key, this.info, this.onEdit, this.isSender}) : super(key: key); @override Widget build(BuildContext context) { info.userName = Provider.of(context).user.username; final subtitle = AppLocalization.of(context).subtitle; - print("url:${info.signature}"); + info.attachments ??= []; return Column( children: [ RequestInfoRow( @@ -29,10 +31,10 @@ class DeviceTransferInfoSection extends StatelessWidget { title: subtitle.department, info: info.department.name, ), - RequestInfoRow( - title: subtitle.engineerName, - info: info.userName, - ), + // RequestInfoRow( + // title: isSender ? "Sender Name " : "Receiver Name", + // info: info.userName, + // ), RequestInfoRow( title: subtitle.workingHours, info: info.workingHours, @@ -46,17 +48,21 @@ class DeviceTransferInfoSection extends StatelessWidget { info: info.comment, ), RequestInfoRow( - title: "Assigned FE", + title: "Assigned Engineer", info: info.assignedEmployeeName, ), RequestInfoRow( title: "Signature", - info: info.signature?.isEmpty != false ? subtitle.noDateFound : null, - contentWidget: info.signature?.isEmpty != false - ? null - : ImageLoader( - url: info.signature, - ), + info: info.engSignature?.isEmpty != false ? subtitle.noDateFound : null, + contentWidget: info.engSignature?.isEmpty != false ? null : ImageLoader(url: info.engSignature), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: MultiFilesPicker( + label: "Attachments", + files: info.attachments, + enabled: false, + ), ), RequestInfoRow( title: subtitle.status, diff --git a/lib/views/widgets/device_trancfer/device_transfer_list.dart b/lib/views/widgets/device_trancfer/device_transfer_list.dart index dd6f0212..a90c74aa 100644 --- a/lib/views/widgets/device_trancfer/device_transfer_list.dart +++ b/lib/views/widgets/device_trancfer/device_transfer_list.dart @@ -16,7 +16,7 @@ class DeviceTransferList extends StatelessWidget { @override Widget build(BuildContext context) { - if (items.length == 0) { + if (items.isEmpty) { Subtitle subtitle = AppLocalization.of(context).subtitle; return NoItemFound( message: subtitle.noServiceRequestFound, @@ -33,11 +33,8 @@ class DeviceTransferList extends StatelessWidget { return DeviceTransferItem( index: itemIndex, item: items[itemIndex], - onPressed: (model) { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => DeviceTransferDetails( - model: model, - ))); + onPressed: (model) async { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => DeviceTransferDetails(model: model))); }, ); }), diff --git a/lib/views/widgets/equipment/device_button.dart b/lib/views/widgets/equipment/device_button.dart index 824547d2..8a8b78c0 100644 --- a/lib/views/widgets/equipment/device_button.dart +++ b/lib/views/widgets/equipment/device_button.dart @@ -56,6 +56,20 @@ class DeviceButton extends StatelessWidget { subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Divider( + color: Theme.of(context).textTheme.subtitle1.color, + ), + Text( + "${_subtitle.assetNumber} : ${device.number}", + style: Theme.of(context).textTheme.subtitle2, + ), + Divider( + color: Theme.of(context).textTheme.subtitle1.color, + ), + Text( + "${_subtitle.assetName} : ${device.modelDefinition.assetName}", + style: Theme.of(context).textTheme.subtitle2, + ), Divider( color: Theme.of(context).textTheme.subtitle1.color, ), diff --git a/lib/views/widgets/equipment/device_item.dart b/lib/views/widgets/equipment/device_item.dart index 0dd41e75..19838675 100644 --- a/lib/views/widgets/equipment/device_item.dart +++ b/lib/views/widgets/equipment/device_item.dart @@ -10,6 +10,7 @@ class DeviceItem extends StatelessWidget { final Function(Device) onPressed; const DeviceItem({Key key, this.device, this.onPressed}) : super(key: key); + @override Widget build(BuildContext context) { Subtitle _subtitle = AppLocalization.of(context).subtitle; diff --git a/lib/views/widgets/equipment/single_device_picker.dart b/lib/views/widgets/equipment/single_device_picker.dart index 508601bd..2acfae14 100644 --- a/lib/views/widgets/equipment/single_device_picker.dart +++ b/lib/views/widgets/equipment/single_device_picker.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/controllers/providers/api/devices_provider.dart'; @@ -18,6 +17,7 @@ import '../qr/scan_qr.dart'; class SingleDevicePicker extends StatefulWidget { static final String id = "/single-device-Picker"; final bool sandraChoice = true; + @override _SingleDevicePickerState createState() => _SingleDevicePickerState(); } @@ -33,12 +33,19 @@ class _SingleDevicePickerState extends State { TextEditingController numberController = TextEditingController(); TextEditingController snController = TextEditingController(); - _getDevice(String result) async { - print(result); + + _getDevice(String result, {bool isQr = false}) async { if (result == null) return; // List devices = await _devicesProvider.getDevicesListBySN(host: _settingProvider.host, user: _userProvider.user, hospitalId: _userProvider.user.clientId, sn: result); _devicesProvider.reset(); - await _devicesProvider.getEquipment(user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: "", number: result); + await _devicesProvider.getEquipment( + user: _userProvider.user, + host: _settingProvider.host, + hospitalId: _userProvider.user.clientId, + serialNumber: "", + number: result, + isQr: isQr, + ); _searchableList.clear(); _searchableList.addAll(_devicesProvider.devices); // Navigator.of(context).pop(); @@ -163,7 +170,7 @@ class _SingleDevicePickerState extends State { String result = await Navigator.of(context).push( MaterialPageRoute(builder: (_) => const ScanQr()), ) as String; - _getDevice(result); + _getDevice(result, isQr: true); }, ), ); diff --git a/lib/views/widgets/gas_refill/building_type_menu.dart b/lib/views/widgets/gas_refill/building_type_menu.dart index 2043f157..b11b48d2 100644 --- a/lib/views/widgets/gas_refill/building_type_menu.dart +++ b/lib/views/widgets/gas_refill/building_type_menu.dart @@ -3,12 +3,22 @@ import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; +import '../loaders/app_loading.dart'; + class BuildingTypeMenu extends StatefulWidget { final Function(Buildings) onSelect; Buildings initialValue; List building; + bool enabled, loading; - BuildingTypeMenu({Key key, this.onSelect, this.initialValue, this.building = const []}) : super(key: key); + BuildingTypeMenu({ + Key key, + this.onSelect, + this.initialValue, + this.building = const [], + this.enabled = true, + this.loading = false, + }) : super(key: key); @override _BuildingTypeMenuState createState() { @@ -47,50 +57,55 @@ class _BuildingTypeMenuState extends State { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: AColors.inputFieldBackgroundColor, - border: Border.all( - color: Color(0xffefefef), - ), - borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), - // boxShadow: const [ - // AppStyle.boxShadow - // ] - ), - child: DropdownButton( - value: _selectedBuilding, - iconSize: 24, - icon: const Icon(Icons.keyboard_arrow_down_rounded), - elevation: 0, - isExpanded: true, - hint: Text( - "Select Building", - style: Theme.of(context).textTheme.subtitle1, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: const Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: const [ + // AppStyle.boxShadow + // ] ), - style: TextStyle(color: Theme.of(context).primaryColor), - underline: SizedBox.shrink(), - onChanged: (Buildings newValue) { - setState(() { - _selectedBuilding = newValue; - }); - widget.onSelect(newValue); - }, - items: _building?.map>((Buildings value) { - return DropdownMenuItem( - value: value, - child: Text( - value.name, - style: Theme.of(context).textTheme.subtitle1.copyWith( - color: Theme.of(context).primaryColor, - fontSize: 11, - //fontWeight: FontWeight.bold - ), - ), - ); - })?.toList() ?? - [], - ), - ); + child: widget.loading + ? const Padding(padding: EdgeInsets.all(8.0), child: ALoading()) + : (widget.enabled && (_building?.isEmpty ?? false)) || (!widget.enabled) + ? ListTile( + title: Center(child: Text(widget.initialValue?.name ?? "")), + ) + : DropdownButton( + value: _selectedBuilding, + iconSize: 24, + icon: const Icon(Icons.keyboard_arrow_down_rounded), + elevation: 0, + isExpanded: true, + hint: Text( + "Select Building", + style: Theme.of(context).textTheme.subtitle1, + ), + style: TextStyle(color: Theme.of(context).primaryColor), + underline: const SizedBox.shrink(), + onChanged: (Buildings newValue) { + setState(() { + _selectedBuilding = newValue; + }); + widget.onSelect(newValue); + }, + items: _building?.map>((Buildings value) { + return DropdownMenuItem( + value: value, + child: Text( + value.name ?? "", + style: Theme.of(context).textTheme.subtitle1.copyWith( + color: Theme.of(context).primaryColor, + fontSize: 11, + //fontWeight: FontWeight.bold + ), + ), + ); + })?.toList() ?? + [], + )); } } diff --git a/lib/views/widgets/gas_refill/department_type_menu.dart b/lib/views/widgets/gas_refill/department_type_menu.dart index 1b58c200..06cdfcdf 100644 --- a/lib/views/widgets/gas_refill/department_type_menu.dart +++ b/lib/views/widgets/gas_refill/department_type_menu.dart @@ -3,12 +3,22 @@ import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; +import '../loaders/app_loading.dart'; + class DepartmentTypeMenu extends StatefulWidget { final Function(Departments) onSelect; Departments initialValue; List departments; + bool enabled, loading; - DepartmentTypeMenu({Key key, this.onSelect, this.initialValue, this.departments = const []}) : super(key: key); + DepartmentTypeMenu({ + Key key, + this.onSelect, + this.initialValue, + this.departments = const [], + this.enabled = true, + this.loading = false, + }) : super(key: key); @override _DepartmentTypeMenuState createState() { @@ -58,39 +68,45 @@ class _DepartmentTypeMenuState extends State { // AppStyle.boxShadow // ] ), - child: DropdownButton( - value: _selected, - iconSize: 24, - icon: const Icon(Icons.keyboard_arrow_down_rounded), - elevation: 0, - isExpanded: true, - hint: Text( - "Select Department", - style: Theme.of(context).textTheme.subtitle1, - ), - style: TextStyle(color: Theme.of(context).primaryColor), - underline: SizedBox.shrink(), - onChanged: (Departments newValue) { - setState(() { - _selected = newValue; - }); - widget.onSelect(newValue); - }, - items: widget?.departments?.map>((Departments value) { - return DropdownMenuItem( - value: value, - child: Text( - value.name, - style: Theme.of(context).textTheme.subtitle1.copyWith( - color: Theme.of(context).primaryColor, - fontSize: 11, - //fontWeight: FontWeight.bold - ), + child: widget.loading + ? const Padding(padding: EdgeInsets.all(8.0), child: ALoading()) + : (widget.enabled && (_departments?.isEmpty ?? false)) || (!widget.enabled) + ? ListTile( + title: Center(child: Text(widget.initialValue?.name ?? "")), + ) + : DropdownButton( + value: _selected, + iconSize: 24, + icon: const Icon(Icons.keyboard_arrow_down_rounded), + elevation: 0, + isExpanded: true, + hint: Text( + "Select Department", + style: Theme.of(context).textTheme.subtitle1, + ), + style: TextStyle(color: Theme.of(context).primaryColor), + underline: SizedBox.shrink(), + onChanged: (Departments newValue) { + setState(() { + _selected = newValue; + }); + widget.onSelect(newValue); + }, + items: widget?.departments?.map>((Departments value) { + return DropdownMenuItem( + value: value, + child: Text( + value?.name ?? "", + style: Theme.of(context).textTheme.subtitle1.copyWith( + color: Theme.of(context).primaryColor, + fontSize: 11, + //fontWeight: FontWeight.bold + ), + ), + ); + })?.toList() ?? + [], ), - ); - })?.toList() ?? - [], - ), ); } } diff --git a/lib/views/widgets/gas_refill/floor_type_menu.dart b/lib/views/widgets/gas_refill/floor_type_menu.dart index e8fe78f7..dcc80c81 100644 --- a/lib/views/widgets/gas_refill/floor_type_menu.dart +++ b/lib/views/widgets/gas_refill/floor_type_menu.dart @@ -3,12 +3,23 @@ import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; +import '../loaders/app_loading.dart'; + class FloorTypeMenu extends StatefulWidget { final Function(Floors) onSelect; Floors initialValue; List floors; + bool enabled; + bool loading; - FloorTypeMenu({Key key, this.onSelect, this.initialValue, this.floors = const []}) : super(key: key); + FloorTypeMenu({ + Key key, + this.onSelect, + this.initialValue, + this.floors = const [], + this.enabled = true, + this.loading = false, + }) : super(key: key); @override _FloorTypeMenuState createState() { @@ -51,46 +62,52 @@ class _FloorTypeMenuState extends State { decoration: BoxDecoration( color: AColors.inputFieldBackgroundColor, border: Border.all( - color: Color(0xffefefef), + color: const Color(0xffefefef), ), borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), // boxShadow: const [ // AppStyle.boxShadow // ] ), - child: DropdownButton( - value: _selected, - iconSize: 24, - icon: const Icon(Icons.keyboard_arrow_down_rounded), - elevation: 0, - isExpanded: true, - hint: Text( - "Select Floor", - style: Theme.of(context).textTheme.subtitle1, - ), - style: TextStyle(color: Theme.of(context).primaryColor), - underline: SizedBox.shrink(), - onChanged: (Floors newValue) { - setState(() { - _selected = newValue; - }); - widget.onSelect(newValue); - }, - items: _floors?.map>((Floors value) { - return DropdownMenuItem( - value: value, - child: Text( - value.name, - style: Theme.of(context).textTheme.subtitle1.copyWith( - color: Theme.of(context).primaryColor, - fontSize: 11, - //fontWeight: FontWeight.bold - ), + child: widget.loading + ? const Padding(padding: EdgeInsets.all(8.0), child: ALoading()) + : (widget.enabled && (_floors?.isEmpty ?? false)) || (!widget.enabled) + ? ListTile( + title: Center(child: Text(widget.initialValue?.name ?? "")), + ) + : DropdownButton( + value: _selected, + iconSize: 24, + icon: const Icon(Icons.keyboard_arrow_down_rounded), + elevation: 0, + isExpanded: true, + hint: Text( + "Select Floor", + style: Theme.of(context).textTheme.subtitle1, + ), + style: TextStyle(color: Theme.of(context).primaryColor), + underline: const SizedBox.shrink(), + onChanged: (Floors newValue) { + setState(() { + _selected = newValue; + }); + widget.onSelect(newValue); + }, + items: _floors?.map>((Floors value) { + return DropdownMenuItem( + value: value, + child: Text( + value.name ?? "", + style: Theme.of(context).textTheme.subtitle1.copyWith( + color: Theme.of(context).primaryColor, + fontSize: 11, + //fontWeight: FontWeight.bold + ), + ), + ); + })?.toList() ?? + [], ), - ); - })?.toList() ?? - [], - ), ); } } diff --git a/lib/views/widgets/gas_refill/gas_refill_item.dart b/lib/views/widgets/gas_refill/gas_refill_item.dart index 0ad575c1..17b2f38a 100644 --- a/lib/views/widgets/gas_refill/gas_refill_item.dart +++ b/lib/views/widgets/gas_refill/gas_refill_item.dart @@ -1,11 +1,7 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:test_sa/controllers/localization/localization.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/models/gas_refill/gas_refill_model.dart'; import 'package:test_sa/models/subtitle.dart'; -import 'package:test_sa/models/user.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; @@ -14,12 +10,12 @@ class GasRefillItem extends StatelessWidget { final int index; final GasRefillModel item; final Function(GasRefillModel) onPressed; + const GasRefillItem({Key key, this.item, this.onPressed, this.index}) : super(key: key); @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context).subtitle; - User _user = Provider.of(context, listen: false).user; + Subtitle subtitle = AppLocalization.of(context).subtitle; Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; @@ -27,7 +23,7 @@ class GasRefillItem extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 4), child: ElevatedButton( style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8), backgroundColor: itemColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), @@ -48,14 +44,14 @@ class GasRefillItem extends StatelessWidget { children: [ Text( item.title ?? "-----", - style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold), ), Row( children: [ Expanded( child: Text( - _subtitle.hospital, - style: Theme.of(context).textTheme.subtitle2.copyWith( + subtitle.hospital, + style: Theme.of(context).textTheme.titleSmall.copyWith( color: onItemColor, ), ), @@ -63,29 +59,48 @@ class GasRefillItem extends StatelessWidget { if (item.clientName != null) Text( item.clientName, - style: Theme.of(context).textTheme.subtitle2.copyWith( + style: Theme.of(context).textTheme.titleSmall.copyWith( color: onItemColor, ), ), ], ), - Divider( - color: onItemColor, - ), + Divider(color: onItemColor), Row( children: [ Expanded( - child: Text( - _subtitle.status, - style: Theme.of(context).textTheme.subtitle2.copyWith( - color: onItemColor, - ), - ), + child: Text(subtitle.status, style: Theme.of(context).textTheme.titleSmall.copyWith(color: onItemColor)), ), if (item.status?.id != null) StatusLabel(label: item.status.name, color: AColors.getGasStatusColor(item.status.id)), ], ), - //Divider(color: onItemColor,), + if (item?.expectedDate != null) Divider(color: onItemColor), + if (item?.expectedDate != null) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("Expected Date", style: Theme.of(context).textTheme.titleSmall.copyWith(color: onItemColor)), + Text(item.expectedDate.toIso8601String().split("T").first, style: Theme.of(context).textTheme.titleSmall.copyWith(color: onItemColor)), + ], + ), + if (item?.details?.isNotEmpty ?? false) Divider(color: onItemColor), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (item?.details?.isNotEmpty ?? false) Text("Gas Type", style: Theme.of(context).textTheme.titleSmall.copyWith(color: onItemColor)), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: item.details + .map( + (gas) => gas?.type?.name?.isNotEmpty ?? false + ? Text(gas?.type?.name, style: Theme.of(context).textTheme.titleSmall.copyWith(color: onItemColor)) + : const SizedBox.shrink(), + ) + .toList(), + ) + ], + ), ], ), ), diff --git a/lib/views/widgets/gas_refill/gas_refill_list.dart b/lib/views/widgets/gas_refill/gas_refill_list.dart index b6f58e83..f805e67c 100644 --- a/lib/views/widgets/gas_refill/gas_refill_list.dart +++ b/lib/views/widgets/gas_refill/gas_refill_list.dart @@ -7,37 +7,45 @@ import 'package:test_sa/views/widgets/gas_refill/gas_refill_item.dart'; import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_item_found.dart'; -class GasRefillList extends StatelessWidget { +class GasRefillList extends StatefulWidget { final List items; final bool nextPage; final Future Function() onLazyLoad; const GasRefillList({Key key, this.items, this.nextPage, this.onLazyLoad}) : super(key: key); + @override + State createState() => _GasRefillListState(); +} + +class _GasRefillListState extends State { @override Widget build(BuildContext context) { - if (items.length == 0) { + if (widget.items.length == 0) { Subtitle subtitle = AppLocalization.of(context).subtitle; return NoItemFound( message: subtitle.noServiceRequestFound, ); } return LazyLoading( - nextPage: nextPage, - onLazyLoad: onLazyLoad, + nextPage: widget.nextPage, + onLazyLoad: widget.onLazyLoad, child: ListView.builder( //physics: const BouncingScrollPhysics(), - itemCount: items.length, + itemCount: widget.items.length, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), itemBuilder: (context, itemIndex) { return GasRefillItem( index: itemIndex, - item: items[itemIndex], + item: widget.items[itemIndex], onPressed: (model) { Navigator.of(context).push(MaterialPageRoute( builder: (_) => GasRefillDetails( model: model, - ))); + ))).then((value) { + model=value; + setState(() {}); + }); }, ); }), diff --git a/lib/views/widgets/hospitals/hospital_auto_complete_field.dart b/lib/views/widgets/hospitals/hospital_auto_complete_field.dart index ea4d662a..a8ae2f22 100644 --- a/lib/views/widgets/hospitals/hospital_auto_complete_field.dart +++ b/lib/views/widgets/hospitals/hospital_auto_complete_field.dart @@ -12,6 +12,7 @@ import 'package:test_sa/views/app_style/sizing.dart'; class HospitalAutoCompleteField extends StatefulWidget { final String initialValue; final Function(Hospital) onSearch; + //final Function(Hospital) onSave; const HospitalAutoCompleteField({ diff --git a/lib/views/widgets/hospitals/hospital_auto_complete_field_new.dart b/lib/views/widgets/hospitals/hospital_auto_complete_field_new.dart index 1bc29fd6..6ca612a4 100644 --- a/lib/views/widgets/hospitals/hospital_auto_complete_field_new.dart +++ b/lib/views/widgets/hospitals/hospital_auto_complete_field_new.dart @@ -8,10 +8,12 @@ import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; class HospitalAutoCompleteField extends StatefulWidget { final String initialValue; final Function(Hospital) onSearch; + final bool enabled; //final Function(Hospital) onSave; @@ -19,6 +21,7 @@ class HospitalAutoCompleteField extends StatefulWidget { Key key, this.onSearch, this.initialValue, + this.enabled = true, }) : super(key: key); @override @@ -66,32 +69,41 @@ class _HospitalAutoCompleteFieldState extends State { // AppStyle.boxShadow // ] ), - child: TypeAheadField( - textFieldConfiguration: TextFieldConfiguration( - style: Theme.of(context).textTheme.headline6, - controller: _controller, - textAlign: TextAlign.center, - decoration: InputDecoration( - hintText: _subtitle.hospital, - border: InputBorder.none, - disabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - ), - textInputAction: TextInputAction.search, - ), - suggestionsCallback: (vale) async { - return await HospitalsProvider().getHospitalsListByVal(searchVal: _controller.text); - }, - itemBuilder: (context, hospital) { - return ListTile( - title: Text(hospital.name), - ); - }, - onSuggestionSelected: (hospital) { - widget.onSearch(hospital); - }, - ), + child: widget.enabled + ? TypeAheadField( + textFieldConfiguration: TextFieldConfiguration( + style: Theme.of(context).textTheme.headline6, + controller: _controller, + textAlign: TextAlign.center, + decoration: InputDecoration( + hintText: _subtitle.hospital, + border: InputBorder.none, + disabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + textInputAction: TextInputAction.search, + ), + suggestionsCallback: (vale) async { + return await HospitalsProvider().getHospitalsListByVal(searchVal: _controller.text); + }, + itemBuilder: (context, hospital) { + return ListTile( + title: Text(hospital.name), + ); + }, + onSuggestionSelected: (hospital) { + widget.onSearch(hospital); + }, + ) + : widget.initialValue == null + ? const Padding( + padding: EdgeInsets.all(8.0), + child: ALoading(), + ) + : ListTile( + title: Center(child: Text(widget.initialValue)), + ), ); } } diff --git a/lib/views/widgets/hospitals/hospital_button.dart b/lib/views/widgets/hospitals/hospital_button.dart index 86fb867e..33ce319c 100644 --- a/lib/views/widgets/hospitals/hospital_button.dart +++ b/lib/views/widgets/hospitals/hospital_button.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/subtitle.dart'; diff --git a/lib/views/widgets/hospitals/hospital_item.dart b/lib/views/widgets/hospitals/hospital_item.dart index 02281449..bc1a1615 100644 --- a/lib/views/widgets/hospitals/hospital_item.dart +++ b/lib/views/widgets/hospitals/hospital_item.dart @@ -8,6 +8,7 @@ class HospitalItem extends StatelessWidget { final Function(Hospital) onPressed; const HospitalItem({Key key, this.hospital, this.onPressed}) : super(key: key); + @override Widget build(BuildContext context) { return Padding( diff --git a/lib/views/widgets/hospitals/single_hospital_picker.dart b/lib/views/widgets/hospitals/single_hospital_picker.dart index 244166f6..afe1f924 100644 --- a/lib/views/widgets/hospitals/single_hospital_picker.dart +++ b/lib/views/widgets/hospitals/single_hospital_picker.dart @@ -14,6 +14,7 @@ import '../app_text_form_field.dart'; class SingleHospitalPicker extends StatefulWidget { static final String id = "/single-Hospital-Picker"; final bool sandraChoice = true; + @override _SingleHospitalPickerState createState() => _SingleHospitalPickerState(); } @@ -23,6 +24,7 @@ class _SingleHospitalPickerState extends State { SettingProvider _settingProvider; List _searchableList = []; bool _firstTime = true; + @override Widget build(BuildContext context) { _hospitalsProvider = Provider.of(context); diff --git a/lib/views/widgets/images/files_list.dart b/lib/views/widgets/images/files_list.dart new file mode 100644 index 00000000..d7f21dff --- /dev/null +++ b/lib/views/widgets/images/files_list.dart @@ -0,0 +1,83 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:open_file/open_file.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; +import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; +import 'package:test_sa/views/widgets/loaders/image_loader.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'image_item.dart'; +import 'images_viewer.dart'; + +class FilesList extends StatelessWidget { + final List images; + final EdgeInsets padding; + + const FilesList({Key key, this.images, this.padding}) : super(key: key); + + @override + Widget build(BuildContext context) { + + return ListView.separated( + padding: padding ?? EdgeInsets.symmetric(horizontal: 32 * AppStyle.getScaleFactor(context)), + scrollDirection: Axis.horizontal, + itemCount: images?.length ?? 0, + separatorBuilder: (context, itemIndex) => 8.width, + itemBuilder: (context, itemIndex) { + if (images[itemIndex] == null || !images[itemIndex].contains(".")) { + return Text("Bad\nFile"); + } + var isImage = + images[itemIndex].split(".").last.toLowerCase() == "png" || images[itemIndex].split(".").last.toLowerCase() == "jpg" || images[itemIndex].split(".").last.toLowerCase() == "jpeg"; + var isPdf = images[itemIndex].split(".").last.toLowerCase() == "pdf"; + var isExcel = images[itemIndex].split(".").last.toLowerCase() == "xlsx"; + + return (isImage + ? (_isLocalUrl(images[itemIndex]) + ? Image.file(File(images[itemIndex])) + : ImageLoader( + url: images[itemIndex], + boxFit: BoxFit.cover, + )) + : Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")) + .onPress(() async { + if (isImage) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + body: SafeArea( + child: Stack( + children: [ + InteractiveViewer(child: Image(image: (_isLocalUrl(images[itemIndex]) ? FileImage(File(images[itemIndex])) : NetworkImage(images[itemIndex])))).center, + const ABackButton(), + ], + ), + ), + ), + ), + ); + } else if (_isLocalUrl(images[itemIndex])) { + OpenFile.open(images[itemIndex]); + } else { + try { + if (!await launchUrl(Uri.parse(images[itemIndex]), mode: LaunchMode.externalApplication)) { + Fluttertoast.showToast(msg: "UnExpected Error with file."); + throw Exception('Could not launch '); + } + } catch (ex) { + Fluttertoast.showToast(msg: "No Viewer found."); + } + } + }); + }); + } + + bool _isLocalUrl(String url) { + if (url?.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } +} diff --git a/lib/views/widgets/images/images_viewer.dart b/lib/views/widgets/images/images_viewer.dart index b4becc05..508cf0ca 100644 --- a/lib/views/widgets/images/images_viewer.dart +++ b/lib/views/widgets/images/images_viewer.dart @@ -5,6 +5,7 @@ import 'package:test_sa/views/widgets/loaders/image_loader.dart'; class ImagesViewer extends StatelessWidget { final List images; final int initialIndex; + const ImagesViewer({ Key key, this.images, diff --git a/lib/views/widgets/images/mini_one_file_picker.dart b/lib/views/widgets/images/mini_one_file_picker.dart new file mode 100644 index 00000000..c831fab2 --- /dev/null +++ b/lib/views/widgets/images/mini_one_file_picker.dart @@ -0,0 +1,145 @@ +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:test_sa/controllers/localization/localization.dart'; +import 'package:test_sa/models/subtitle.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class AMiniOneFilePicker extends StatefulWidget { + final Function(File) onPick; + final File file; + final String label; + final bool error; + + const AMiniOneFilePicker({Key key, this.label, this.error, this.file, this.onPick}) : super(key: key); + + @override + _AMiniOneFilePickerState createState() => _AMiniOneFilePickerState(); +} + +class _AMiniOneFilePickerState extends State { + File _file; + Subtitle _subtitle; + + @override + void initState() { + super.initState(); + _file = widget.file; + } + + @override + Widget build(BuildContext context) { + _subtitle = AppLocalization.of(context).subtitle; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Visibility( + visible: widget.label != null, + child: Column( + children: [ + SizedBox(height: 8 * AppStyle.getScaleFactor(context)), + Text( + widget.label ?? '', + style: Theme.of(context).textTheme.titleLarge, + textScaleFactor: AppStyle.getScaleFactor(context), + ), + ], + ), + ), + Visibility( + visible: _file == null && widget.error == true, + child: Column( + children: [ + const SizedBox(height: 4), + Text( + _subtitle.requiredFile, + style: Theme.of(context).textTheme.titleLarge.copyWith(color: Colors.red), + textScaleFactor: AppStyle.getScaleFactor(context), + ), + ], + ), + ), + const SizedBox(height: 8), + SizedBox( + width: MediaQuery.of(context).size.width, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context))), + //primary: Colors.grey[200], + textStyle: Theme.of(context).textTheme.labelSmall, + padding: _file == null ? null : EdgeInsets.zero, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + _file == null ? _subtitle.pickFile : _file.path.split("/").last, + textScaleFactor: AppStyle.getScaleFactor(context), + ), + ), + onPressed: () async { + onFilePicker(_subtitle); + }, + ), + ), + ], + ); + } + + fromFilePicker(Subtitle subtitle) async { + FilePickerResult result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], + ); + if (result != null) { + for (var path in result.paths) { + _file = File(path); + widget.onPick(_file); + } + setState(() {}); + } + } + + onFilePicker(Subtitle subtitle) async { + ImageSource source = await showDialog( + context: context, + builder: (dialogContext) => CupertinoAlertDialog( + actions: [ + TextButton( + child: Text(subtitle.pickFromCamera), + onPressed: () { + Navigator.of(dialogContext).pop(ImageSource.camera); + }, + ), + TextButton( + child: Text(subtitle.pickFromGallery), + onPressed: () { + Navigator.of(dialogContext).pop(ImageSource.gallery); + }, + ), + TextButton( + child: Text(subtitle.pickFromFiles), + onPressed: () async { + await fromFilePicker(subtitle); + Navigator.pop(context); + }, + ), + ], + ), + ); + if (source == null) return; + + final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); + + if (pickedFile != null) { + File fileImage = File(pickedFile.path); + if (fileImage != null) { + _file = File(pickedFile.path); + widget.onPick(_file); + } + } + setState(() {}); + } +} diff --git a/lib/views/widgets/images/mini_one_image_picker.dart b/lib/views/widgets/images/mini_one_image_picker.dart deleted file mode 100644 index 13c8f424..00000000 --- a/lib/views/widgets/images/mini_one_image_picker.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:test_sa/controllers/localization/localization.dart'; -import 'package:test_sa/models/subtitle.dart'; -import 'package:test_sa/views/app_style/sizing.dart'; - -class AMiniOneImagePicker extends StatefulWidget { - final Function(File) onPick; - final File image; - final String label; - final bool error; - const AMiniOneImagePicker({Key key, this.label, this.error, this.image, this.onPick}) : super(key: key); - - @override - _AMiniOneImagePickerState createState() => _AMiniOneImagePickerState(); -} - -class _AMiniOneImagePickerState extends State { - File _image; - Subtitle _subtitle; - @override - void initState() { - super.initState(); - _image = widget.image; - } - - @override - Widget build(BuildContext context) { - _subtitle = AppLocalization.of(context).subtitle; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Visibility( - visible: widget.label != null, - child: Column( - children: [ - SizedBox( - height: 8 * AppStyle.getScaleFactor(context), - ), - Text( - widget.label ?? '', - style: Theme.of(context).textTheme.headline6, - textScaleFactor: AppStyle.getScaleFactor(context), - ), - ], - ), - ), - Visibility( - visible: _image == null && widget.error == true, - child: Column( - children: [ - SizedBox( - height: 4, - ), - Text( - _subtitle.requiredImage, - style: Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), - textScaleFactor: AppStyle.getScaleFactor(context), - ), - ], - ), - ), - SizedBox( - height: 8, - ), - Container( - width: MediaQuery.of(context).size.width, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context))), - //primary: Colors.grey[200], - textStyle: Theme.of(context).textTheme.overline, - padding: _image == null ? null : EdgeInsets.zero, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - _image == null ? _subtitle.pickImage : _image.path.split("/").last, - textScaleFactor: AppStyle.getScaleFactor(context), - ), - ), - onPressed: () async { - ImageSource source = await showDialog( - context: context, - builder: (_) => CupertinoAlertDialog( - actions: [ - TextButton( - child: Text("pick from camera"), - onPressed: () { - Navigator.of(context).pop(ImageSource.camera); - }, - ), - TextButton( - child: Text("pick from gallery"), - onPressed: () { - Navigator.of(context).pop(ImageSource.gallery); - }, - ), - ], - )); - if (source == null) return; - - final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 1000, maxHeight: 1000); - - setState(() { - if (pickedFile != null) { - _image = File(pickedFile.path); - widget.onPick(_image); - } else {} - }); - }, - ), - ), - ], - ); - } -} diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index 854209bb..aa3bfefc 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -13,159 +14,195 @@ import 'package:test_sa/views/widgets/buttons/app_flat_button.dart'; import 'multi_image_picker_item.dart'; -class MultiImagesPicker extends StatefulWidget { +class MultiFilesPicker extends StatefulWidget { final String label; final bool error; - final List images; + final List files; + final bool enabled; - const MultiImagesPicker({Key key, this.images, this.label, this.error = false}) : super(key: key); + const MultiFilesPicker({Key key, this.files, this.label, this.error = false, this.enabled = true}) : super(key: key); @override - _MultiImagesPickerState createState() => _MultiImagesPickerState(); + _MultiFilesPickerState createState() => _MultiFilesPickerState(); } -class _MultiImagesPickerState extends State with TickerProviderStateMixin { +class _MultiFilesPickerState extends State with TickerProviderStateMixin { Size _size; @override Widget build(BuildContext context) { _size = MediaQuery.of(context).size; - Subtitle _subtitle = AppLocalization.of(context).subtitle; - return Container( - padding: EdgeInsets.all(12), - decoration: BoxDecoration( - color: Color(0xfff5f5f5), - border: Border.all( - color: Color(0xffefefef), - ), - borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // SizedBox(height: 8 * AppStyle.getScaleFactor(context),), - Row( - children: [ - Expanded( - child: Text( - widget.label ?? _subtitle.images, - style: Theme.of(context).textTheme.headline6.copyWith( - fontSize: 14, - ), - textScaleFactor: AppStyle.getScaleFactor(context), - ), + Subtitle subtitle = AppLocalization.of(context).subtitle; + return (widget.enabled == false && (widget.files?.isEmpty ?? false)) + ? const SizedBox() + : Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xfff5f5f5), + border: Border.all( + color: const Color(0xffefefef), ), - AFlatButton( - text: _subtitle.add, - onPressed: () { - onImagePick(_subtitle); - }, - ), - ], - ), - 12.height, - AnimatedSize( - duration: Duration(milliseconds: 400), - child: !widget.error - ? SizedBox.shrink() - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _subtitle.imagesRequired, + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // SizedBox(height: 8 * AppStyle.getScaleFactor(context),), + Row( + children: [ + Expanded( + child: Text( + widget.label ?? subtitle.images, style: Theme.of(context).textTheme.headline6.copyWith( fontSize: 14, - color: AColors.red, ), textScaleFactor: AppStyle.getScaleFactor(context), ), - SizedBox( - height: 8 * AppStyle.getScaleFactor(context), + ), + if (widget.enabled) + AFlatButton( + text: subtitle.add, + onPressed: widget.enabled + ? () { + // onImagePick(_subtitle); + onFilePicker(subtitle); + } + : null, ), - ], - ), - ), - AnimatedSwitcher( - duration: Duration(milliseconds: 400), - child: Container( - key: ValueKey(widget.images.length), - width: _size.width, - height: 200 * AppStyle.getScaleFactor(context), - padding: EdgeInsets.all( - 8 * AppStyle.getScaleFactor(context), - ), - alignment: Alignment.topLeft, - decoration: BoxDecoration( - border: Border.all(color: Theme.of(context).primaryColor, width: 2), - borderRadius: BorderRadius.circular(8 * AppStyle.getScaleFactor(context)), - ), - child: widget.images.isEmpty - ? MaterialButton( - onPressed: () { - onImagePick(_subtitle); - }, - child: Center( - child: Icon( - Icons.add_a_photo_outlined, - size: 48 * AppStyle.getScaleFactor(context), - color: Theme.of(context).primaryColor, - )), - ) - : GridView.count( - crossAxisCount: 2, - //_size.width ~/ 80, - scrollDirection: Axis.horizontal, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - children: List.generate(widget.images.length, (index) { - File _image = widget.images[index]; - return MultiImagesPickerItem( - image: _image, - onRemoveTap: (image) { - widget.images.remove(image); - setState(() {}); - }, - ); - }), + ], + ), + 12.height, + AnimatedSize( + duration: const Duration(milliseconds: 400), + child: !widget.error + ? const SizedBox.shrink() + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + subtitle.imagesRequired, + style: Theme.of(context).textTheme.headline6.copyWith( + fontSize: 14, + color: AColors.red, + ), + textScaleFactor: AppStyle.getScaleFactor(context), + ), + SizedBox( + height: 8 * AppStyle.getScaleFactor(context), + ), + ], + ), + ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + child: Container( + key: ValueKey(widget.files.length), + width: _size.width, + height: 200 * AppStyle.getScaleFactor(context), + padding: EdgeInsets.all( + 8 * AppStyle.getScaleFactor(context), + ), + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(color: Theme.of(context).primaryColor, width: 2), + borderRadius: BorderRadius.circular(8 * AppStyle.getScaleFactor(context)), ), + child: widget.files.isEmpty && widget.enabled + ? MaterialButton( + onPressed: widget.enabled + ? () { + // onImagePick(_subtitle); + onFilePicker(subtitle); + } + : null, + child: Center( + child: Icon( + Icons.file_upload, + size: 48 * AppStyle.getScaleFactor(context), + color: Theme.of(context).primaryColor, + )), + ) + : GridView.count( + crossAxisCount: 2, + //_size.width ~/ 80, + scrollDirection: Axis.horizontal, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + children: List.generate(widget.files.length, (index) { + File _image = widget.files[index]; + return MultiFilesPickerItem( + file: _image, + enabled: widget.enabled, + onRemoveTap: (image) { + if (!widget.enabled) { + return; + } + widget.files.remove(image); + setState(() {}); + }, + ); + }), + ), + ), + ), + ], ), - ), - ], - ), + ); + } + + fromFilePicker(Subtitle subtitle) async { + FilePickerResult result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowMultiple: true, + allowedExtensions: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], ); + if (result != null) { + for (var path in result.paths) { + widget.files.insert(0, File(path)); + } + setState(() {}); + } } - onImagePick(Subtitle _subtitle) async { - if (widget.images.length >= 5) { - Fluttertoast.showToast(msg: _subtitle.maxImagesNumberIs5); + onFilePicker(Subtitle subtitle) async { + if (widget.files.length >= 5) { + Fluttertoast.showToast(msg: subtitle.maxImagesNumberIs5); return; } ImageSource source = await showDialog( - context: context, - builder: (dialogContext) => CupertinoAlertDialog( - actions: [ - TextButton( - child: Text(_subtitle.pickFromCamera), - onPressed: () { - Navigator.of(dialogContext).pop(ImageSource.camera); - }, - ), - TextButton( - child: Text(_subtitle.pickFromGallery), - onPressed: () { - Navigator.of(dialogContext).pop(ImageSource.gallery); - }, - ), - ], - )); + context: context, + builder: (dialogContext) => CupertinoAlertDialog( + actions: [ + TextButton( + child: Text(subtitle.pickFromCamera), + onPressed: () { + Navigator.of(dialogContext).pop(ImageSource.camera); + }, + ), + TextButton( + child: Text(subtitle.pickFromGallery), + onPressed: () { + Navigator.of(dialogContext).pop(ImageSource.gallery); + }, + ), + TextButton( + child: Text(subtitle.pickFromFiles), + onPressed: () async { + await fromFilePicker(subtitle); + Navigator.pop(context); + }, + ), + ], + ), + ); if (source == null) return; final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); if (pickedFile != null) { - File _fileImage = File(pickedFile.path); - if (_fileImage != null) { - widget.images.insert(0, _fileImage); + File fileImage = File(pickedFile.path); + if (fileImage != null) { + widget.files.insert(0, fileImage); setState(() {}); } } diff --git a/lib/views/widgets/images/multi_image_picker_item.dart b/lib/views/widgets/images/multi_image_picker_item.dart index e540cc2b..907c20fa 100644 --- a/lib/views/widgets/images/multi_image_picker_item.dart +++ b/lib/views/widgets/images/multi_image_picker_item.dart @@ -1,59 +1,99 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:open_file/open_file.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; +import 'package:test_sa/views/widgets/loaders/image_loader.dart'; +import 'package:url_launcher/url_launcher.dart'; -class MultiImagesPickerItem extends StatelessWidget { - final File image; +class MultiFilesPickerItem extends StatelessWidget { + final File file; + final bool enabled; final Function(File) onRemoveTap; - const MultiImagesPickerItem({Key key, this.image, this.onRemoveTap}) : super(key: key); + const MultiFilesPickerItem({Key key, this.file, this.enabled, this.onRemoveTap}) : super(key: key); @override Widget build(BuildContext context) { + var isImage = file.path.split(".").last.toLowerCase() == "png" || file.path.split(".").last.toLowerCase() == "jpg" || file.path.split(".").last.toLowerCase() == "jpeg"; + var isPdf = file.path.split(".").last.toLowerCase() == "pdf"; + var isExcel = file.path.split(".").last.toLowerCase() == "xlsx"; return Container( width: 80 * AppStyle.getScaleFactor(context), height: 80 * AppStyle.getScaleFactor(context), - decoration: - BoxDecoration(boxShadow: [BoxShadow(color: Colors.black38, blurRadius: 2)], image: DecorationImage(image: FileImage(image), fit: BoxFit.cover), borderRadius: BorderRadius.circular(8)), + decoration: BoxDecoration( + boxShadow: [BoxShadow(color: isImage ? Colors.black38 : AColors.cyan.withOpacity(0.5), blurRadius: 2)], + image: DecorationImage( + image: isImage + ? (_isLocalUrl(file.path) ? FileImage(file) : NetworkImage(file.path)) + : AssetImage("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png"), + fit: BoxFit.cover, + ), + borderRadius: BorderRadius.circular(8), + ), child: MaterialButton( padding: EdgeInsets.zero, - onPressed: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - Center( - child: InteractiveViewer( - child: Image( - image: FileImage(image), - )), - ), - ABackButton(), - ], - ), + onPressed: () async { + if (isImage) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + body: SafeArea( + child: Stack( + children: [ + InteractiveViewer( + child: _isLocalUrl(file.path) + ? Image.file(file) + : ImageLoader( + url: file.path, + boxFit: BoxFit.cover, + )) + .center, + const ABackButton(), + ], ), - ))); + ), + ), + ), + ); + } else if (_isLocalUrl(file.path)) { + OpenFile.open(file.path); + } else { + if (!await launchUrl(Uri.parse(file.path), mode: LaunchMode.externalApplication)) { + Fluttertoast.showToast(msg: "UnExpected Error with file."); + throw Exception('Could not launch '); + } + } }, - child: Align( - alignment: Alignment.topRight, - child: IconButton( - padding: const EdgeInsets.all(2.0), - icon: Container( - padding: EdgeInsets.all(1), - decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.3), borderRadius: BorderRadius.circular(8)), - child: Icon( - Icons.remove_circle, - color: AColors.red, - )), - onPressed: () { - onRemoveTap(image); - }, - )), + child: enabled + ? Align( + alignment: Alignment.topRight, + child: IconButton( + padding: const EdgeInsets.all(2.0), + icon: Container( + padding: const EdgeInsets.all(1), + decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.3), borderRadius: BorderRadius.circular(8)), + child: const Icon( + Icons.remove_circle, + color: AColors.red, + ), + ), + onPressed: () { + onRemoveTap(file); + }, + ), + ) + : const SizedBox(), ), ); } + + bool _isLocalUrl(String url) { + if (url?.isEmpty != false) return false; + return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); + } } diff --git a/lib/views/widgets/images/one_image_picker.dart b/lib/views/widgets/images/one_image_picker.dart index 08647cb7..de5124d0 100644 --- a/lib/views/widgets/images/one_image_picker.dart +++ b/lib/views/widgets/images/one_image_picker.dart @@ -12,6 +12,7 @@ class AOneImagePicker extends StatefulWidget { final File image; final String label; final bool error; + const AOneImagePicker({Key key, this.label, this.error, this.image, this.onPick}) : super(key: key); @override @@ -21,6 +22,7 @@ class AOneImagePicker extends StatefulWidget { class _AOneImagePickerState extends State { File _image; Subtitle _subtitle; + @override void initState() { super.initState(); diff --git a/lib/views/widgets/loaders/failed_loading.dart b/lib/views/widgets/loaders/failed_loading.dart index dc8f39b5..b14b45a7 100644 --- a/lib/views/widgets/loaders/failed_loading.dart +++ b/lib/views/widgets/loaders/failed_loading.dart @@ -6,6 +6,7 @@ class FailedLoading extends StatelessWidget { final VoidCallback onReload; const FailedLoading({Key key, this.message, this.onReload}) : super(key: key); + @override Widget build(BuildContext context) { return Center( diff --git a/lib/views/widgets/notifications/notification_item.dart b/lib/views/widgets/notifications/notification_item.dart index c548f628..6bce172c 100644 --- a/lib/views/widgets/notifications/notification_item.dart +++ b/lib/views/widgets/notifications/notification_item.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:test_sa/models/app_notification.dart'; import 'package:test_sa/views/app_style/colors.dart'; @@ -7,6 +6,7 @@ import 'package:test_sa/views/app_style/sizing.dart'; class NotificationItem extends StatelessWidget { final AppNotification notification; final Function(AppNotification) onPressed; + const NotificationItem({Key key, this.notification, this.onPressed}) : super(key: key); @override diff --git a/lib/views/widgets/parts/auto_complete_parts_field.dart b/lib/views/widgets/parts/auto_complete_parts_field.dart index d499b815..71bf0098 100644 --- a/lib/views/widgets/parts/auto_complete_parts_field.dart +++ b/lib/views/widgets/parts/auto_complete_parts_field.dart @@ -7,14 +7,14 @@ import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/models/part.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; -import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; class AutoCompletePartsField extends StatefulWidget { final String initialValue; + final num assetId; final bool clearAfterPick; final Function(Part) onPick; - const AutoCompletePartsField({Key key, this.initialValue, this.onPick, this.clearAfterPick = true}) : super(key: key); + const AutoCompletePartsField({Key key, this.initialValue, this.assetId, this.onPick, this.clearAfterPick = true}) : super(key: key); @override _AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState(); @@ -65,13 +65,13 @@ class _AutoCompletePartsFieldState extends State { textInputAction: TextInputAction.search, ), suggestionsCallback: (vale) async { - return await _partsProvider.getPartsList(host: _settingProvider.host, title: vale); + return await _partsProvider.getPartsList(host: _settingProvider.host, title: vale, assetId: widget.assetId); }, itemBuilder: (context, part) { return ListTile( - title: Text(part.code), + title: Text(part.partNo), subtitle: Text( - part.name, + part.partName, style: Theme.of(context).textTheme.caption, ), ); @@ -80,7 +80,7 @@ class _AutoCompletePartsFieldState extends State { if (widget.clearAfterPick) { _controller.clear(); } else { - _controller.text = part.code; + _controller.text = part.partNo; } widget.onPick(part); }, diff --git a/lib/views/widgets/parts/part_item.dart b/lib/views/widgets/parts/part_item.dart index c108d07e..0d98b0e0 100644 --- a/lib/views/widgets/parts/part_item.dart +++ b/lib/views/widgets/parts/part_item.dart @@ -22,6 +22,7 @@ class _PartItemState extends State { children: [ const Divider(), Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( @@ -31,7 +32,7 @@ class _PartItemState extends State { children: [ Expanded( child: Text( - widget?.part?.code ?? "", + widget?.part?.partNo ?? "", style: Theme.of(context).textTheme.bodyText1.copyWith(fontSize: 12, fontWeight: FontWeight.bold), ), ), @@ -76,14 +77,16 @@ class _PartItemState extends State { ), ], ), - widget.part.name == null + widget.part.partName == null ? const SizedBox.shrink() : Text( - widget.part.name, + widget.part.partName, style: Theme.of(context).textTheme.caption.copyWith(fontSize: 11, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis, ), + + // Row(crossAxisAlignment: ,) ], ), ), diff --git a/lib/views/widgets/pentry/pentry_info_form.dart b/lib/views/widgets/pentry/pentry_info_form.dart index 37989014..f5f1f6a5 100644 --- a/lib/views/widgets/pentry/pentry_info_form.dart +++ b/lib/views/widgets/pentry/pentry_info_form.dart @@ -9,16 +9,17 @@ import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; -import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart'; import 'package:test_sa/views/widgets/status/pentry/pentry_visit_status_mune.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; +import '../images/multi_image_picker.dart'; import '../status/pentry/pentry_status_mune.dart'; class PentryInfoForm extends StatefulWidget { final Pentry model; final bool enableValidate; + const PentryInfoForm({ Key key, this.model, @@ -32,173 +33,177 @@ class PentryInfoForm extends StatefulWidget { class _PentryInfoFormState extends State { @override Widget build(BuildContext context) { + widget.model?.files ??= []; final subtitle = AppLocalization.of(context).subtitle; final userProvider = Provider.of(context); - return ListView( + return Padding( padding: EdgeInsets.only( top: 12 * AppStyle.getScaleFactor(context), left: 12 * AppStyle.getScaleFactor(context), right: 12 * AppStyle.getScaleFactor(context), bottom: 80 * AppStyle.getScaleFactor(context)), - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - children: [ - const SizedBox( - height: 8, - ), - const ASubTitle("PPM Visit Status"), - if (widget.enableValidate && widget.model.ppmVisitStatus == null) - ASubTitle( - subtitle.requiredWord, - color: Colors.red, - ), - const SizedBox( - height: 4, - ), - PentryVisitsStatusMenu( - initialValue: widget.model.ppmVisitStatus, - onSelect: (status) { - widget.model.ppmVisitStatus = status; - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Timer"), - if (widget.enableValidate && widget.model?.timer?.endAt == null) - ASubTitle( - subtitle.requiredWord, - color: Colors.red, - ), - const SizedBox( - height: 4, - ), - AppTimer( - timer: widget.model.timer, - enabled: widget.model.timer.endAt == null, - onChange: (timer) async { - widget.model.timer = timer; - return true; - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Status"), - if (widget.enableValidate && widget.model.status == null) - ASubTitle( - subtitle.requiredWord, - color: Colors.red, - ), - const SizedBox( - height: 4, - ), - PentryStatusMenu( - initialValue: widget.model.status, - onSelect: (status) { - widget.model.status = status; - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Actual Visit Date"), - if (widget.enableValidate && widget.model.actualVisitDate == null) - ASubTitle( - subtitle.requiredWord, - color: Colors.red, - ), - const SizedBox( - height: 4, - ), - ADatePicker( - date: widget.model.actualVisitDate, - from: DateTime.now().subtract(const Duration(days: 30)), - onDatePicker: (date) { - if (date == null) return; - widget.model.actualVisitDate = date; - setState(() {}); - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Expected Visit Date"), - if (widget.enableValidate && widget.model.expectedVisitDate == null) - ASubTitle( - subtitle.requiredWord, - color: Colors.red, - ), - const SizedBox( - height: 4, - ), - ADatePicker( - date: widget.model.expectedVisitDate, - from: DateTime.now().subtract(const Duration(days: 30)), - onDatePicker: (date) { - if (date == null) return; - widget.model.expectedVisitDate = date; - setState(() {}); - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Traveling Hours"), - const SizedBox( - height: 4, - ), - ATextFormField( - initialValue: (widget.model.travelingHours ?? "").toString(), - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, - textInputType: TextInputType.number, - onChange: (value) { - widget.model.travelingHours = value; - }, - ), - const SizedBox( - height: 12, - ), - const ASubTitle("PPM Attachment"), - AMiniOneImagePicker( - //error: _validate && _serviceReport.image == null, - image: widget.model.imageFile, - onPick: (image) { - widget.model.imageFile = image; - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Nurse Signature"), - ESignature( - oldSignature: widget.model.signatureNurse, - newSignature: widget.model.localNurseSignature, - onChange: (signature) { - if (signature == null || signature.isEmpty) { - return; - } - widget.model.localNurseSignature = signature; - widget.model.signatureNurse = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; - }, - ), - const SizedBox( - height: 8, - ), - const ASubTitle("Engineer Signature"), - ESignature( - oldSignature: widget.model.signatureEngineer, - newSignature: widget.model.localNurseSignature, - onChange: (signature) { - if (signature == null || signature.isEmpty) { - return; - } - widget.model.localNurseSignature = signature; - widget.model.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; - }, - ), - const SizedBox( - height: 8, - ), - ], + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox( + height: 8, + ), + const ASubTitle("PPM Visit Status"), + if (widget.enableValidate && widget.model.ppmVisitStatus == null) + ASubTitle( + subtitle.requiredWord, + color: Colors.red, + ), + const SizedBox( + height: 4, + ), + PentryVisitsStatusMenu( + initialValue: widget.model.ppmVisitStatus, + onSelect: (status) { + if (status != null) { + widget.model.ppmVisitStatus = status; + } + }, + ), + const SizedBox( + height: 8, + ), + const ASubTitle("Timer"), + if (widget.enableValidate && widget.model?.timer?.endAt == null) + ASubTitle( + subtitle.requiredWord, + color: Colors.red, + ), + const SizedBox( + height: 4, + ), + AppTimer( + timer: widget.model.timer, + enabled: widget.model.timer.endAt == null, + onChange: (timer) async { + widget.model.timer = timer; + return true; + }, + ), + const SizedBox( + height: 8, + ), + const ASubTitle("Status"), + if (widget.enableValidate && widget.model.status == null) + ASubTitle( + subtitle.requiredWord, + color: Colors.red, + ), + const SizedBox( + height: 4, + ), + PentryStatusMenu( + initialValue: widget.model.status, + onSelect: (status) { + widget.model.status = status; + }, + ), + const SizedBox( + height: 8, + ), + const ASubTitle("Actual Visit Date"), + if (widget.enableValidate && widget.model.actualVisitDate == null) + ASubTitle( + subtitle.requiredWord, + color: Colors.red, + ), + const SizedBox( + height: 4, + ), + ADatePicker( + date: widget.model.actualVisitDate, + from: DateTime.now().subtract(const Duration(days: 30)), + onDatePicker: (date) { + if (date == null) return; + widget.model.actualVisitDate = date; + setState(() {}); + }, + ), + const SizedBox( + height: 8, + ), + const ASubTitle("Expected Visit Date"), + if (widget.enableValidate && widget.model.expectedVisitDate == null) + ASubTitle( + subtitle.requiredWord, + color: Colors.red, + ), + const SizedBox( + height: 4, + ), + ADatePicker( + date: widget.model.expectedVisitDate, + from: DateTime.now().subtract(const Duration(days: 30)), + onDatePicker: (date) { + if (date == null) return; + widget.model.expectedVisitDate = date; + setState(() {}); + }, + ), + const SizedBox( + height: 8, + ), + const ASubTitle("Traveling Hours"), + const SizedBox( + height: 4, + ), + ATextFormField( + initialValue: (widget.model.travelingHours ?? "").toString(), + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.number, + onChange: (value) { + widget.model.travelingHours = value; + }, + ), + const SizedBox(height: 12), + MultiFilesPicker(label: "PPM Attachments", files: widget.model.files), + // AMiniOneFilePicker( + // //error: _validate && _serviceReport.image == null, + // file: widget.model.file, + // onPick: (file) { + // widget.model.file = file; + // }, + // ), + const SizedBox( + height: 8, + ), + const ASubTitle("Nurse Signature"), + ESignature( + oldSignature: widget.model.signatureNurse, + newSignature: widget.model.localNurseSignature, + onChange: (signature) { + if (signature == null || signature.isEmpty) { + return; + } + widget.model.localNurseSignature = signature; + widget.model.signatureNurse = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }, + ), + const SizedBox( + height: 8, + ), + const ASubTitle("Engineer Signature"), + ESignature( + oldSignature: widget.model.signatureEngineer, + newSignature: widget.model.localEngineerSignature, + onChange: (signature) { + if (signature == null || signature.isEmpty) { + return; + } + widget.model.localEngineerSignature = signature; + widget.model.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }, + ), + const SizedBox( + height: 8, + ), + ], + ), + ), ); } } diff --git a/lib/views/widgets/pentry/pentry_pm_kit_form.dart b/lib/views/widgets/pentry/pentry_pm_kit_form.dart index 3fb154d7..2f83c8fa 100644 --- a/lib/views/widgets/pentry/pentry_pm_kit_form.dart +++ b/lib/views/widgets/pentry/pentry_pm_kit_form.dart @@ -11,9 +11,11 @@ import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; class PentryPMKitForm extends StatefulWidget { final List models; final bool enableValidate; + final num assetId; const PentryPMKitForm({ Key key, this.models, + this.assetId, this.enableValidate, }) : super(key: key); @@ -71,10 +73,11 @@ class _PentryPMKitFormState extends State { height: 4, ), AutoCompletePartsField( + assetId: widget.assetId, clearAfterPick: false, initialValue: (model.itemCode?.name ?? "").toString(), onPick: (part) { - model.itemCode = Lookup(id: part.id, name: part.code); + model.itemCode = Lookup(id: part.id, name: part.partNo); }, ), const SizedBox( diff --git a/lib/views/widgets/pentry/pentry_ppm_check_list_form.dart b/lib/views/widgets/pentry/pentry_ppm_check_list_form.dart index 3f7eecf8..6bf2d43e 100644 --- a/lib/views/widgets/pentry/pentry_ppm_check_list_form.dart +++ b/lib/views/widgets/pentry/pentry_ppm_check_list_form.dart @@ -11,6 +11,7 @@ import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; class PentryPPMCheckListForm extends StatefulWidget { final List models; final bool enableValidate; + const PentryPPMCheckListForm({ Key key, this.models, diff --git a/lib/views/widgets/requests/info_row.dart b/lib/views/widgets/requests/info_row.dart index e92195e1..ea60f6e7 100644 --- a/lib/views/widgets/requests/info_row.dart +++ b/lib/views/widgets/requests/info_row.dart @@ -9,6 +9,7 @@ class RequestInfoRow extends StatelessWidget { final Widget infoWidget; const RequestInfoRow({Key key, this.title, this.info, this.content, this.contentWidget, this.infoWidget}) : super(key: key); + @override Widget build(BuildContext context) { if (info != null && info.isEmpty) { diff --git a/lib/views/widgets/requests/service_request_item.dart b/lib/views/widgets/requests/service_request_item.dart index 2580deef..25dd7c79 100644 --- a/lib/views/widgets/requests/service_request_item.dart +++ b/lib/views/widgets/requests/service_request_item.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; @@ -20,6 +19,7 @@ class ServiceRequestItem extends StatelessWidget { final int index; final ServiceRequest request; final Function(ServiceRequest) onPressed; + const ServiceRequestItem({Key key, this.request, this.onPressed, this.index}) : super(key: key); @override @@ -133,6 +133,13 @@ class ServiceRequestItem extends StatelessWidget { Divider( color: onItemColor, ), + Text( + request.deviceNumber, + style: Theme.of(context).textTheme.subtitle2.copyWith(color: onItemColor, fontSize: 12, fontWeight: FontWeight.normal), + ), + Divider( + color: onItemColor, + ), Row( children: [ Expanded( diff --git a/lib/views/widgets/search/asset_transfer_search_dialog.dart b/lib/views/widgets/search/asset_transfer_search_dialog.dart new file mode 100644 index 00000000..9dd79991 --- /dev/null +++ b/lib/views/widgets/search/asset_transfer_search_dialog.dart @@ -0,0 +1,202 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/localization/localization.dart'; +import 'package:test_sa/models/device/device_transfer_search.dart'; +import 'package:test_sa/models/subtitle.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; +import 'package:test_sa/views/widgets/buttons/app_button.dart'; +import 'package:test_sa/views/widgets/buttons/app_small_button.dart'; +import 'package:test_sa/views/widgets/equipment/device_button.dart'; + +import '../../../controllers/providers/api/hospitals_provider.dart'; +import '../app_text_form_field.dart'; +import '../gas_refill/building_type_menu.dart'; +import '../gas_refill/department_type_menu.dart'; +import '../gas_refill/floor_type_menu.dart'; +import '../hospitals/hospital_auto_complete_field.dart'; +import '../switch_button.dart'; + +class AssetTransferSearchDialog extends StatefulWidget { + final DeviceTransferSearch initialSearchValue; + final bool expandedSearch; + final Function(DeviceTransferSearch) onSearch; + + const AssetTransferSearchDialog({Key key, this.initialSearchValue, this.expandedSearch, this.onSearch}) : super(key: key); + @override + AssetTransferSearchDialogState createState() => AssetTransferSearchDialogState(); +} + +class AssetTransferSearchDialogState extends State with TickerProviderStateMixin { + DeviceTransferSearch _search; + final GlobalKey _formKey = GlobalKey(); + bool _isLoading = false; + + @override + void initState() { + super.initState(); + _search = DeviceTransferSearch(); + _search.fromSearch(widget.initialSearchValue); + } + + @override + Widget build(BuildContext context) { + Subtitle subtitle = AppLocalization.of(context).subtitle; + return Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: ClipRRect( + borderRadius: const BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)), + clipBehavior: Clip.antiAliasWithSaveLayer, + child: Container( + color: Colors.white, + height: MediaQuery.of(context).size.height / 1.3, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 20), + child: Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ASmallButton( + text: subtitle.cancel, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ASmallButton( + text: subtitle.search, + onPressed: () { + if (!_formKey.currentState.validate()) { + return; + } + _formKey.currentState.save(); + Navigator.of(context).pop(_search); + }, + ) + ], + ), + ASwitchButton( + title: "Most Recent", + value: _search.mostRecent ?? false, + onChange: (value) { + _search.mostRecent = value; + setState(() {}); + }, + ), + SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)), + DeviceButton( + device: _search.device, + onDevicePick: (device) { + _search.device = device; + setState(() {}); + }, + ), + SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)), + ATextFormField( + initialValue: _search.title, + hintText: subtitle.title, + style: Theme.of(context).textTheme.titleLarge, + textInputAction: TextInputAction.search, + onAction: () { + if (!_formKey.currentState.validate()) { + return; + } + _formKey.currentState.save(); + Navigator.of(context).pop(_search); + }, + onSaved: (value) { + _search.title = value; + }, + ), + SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)), + HospitalAutoCompleteField( + initialValue: _search?.hospital?.name, + onSearch: (selected) async { + _search.building = null; + _search.floor = null; + _search.department = null; + _search.buildingsList = null; + _search.floorsList = null; + _search.departmentsList = null; + _isLoading = true; + setState(() {}); + await HospitalsProvider().getHospitalsListByVal(searchVal: selected?.name ?? "").then((value) { + _search.hospital = value?.firstWhere((element) => element.name == selected.name, orElse: () => null); + _search.buildingsList = _search.hospital?.buildings; + }); + _isLoading = false; + setState(() {}); + }, + ), + const SizedBox(height: 8), + BuildingTypeMenu( + initialValue: _search?.building, + building: _search.buildingsList, + enabled: !_isLoading, + onSelect: (status) { + _search.building = status; + _search.floorsList = status?.floors; + setState(() {}); + }, + ), + const SizedBox(height: 8), + FloorTypeMenu( + initialValue: _search?.floor, + floors: _search.floorsList, + enabled: !_isLoading, + onSelect: (status) { + _search.floor = status; + _search.departmentsList = _search.floor?.departments; + setState(() {}); + }, + ), + const SizedBox(height: 8), + DepartmentTypeMenu( + initialValue: _search?.department, + departments: _search.departmentsList, + enabled: !_isLoading, + onSelect: (status) { + _search.department = status; + setState(() {}); + }, + ), + SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)), + ATextFormField( + initialValue: _search.room, + hintText: subtitle.room, + style: Theme.of(context).textTheme.titleLarge, + textInputAction: TextInputAction.search, + onAction: () { + if (!_formKey.currentState.validate()) { + return; + } + _formKey.currentState.save(); + Navigator.of(context).pop(_search); + }, + onSaved: (value) { + _search.room = value; + }, + ), + SizedBox(height: 16.0 * AppStyle.getScaleFactor(context)), + Visibility( + visible: (_search.toMap()..remove("mostRecent"))?.isNotEmpty ?? false, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: AButton( + padding: EdgeInsets.zero, + text: subtitle.clearSearch, + onPressed: () { + _search = DeviceTransferSearch(); + Navigator.of(context).pop(_search); + }, + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/views/widgets/search/service_request_search_bar.dart b/lib/views/widgets/search/service_request_search_bar.dart index c5b31e29..682b4177 100644 --- a/lib/views/widgets/search/service_request_search_bar.dart +++ b/lib/views/widgets/search/service_request_search_bar.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/models/lookup.dart'; @@ -9,9 +8,15 @@ import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/buttons/app_small_button.dart'; import 'package:test_sa/views/widgets/hospitals/hospital_auto_complete_field.dart'; import 'package:test_sa/views/widgets/status/service_request/service_request_status_mune.dart'; +import 'package:test_sa/views/widgets/switch_button.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; +import '../../../models/call_request_for_work_order_model.dart'; +import '../../../models/engineer.dart'; import '../app_text_form_field.dart'; +import '../date_and_time/date_picker.dart'; +import '../status/report/service_report_all_users.dart'; +import '../status/report/service_report_visit_date_operator.dart'; class ServiceRequestsSearchDialog extends StatefulWidget { final ServiceRequestSearch initialSearchValue; @@ -63,157 +68,260 @@ class _ServiceRequestsSearchDialogState extends State with TickerProv ) ], ), + ASwitchButton( + title: "Most Recent", + value: _search.mostRecent ?? false, + onChange: (value) { + _search.mostRecent = value; + setState(() {}); + }, + ), + SizedBox( + height: 8.0 * AppStyle.getScaleFactor(context), + ), + ATextFormField( + initialValue: _search.deviceNumber, + hintText: _subtitle.assetNumber, + style: Theme.of(context).textTheme.headline6, + textInputAction: TextInputAction.search, + onAction: () { + if (!_formKey.currentState.validate()) { + return; + } + _formKey.currentState.save(); + Navigator.of(context).pop(_search); + }, + onSaved: (value) { + _search.deviceNumber = value; + }, + ), + SizedBox( + height: 8.0 * AppStyle.getScaleFactor(context), + ), + ATextFormField( + initialValue: _search.deviceName, + hintText: _subtitle.assetName, + style: Theme.of(context).textTheme.headline6, + textInputAction: TextInputAction.search, + onAction: () { + if (!_formKey.currentState.validate()) { + return; + } + _formKey.currentState.save(); + Navigator.of(context).pop(_search); + }, + onSaved: (value) { + _search.deviceName = value; + }, + ), + SizedBox( + height: 8.0 * AppStyle.getScaleFactor(context), + ), ATextFormField( initialValue: _search.deviceSerialNumber, hintText: _subtitle.serialNumber, diff --git a/lib/views/widgets/sound/record_sound.dart b/lib/views/widgets/sound/record_sound.dart index 5ca797e4..3b6b75b6 100644 --- a/lib/views/widgets/sound/record_sound.dart +++ b/lib/views/widgets/sound/record_sound.dart @@ -1,28 +1,33 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_sound/flutter_sound.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:rive/rive.dart'; import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart'; import 'package:test_sa/views/widgets/buttons/app_small_button.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart'; - +import 'package:record_mp3/record_mp3.dart'; import '../../app_style/sizing.dart'; class RecordSound extends StatefulWidget { final Function(String) onRecord; + final bool enabled; - const RecordSound({Key key, @required this.onRecord}) : super(key: key); + const RecordSound({Key key, @required this.onRecord, this.enabled = true}) : super(key: key); @override State createState() => _RecordSoundState(); } class _RecordSoundState extends State { - FlutterSoundRecorder _myRecorder = FlutterSoundRecorder(); + // FlutterSoundRecorder _myRecorder = FlutterSoundRecorder(); + bool _recorderIsOpened = false; bool _recording = false; - bool _fastTab = false; String _record; Artboard _rive; @@ -34,10 +39,15 @@ class _RecordSoundState extends State { @override void initState() { super.initState(); - _myRecorder.openRecorder().then((value) { - _recorderIsOpened = true; - setState(() {}); - }); + + _recorderIsOpened = true; + // RecordMp3.instance.start(recordFilePath, (type) { + // // record fail callback + // }); + // _myRecorder.openRecorder().then((value) { + // _recorderIsOpened = true; + // setState(() {}); + // }); // Load the animation file from the bundle, note that you could also // download this. The RiveFile just expects a list of bytes. @@ -61,25 +71,36 @@ class _RecordSoundState extends State { @override void dispose() { // Be careful : you must `close` the audio session when you have finished with it. - _myRecorder.closeRecorder(); - _myRecorder = null; + RecordMp3.instance.stop(); + //_myRecorder.closeRecorder(); + // _myRecorder = null; super.dispose(); } + String recordingFileDirectory; + _startRecording() async { - _fastTab = false; // await Permission.camera PermissionStatus status = await Permission.microphone.request(); if (!status.isGranted) { - return; + PermissionStatus status = await Permission.microphone.request(); + if (!status.isGranted) { + Fluttertoast.showToast(msg: "Permission Denied"); + return; + } } _rive.addController(SimpleAnimation('recording')); if (!_recorderIsOpened) { - await _myRecorder.openRecorder(); + // await _myRecorder.openRecorder(); _recorderIsOpened = true; } + final Directory tempDir = await getTemporaryDirectory(); + recordingFileDirectory = "${tempDir.path}/record_${DateTime.now().millisecondsSinceEpoch}.mp3"; + RecordMp3.instance.start(recordingFileDirectory, (type) { + // record fail callback + }); - await _myRecorder.startRecorder(toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp4", codec: Codec.aacMP4, sampleRate: 360000, bitRate: 360000); + // await _myRecorder.startRecorder(toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp3", codec: Codec.aacADTS, sampleRate: 360000, bitRate: 360000); _recording = true; setState(() {}); @@ -87,21 +108,24 @@ class _RecordSoundState extends State { _stopRecording() async { if (!_recording) { - _fastTab = true; setState(() {}); return; } - String path = (await _myRecorder.stopRecorder()).toString(); - _record = path; - widget.onRecord(path); + + RecordMp3.instance.stop(); + + //String path = (await _myRecorder.stopRecorder()).toString(); + _record = recordingFileDirectory; + widget.onRecord(recordingFileDirectory); _recording = false; setState(() {}); } _cancelRecording() async { if (!_recording) return; - String path = await _myRecorder.stopRecorder(); - _myRecorder.deleteRecord(fileName: path); + RecordMp3.instance.stop(); + // String path = await _myRecorder.stopRecorder(); + // _myRecorder.deleteRecord(fileName: path); _rive.addController(SimpleAnimation('delete')); // rebuild(); @@ -114,11 +138,11 @@ class _RecordSoundState extends State { @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.only(left: 12, right: 0), + padding: const EdgeInsets.only(left: 12, right: 0), decoration: BoxDecoration( - color: Color(0xfff5f5f5), + color: const Color(0xfff5f5f5), border: Border.all( - color: Color(0xffefefef), + color: const Color(0xffefefef), ), borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), ), @@ -178,20 +202,23 @@ class _RecordSoundState extends State { color: Colors.transparent, child: GestureDetector( //key: ValueKey("voice"), - child: const Padding( - padding: EdgeInsets.all(12.0), - child: Icon(Icons.mic), - ), - - onTapDown: (TapDownDetails details) async { - _startRecording(); - }, - onTapUp: (TapUpDetails details) async { - _stopRecording(); - }, - onTapCancel: () async { - _cancelRecording(); - }, + onTapDown: widget.enabled + ? (TapDownDetails details) async { + _startRecording(); + } + : null, + onTapUp: widget.enabled + ? (TapUpDetails details) async { + _stopRecording(); + } + : null, + onTapCancel: widget.enabled + ? () async { + _cancelRecording(); + } + : null, + //key: ValueKey("voice"), + child: const Padding(padding: EdgeInsets.all(12.0), child: Icon(Icons.mic)), ), ), ], diff --git a/lib/views/widgets/speech_to_text/speech_to_text.dart b/lib/views/widgets/speech_to_text/speech_to_text.dart index 59b3d929..7d9e1d55 100644 --- a/lib/views/widgets/speech_to_text/speech_to_text.dart +++ b/lib/views/widgets/speech_to_text/speech_to_text.dart @@ -5,15 +5,16 @@ import 'package:speech_to_text/speech_recognition_error.dart'; import 'package:speech_to_text/speech_recognition_result.dart'; import 'package:speech_to_text/speech_to_text.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; -import 'package:test_sa/views/app_style/sizing.dart'; class SpeechToTextButton extends StatefulWidget { final TextEditingController controller; final bool mini; + final bool enabled; - const SpeechToTextButton({Key key, this.controller, this.mini = false}) : super(key: key); + const SpeechToTextButton({Key key, this.controller, this.mini = false, this.enabled = true}) : super(key: key); @override _SpeechToTextButtonState createState() => _SpeechToTextButtonState(); @@ -22,7 +23,7 @@ class SpeechToTextButton extends StatefulWidget { class _SpeechToTextButtonState extends State { bool _speechEnabled = false; SettingProvider _settingProvider; - SpeechToText _speechToText = SpeechToText(); + final SpeechToText _speechToText = SpeechToText(); /// This has to happen only once per app void _initSpeech() async { @@ -63,12 +64,15 @@ class _SpeechToTextButtonState extends State { @override void initState() { _initSpeech(); + widget.controller.addListener(() { + setState(() {}); + }); super.initState(); } @override void setState(VoidCallback fn) { - if (!this.mounted) return; + if (!mounted) return; super.setState(fn); } @@ -76,18 +80,18 @@ class _SpeechToTextButtonState extends State { Widget build(BuildContext context) { _settingProvider = Provider.of(context); return Container( - padding: EdgeInsets.only(left: 12, right: 12), + padding: const EdgeInsets.only(left: 12, right: 12), decoration: BoxDecoration( - color: Color(0xfff5f5f5), + color: const Color(0xfff5f5f5), border: Border.all( - color: Color(0xffefefef), + color: const Color(0xffefefef), ), borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), ), child: Row( children: [ - widget.mini ? SizedBox.shrink() : ASubTitle("Text To Speech"), - widget.controller.text.isNotEmpty + widget.mini ? const SizedBox.shrink() : const ASubTitle("Speech To Text"), + widget.controller.text.isNotEmpty && widget.enabled ? AIconButton2( iconData: Icons.delete, onPressed: () { @@ -95,22 +99,24 @@ class _SpeechToTextButtonState extends State { setState(() {}); }, ) - : SizedBox.shrink(), - Spacer(), + : const SizedBox.shrink(), + const Spacer(), TextButton( - onPressed: () { - if (_speechToText.isListening) return; + onPressed: widget.enabled + ? () { + if (_speechToText.isListening) return; - if (_settingProvider.speechToText == "ar") { - _settingProvider.setSpeechToText("en"); - } else { - _settingProvider.setSpeechToText("ar"); - } - }, + if (_settingProvider.speechToText == "ar") { + _settingProvider.setSpeechToText("en"); + } else { + _settingProvider.setSpeechToText("ar"); + } + } + : null, child: Text(_settingProvider.speechToText)), GestureDetector( child: _speechToText.isListening - ? Icon( + ? const Icon( Icons.fiber_manual_record, color: Colors.red, ) @@ -118,13 +124,19 @@ class _SpeechToTextButtonState extends State { Icons.mic, color: Theme.of(context).colorScheme.primary, ), - onTap: () async { - if (!_speechEnabled) { - Fluttertoast.showToast(msg: "microphone not available"); - return; - } - _startListening(); - }, + onTap: widget.enabled + ? () async { + if (!_speechEnabled) { + Fluttertoast.showToast(msg: "microphone not available"); + return; + } + if (_speechToText.isListening) { + _stopListening(); + } else { + _startListening(); + } + } + : null, ), ], ), diff --git a/lib/views/widgets/status/asset_status.dart b/lib/views/widgets/status/asset_status.dart new file mode 100644 index 00000000..c1b0f9dc --- /dev/null +++ b/lib/views/widgets/status/asset_status.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/status_drop_down/asset_transfer_status_provider.dart'; +import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_status_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/models/lookup.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/status/single_status_menu.dart'; + +class AssetStatusMenu extends StatelessWidget { + final Function(Lookup) onSelect; + final Lookup initialValue; + final bool enabled; + + const AssetStatusMenu({Key key, this.enabled = true, this.onSelect, this.initialValue}) : super(key: key); + + @override + Widget build(BuildContext context) { + final settingProvider = Provider.of(context); + final userProvider = Provider.of(context); + final assetProvider = Provider.of(context); + return LoadingManager( + isLoading: assetProvider.isLoading, + isFailedLoading: assetProvider.items == null, + stateCode: assetProvider.stateCode, + onRefresh: () async { + assetProvider.reset(); + await assetProvider.getData(user: userProvider.user, host: settingProvider.host); + }, + child: SingleStatusMenu( + initialStatus: initialValue, + statuses: assetProvider.items, + onSelect: onSelect, + enabled: enabled, + )); + } +} diff --git a/lib/views/widgets/status/employee/single_type_menu.dart b/lib/views/widgets/status/employee/single_type_menu.dart index 8c480a91..30eda5bd 100644 --- a/lib/views/widgets/status/employee/single_type_menu.dart +++ b/lib/views/widgets/status/employee/single_type_menu.dart @@ -9,6 +9,7 @@ class SingleEngineerMenu extends StatefulWidget { final Function(Engineer) onSelect; const SingleEngineerMenu({Key key, this.engineers, this.onSelect, this.initialStatus}) : super(key: key); + @override _SingleEngineerMenuState createState() => _SingleEngineerMenuState(); } diff --git a/lib/views/widgets/status/multi_status_menu.dart b/lib/views/widgets/status/multi_status_menu.dart index 52330a62..50ae83bc 100644 --- a/lib/views/widgets/status/multi_status_menu.dart +++ b/lib/views/widgets/status/multi_status_menu.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:test_sa/models/lookup.dart'; @@ -11,6 +10,7 @@ class MultiStatusMenu extends StatefulWidget { final Function(List) onSelect; const MultiStatusMenu({Key key, this.statuses, this.onSelect, this.initialSelectedStatus}) : super(key: key); + @override _MultiStatusMenuState createState() => _MultiStatusMenuState(); } diff --git a/lib/views/widgets/status/report/fault_desc_menu.dart b/lib/views/widgets/status/report/fault_desc_menu.dart index a2b670de..696c18b3 100644 --- a/lib/views/widgets/status/report/fault_desc_menu.dart +++ b/lib/views/widgets/status/report/fault_desc_menu.dart @@ -79,10 +79,10 @@ class _SingleStatusMenuState extends State { isExpanded: true, hint: Text( "Select", - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.subtitle1.copyWith(color: widget.statuses.isEmpty ? Colors.grey : null), ), style: TextStyle(color: Theme.of(context).primaryColor), - underline: SizedBox.shrink(), + underline: const SizedBox.shrink(), onChanged: (FaultDescription newValue) { setState(() { _selectedStatus = newValue; diff --git a/lib/views/widgets/status/report/service_report_equipment_status.dart b/lib/views/widgets/status/report/service_report_equipment_status.dart index 95182977..63f9dfc0 100644 --- a/lib/views/widgets/status/report/service_report_equipment_status.dart +++ b/lib/views/widgets/status/report/service_report_equipment_status.dart @@ -2,8 +2,8 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_equipment_status_provider.dart'; +import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_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/models/lookup.dart'; diff --git a/lib/views/widgets/status/report/service_report_fault_description.dart b/lib/views/widgets/status/report/service_report_fault_description.dart index 544fcbb3..0f2990bb 100644 --- a/lib/views/widgets/status/report/service_report_fault_description.dart +++ b/lib/views/widgets/status/report/service_report_fault_description.dart @@ -7,14 +7,13 @@ import 'package:test_sa/models/fault_description.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/status/report/fault_desc_menu.dart'; -import '../../app_text_form_field.dart'; - class ServiceReportFaultDescription extends StatelessWidget { final String requestId; final Function(FaultDescription) onSelect; final FaultDescription initialValue; const ServiceReportFaultDescription({Key key, this.requestId, this.onSelect, this.initialValue}) : super(key: key); + @override Widget build(BuildContext context) { SettingProvider settingProvider = Provider.of(context); @@ -28,16 +27,11 @@ class ServiceReportFaultDescription extends StatelessWidget { menuProvider.reset(); await menuProvider.getCallRequestForWorkOrder(user: userProvider.user, host: settingProvider.host, requestId: requestId); }, - child: (menuProvider.items?.isEmpty ?? true) - ? const ATextFormField( - initialValue: "", - enable: false, - ) - : FaultDescriptionMenu( - initialStatus: initialValue, - statuses: menuProvider.items, - onSelect: onSelect, - ), + child: FaultDescriptionMenu( + initialStatus: initialValue, + statuses: menuProvider.items ?? [], + onSelect: onSelect, + ), ); } } diff --git a/lib/views/widgets/status/report/service_report_last_call.dart b/lib/views/widgets/status/report/service_report_last_call.dart index 4433a4fd..42a732ba 100644 --- a/lib/views/widgets/status/report/service_report_last_call.dart +++ b/lib/views/widgets/status/report/service_report_last_call.dart @@ -11,10 +11,10 @@ class ServiceReportLastCallsMenu extends StatelessWidget { final ServiceReport report; const ServiceReportLastCallsMenu({Key key, @required this.onSelect, @required this.report}) : super(key: key); + @override Widget build(BuildContext context) { ServiceReportLastCallsProvider _menuProvider = Provider.of(context); - print("report?.callLastSituation:${report?.callLastSituation?.toMap()}"); return LoadingManager( isLoading: _menuProvider.isLoading, isFailedLoading: _menuProvider.calls == null, diff --git a/lib/views/widgets/status/report/service_report_reasons.dart b/lib/views/widgets/status/report/service_report_reasons.dart index 18115724..81092b5c 100644 --- a/lib/views/widgets/status/report/service_report_reasons.dart +++ b/lib/views/widgets/status/report/service_report_reasons.dart @@ -12,6 +12,7 @@ class ServiceReportReasonsMenu extends StatelessWidget { final Function(Lookup) onSelect; const ServiceReportReasonsMenu({Key key, this.onSelect, this.initialValue}) : super(key: key); + @override Widget build(BuildContext context) { SettingProvider _settingProvider = Provider.of(context); diff --git a/lib/views/widgets/status/report/service_report_repair_location.dart b/lib/views/widgets/status/report/service_report_repair_location.dart index 4892a3a7..52cb3038 100644 --- a/lib/views/widgets/status/report/service_report_repair_location.dart +++ b/lib/views/widgets/status/report/service_report_repair_location.dart @@ -12,6 +12,7 @@ class ServiceReportRepairLocation extends StatelessWidget { final Function(Lookup) onSelect; const ServiceReportRepairLocation({Key key, this.onSelect, this.initialValue}) : super(key: key); + @override Widget build(BuildContext context) { SettingProvider _settingProvider = Provider.of(context); diff --git a/lib/views/widgets/status/report/service_status.dart b/lib/views/widgets/status/report/service_status.dart index 245e0997..99c968c0 100644 --- a/lib/views/widgets/status/report/service_status.dart +++ b/lib/views/widgets/status/report/service_status.dart @@ -12,6 +12,7 @@ class ServiceAssetTypeMenu extends StatelessWidget { final Lookup initialValue; const ServiceAssetTypeMenu({Key key, this.onSelect, this.initialValue}) : super(key: key); + @override Widget build(BuildContext context) { SettingProvider _settingProvider = Provider.of(context); diff --git a/lib/views/widgets/status/service_request/service_request_defect_types_mune.dart b/lib/views/widgets/status/service_request/service_request_defect_types_mune.dart index 8607cffe..3496f3c0 100644 --- a/lib/views/widgets/status/service_request/service_request_defect_types_mune.dart +++ b/lib/views/widgets/status/service_request/service_request_defect_types_mune.dart @@ -10,8 +10,10 @@ import 'package:test_sa/views/widgets/status/single_status_menu.dart'; class ServiceRequestDefectTypesMenu extends StatelessWidget { final Function(Lookup) onSelect; final Lookup initialValue; + final bool enabled; + + const ServiceRequestDefectTypesMenu({Key key, this.onSelect, this.initialValue, this.enabled = true}) : super(key: key); - const ServiceRequestDefectTypesMenu({Key key, this.onSelect, this.initialValue}) : super(key: key); @override Widget build(BuildContext context) { final settingProvider = Provider.of(context); @@ -29,6 +31,7 @@ class ServiceRequestDefectTypesMenu extends StatelessWidget { initialStatus: initialValue, statuses: menuProvider.items, onSelect: onSelect, + enabled: enabled, )); } } diff --git a/lib/views/widgets/status/service_request/service_request_first_action.dart b/lib/views/widgets/status/service_request/service_request_first_action.dart index 02c5f94e..99511972 100644 --- a/lib/views/widgets/status/service_request/service_request_first_action.dart +++ b/lib/views/widgets/status/service_request/service_request_first_action.dart @@ -11,8 +11,9 @@ import '../../../../controllers/providers/api/status_drop_down/service_reqest/se class ServiceRequestedFirstAction extends StatelessWidget { final Function(Lookup) onSelect; final Lookup initialValue; + final bool enabled; - const ServiceRequestedFirstAction({Key key, this.onSelect, this.initialValue}) : super(key: key); + const ServiceRequestedFirstAction({Key key, this.onSelect, this.initialValue, this.enabled = true}) : super(key: key); @override Widget build(BuildContext context) { final settingProvider = Provider.of(context); @@ -30,6 +31,7 @@ class ServiceRequestedFirstAction extends StatelessWidget { initialStatus: initialValue, statuses: menuProvider.items, onSelect: onSelect, + enabled: enabled, ), ); } diff --git a/lib/views/widgets/status/service_request/service_request_priority_mune.dart b/lib/views/widgets/status/service_request/service_request_priority_mune.dart index 4896fdcc..7cd90242 100644 --- a/lib/views/widgets/status/service_request/service_request_priority_mune.dart +++ b/lib/views/widgets/status/service_request/service_request_priority_mune.dart @@ -10,8 +10,9 @@ import 'package:test_sa/views/widgets/status/single_status_menu.dart'; class ServiceRequestPriorityMenu extends StatelessWidget { final Function(Lookup) onSelect; final Lookup initialValue; + final bool enabled; - const ServiceRequestPriorityMenu({Key key, this.onSelect, this.initialValue}) : super(key: key); + const ServiceRequestPriorityMenu({Key key, this.onSelect, this.initialValue, this.enabled}) : super(key: key); @override Widget build(BuildContext context) { final settingProvider = Provider.of(context); @@ -30,6 +31,7 @@ class ServiceRequestPriorityMenu extends StatelessWidget { initialStatus: initialValue, statuses: menuProvider.items, onSelect: onSelect, + enabled: enabled, )); } } diff --git a/lib/views/widgets/status/service_request/service_request_through_mune.dart b/lib/views/widgets/status/service_request/service_request_through_mune.dart index 986a5953..1a735dc8 100644 --- a/lib/views/widgets/status/service_request/service_request_through_mune.dart +++ b/lib/views/widgets/status/service_request/service_request_through_mune.dart @@ -10,8 +10,9 @@ import 'package:test_sa/views/widgets/status/single_status_menu.dart'; class ServiceRequestedThroughMenu extends StatelessWidget { final Function(Lookup) onSelect; final Lookup initialValue; + final bool enabled; - const ServiceRequestedThroughMenu({Key key, this.onSelect, this.initialValue}) : super(key: key); + const ServiceRequestedThroughMenu({Key key, this.onSelect, this.initialValue, this.enabled = true}) : super(key: key); @override Widget build(BuildContext context) { final settingProvider = Provider.of(context); @@ -26,9 +27,10 @@ class ServiceRequestedThroughMenu extends StatelessWidget { await menuProvider.getData(user: userProvider.user, host: settingProvider.host); }, child: SingleStatusMenu( - initialStatus: initialValue, + initialStatus: enabled ? initialValue : menuProvider.getDefaultItem(), statuses: menuProvider.items, onSelect: onSelect, + enabled: enabled, )); } } diff --git a/lib/views/widgets/status/service_request/service_request_types_mune.dart b/lib/views/widgets/status/service_request/service_request_types_mune.dart index a588cb8b..4f5e34a7 100644 --- a/lib/views/widgets/status/service_request/service_request_types_mune.dart +++ b/lib/views/widgets/status/service_request/service_request_types_mune.dart @@ -10,25 +10,29 @@ import 'package:test_sa/views/widgets/status/single_status_menu.dart'; class ServiceRequestTypesMenu extends StatelessWidget { final Function(Lookup) onSelect; final Lookup initialValue; + final bool enabled; + final bool withDefaultItem; - const ServiceRequestTypesMenu({Key key, this.onSelect, this.initialValue}) : super(key: key); + const ServiceRequestTypesMenu({Key key, this.onSelect, this.initialValue, this.withDefaultItem = false, this.enabled = true}) : super(key: key); @override Widget build(BuildContext context) { final settingProvider = Provider.of(context); final userProvider = Provider.of(context); final menuProvider = Provider.of(context); return LoadingManager( - isLoading: menuProvider.isLoading, - isFailedLoading: menuProvider.items == null, - stateCode: menuProvider.stateCode, - onRefresh: () async { - menuProvider.reset(); - await menuProvider.getData(user: userProvider.user, host: settingProvider.host); - }, - child: SingleStatusMenu( - initialStatus: initialValue, - statuses: menuProvider.items, - onSelect: onSelect, - )); + isLoading: menuProvider.isLoading, + isFailedLoading: menuProvider.items == null, + stateCode: menuProvider.stateCode, + onRefresh: () async { + menuProvider.reset(); + await menuProvider.getData(user: userProvider.user, host: settingProvider.host); + }, + child: SingleStatusMenu( + initialStatus: (enabled || !withDefaultItem) ? initialValue : menuProvider.getDefaultItem(), + statuses: menuProvider.items, + enabled: enabled, + onSelect: onSelect, + ), + ); } } diff --git a/lib/views/widgets/status/service_request/supplier_engineers_menu.dart b/lib/views/widgets/status/service_request/supplier_engineers_menu.dart new file mode 100644 index 00000000..44b30c84 --- /dev/null +++ b/lib/views/widgets/status/service_request/supplier_engineers_menu.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; +import 'package:test_sa/views/app_style/colors.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class SupplierEngineersMenu extends StatefulWidget { + final List engineers; + final SuppEngineerWorkOrders initialValue; + final Function(SuppEngineerWorkOrders) onSelect; + + const SupplierEngineersMenu({Key key, this.engineers, this.onSelect, this.initialValue}) : super(key: key); + + @override + SingleAssistantEmployeeMenuState createState() => SingleAssistantEmployeeMenuState(); +} + +class SingleAssistantEmployeeMenuState extends State { + SuppPersons _selectedEngineer; + + @override + void setState(VoidCallback fn) { + if (mounted) super.setState(fn); + } + + @override + void didUpdateWidget(covariant SupplierEngineersMenu oldWidget) { + if (widget.initialValue != null) { + final result = widget.engineers?.where((element) { + return element?.id == widget.initialValue?.supplierContactId; + }); + if (result.isNotEmpty) { + _selectedEngineer = result.first; + } else { + _selectedEngineer = null; + } + if ((widget.initialValue?.supplierContactId ?? "") != (_selectedEngineer?.id ?? "")) { + onSelect(_selectedEngineer); + } + } else { + _selectedEngineer = null; + } + super.didUpdateWidget(oldWidget); + } + + @override + void initState() { + if (widget.initialValue != null) { + final result = widget.engineers?.where((element) { + return element?.id == widget.initialValue?.supplierContactId; + }); + if (result.isNotEmpty) _selectedEngineer = result.first; + if (widget.initialValue?.supplierContactId != _selectedEngineer?.id) { + onSelect(_selectedEngineer); + } + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: const Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: const [ + // AppStyle.boxShadow + // ] + ), + child: DropdownButton( + value: _selectedEngineer, + iconSize: 24, + icon: const Icon(Icons.keyboard_arrow_down_rounded), + elevation: 0, + isExpanded: true, + hint: Text("Vendor Engineer", style: Theme.of(context).textTheme.titleMedium), + style: TextStyle(color: Theme.of(context).primaryColor), + underline: const SizedBox.shrink(), + onChanged: (SuppPersons newValue) { + setState(() { + _selectedEngineer = newValue; + }); + onSelect(newValue); + }, + items: widget.engineers?.map>((SuppPersons value) { + return DropdownMenuItem( + value: value, + child: Text( + value?.personName ?? "NULL", + style: Theme.of(context).textTheme.titleMedium.copyWith( + color: Theme.of(context).primaryColor, + fontSize: 11, + //fontWeight: FontWeight.bold + ), + ), + ); + })?.toList(), + ), + ); + } + + void onSelect(SuppPersons engineer) { + widget.onSelect( + SuppEngineerWorkOrders( + id: engineer?.supplierId, + supplierContactId: engineer?.id, + personName: engineer?.personName, + contact: engineer?.contact, + externalEngCode: engineer?.externalEngCode, + email: engineer?.email, + ), + ); + } +} diff --git a/lib/views/widgets/switch_button.dart b/lib/views/widgets/switch_button.dart new file mode 100644 index 00000000..ccab66a4 --- /dev/null +++ b/lib/views/widgets/switch_button.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; + +import '../app_style/colors.dart'; +import '../app_style/sizing.dart'; + +class ASwitchButton extends StatelessWidget { + final String title; + final bool value; + final void Function(bool) onChange; + + const ASwitchButton({ + @required this.title, + @required this.value, + @required this.onChange, + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + margin: const EdgeInsets.symmetric(vertical: 8), + decoration: BoxDecoration( + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: const Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ASubTitle(title), + Switch.adaptive( + value: value, + activeColor: AColors.primaryColor, + onChanged: onChange, + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/timer/app_timer.dart b/lib/views/widgets/timer/app_timer.dart index e67a34ce..fdfe2483 100644 --- a/lib/views/widgets/timer/app_timer.dart +++ b/lib/views/widgets/timer/app_timer.dart @@ -10,6 +10,7 @@ class AppTimer extends StatefulWidget { final Future Function(TimerModel) onChange; final TextStyle style; final bool enabled; + const AppTimer({ Key key, this.timer, diff --git a/lib/views/widgets/titles/app_sub_title.dart b/lib/views/widgets/titles/app_sub_title.dart index d1fc3786..4dc839cb 100644 --- a/lib/views/widgets/titles/app_sub_title.dart +++ b/lib/views/widgets/titles/app_sub_title.dart @@ -6,7 +6,9 @@ class ASubTitle extends StatelessWidget { final EdgeInsets padding; final Color color; final double font; + const ASubTitle(this.text, {Key key, this.padding, this.color, this.font}) : super(key: key); + @override Widget build(BuildContext context) { return Padding( diff --git a/lib/views/widgets/titles/app_title.dart b/lib/views/widgets/titles/app_title.dart index 15e0c588..69020bc9 100644 --- a/lib/views/widgets/titles/app_title.dart +++ b/lib/views/widgets/titles/app_title.dart @@ -5,7 +5,9 @@ class ATitle extends StatelessWidget { final String text; final EdgeInsets padding; final bool center; + const ATitle(this.text, {Key key, this.padding, this.center = false}) : super(key: key); + @override Widget build(BuildContext context) { return Padding( diff --git a/lib/views/widgets/titles/expandable_info_row.dart b/lib/views/widgets/titles/expandable_info_row.dart index 318ca323..369b078c 100644 --- a/lib/views/widgets/titles/expandable_info_row.dart +++ b/lib/views/widgets/titles/expandable_info_row.dart @@ -15,6 +15,7 @@ class ExpandableInfoRow extends StatefulWidget { class _ExpandableInfoRowState extends State with TickerProviderStateMixin { bool _isExpanded = false; + @override Widget build(BuildContext context) { return InkWell( diff --git a/lib/views/widgets/visits/visit_item.dart b/lib/views/widgets/visits/visit_item.dart index e6ca6676..fc8e2052 100644 --- a/lib/views/widgets/visits/visit_item.dart +++ b/lib/views/widgets/visits/visit_item.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/localization/localization.dart'; @@ -22,27 +21,28 @@ class VisitItem extends StatelessWidget { @override Widget build(BuildContext context) { - UserProvider _userProvider = Provider.of(context); + UserProvider userProvider = Provider.of(context); Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; - Subtitle _subtitle = AppLocalization.of(context).subtitle; + Subtitle subtitle = AppLocalization.of(context).subtitle; return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: ElevatedButton( style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), - primary: itemColor, + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8), + backgroundColor: itemColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), ), ), onPressed: () { - if (activeSelectMod && _userProvider.user.type == UsersTypes.engineer) + if (activeSelectMod && userProvider.user.type == UsersTypes.engineer) { onSelect(visit); - else + } else { onPressed(visit); + } }, - onLongPress: _userProvider.user.type == UsersTypes.engineer + onLongPress: userProvider.user.type == UsersTypes.engineer ? () { onLongPress(visit); } @@ -54,12 +54,12 @@ class VisitItem extends StatelessWidget { children: [ Expanded( child: Text( - "S.N: " + visit.deviceSerialNumber ?? "No serial number", - style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold), + "S.N: ${visit.deviceSerialNumber}" ?? "No serial number", + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold), ), ), AnimatedSwitcher( - duration: Duration(milliseconds: 400), + duration: const Duration(milliseconds: 400), child: Visibility( key: ValueKey(activeSelectMod), visible: activeSelectMod, @@ -82,12 +82,19 @@ class VisitItem extends StatelessWidget { Divider( color: onItemColor, ), + Text( + visit.deviceNumber ?? "", + style: Theme.of(context).textTheme.titleMedium.copyWith(color: onItemColor, fontSize: 14), + ), + Divider( + color: onItemColor, + ), Row( children: [ Expanded( child: Text( visit.hospitalName ?? "No client found", - style: Theme.of(context).textTheme.subtitle1.copyWith( + style: Theme.of(context).textTheme.titleMedium.copyWith( color: onItemColor, fontSize: 14, ), @@ -97,29 +104,30 @@ class VisitItem extends StatelessWidget { ), Text( visit.modelAndBrand ?? "", - style: Theme.of(context).textTheme.subtitle1.copyWith( + style: Theme.of(context).textTheme.titleMedium.copyWith( color: onItemColor, fontSize: 14, ), ), - Divider(color: onItemColor), - Row( - children: [ - Expanded( - child: Text( - visit.employName ?? "No employ found", - style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 14, fontWeight: FontWeight.bold), + if (visit.employName != null && visit.employName.isNotEmpty) Divider(color: onItemColor), + if (visit.employName != null && visit.employName.isNotEmpty) + Row( + children: [ + Expanded( + child: Text( + visit.employName ?? "No employ found", + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14, fontWeight: FontWeight.bold), + ), ), - ), - // Text( - // visit.contactStatus ?? "", - // style: Theme.of(context).textTheme.subtitle1.copyWith( - // color: onItemColor, - // fontSize: 14, - // ), - // ), - ], - ), + // Text( + // visit.contactStatus ?? "", + // style: Theme.of(context).textTheme.subtitle1.copyWith( + // color: onItemColor, + // fontSize: 14, + // ), + // ), + ], + ), Divider( color: onItemColor, ), @@ -130,18 +138,12 @@ class VisitItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - _subtitle.expectDate, - style: Theme.of(context).textTheme.headline6.copyWith( - color: onItemColor, - fontSize: 14, - ), + subtitle.expectDate, + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14), ), Text( - visit.expectDate ?? _subtitle.noDateFound, - style: Theme.of(context).textTheme.headline6.copyWith( - color: onItemColor, - fontSize: 14, - ), + visit.expectDate ?? subtitle.noDateFound, + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14), ), ], ), @@ -150,25 +152,12 @@ class VisitItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - _subtitle.actualDate, - style: Theme.of(context).textTheme.headline6.copyWith( - color: onItemColor, - fontSize: 14, - ), + subtitle.actualDate, + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14), ), Text( - visit.actualDate ?? _subtitle.noDateFound, - style: Theme.of(context).textTheme.headline6.copyWith( - color: onItemColor, - fontSize: 14, - ), - // Text( - // visit.contactStatus ?? "", - // style: Theme.of(context).textTheme.subtitle1.copyWith( - // color: onItemColor, - // fontSize: 14, - // ), - // ), + visit.actualDate ?? subtitle.noDateFound, + style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14), ), ], ), diff --git a/lib/views/widgets/visits/visits_list.dart b/lib/views/widgets/visits/visits_list.dart index c8488921..bb327679 100644 --- a/lib/views/widgets/visits/visits_list.dart +++ b/lib/views/widgets/visits/visits_list.dart @@ -21,7 +21,8 @@ class VisitsList extends StatefulWidget { } class _VisitsListState extends State { - List _selectedVisits = []; + final List _selectedVisits = []; + @override void initState() { _selectedVisits.clear(); @@ -30,10 +31,10 @@ class _VisitsListState extends State { @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context).subtitle; - if (widget.visits.length == 0) { + Subtitle subtitle = AppLocalization.of(context).subtitle; + if (widget.visits.isEmpty) { return NoItemFound( - message: _subtitle.noVisitsFound, + message: subtitle.noVisitsFound, ); } return Stack( @@ -44,13 +45,13 @@ class _VisitsListState extends State { child: ListView.builder( //physics: BouncingScrollPhysics(), itemCount: widget.visits.length, - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), itemBuilder: (context, itemIndex) { - Visit _visit = widget.visits[itemIndex]; - bool _isSelected = _selectedVisits.contains(_visit); + Visit visit = widget.visits[itemIndex]; + bool isSelected = _selectedVisits.contains(visit); return VisitItem( - visit: _visit, - isSelected: _isSelected, + visit: visit, + isSelected: isSelected, index: itemIndex, activeSelectMod: _selectedVisits.isNotEmpty, onPressed: (visit) { @@ -60,7 +61,7 @@ class _VisitsListState extends State { ))); }, onSelect: (visit) { - if (_isSelected) { + if (isSelected) { _selectedVisits.remove(visit); } else { _selectedVisits.add(visit); @@ -68,7 +69,7 @@ class _VisitsListState extends State { setState(() {}); }, onLongPress: (visit) { - if (_isSelected) { + if (isSelected) { _selectedVisits.remove(visit); } else { _selectedVisits.add(visit); @@ -83,7 +84,7 @@ class _VisitsListState extends State { child: Padding( padding: EdgeInsets.all(8.0 * AppStyle.getScaleFactor(context)), child: AnimatedSwitcher( - duration: Duration(milliseconds: 400), + duration: const Duration(milliseconds: 400), child: Visibility( key: ValueKey(_selectedVisits.isNotEmpty), visible: _selectedVisits.isNotEmpty, @@ -92,7 +93,7 @@ class _VisitsListState extends State { children: [ FloatingActionButton( heroTag: "cancel", - child: Icon(Icons.cancel), + child: const Icon(Icons.cancel), onPressed: () { _selectedVisits.clear(); setState(() {}); @@ -100,7 +101,7 @@ class _VisitsListState extends State { ), FloatingActionButton( heroTag: "edit", - child: Icon(Icons.edit), + child: const Icon(Icons.edit), onPressed: () { if (!widget.visits.contains(_selectedVisits.first)) { _selectedVisits.clear(); diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 00000000..87291639 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,1239 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "5dce45a06d386358334eb1689108db6455d90ceb0d75848d5f4819283d4ee2b8" + url: "https://pub.dev" + source: hosted + version: "1.3.4" + archive: + dependency: transitive + description: + name: archive + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + url: "https://pub.dev" + source: hosted + version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + audioplayers: + dependency: "direct main" + description: + name: audioplayers + sha256: bb506873ab4fb663db9b47243754ef669adf684dbe6ba8b57c26e27b834065c4 + url: "https://pub.dev" + source: hosted + version: "1.2.0" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + sha256: "53969a1c5d94ebdaef72e334f1c0ea2f3946ab2baa8d398a9584ac27baf4f037" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + sha256: dcd5a4ceef5aa3d04e8ae49441f13a3d9f93fe6e9e88fe121ff6b6f391b2a40b + url: "https://pub.dev" + source: hosted + version: "1.0.4" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + sha256: ea1cb9a5c9389b38f293ee1375b22b02fb1d1f7a2e1517fcb674297dd074dc7b + url: "https://pub.dev" + source: hosted + version: "1.0.2" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + sha256: "589c3106d0c656540e81ac2c7a78a9414a4a6534ae7b77f06ddb5d6aa5dc653c" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + sha256: "13fb044a443276223774f8ed1f8d2b82f443cf8980edd0e172e55967c1556a49" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + sha256: "87964ddece7275b97277935df67af60536155914c81c633f708914b99433129b" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 + url: "https://pub.dev" + source: hosted + version: "3.2.3" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + carousel_slider: + dependency: "direct main" + description: + name: carousel_slider + sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42" + url: "https://pub.dev" + source: hosted + version: "4.2.1" + characters: + dependency: transitive + description: + name: characters + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" + source: hosted + version: "1.2.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + url: "https://pub.dev" + source: hosted + version: "0.3.5" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" + source: hosted + version: "1.17.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + dbus: + dependency: transitive + description: + name: dbus + sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" + url: "https://pub.dev" + source: hosted + version: "0.7.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" + url: "https://pub.dev" + source: hosted + version: "5.3.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "4ada532862917bf16e3adb3891fe3a5917a58bae03293e497082203a80909412" + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + url: "https://pub.dev" + source: hosted + version: "0.9.3" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "2e9324f719e90200dc7d3c4f5d2abc26052f9f2b995d3b6626c47a0dfe1c8192" + url: "https://pub.dev" + source: hosted + version: "2.15.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2 + url: "https://pub.dev" + source: hosted + version: "4.8.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0fd5c4b228de29b55fac38aed0d9e42514b3d3bd47675de52bf7f8fccaf922fa" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "8ac91d83a028eef050de770f1dc98421e215714d245f34de7b154d436676fbd0" + url: "https://pub.dev" + source: hosted + version: "14.6.5" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: b2995e3640efb646e9ebf0e2fa50dea84895f0746a31d7e3af0e5e009a533a1a + url: "https://pub.dev" + source: hosted + version: "4.5.4" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "5d8446a28339124a2cb4f57a6ca454a3aca7d0c5c0cdfa5707afb192f7c830a7" + url: "https://pub.dev" + source: hosted + version: "3.5.4" + flare_flutter: + dependency: "direct main" + description: + name: flare_flutter + sha256: "99d63c60f00fac81249ce6410ee015d7b125c63d8278a30da81edf3317a1f6a0" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + flutter_keyboard_visibility: + dependency: transitive + description: + name: flutter_keyboard_visibility + sha256: "4983655c26ab5b959252ee204c2fffa4afeb4413cd030455194ec0caa3b8e7cb" + url: "https://pub.dev" + source: hosted + version: "5.4.1" + flutter_keyboard_visibility_linux: + dependency: transitive + description: + name: flutter_keyboard_visibility_linux + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_macos: + dependency: transitive + description: + name: flutter_keyboard_visibility_macos + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_windows: + dependency: transitive + description: + name: flutter_keyboard_visibility_windows + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_launcher_icons: + dependency: "direct main" + description: + name: flutter_launcher_icons + sha256: a9de6706cd844668beac27c0aed5910fa0534832b3c2cad61a5fd977fce82a5d + url: "https://pub.dev" + source: hosted + version: "0.10.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: f222919a34545931e47b06000836b5101baeffb0e6eb5a4691d2d42851740dd9 + url: "https://pub.dev" + source: hosted + version: "12.0.4" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: "3c6d6db334f609a92be0c0915f40871ec56f5d2adf01e77ae364162c587c0ca8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "5ec1feac5f7f7d9266759488bc5f76416152baba9aa1b26fe572246caa00d1ab" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + flutter_sound: + dependency: "direct main" + description: + name: flutter_sound + sha256: "090a4694b11ecc744c2010621c4ffc5fe7c3079d304ea014961a72c7b72cfe6c" + url: "https://pub.dev" + source: hosted + version: "9.2.13" + flutter_sound_platform_interface: + dependency: transitive + description: + name: flutter_sound_platform_interface + sha256: "4537eaeb58a32748c42b621ad6116f7f4c6ee0a8d6ffaa501b165fe1c9df4753" + url: "https://pub.dev" + source: hosted + version: "9.2.13" + flutter_sound_web: + dependency: transitive + description: + name: flutter_sound_web + sha256: ad4ca92671a1879e1f613e900bbbdb8170b20d57d1e4e6363018fe56b055594f + url: "https://pub.dev" + source: hosted + version: "9.2.13" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" + url: "https://pub.dev" + source: hosted + version: "1.1.6" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_typeahead: + dependency: "direct main" + description: + name: flutter_typeahead + sha256: a3539f7a90246b152f569029dedcf0b842532d3f2a440701b520e0bf2acbcf42 + url: "https://pub.dev" + source: hosted + version: "4.6.2" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "474f7d506230897a3cd28c965ec21c5328ae5605fc9c400cd330e9e9d6ac175c" + url: "https://pub.dev" + source: hosted + version: "8.2.2" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: "959ef4add147753f990b4a7c6cccb746d5792dbdc81b1cde99e62e7edb31b206" + url: "https://pub.dev" + source: hosted + version: "10.4.0" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c + url: "https://pub.dev" + source: hosted + version: "0.8.9" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb + url: "https://pub.dev" + source: hosted + version: "0.8.7+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b + url: "https://pub.dev" + source: hosted + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee" + url: "https://pub.dev" + source: hosted + version: "2.8.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + intl: + dependency: "direct main" + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: transitive + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + logger: + dependency: transitive + description: + name: logger + sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" + source: hosted + version: "0.12.13" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + open_file: + dependency: "direct main" + description: + name: open_file + sha256: a5a32d44acb7c899987d0999e1e3cbb0a0f1adebbf41ac813ec6d2d8faa0af20 + url: "https://pub.dev" + source: hosted + version: "3.3.2" + package_info: + dependency: "direct main" + description: + name: package_info + sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + path: + dependency: transitive + description: + name: path + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" + source: hosted + version: "1.8.2" + path_drawing: + dependency: transitive + description: + name: path_drawing + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81" + url: "https://pub.dev" + source: hosted + version: "10.4.3" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: c0c9754479a4c4b1c1f3862ddc11930c9b3f03bef2816bb4ea6eed1e13551d6f + url: "https://pub.dev" + source: hosted + version: "10.3.2" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" + url: "https://pub.dev" + source: hosted + version: "9.1.4" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9" + url: "https://pub.dev" + source: hosted + version: "3.11.3" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 + url: "https://pub.dev" + source: hosted + version: "0.1.3" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pointer_interceptor: + dependency: transitive + description: + name: pointer_interceptor + sha256: "6aa680b30d96dccef496933d00208ad25f07e047f644dc98ce03ec6141633a9a" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + provider: + dependency: "direct main" + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" + qr_code_scanner: + dependency: "direct main" + description: + name: qr_code_scanner + sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd + url: "https://pub.dev" + source: hosted + version: "1.0.1" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + record_mp3: + dependency: "direct main" + description: + name: record_mp3 + sha256: "2da2cd2f8c053f9ff03388019bc3eff035ef72f8ea8efac24674c5e528a1cc68" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + rive: + dependency: "direct main" + description: + name: rive + sha256: "22e3755b75f4ea4492d2fecf4fc2acf1c8d0073df39781d290a20cbfe74c3760" + url: "https://pub.dev" + source: hosted + version: "0.9.1" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + share: + dependency: "direct main" + description: + name: share + sha256: "97e6403f564ed1051a01534c2fc919cb6e40ea55e60a18ec23cee6e0ce19f4be" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.dev" + source: hosted + version: "2.3.0" + signature: + dependency: "direct main" + description: + name: signature + sha256: ad23383717dfa926204695ef6928ff513a77387be1b4a8c685099ce3ec35e5f8 + url: "https://pub.dev" + source: hosted + version: "5.3.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + speech_to_text: + dependency: "direct main" + description: + name: speech_to_text + sha256: ff8fbd31d039bdbac6c7ec9f0516d37df2cbea62c45198326d3b64034e6fb920 + url: "https://pub.dev" + source: hosted + version: "6.1.1" + speech_to_text_macos: + dependency: transitive + description: + name: speech_to_text_macos + sha256: "6b5575e5a8346be1779838b0a482c259474965b5943668830b479147a75b5bfc" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + speech_to_text_platform_interface: + dependency: transitive + description: + name: speech_to_text_platform_interface + sha256: "13d90215a7554b9a8c1ce47c0a1739af8eacd2cf196ca66351e54dfd2172746d" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9 + url: "https://pub.dev" + source: hosted + version: "2.2.8+4" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f" + url: "https://pub.dev" + source: hosted + version: "2.4.5+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" + source: hosted + version: "0.4.16" + timezone: + dependency: transitive + description: + name: timezone + sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + url: "https://pub.dev" + source: hosted + version: "6.1.11" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" + url: "https://pub.dev" + source: hosted + version: "6.0.36" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea + url: "https://pub.dev" + source: hosted + version: "2.1.3" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 + url: "https://pub.dev" + source: hosted + version: "2.0.18" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + url: "https://pub.dev" + source: hosted + version: "4.1.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + url: "https://pub.dev" + source: hosted + version: "0.2.0+3" + xml: + dependency: transitive + description: + name: xml + sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=2.19.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4f82161b..031a8b0d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.1+2 +version: 1.0.4+3 environment: sdk: ">=2.7.0 <3.0.0" @@ -61,7 +61,10 @@ dependencies: flare_flutter: ^3.0.2 signature: ^5.3.0 flutter_svg: ^1.1.6 - + file_picker: ^5.2.5 + record_mp3: ^2.1.0 + path_provider: ^2.1.0 + open_file: ^3.3.2 dev_dependencies: flutter_test: