diff --git a/assets/subtitles/ar_subtitle.json b/assets/subtitles/ar_subtitle.json index c39d143d..c8f3b057 100644 --- a/assets/subtitles/ar_subtitle.json +++ b/assets/subtitles/ar_subtitle.json @@ -203,5 +203,7 @@ "room": "غرفه", "actions": "اجراءات", "deviceFiles": "ملفات الجهاز", - "pickFromFiles" : "اختر من الملفات" + "pickFromFiles" : "اختر من الملفات", + "requiredFile" : "الملف مطلوب", + "pickFile" : "اختر ملف" } \ No newline at end of file diff --git a/assets/subtitles/en_subtitle.json b/assets/subtitles/en_subtitle.json index 1decda42..a30908c9 100644 --- a/assets/subtitles/en_subtitle.json +++ b/assets/subtitles/en_subtitle.json @@ -203,5 +203,7 @@ "room": "Room", "actions": "Actions", "deviceFiles": "Asset Files", - "pickFromFiles" : "Pick From Files" + "pickFromFiles" : "Pick From Files", + "requiredFile" : "File Required", + "pickFile" : "Pick File" } \ No newline at end of file diff --git a/lib/models/pantry/pentry.dart b/lib/models/pantry/pentry.dart index 45b750da..e1bb74fd 100644 --- a/lib/models/pantry/pentry.dart +++ b/lib/models/pantry/pentry.dart @@ -18,7 +18,7 @@ class Pentry { DateTime expectedVisitDate; String travelingHours; String image; - File imageFile; + File file; // List contacts; List ppmCheckLists; @@ -37,7 +37,7 @@ class Pentry { this.actualVisitDate, this.expectedVisitDate, this.image, - this.imageFile, + this.file, // this.contacts, this.ppmCheckLists, this.calibrationTools, @@ -86,9 +86,9 @@ class Pentry { map["endDate"] = timer.endAt?.toIso8601String() ?? DateTime.now().toIso8601String(); map["workingHours"] = (timer.durationInSecond / 60 / 60).toStringAsFixed(5); } - if (imageFile != null) { + if (file != null) { map["vAttachments"] = [ - {"attachmentName": (imageFile.path.split("/").last + base64Encode(imageFile.readAsBytesSync()))} + {"attachmentName": (file.path.split("/").last + base64Encode(file.readAsBytesSync()))} ]; } map["travelingHours"] = travelingHours; @@ -172,7 +172,7 @@ class Pentry { expectedVisitDate: expectedVisitDate ?? this.expectedVisitDate, travelingHours: travelingHours ?? this.travelingHours, image: image ?? this.image, - imageFile: imageFile ?? this.imageFile, + file: imageFile ?? this.file, 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(), diff --git a/lib/models/service_report.dart b/lib/models/service_report.dart index 5b661458..abf93564 100644 --- a/lib/models/service_report.dart +++ b/lib/models/service_report.dart @@ -34,7 +34,7 @@ class ServiceReport { String invoiceNumber; String invoiceCode; List parts; - List image; + List files; Device device; String quantity; String jobSheetNumber; @@ -66,7 +66,7 @@ class ServiceReport { this.callLastSituation, this.currentSituation, this.jobSheetNumber, - this.image, + this.files, this.device, this.invoiceCode, this.invoiceNumber, @@ -136,8 +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"] = image.map((e) => {"name": e}).toList(); + if (files != null) { + _map["attachmentsWorkOrder"] = files.map((e) => {"name": e}).toList(); print(_map["attachmentsWorkOrder"]); } _map["nurseSignature"] = signatureNurse; diff --git a/lib/models/subtitle.dart b/lib/models/subtitle.dart index 1304614a..e2c8df61 100644 --- a/lib/models/subtitle.dart +++ b/lib/models/subtitle.dart @@ -187,6 +187,7 @@ class Subtitle { String image; String pickImage; String requiredImage; + String requiredFile; String taskStatus; String activationAlert; @@ -238,6 +239,7 @@ class Subtitle { String room; String actions; String pickFromFiles; + String pickFile; void setIssues(List issues) { issues.clear(); @@ -407,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, @@ -451,6 +454,7 @@ class Subtitle { @required this.room, @required this.actions, @required this.pickFromFiles, + @required this.pickFile, }); factory Subtitle.fromJson(Map parsedJson) { @@ -612,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"], @@ -657,6 +662,7 @@ class Subtitle { room: parsedJson["room"], actions: parsedJson["actions"], pickFromFiles: parsedJson["pickFromFiles"], + pickFile: parsedJson["pickFile"], ); } } 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 75181ef3..5358ded3 100644 --- a/lib/views/pages/sub_workorder/create_sub_workorder_page.dart +++ b/lib/views/pages/sub_workorder/create_sub_workorder_page.dart @@ -27,7 +27,7 @@ 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/images/mini_one_file_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; + File _file; bool _isLoading = false; bool _validate = false; @@ -304,12 +304,12 @@ class _CreateSubWorkOrderPageState extends State { ), ), const SizedBox(height: 8), - AMiniOneImagePicker( - image: _image, - onPick: (image) { - _image = image; + AMiniOneFilePicker( + file: _file, + onPick: (file) { + _file = file; _subWorkOrders.attachmentsWorkOrder ??= []; - _subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}")); + _subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}")); }, ), const SizedBox(height: 50), 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 0c3d6fe1..3ef3f758 100644 --- a/lib/views/pages/user/requests/report/create_service_report.dart +++ b/lib/views/pages/user/requests/report/create_service_report.dart @@ -24,7 +24,7 @@ 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/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/images/mini_one_file_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'; @@ -60,7 +60,7 @@ class _CreateServiceReportState extends State with TickerPr bool _showCommentField = false; Subtitle _subtitle; - File _image; + File _file; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); final TextEditingController _faultController = TextEditingController(); @@ -632,13 +632,13 @@ class _CreateServiceReportState extends State with TickerPr child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ASubTitle(_subtitle.attachImage), - AMiniOneImagePicker( + const ASubTitle("Attachment"), + AMiniOneFilePicker( //error: _validate && _serviceReport.image == null, - image: _image, - onPick: (image) { - _image = image; - _serviceReport.image[0] = "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}"; + file: _file, + onPick: (file) { + _file = file; + _serviceReport.files[0] = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; }, ), ], 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 828e6b11..6aa64bdf 100644 --- a/lib/views/pages/user/requests/report/edit_service_report.dart +++ b/lib/views/pages/user/requests/report/edit_service_report.dart @@ -1070,7 +1070,7 @@ class _EditServiceReportState extends State with TickerProvid _isLoading = true; setState(() {}); - _serviceReport.image = _images.map((e) => base64Encode(e.readAsBytesSync())).toList(); + _serviceReport.files = _images.map((e) => base64Encode(e.readAsBytesSync())).toList(); int status = await _serviceRequestsProvider.updateServiceReport(user: _userProvider.user, host: _settingProvider.host, report: _serviceReport, request: widget.request); _isLoading = false; setState(() {}); 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 26b7f768..00000000 --- a/lib/views/widgets/images/mini_one_image_picker.dart +++ /dev/null @@ -1,122 +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/pentry/pentry_info_form.dart b/lib/views/widgets/pentry/pentry_info_form.dart index 577e28e2..1484a2ca 100644 --- a/lib/views/widgets/pentry/pentry_info_form.dart +++ b/lib/views/widgets/pentry/pentry_info_form.dart @@ -9,7 +9,7 @@ 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/images/mini_one_file_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'; @@ -159,11 +159,11 @@ class _PentryInfoFormState extends State { height: 12, ), const ASubTitle("PPM Attachment"), - AMiniOneImagePicker( + AMiniOneFilePicker( //error: _validate && _serviceReport.image == null, - image: widget.model.imageFile, - onPick: (image) { - widget.model.imageFile = image; + file: widget.model.file, + onPick: (file) { + widget.model.file = file; }, ), const SizedBox(