| <meta-data | <meta-data | ||||
| android:name="flutterEmbedding" | android:name="flutterEmbedding" | ||||
| android:value="2" /> | android:value="2" /> | ||||
| <provider | |||||
| android:name="androidx.core.content.FileProvider" | |||||
| android:authorities="au.com.homecarenet.caregiver.fileprovider" | |||||
| android:exported="false" | |||||
| android:grantUriPermissions="true"> | |||||
| <meta-data | |||||
| android:name="android.support.FILE_PROVIDER_PATHS" | |||||
| android:resource="@xml/provider_paths" | |||||
| tools:replace="android:resource" /> | |||||
| </provider> | |||||
| </application> | </application> | ||||
| </manifest> | </manifest> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <paths xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <external-path | |||||
| name="external_files" | |||||
| path="." /> | |||||
| </paths> |
| } | } | ||||
| subprojects { | subprojects { | ||||
| project.evaluationDependsOn(':app') | project.evaluationDependsOn(':app') | ||||
| project.configurations.all { | |||||
| resolutionStrategy.eachDependency { details -> | |||||
| if (details.requested.group == 'com.android.support' | |||||
| && !details.requested.name.contains('multidex') ) { | |||||
| details.useVersion "27.1.1" | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| task clean(type: Delete) { | task clean(type: Delete) { |
| - nanopb/encode (= 2.30909.0) | - nanopb/encode (= 2.30909.0) | ||||
| - nanopb/decode (2.30909.0) | - nanopb/decode (2.30909.0) | ||||
| - nanopb/encode (2.30909.0) | - nanopb/encode (2.30909.0) | ||||
| - open_filex (0.0.2): | |||||
| - Flutter | |||||
| - package_info_plus (0.4.5): | - package_info_plus (0.4.5): | ||||
| - Flutter | - Flutter | ||||
| - path_provider_foundation (0.0.1): | - path_provider_foundation (0.0.1): | ||||
| - Flutter (from `Flutter`) | - Flutter (from `Flutter`) | ||||
| - flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`) | - flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`) | ||||
| - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) | - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) | ||||
| - open_filex (from `.symlinks/plugins/open_filex/ios`) | |||||
| - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) | - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) | ||||
| - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) | ||||
| - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) | - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) | ||||
| :path: ".symlinks/plugins/flutter_image_compress_common/ios" | :path: ".symlinks/plugins/flutter_image_compress_common/ios" | ||||
| image_picker_ios: | image_picker_ios: | ||||
| :path: ".symlinks/plugins/image_picker_ios/ios" | :path: ".symlinks/plugins/image_picker_ios/ios" | ||||
| open_filex: | |||||
| :path: ".symlinks/plugins/open_filex/ios" | |||||
| package_info_plus: | package_info_plus: | ||||
| :path: ".symlinks/plugins/package_info_plus/ios" | :path: ".symlinks/plugins/package_info_plus/ios" | ||||
| path_provider_foundation: | path_provider_foundation: | ||||
| Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d | Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d | ||||
| MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb | MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb | ||||
| nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 | nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 | ||||
| open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 | |||||
| package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 | package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 | ||||
| path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 | path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 | ||||
| PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 | PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 | ||||
| PODFILE CHECKSUM: f08360d062df7ffa8ee251115991830e526d3068 | PODFILE CHECKSUM: f08360d062df7ffa8ee251115991830e526d3068 | ||||
| COCOAPODS: 1.12.1 | |||||
| COCOAPODS: 1.15.2 |
| CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | ||||
| CODE_SIGN_IDENTITY = "Apple Development"; | CODE_SIGN_IDENTITY = "Apple Development"; | ||||
| CODE_SIGN_STYLE = Automatic; | CODE_SIGN_STYLE = Automatic; | ||||
| CURRENT_PROJECT_VERSION = 20; | |||||
| CURRENT_PROJECT_VERSION = 21; | |||||
| DEVELOPMENT_TEAM = C3DTD2JH94; | DEVELOPMENT_TEAM = C3DTD2JH94; | ||||
| ENABLE_BITCODE = NO; | ENABLE_BITCODE = NO; | ||||
| FRAMEWORK_SEARCH_PATHS = ( | FRAMEWORK_SEARCH_PATHS = ( | ||||
| CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | ||||
| CODE_SIGN_IDENTITY = "Apple Development"; | CODE_SIGN_IDENTITY = "Apple Development"; | ||||
| CODE_SIGN_STYLE = Automatic; | CODE_SIGN_STYLE = Automatic; | ||||
| CURRENT_PROJECT_VERSION = 20; | |||||
| CURRENT_PROJECT_VERSION = 21; | |||||
| DEVELOPMENT_TEAM = C3DTD2JH94; | DEVELOPMENT_TEAM = C3DTD2JH94; | ||||
| ENABLE_BITCODE = NO; | ENABLE_BITCODE = NO; | ||||
| FRAMEWORK_SEARCH_PATHS = ( | FRAMEWORK_SEARCH_PATHS = ( | ||||
| CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | ||||
| CODE_SIGN_IDENTITY = "Apple Development"; | CODE_SIGN_IDENTITY = "Apple Development"; | ||||
| CODE_SIGN_STYLE = Automatic; | CODE_SIGN_STYLE = Automatic; | ||||
| CURRENT_PROJECT_VERSION = 20; | |||||
| CURRENT_PROJECT_VERSION = 21; | |||||
| DEVELOPMENT_TEAM = C3DTD2JH94; | DEVELOPMENT_TEAM = C3DTD2JH94; | ||||
| ENABLE_BITCODE = NO; | ENABLE_BITCODE = NO; | ||||
| FRAMEWORK_SEARCH_PATHS = ( | FRAMEWORK_SEARCH_PATHS = ( |
| @override | @override | ||||
| void onResponse(Response<dynamic> response, ResponseInterceptorHandler handler) { | void onResponse(Response<dynamic> response, ResponseInterceptorHandler handler) { | ||||
| log('🍏🍏🍏🍏🍏🍏 onResponse: ${response.requestOptions.uri}\n' | |||||
| 'statusCode=${response.statusCode}\n' | |||||
| 'data=${response.data is Map ? json.encode(response.data) : response.data}'); | |||||
| // log('🍏🍏🍏🍏🍏🍏 onResponse: ${response.requestOptions.uri}\n' | |||||
| // 'statusCode=${response.statusCode}\n' | |||||
| // 'data=${response.data is Map ? json.encode(response.data) : response.data}'); | |||||
| return handler.next(response); | return handler.next(response); | ||||
| } | } | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/activity_request.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/activity_request.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/activity_type.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/activity_type.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_filter_request.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_request.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp_request.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | ||||
| import 'package:farm_tpf/utils/const_common.dart'; | import 'package:farm_tpf/utils/const_common.dart'; | ||||
| } | } | ||||
| // Stamp | // Stamp | ||||
| Future<List<Stamp>> stamps({int page = 0, int size = 20}) async { | |||||
| Future<List<Stamp>> stamps({ | |||||
| int page = 0, | |||||
| int size = 20, | |||||
| required StampFilterRequest filter, | |||||
| }) async { | |||||
| try { | try { | ||||
| var url = '${ConstCommon.baseUrl}/api/tb-codes/list?page=$page&size=$size&sort=id,desc'; | |||||
| var res = await dio.post(url, data: {}); | |||||
| var url = '${ConstCommon.baseUrl}/api/tb-codes/list?page=$page&size=$size&sort=createdDate,${filter.sort ?? 'asc'}'; | |||||
| var res = await dio.post(url, data: { | |||||
| 'status': filter.status, | |||||
| 'description': filter.description, | |||||
| }); | |||||
| return (res.data as List).map((e) => Stamp.fromJson(e)).toList(); | return (res.data as List).map((e) => Stamp.fromJson(e)).toList(); | ||||
| } catch (e) { | } catch (e) { | ||||
| rethrow; | rethrow; | ||||
| }) async { | }) async { | ||||
| try { | try { | ||||
| var url = '${ConstCommon.baseUrl}/api/tb-codes/create/activity'; | var url = '${ConstCommon.baseUrl}/api/tb-codes/create/activity'; | ||||
| await dio.post(url, data: item).then( | |||||
| var formData = FormData(); | |||||
| formData.fields.add(MapEntry('code', item.code ?? '')); | |||||
| formData.fields.add(MapEntry('activityTypeId', item.activityTypeId?.toString() ?? '')); | |||||
| formData.fields.add(MapEntry('executeDate', item.executeDate ?? '')); | |||||
| formData.fields.add(MapEntry('description', item.description ?? '')); | |||||
| formData.fields.add(MapEntry('location', item.location ?? '')); | |||||
| await dio.post(url, data: formData).then( | |||||
| (value) { | (value) { | ||||
| onSuccess(value); | onSuccess(value); | ||||
| }, | }, | ||||
| } | } | ||||
| } | } | ||||
| Future<Stamp> getStampDetailByCode({required String code}) async { | |||||
| try { | |||||
| var url = '${ConstCommon.baseUrl}/api/tb-codes-scan-qrCode/$code'; | |||||
| var res = await dio.get(url); | |||||
| return Stamp.fromJson(res.data); | |||||
| } catch (e) { | |||||
| rethrow; | |||||
| } | |||||
| } | |||||
| Future<StampTimeline> getStampTimeline({required int stampId}) async { | Future<StampTimeline> getStampTimeline({required int stampId}) async { | ||||
| try { | try { | ||||
| var url = '${ConstCommon.baseUrl}/api/tb-codes-timeline/$stampId'; | var url = '${ConstCommon.baseUrl}/api/tb-codes-timeline/$stampId'; | ||||
| onError(AppException.handleError(e)); | onError(AppException.handleError(e)); | ||||
| } | } | ||||
| } | } | ||||
| Future<List<TbCropDTO>> getPlotsWithoutPaging() async { | |||||
| try { | |||||
| var url = '${ConstCommon.baseUrl}/api/_search/tb-crops'; | |||||
| var res = await dio.get( | |||||
| url, | |||||
| ); | |||||
| return (res.data as List).map((e) => TbCropDTO.fromJson(e)).toList(); | |||||
| } catch (e) { | |||||
| rethrow; | |||||
| } | |||||
| } | |||||
| } | } |
| ), | ), | ||||
| Text( | Text( | ||||
| title, | title, | ||||
| style: StylesText.body5, | |||||
| style: StylesText.caption2, | |||||
| ), | ), | ||||
| const SizedBox( | const SizedBox( | ||||
| width: 4, | width: 4, |
| import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart'; | |||||
| import 'package:flutter/cupertino.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:get/get.dart'; | |||||
| import 'package:multi_select_flutter/multi_select_flutter.dart'; | |||||
| import '../../../models/item_dropdown.dart'; | |||||
| import '../../../themes/app_colors.dart'; | |||||
| import '../../../themes/styles_text.dart'; | |||||
| import '../button/button_2_icon.dart'; | |||||
| class MultipleSelectBottomSheet extends StatefulWidget { | |||||
| final List<ItemDropDown>? initValue; | |||||
| final List<ItemDropDown> dataSources; | |||||
| final Function(List<ItemDropDown>) onSelected; | |||||
| final Color? borderColor; | |||||
| final String hint; | |||||
| final double? height; | |||||
| final String? errorText; | |||||
| final bool isDisable; | |||||
| final EdgeInsetsGeometry? contentPadding; | |||||
| final Color? disabledColor; | |||||
| const MultipleSelectBottomSheet({ | |||||
| Key? key, | |||||
| required this.dataSources, | |||||
| required this.onSelected, | |||||
| required this.hint, | |||||
| this.initValue, | |||||
| this.borderColor, | |||||
| this.height, | |||||
| this.errorText, | |||||
| this.isDisable = false, | |||||
| this.contentPadding, | |||||
| this.disabledColor, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| _MultipleSelectBottomSheetState createState() => _MultipleSelectBottomSheetState(); | |||||
| } | |||||
| class _MultipleSelectBottomSheetState extends State<MultipleSelectBottomSheet> { | |||||
| var dataSources = ValueNotifier(<ItemDropDown>[]); | |||||
| var selectValue = ValueNotifier(<ItemDropDown>[]); | |||||
| FixedExtentScrollController? scrollController; | |||||
| var items = <MultiSelectItem<ItemDropDown>>[]; | |||||
| final _searchCtl = TextEditingController(); | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| } | |||||
| @override | |||||
| void dispose() { | |||||
| super.dispose(); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| items = widget.dataSources.map((e) => MultiSelectItem(e, e.value ?? '')).toList(); | |||||
| selectValue.value = widget.initValue ?? <ItemDropDown>[]; | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: selectValue, | |||||
| builder: (context, selecteds, _) { | |||||
| return Button2Icon( | |||||
| leftIcon: CupertinoIcons.slider_horizontal_3, | |||||
| title: widget.hint, | |||||
| rightWidget: Container( | |||||
| width: 16, | |||||
| height: 16, | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(12), | |||||
| color: Colors.blue, | |||||
| ), | |||||
| child: Center( | |||||
| child: Text( | |||||
| '${selecteds.length}', | |||||
| style: StylesText.caption6.copyWith(color: Colors.white), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| onPressed: () { | |||||
| FocusScope.of(context).requestFocus(FocusNode()); | |||||
| _showMultiSelect(context); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| void _showMultiSelect(BuildContext context) async { | |||||
| var selectedIds = selectValue.value.map((e) => e.key).toList(); | |||||
| var selecteds = ValueNotifier( | |||||
| items | |||||
| .where((element) => selectedIds.contains(element.value.key)) | |||||
| .map( | |||||
| (e) => e.value, | |||||
| ) | |||||
| .toList(), | |||||
| ); | |||||
| // var selectValue = ValueNotifier(<ItemDropDown>[]); | |||||
| _searchCtl.clear(); | |||||
| dataSources.value = List.of(widget.dataSources); | |||||
| return showDialog( | |||||
| context: context, | |||||
| builder: (context) { | |||||
| return AlertDialog( | |||||
| contentPadding: const EdgeInsets.all(8), | |||||
| content: Container( | |||||
| width: double.maxFinite, | |||||
| child: Column( | |||||
| mainAxisSize: MainAxisSize.min, | |||||
| children: <Widget>[ | |||||
| _buildSelectAll(selecteds), | |||||
| Expanded( | |||||
| child: ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: dataSources, | |||||
| builder: (context, sources, _) { | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: selecteds, | |||||
| builder: (context, valueSelected, _) { | |||||
| return ListView.builder( | |||||
| shrinkWrap: true, | |||||
| itemBuilder: ((context, index) { | |||||
| var item = sources[index]; | |||||
| var isSelected = valueSelected.map((e) => e.key ?? '').contains(item.key); | |||||
| return InkWell( | |||||
| onTap: () { | |||||
| if (!isSelected) { | |||||
| selecteds.value.add(item); | |||||
| selecteds.notifyListeners(); | |||||
| } else { | |||||
| selecteds.value.removeWhere((element) => element.key == item.key); | |||||
| selecteds.notifyListeners(); | |||||
| } | |||||
| }, | |||||
| child: Row( | |||||
| children: [ | |||||
| Checkbox( | |||||
| value: isSelected, | |||||
| onChanged: (val) { | |||||
| if (val == true) { | |||||
| selecteds.value.add(item); | |||||
| selecteds.notifyListeners(); | |||||
| } else { | |||||
| selecteds.value.removeWhere((element) => element.key == item.key); | |||||
| selecteds.notifyListeners(); | |||||
| } | |||||
| }, | |||||
| ), | |||||
| Expanded( | |||||
| child: Text( | |||||
| item.value ?? '', | |||||
| style: StylesText.body6, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| }), | |||||
| itemCount: sources.length, | |||||
| ); | |||||
| }); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| Row( | |||||
| children: [ | |||||
| Expanded( | |||||
| child: SecondButton( | |||||
| title: 'Huỷ', | |||||
| color: AppColors.neutral3, | |||||
| onPressed: () { | |||||
| Get.back(); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| const SizedBox( | |||||
| width: 16, | |||||
| ), | |||||
| Expanded( | |||||
| child: SecondButton( | |||||
| title: 'Chọn', | |||||
| color: AppColors.primary1, | |||||
| onPressed: () { | |||||
| Get.back(); | |||||
| selectValue.value = selecteds.value; | |||||
| widget.onSelected(selectValue.value); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| Widget _buildSelectAll(ValueNotifier<List<ItemDropDown>> selecteds) { | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: dataSources, | |||||
| builder: (context, sources, _) { | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: selecteds, | |||||
| builder: (context, valueSelected, _) { | |||||
| final isSelectAll = valueSelected.where((e) => sources.any((t) => t.key == e.key)).length == sources.length && sources.isNotEmpty; | |||||
| final tristate = valueSelected.where((e) => sources.firstWhereOrNull((t) => t.key == e.key) != null).isNotEmpty; | |||||
| return Visibility( | |||||
| visible: sources.isNotEmpty, | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| border: Border( | |||||
| bottom: BorderSide( | |||||
| color: AppColors.neutral1, | |||||
| width: 0.5, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| child: InkWell( | |||||
| onTap: () { | |||||
| if (isSelectAll) { | |||||
| selecteds.value = List.of(valueSelected)..removeWhere((e) => sources.firstWhereOrNull((t) => t.key == e.key) != null); | |||||
| } else { | |||||
| final itemsAdded = List.of(sources)..removeWhere((e) => valueSelected.firstWhereOrNull((t) => t.key == e.key) != null); | |||||
| selecteds.value = [...valueSelected, ...itemsAdded]; | |||||
| } | |||||
| }, | |||||
| child: Row( | |||||
| children: [ | |||||
| Checkbox( | |||||
| value: isSelectAll ? isSelectAll : (tristate ? null : tristate), | |||||
| tristate: true, | |||||
| onChanged: (val) { | |||||
| if (isSelectAll) { | |||||
| selecteds.value = List.of(valueSelected)..removeWhere((e) => sources.firstWhereOrNull((t) => t.key == e.key) != null); | |||||
| } else { | |||||
| final itemsAdded = List.of(sources)..removeWhere((e) => valueSelected.firstWhereOrNull((t) => t.key == e.key) != null); | |||||
| selecteds.value = [...valueSelected, ...itemsAdded]; | |||||
| } | |||||
| }, | |||||
| ), | |||||
| Text( | |||||
| 'Tất cả', | |||||
| style: StylesText.body6, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } |
| import 'package:bloc/bloc.dart'; | import 'package:bloc/bloc.dart'; | ||||
| import 'package:equatable/equatable.dart'; | import 'package:equatable/equatable.dart'; | ||||
| import 'package:farm_tpf/utils/helpers.dart'; | |||||
| import 'package:flutter/foundation.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import '../../../../data/api/app_exception.dart'; | import '../../../../data/api/app_exception.dart'; | ||||
| import '../../../../data/repository/repository.dart'; | import '../../../../data/repository/repository.dart'; | ||||
| import '../../../../models/item_dropdown.dart'; | |||||
| import '../../../../utils/const_common.dart'; | |||||
| import '../models/stamp.dart'; | |||||
| import '../models/stamp_filter_request.dart'; | |||||
| part 'stamp_event.dart'; | part 'stamp_event.dart'; | ||||
| part 'stamp_state.dart'; | part 'stamp_state.dart'; | ||||
| final Repository repository; | final Repository repository; | ||||
| int pageSize = 20; | int pageSize = 20; | ||||
| StampBloc(this.repository) : super(StampInitial()); | StampBloc(this.repository) : super(StampInitial()); | ||||
| final searchCtl = TextEditingController(); | |||||
| var status = ValueNotifier( | |||||
| StampStatus.values | |||||
| .map( | |||||
| (e) => ItemDropDown(key: describeEnum(e), value: Helpers.getStampStatus(describeEnum(e))), | |||||
| ) | |||||
| .toList(), | |||||
| ); | |||||
| var selectedStatus = ValueNotifier( | |||||
| StampStatus.values | |||||
| .map( | |||||
| (e) => ItemDropDown(key: describeEnum(e), value: Helpers.getStampStatus(describeEnum(e))), | |||||
| ) | |||||
| .toList(), | |||||
| ); | |||||
| var sort = ValueNotifier(describeEnum(SortType.asc)); | |||||
| @override | @override | ||||
| Stream<StampState> mapEventToState( | Stream<StampState> mapEventToState( | ||||
| try { | try { | ||||
| if (state is StampInitial) { | if (state is StampInitial) { | ||||
| yield (StampLoading()); | yield (StampLoading()); | ||||
| final response = await repository.stamps(page: 0); | |||||
| final response = await getListStamp(0); | |||||
| yield StampSuccess( | yield StampSuccess( | ||||
| items: response, | items: response, | ||||
| page: 0, | page: 0, | ||||
| } | } | ||||
| if (state is StampSuccess) { | if (state is StampSuccess) { | ||||
| final currentState = state as StampSuccess; | final currentState = state as StampSuccess; | ||||
| if (currentState.hasReachedMax ?? false) { | |||||
| return; | |||||
| } | |||||
| int page = (currentState.page ?? 0) + 1; | int page = (currentState.page ?? 0) + 1; | ||||
| final response = await repository.stamps(page: page); | |||||
| final response = await getListStamp(page); | |||||
| yield response.isEmpty | yield response.isEmpty | ||||
| ? currentState.copyWith(hasReachedMax: true) | ? currentState.copyWith(hasReachedMax: true) | ||||
| : StampSuccess( | : StampSuccess( | ||||
| if (event is OnRefresh) { | if (event is OnRefresh) { | ||||
| try { | try { | ||||
| yield (StampLoading()); | yield (StampLoading()); | ||||
| final response = await repository.stamps(page: 0); | |||||
| final response = await getListStamp(0); | |||||
| yield StampSuccess( | yield StampSuccess( | ||||
| items: response, | items: response, | ||||
| page: 0, | page: 0, | ||||
| } else if (event is OnSearch) { | } else if (event is OnSearch) { | ||||
| try { | try { | ||||
| yield (StampLoading()); | yield (StampLoading()); | ||||
| final response = await repository.stamps(page: 0); | |||||
| final response = await getListStamp(0); | |||||
| yield StampSuccess(items: response, page: 0, hasReachedMax: response.length < pageSize ? true : false); | yield StampSuccess(items: response, page: 0, hasReachedMax: response.length < pageSize ? true : false); | ||||
| } catch (e) { | } catch (e) { | ||||
| yield (StampFailure(errorString: AppException.handleError(e))); | yield (StampFailure(errorString: AppException.handleError(e))); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Future<List<Stamp>> getListStamp(int page) async { | |||||
| var filter = StampFilterRequest() | |||||
| ..sort = sort.value | |||||
| ..description = searchCtl.text | |||||
| ..status = selectedStatus.value.map((e) => e.key ?? '').toList(); | |||||
| return await repository.stamps(page: 0, filter: filter); | |||||
| } | |||||
| } | } |
| import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart'; | import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/bloc/stamp_bloc.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/cubit/detail_stamp_cubit.dart'; | import 'package:farm_tpf/presentation/screens/codes/cubit/detail_stamp_cubit.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/update_activity_page.dart'; | import 'package:farm_tpf/presentation/screens/codes/update_activity_page.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/widgets/item_code_timeline.dart'; | import 'package:farm_tpf/presentation/screens/codes/widgets/item_code_timeline.dart'; | ||||
| import 'package:farm_tpf/utils/helpers.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:get/get.dart'; | import 'package:get/get.dart'; | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| appBar: AppBarWidget( | |||||
| action: IconButton( | |||||
| onPressed: () { | |||||
| // Get.to( | |||||
| // () => UpdateActivityPage( | |||||
| // stampCode: widget.stampCode, | |||||
| // ), | |||||
| // ); | |||||
| }, | |||||
| icon: Icon( | |||||
| Icons.edit, | |||||
| color: Colors.blue, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| appBar: AppBarWidget(), | |||||
| body: Padding( | body: Padding( | ||||
| padding: const EdgeInsets.all(8.0), | padding: const EdgeInsets.all(8.0), | ||||
| child: Column( | child: Column( | ||||
| children: [ | children: [ | ||||
| _itemCodeDetail( | _itemCodeDetail( | ||||
| title: 'Tên sản phẩm', | title: 'Tên sản phẩm', | ||||
| detail: 'Cà rốt', | |||||
| detail: stamp.productName ?? '', | |||||
| titleStyle: StylesText.body4, | titleStyle: StylesText.body4, | ||||
| detailStyle: StylesText.body4.copyWith( | detailStyle: StylesText.body4.copyWith( | ||||
| color: Colors.blue, | color: Colors.blue, | ||||
| ), | ), | ||||
| _itemCodeDetail(title: 'Mô tả', detail: stamp.description ?? ''), | _itemCodeDetail(title: 'Mô tả', detail: stamp.description ?? ''), | ||||
| _itemCodeDetail(title: 'Số lượng tem', detail: stamp.quantity?.formatNumtoStringDecimal().toString() ?? ''), | _itemCodeDetail(title: 'Số lượng tem', detail: stamp.quantity?.formatNumtoStringDecimal().toString() ?? ''), | ||||
| _itemCodeDetail(title: 'Trạng thái', detail: stamp.status ?? ''), | |||||
| _itemCodeDetail(title: 'Trạng thái', detail: Helpers.getStampStatus(stamp.status ?? '')), | |||||
| _itemCodeDetail(title: 'Hạn sử dụng', detail: stamp.expiredDate?.format_DDMMYY().toString() ?? ''), | _itemCodeDetail(title: 'Hạn sử dụng', detail: stamp.expiredDate?.format_DDMMYY().toString() ?? ''), | ||||
| _itemCodeDetail(title: 'Mẫu tem', detail: stamp.stampType?.exampleStampName ?? ''), | _itemCodeDetail(title: 'Mẫu tem', detail: stamp.stampType?.exampleStampName ?? ''), | ||||
| const SizedBox( | const SizedBox( | ||||
| ), | ), | ||||
| Expanded( | Expanded( | ||||
| child: SecondButton( | child: SecondButton( | ||||
| onPressed: () {}, | |||||
| onPressed: () { | |||||
| bloc.downloadFile(widget.stampCode); | |||||
| }, | |||||
| title: 'In / Xuất file', | title: 'In / Xuất file', | ||||
| borderColor: Colors.cyan, | borderColor: Colors.cyan, | ||||
| textColor: Colors.white, | textColor: Colors.white, |
| import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/widgets/item_code.dart'; | import 'package:farm_tpf/presentation/screens/codes/widgets/item_code.dart'; | ||||
| import 'package:farm_tpf/themes/app_colors.dart'; | import 'package:farm_tpf/themes/app_colors.dart'; | ||||
| import 'package:farm_tpf/utils/const_common.dart'; | |||||
| import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/foundation.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:get/get.dart'; | import 'package:get/get.dart'; | ||||
| import '../../../models/item_dropdown.dart'; | |||||
| import '../../../themes/styles_text.dart'; | import '../../../themes/styles_text.dart'; | ||||
| import '../../../utils/const_string.dart'; | import '../../../utils/const_string.dart'; | ||||
| import '../../../utils/helpers.dart'; | |||||
| import '../../custom_widgets/bottom_loader.dart'; | import '../../custom_widgets/bottom_loader.dart'; | ||||
| import '../../custom_widgets/dropdown/multiple_select_bottom_sheet.dart'; | |||||
| import '../../custom_widgets/loading_list_page.dart'; | import '../../custom_widgets/loading_list_page.dart'; | ||||
| import '../plot/widget_search.dart'; | import '../plot/widget_search.dart'; | ||||
| import 'bloc/stamp_bloc.dart'; | import 'bloc/stamp_bloc.dart'; | ||||
| style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22), | style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22), | ||||
| ), | ), | ||||
| ), | ), | ||||
| WidgetSearch(), | |||||
| WidgetSearch( | |||||
| searchController: bloc.searchCtl, | |||||
| onPressed: (value) { | |||||
| Helpers.hideKeyboard(context); | |||||
| bloc.add(OnRefresh()); | |||||
| }, | |||||
| ), | |||||
| Row( | Row( | ||||
| children: [ | children: [ | ||||
| Button2Icon( | |||||
| leftIcon: CupertinoIcons.arrow_up_arrow_down, | |||||
| rightIcon: CupertinoIcons.chevron_down, | |||||
| title: 'Sort', | |||||
| onPressed: () {}, | |||||
| ValueListenableBuilder<String>( | |||||
| valueListenable: bloc.sort, | |||||
| builder: (context, sort, _) { | |||||
| return Button2Icon( | |||||
| leftIcon: (sort == describeEnum(SortType.asc)) ? CupertinoIcons.arrow_up : CupertinoIcons.arrow_down, | |||||
| title: 'Ngày tạo', | |||||
| onPressed: () { | |||||
| if (sort == describeEnum(SortType.asc)) { | |||||
| bloc.sort.value = describeEnum(SortType.desc); | |||||
| } else { | |||||
| bloc.sort.value = describeEnum(SortType.asc); | |||||
| } | |||||
| bloc.sort.notifyListeners(); | |||||
| bloc.add(OnRefresh()); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | ), | ||||
| Button2Icon( | |||||
| leftIcon: CupertinoIcons.slider_horizontal_3, | |||||
| title: 'Filter', | |||||
| rightWidget: Container( | |||||
| width: 16, | |||||
| height: 16, | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(12), | |||||
| color: Colors.blue, | |||||
| ), | |||||
| child: Center( | |||||
| child: Text( | |||||
| '1', | |||||
| style: StylesText.caption6.copyWith(color: Colors.white), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| onPressed: () {}, | |||||
| ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: bloc.selectedStatus, | |||||
| builder: (context, selecteds, _) { | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: bloc.status, | |||||
| builder: (context, status, _) { | |||||
| return MultipleSelectBottomSheet( | |||||
| dataSources: status, | |||||
| initValue: selecteds, | |||||
| onSelected: (val) { | |||||
| bloc.selectedStatus.value = val; | |||||
| Helpers.hideKeyboard(context); | |||||
| bloc.add(OnRefresh()); | |||||
| }, | |||||
| hint: 'Trạng thái', | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | ), | ||||
| const Spacer(), | const Spacer(), | ||||
| SecondButton( | SecondButton( |
| child: Column( | child: Column( | ||||
| crossAxisAlignment: CrossAxisAlignment.start, | crossAxisAlignment: CrossAxisAlignment.start, | ||||
| children: [ | children: [ | ||||
| ItemColumnWidget( | |||||
| title: 'Lô', | |||||
| child: ValueListenableBuilder<String>( | |||||
| valueListenable: bloc.selectedPlot, | |||||
| builder: (context, selected, _) { | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: bloc.plots, | |||||
| builder: (context, plots, _) { | |||||
| return DropdownBottomSheet( | |||||
| dataSources: plots, | |||||
| initValue: selected, | |||||
| onSelected: (val) { | |||||
| bloc.selectedPlot.value = val.key ?? ''; | |||||
| }, | |||||
| hint: 'Lô', | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| ItemColumnWidget( | |||||
| title: 'Tên sản phẩm', | |||||
| child: TextFieldNormal( | |||||
| controller: bloc.productNameCtl, | |||||
| maxLines: 1, | |||||
| hint: 'Tên sản phẩm', | |||||
| ), | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| ItemColumnWidget( | ItemColumnWidget( | ||||
| title: 'Mô tả', | title: 'Mô tả', | ||||
| child: TextFieldNormal( | child: TextFieldNormal( | ||||
| title: 'Số lượng tem', | title: 'Số lượng tem', | ||||
| child: TextFieldNormal( | child: TextFieldNormal( | ||||
| controller: bloc.quantityCtl, | controller: bloc.quantityCtl, | ||||
| keyboardType: TextInputType.number, | |||||
| inputFormatters: [ | |||||
| FilteringTextInputFormatter.digitsOnly, | |||||
| ], | |||||
| maxLines: 1, | maxLines: 1, | ||||
| hint: 'Số lượng tem', | hint: 'Số lượng tem', | ||||
| ), | ), |
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:get/get.dart'; | import 'package:get/get.dart'; | ||||
| import '../../../../custom_model/TbCropDTO.dart'; | |||||
| import '../../../../data/api/app_exception.dart'; | import '../../../../data/api/app_exception.dart'; | ||||
| import '../../../../data/repository/repository.dart'; | import '../../../../data/repository/repository.dart'; | ||||
| import '../../../../models/item_dropdown.dart'; | import '../../../../models/item_dropdown.dart'; | ||||
| final descriptionCtl = TextEditingController(); | final descriptionCtl = TextEditingController(); | ||||
| final quantityCtl = TextEditingController(); | final quantityCtl = TextEditingController(); | ||||
| final expiredDateCtl = TextEditingController(); | final expiredDateCtl = TextEditingController(); | ||||
| final productNameCtl = TextEditingController(); | |||||
| var stampTypeRaws = <StampType>[]; | var stampTypeRaws = <StampType>[]; | ||||
| var stampTypes = ValueNotifier(<ItemDropDown>[]); | var stampTypes = ValueNotifier(<ItemDropDown>[]); | ||||
| var selectedStampType = ValueNotifier(''); | var selectedStampType = ValueNotifier(''); | ||||
| var plotRaws = <TbCropDTO>[]; | |||||
| var plots = ValueNotifier(<ItemDropDown>[]); | |||||
| var selectedPlot = ValueNotifier(''); | |||||
| // var existedCreateStamp = UpdateCreateStamp(); | // var existedCreateStamp = UpdateCreateStamp(); | ||||
| void dispose() { | void dispose() { | ||||
| descriptionCtl.dispose(); | descriptionCtl.dispose(); | ||||
| quantityCtl.dispose(); | quantityCtl.dispose(); | ||||
| expiredDateCtl.dispose(); | expiredDateCtl.dispose(); | ||||
| productNameCtl.dispose(); | |||||
| } | } | ||||
| Future<void> preparedData() async { | Future<void> preparedData() async { | ||||
| (e) => ItemDropDown(key: e.id?.toString(), value: e.exampleStampName), | (e) => ItemDropDown(key: e.id?.toString(), value: e.exampleStampName), | ||||
| ) | ) | ||||
| .toList(); | .toList(); | ||||
| plotRaws = await repository.getPlotsWithoutPaging(); | |||||
| plots.value = plotRaws | |||||
| .map( | |||||
| (e) => ItemDropDown(key: e.id?.toString(), value: e.code), | |||||
| ) | |||||
| .toList(); | |||||
| emit(CreateStampPrepareDataSuccessful()); | emit(CreateStampPrepareDataSuccessful()); | ||||
| } catch (e) { | } catch (e) { | ||||
| emit(CreateStampFailure(AppException.handleError(e))); | emit(CreateStampFailure(AppException.handleError(e))); | ||||
| Future<void> onSubmit() async { | Future<void> onSubmit() async { | ||||
| if (formKey.currentState!.validate()) { | if (formKey.currentState!.validate()) { | ||||
| var requestStamp = RequestStamp(); | var requestStamp = RequestStamp(); | ||||
| var stamp = stampTypeRaws.firstWhere( | |||||
| (e) => selectedStampType.value == e.id?.toString(), | |||||
| orElse: () => StampType(), | |||||
| ); | |||||
| var expiredDate = DateTime.now().add(Duration(days: int.tryParse(expiredDateCtl.text) ?? 0)); | var expiredDate = DateTime.now().add(Duration(days: int.tryParse(expiredDateCtl.text) ?? 0)); | ||||
| requestStamp | requestStamp | ||||
| ..tBCropId = int.tryParse(selectedPlot.value) | |||||
| ..productName = productNameCtl.text | |||||
| ..description = descriptionCtl.text | ..description = descriptionCtl.text | ||||
| ..quantity = int.tryParse(quantityCtl.text) ?? 0 | ..quantity = int.tryParse(quantityCtl.text) ?? 0 | ||||
| ..expiredDate = expiredDate.convertLocalDateTimeToStringUtcDateTime() | ..expiredDate = expiredDate.convertLocalDateTimeToStringUtcDateTime() | ||||
| ..tbExampleStampId = int.tryParse(selectedStampType.value); | ..tbExampleStampId = int.tryParse(selectedStampType.value); | ||||
| if (selectedPlot.value.isEmpty) { | |||||
| Utils.showSnackBarWarning(message: 'Vui lòng chọn lô'); | |||||
| return; | |||||
| } else if (descriptionCtl.text.trim().isEmpty) { | |||||
| Utils.showSnackBarWarning(message: 'Vui lòng nhập mô tả'); | |||||
| return; | |||||
| } else if (productNameCtl.text.trim().isEmpty) { | |||||
| Utils.showSnackBarWarning(message: 'Vui lòng nhập tên sản phẩm'); | |||||
| return; | |||||
| } else if ((int.tryParse(quantityCtl.text) ?? 0) == 0) { | |||||
| Utils.showSnackBarWarning(message: 'Vui lòng nhập số lượng tem'); | |||||
| return; | |||||
| } else if ((int.tryParse(expiredDateCtl.text) ?? 0) == 0) { | |||||
| Utils.showSnackBarWarning(message: 'Vui lòng nhập hạn sử dụng'); | |||||
| return; | |||||
| } else if (selectedStampType.value.isEmpty) { | |||||
| Utils.showSnackBarWarning(message: 'Vui lòng nhập mẫu tem'); | |||||
| return; | |||||
| } | |||||
| print(requestStamp.toJson()); | print(requestStamp.toJson()); | ||||
| UtilWidget.showLoading(); | UtilWidget.showLoading(); | ||||
| await repository.createStamp( | await repository.createStamp( |
| import 'package:bloc/bloc.dart'; | import 'package:bloc/bloc.dart'; | ||||
| import 'package:dio/dio.dart'; | |||||
| import 'package:equatable/equatable.dart'; | import 'package:equatable/equatable.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/bloc/stamp_bloc.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | ||||
| import 'package:flutter/widgets.dart'; | |||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
| import 'package:open_filex/open_filex.dart'; | |||||
| import 'package:path_provider/path_provider.dart'; | |||||
| import '../../../../data/api/app_exception.dart'; | import '../../../../data/api/app_exception.dart'; | ||||
| import '../../../../data/api/dio_provider.dart'; | |||||
| import '../../../../data/repository/repository.dart'; | import '../../../../data/repository/repository.dart'; | ||||
| import '../../../../utils/const_common.dart'; | |||||
| import '../../../../utils/utils.dart'; | import '../../../../utils/utils.dart'; | ||||
| import '../../../custom_widgets/widget_utils.dart'; | import '../../../custom_widgets/widget_utils.dart'; | ||||
| import '../models/stamp.dart'; | import '../models/stamp.dart'; | ||||
| class DetailStampCubit extends Cubit<DetailStampState> { | class DetailStampCubit extends Cubit<DetailStampState> { | ||||
| final repository = Repository(); | final repository = Repository(); | ||||
| DetailStampCubit() : super(DetailStampInitial()); | DetailStampCubit() : super(DetailStampInitial()); | ||||
| static String pathDownload = 'download'; | |||||
| String currentLocalPath = ''; | |||||
| Future<void> preparedData(int stampId) async { | Future<void> preparedData(int stampId) async { | ||||
| try { | try { | ||||
| emit(DetailStampLoading()); | emit(DetailStampLoading()); | ||||
| var stamp = await repository.getStampDetail(id: stampId); | var stamp = await repository.getStampDetail(id: stampId); | ||||
| var timeline = await repository.getStampTimeline(stampId: stampId); | var timeline = await repository.getStampTimeline(stampId: stampId); | ||||
| // stampTypeRaws = await repository.stampTypes(); | |||||
| // stampTypes.value = stampTypeRaws | |||||
| // .map( | |||||
| // (e) => ItemDropDown(key: e.id?.toString(), value: e.exampleStampName), | |||||
| // ) | |||||
| // .toList(); | |||||
| emit(DetailStampSuccessful(stamp, timeline)); | emit(DetailStampSuccessful(stamp, timeline)); | ||||
| } catch (e) { | } catch (e) { | ||||
| emit(DetailStampFailure(AppException.handleError(e))); | emit(DetailStampFailure(AppException.handleError(e))); | ||||
| status: status, | status: status, | ||||
| ); | ); | ||||
| } | } | ||||
| Future downloadFile(String stampCode) async { | |||||
| try { | |||||
| var dio = DioProvider(); | |||||
| print(DateTime.now().millisecondsSinceEpoch); | |||||
| var fileName = '${DateTime.now().millisecondsSinceEpoch.toString()}.xlsx'; | |||||
| currentLocalPath = await getFilePath(fileName); | |||||
| UtilWidget.showLoading(); | |||||
| await dio.download( | |||||
| '${ConstCommon.baseUrl}/api/tb-codes/export?tbCodeValue=$stampCode', | |||||
| currentLocalPath, | |||||
| onReceiveProgress: (rec, total) {}, | |||||
| ); | |||||
| UtilWidget.hideDialog(); | |||||
| await onOpenFile(); | |||||
| } catch (e) { | |||||
| UtilWidget.hideDialog(); | |||||
| Utils.showSnackBarError(message: 'Không thể mở tập tin'); | |||||
| print(e.toString()); | |||||
| } | |||||
| } | |||||
| Future<void> onOpenFile() async { | |||||
| var result = await OpenFilex.open(currentLocalPath); | |||||
| if (result.type == ResultType.done) { | |||||
| //can open | |||||
| } else { | |||||
| Utils.showSnackBarError(message: 'Không thể mở tập tin'); | |||||
| } | |||||
| } | |||||
| Future<String> getFilePath(uniqueFileName) async { | |||||
| var dir = await getApplicationDocumentsDirectory(); | |||||
| var path = '${dir.path}/$pathDownload/$uniqueFileName'; | |||||
| print(path); | |||||
| return path; | |||||
| } | |||||
| } | } |
| TbCropDTO? tbCropDTO; | TbCropDTO? tbCropDTO; | ||||
| String? code; | String? code; | ||||
| num? quantity; | num? quantity; | ||||
| String? productName; | |||||
| String? description; | String? description; | ||||
| String? pathImage; | String? pathImage; | ||||
| String? status; | String? status; | ||||
| this.tbCropDTO, | this.tbCropDTO, | ||||
| this.code, | this.code, | ||||
| this.quantity, | this.quantity, | ||||
| this.productName, | |||||
| this.description, | this.description, | ||||
| this.pathImage, | this.pathImage, | ||||
| this.status, | this.status, | ||||
| Stamp.fromJson(Map<String, dynamic> json) { | Stamp.fromJson(Map<String, dynamic> json) { | ||||
| id = json['id']; | id = json['id']; | ||||
| tbCropDTO = json['TbCropDTO'] != null ? new TbCropDTO.fromJson(json['TbCropDTO']) : null; | |||||
| tbCropDTO = json['tbCrop'] != null ? new TbCropDTO.fromJson(json['tbCrop']) : null; | |||||
| code = json['code']; | code = json['code']; | ||||
| quantity = json['quantity']; | quantity = json['quantity']; | ||||
| productName = json['productName']; | |||||
| description = json['description']; | description = json['description']; | ||||
| pathImage = json['pathImage']; | pathImage = json['pathImage']; | ||||
| status = json['status']; | status = json['status']; | ||||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
| data['id'] = this.id; | data['id'] = this.id; | ||||
| if (this.tbCropDTO != null) { | if (this.tbCropDTO != null) { | ||||
| data['TbCropDTO'] = this.tbCropDTO?.toJson(); | |||||
| data['tbCrop'] = this.tbCropDTO?.toJson(); | |||||
| } | } | ||||
| data['code'] = this.code; | data['code'] = this.code; | ||||
| data['quantity'] = this.quantity; | data['quantity'] = this.quantity; | ||||
| data['productName'] = this.productName; | |||||
| data['description'] = this.description; | data['description'] = this.description; | ||||
| data['pathImage'] = this.pathImage; | data['pathImage'] = this.pathImage; | ||||
| data['status'] = this.status; | data['status'] = this.status; |
| class StampFilterRequest { | |||||
| List<String>? status; | |||||
| String? description; | |||||
| String? sort; | |||||
| StampFilterRequest({this.status, this.description, this.sort}); | |||||
| StampFilterRequest.fromJson(Map<String, dynamic> json) { | |||||
| status = json['status'].cast<String>(); | |||||
| description = json['description']; | |||||
| sort = json['sort']; | |||||
| } | |||||
| Map<String, dynamic> toJson() { | |||||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
| data['status'] = this.status; | |||||
| data['description'] = this.description; | |||||
| data['sort'] = this.sort; | |||||
| return data; | |||||
| } | |||||
| } |
| int? quantity; | int? quantity; | ||||
| String? description; | String? description; | ||||
| String? expiredDate; | String? expiredDate; | ||||
| String? productName; | |||||
| RequestStamp({ | RequestStamp({ | ||||
| this.tBCropId, | this.tBCropId, | ||||
| this.quantity, | this.quantity, | ||||
| this.description, | this.description, | ||||
| this.expiredDate, | this.expiredDate, | ||||
| this.productName, | |||||
| }); | }); | ||||
| RequestStamp.fromJson(Map<String, dynamic> json) { | RequestStamp.fromJson(Map<String, dynamic> json) { | ||||
| quantity = json['quantity']; | quantity = json['quantity']; | ||||
| description = json['description']; | description = json['description']; | ||||
| expiredDate = json['expiredDate']; | expiredDate = json['expiredDate']; | ||||
| productName = json['productName']; | |||||
| } | } | ||||
| Map<String, dynamic> toJson() { | Map<String, dynamic> toJson() { | ||||
| data['quantity'] = this.quantity; | data['quantity'] = this.quantity; | ||||
| data['description'] = this.description; | data['description'] = this.description; | ||||
| data['expiredDate'] = this.expiredDate; | data['expiredDate'] = this.expiredDate; | ||||
| data['productName'] = this.productName; | |||||
| return data; | return data; | ||||
| } | } | ||||
| } | } |
| int? cropId; | int? cropId; | ||||
| String? executeDate; | String? executeDate; | ||||
| String? description; | String? description; | ||||
| String? location; | |||||
| String? createdDate; | String? createdDate; | ||||
| int? createdById; | int? createdById; | ||||
| String? createdByName; | String? createdByName; | ||||
| cropId = json['cropId']; | cropId = json['cropId']; | ||||
| executeDate = json['executeDate']; | executeDate = json['executeDate']; | ||||
| description = json['description']; | description = json['description']; | ||||
| location = json['location']; | |||||
| createdDate = json['createdDate']; | createdDate = json['createdDate']; | ||||
| createdById = json['createdById']; | createdById = json['createdById']; | ||||
| createdByName = json['createdByName']; | createdByName = json['createdByName']; | ||||
| data['cropId'] = this.cropId; | data['cropId'] = this.cropId; | ||||
| data['executeDate'] = this.executeDate; | data['executeDate'] = this.executeDate; | ||||
| data['description'] = this.description; | data['description'] = this.description; | ||||
| data['location'] = this.location; | |||||
| data['createdDate'] = this.createdDate; | data['createdDate'] = this.createdDate; | ||||
| data['createdById'] = this.createdById; | data['createdById'] = this.createdById; | ||||
| data['createdByName'] = this.createdByName; | data['createdByName'] = this.createdByName; |
| // ignore_for_file: public_member_api_docs, sort_constructors_first | // ignore_for_file: public_member_api_docs, sort_constructors_first | ||||
| import 'package:farm_tpf/utils/helpers.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| var expiredDate = item.expiredDate?.format_DDMMYY().toString() ?? ''; | var expiredDate = item.expiredDate?.format_DDMMYY().toString() ?? ''; | ||||
| var quantity = item.quantity; | var quantity = item.quantity; | ||||
| var status = 'mới'; | |||||
| switch (item.status) { | |||||
| case 'NEW': | |||||
| status = 'mới'; | |||||
| break; | |||||
| default: | |||||
| } | |||||
| var status = Helpers.getStampStatus(item.status ?? ''); | |||||
| return GestureDetector( | return GestureDetector( | ||||
| onTap: () { | onTap: () { | ||||
| onPressed(); | onPressed(); | ||||
| crossAxisAlignment: CrossAxisAlignment.start, | crossAxisAlignment: CrossAxisAlignment.start, | ||||
| children: [ | children: [ | ||||
| Text( | Text( | ||||
| item.description ?? '', | |||||
| style: StylesText.body1, | |||||
| '${item.description ?? ''} - ${item.tbCropDTO?.code ?? ''}', | |||||
| style: StylesText.body4, | |||||
| ), | ), | ||||
| const SizedBox( | const SizedBox( | ||||
| height: 8, | height: 8, |
| _widgetItemInfoCompleted( | _widgetItemInfoCompleted( | ||||
| title: 'Mô tả', | title: 'Mô tả', | ||||
| actionDate: item.description ?? '', | actionDate: item.description ?? '', | ||||
| location: 'dsfsdfsd f sdf dsf sd fds ', | |||||
| location: item.location ?? '', | |||||
| ), | ), | ||||
| ], | ], | ||||
| ), | ), |
| import 'package:farm_tpf/custom_model/TbCropDTO.dart'; | |||||
| import 'package:farm_tpf/data/repository/repository.dart'; | import 'package:farm_tpf/data/repository/repository.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; | import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; | import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/plot/widget_search.dart'; | import 'package:farm_tpf/presentation/screens/plot/widget_search.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | ||||
| import 'package:farm_tpf/utils/const_assets.dart'; | |||||
| import 'package:farm_tpf/utils/const_color.dart'; | |||||
| import 'package:farm_tpf/utils/pref.dart'; | import 'package:farm_tpf/utils/pref.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:farm_tpf/utils/const_string.dart'; | import 'package:farm_tpf/utils/const_string.dart'; | ||||
| import 'package:farm_tpf/utils/formatter.dart'; | |||||
| import 'bloc/plot_bloc.dart'; | import 'bloc/plot_bloc.dart'; | ||||
| import 'widgets/item_plot.dart'; | |||||
| class PlotListScreen extends StatefulWidget { | class PlotListScreen extends StatefulWidget { | ||||
| @override | @override | ||||
| style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22), | style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22), | ||||
| ), | ), | ||||
| ), | ), | ||||
| WidgetSearch(), | |||||
| WidgetSearch( | |||||
| searchController: TextEditingController(), | |||||
| onPressed: (value) { | |||||
| FocusScope.of(context).requestFocus(FocusNode()); | |||||
| BlocProvider.of<PlotBloc>(context).add(OnSearch(searchString: value)); | |||||
| }, | |||||
| ), | |||||
| Expanded(child: BlocBuilder<PlotBloc, PlotState>( | Expanded(child: BlocBuilder<PlotBloc, PlotState>( | ||||
| builder: (context, state) { | builder: (context, state) { | ||||
| if (state is PlotFailure) { | if (state is PlotFailure) { | ||||
| return Center(child: Text(label_list_empty)); | return Center(child: Text(label_list_empty)); | ||||
| } | } | ||||
| return RefreshIndicator( | return RefreshIndicator( | ||||
| child: ListView.builder( | |||||
| physics: AlwaysScrollableScrollPhysics(), | |||||
| itemBuilder: (BuildContext context, int index) { | |||||
| return index >= (state.items ?? []).length ? BottomLoader() : ItemInfinityWidget(item: state.items?[index]); | |||||
| }, | |||||
| itemCount: (state.hasReachedMax ?? false) ? (state.items ?? []).length : (state.items ?? []).length + 1, | |||||
| controller: _scrollController, | |||||
| ), | |||||
| onRefresh: () async { | |||||
| _plotBloc?.add(OnRefresh()); | |||||
| }); | |||||
| child: ListView.builder( | |||||
| physics: AlwaysScrollableScrollPhysics(), | |||||
| itemBuilder: (BuildContext context, int index) { | |||||
| return index >= (state.items ?? []).length | |||||
| ? BottomLoader() | |||||
| : ItemPlot( | |||||
| item: state.items?[index], | |||||
| onPressed: () { | |||||
| Navigator.push( | |||||
| context, | |||||
| MaterialPageRoute( | |||||
| builder: (BuildContext context) => PlotDetailScreen( | |||||
| cropId: state.items?[index].id ?? -1, | |||||
| initialIndex: 0, | |||||
| cropType: state.items?[index].tbCropTypeId ?? -1, | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| itemCount: (state.hasReachedMax ?? false) ? (state.items ?? []).length : (state.items ?? []).length + 1, | |||||
| controller: _scrollController, | |||||
| ), | |||||
| onRefresh: () async { | |||||
| _plotBloc?.add(OnRefresh()); | |||||
| }, | |||||
| ); | |||||
| } | } | ||||
| return Center( | return Center( | ||||
| child: LoadingListPage(), | child: LoadingListPage(), | ||||
| super.dispose(); | super.dispose(); | ||||
| } | } | ||||
| } | } | ||||
| class ItemInfinityWidget extends StatelessWidget { | |||||
| final TbCropDTO item; | |||||
| const ItemInfinityWidget({Key? key, required this.item}) : super(key: key); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| var backgroundColor; | |||||
| var textColor; | |||||
| switch (item.status) { | |||||
| case "STATUS_ARE_ACTIVE": | |||||
| backgroundColor = Colors.white; | |||||
| textColor = AppColors.DEFAULT; | |||||
| break; | |||||
| case "STATUS_FINISHED": | |||||
| backgroundColor = AppColors.DEFAULT; | |||||
| textColor = Colors.white; | |||||
| break; | |||||
| default: | |||||
| backgroundColor = Colors.white; | |||||
| textColor = Colors.black; | |||||
| } | |||||
| return GestureDetector( | |||||
| child: Container( | |||||
| margin: EdgeInsets.all(8), | |||||
| decoration: BoxDecoration( | |||||
| color: backgroundColor, | |||||
| border: Border.all(color: Colors.grey, width: 0.35), | |||||
| borderRadius: BorderRadius.circular(8), | |||||
| boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 3, offset: Offset(0, 3))]), | |||||
| padding: EdgeInsets.all(8), | |||||
| child: Row( | |||||
| children: [ | |||||
| Container( | |||||
| child: Stack( | |||||
| children: [ | |||||
| Image.asset( | |||||
| AppAssets.tempImage, | |||||
| width: 65, | |||||
| height: 65, | |||||
| ), | |||||
| Positioned( | |||||
| child: Container( | |||||
| color: Colors.grey.withOpacity(0.5), | |||||
| width: 65, | |||||
| height: 20, | |||||
| child: Text(item.areaM2?.formatNumtoStringDecimal().toString() ?? '' + " m\u00B2", | |||||
| textAlign: TextAlign.center, style: TextStyle(color: Colors.white)), | |||||
| ), | |||||
| bottom: 0, | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| SizedBox( | |||||
| width: 12, | |||||
| ), | |||||
| Expanded( | |||||
| child: Container( | |||||
| height: 75, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| mainAxisSize: MainAxisSize.min, | |||||
| children: [ | |||||
| Text("${item.code ?? ''} - ${item.suppliesName ?? ''}", style: TextStyle(color: textColor, fontWeight: FontWeight.bold)), | |||||
| Expanded( | |||||
| child: SizedBox(), | |||||
| ), | |||||
| Row( | |||||
| children: [ | |||||
| Icon( | |||||
| Icons.access_time, | |||||
| size: 16, | |||||
| color: textColor, | |||||
| ), | |||||
| SizedBox( | |||||
| width: 4, | |||||
| ), | |||||
| Expanded( | |||||
| child: Text(item.startDate?.format_DDMMYY_HHmm().toString() ?? '', style: TextStyle(color: textColor)), | |||||
| ), | |||||
| ], | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| onTap: () { | |||||
| Navigator.push( | |||||
| context, | |||||
| MaterialPageRoute( | |||||
| builder: (BuildContext context) => PlotDetailScreen( | |||||
| cropId: item.id ?? -1, | |||||
| initialIndex: 0, | |||||
| cropType: item.tbCropTypeId ?? -1, | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }); | |||||
| } | |||||
| } |
| import 'bloc/plot_bloc.dart'; | import 'bloc/plot_bloc.dart'; | ||||
| class WidgetSearch extends StatefulWidget { | class WidgetSearch extends StatefulWidget { | ||||
| final TextEditingController searchController; | |||||
| final Function(String) onPressed; | |||||
| const WidgetSearch({ | |||||
| super.key, | |||||
| required this.searchController, | |||||
| required this.onPressed, | |||||
| }); | |||||
| @override | @override | ||||
| _WidgetSearchState createState() => _WidgetSearchState(); | _WidgetSearchState createState() => _WidgetSearchState(); | ||||
| } | } | ||||
| class _WidgetSearchState extends State<WidgetSearch> { | class _WidgetSearchState extends State<WidgetSearch> { | ||||
| BuildContext? _blocContext; | |||||
| TextEditingController _searchController = TextEditingController(); | |||||
| @override | @override | ||||
| void initState() { | void initState() { | ||||
| super.initState(); | super.initState(); | ||||
| _searchController.addListener(() { | |||||
| final keyword = _searchController.text; | |||||
| widget.searchController.addListener(() { | |||||
| final keyword = widget.searchController.text; | |||||
| if (keyword.isNotEmpty) { | if (keyword.isNotEmpty) { | ||||
| //search when text change | //search when text change | ||||
| } | } | ||||
| } | } | ||||
| Widget getSearchBarUI() { | Widget getSearchBarUI() { | ||||
| _searchController.text = ""; | |||||
| // widget.searchController.text = ""; | |||||
| return Padding( | return Padding( | ||||
| padding: const EdgeInsets.only(left: 8, right: 8, top: 0, bottom: 4), | padding: const EdgeInsets.only(left: 8, right: 8, top: 0, bottom: 4), | ||||
| child: Row( | child: Row( | ||||
| padding: const EdgeInsets.only(left: 16, right: 16, top: 4, bottom: 4), | padding: const EdgeInsets.only(left: 16, right: 16, top: 4, bottom: 4), | ||||
| child: TextField( | child: TextField( | ||||
| textInputAction: TextInputAction.done, | textInputAction: TextInputAction.done, | ||||
| controller: _searchController, | |||||
| controller: widget.searchController, | |||||
| onChanged: (String txt) {}, | onChanged: (String txt) {}, | ||||
| cursorColor: AppColors.GRAY1, | cursorColor: AppColors.GRAY1, | ||||
| decoration: InputDecoration( | decoration: InputDecoration( | ||||
| suffixIcon: IconButton( | suffixIcon: IconButton( | ||||
| icon: Icon( | |||||
| Icons.search, | |||||
| size: 30, | |||||
| ), | |||||
| onPressed: () { | |||||
| FocusScope.of(context).requestFocus(FocusNode()); | |||||
| BlocProvider.of<PlotBloc>(_blocContext!).add(OnSearch(searchString: _searchController.text)); | |||||
| }), | |||||
| icon: Icon( | |||||
| Icons.search, | |||||
| size: 30, | |||||
| ), | |||||
| onPressed: () { | |||||
| widget.onPressed(widget.searchController.text); | |||||
| }, | |||||
| ), | |||||
| hintText: 'Tìm theo mã, tên lô', | hintText: 'Tìm theo mã, tên lô', | ||||
| hintStyle: TextStyle(color: Colors.grey[500])), | hintStyle: TextStyle(color: Colors.grey[500])), | ||||
| onSubmitted: (value) { | onSubmitted: (value) { | ||||
| FocusScope.of(context).requestFocus(FocusNode()); | |||||
| BlocProvider.of<PlotBloc>(_blocContext!).add(OnSearch(searchString: value)); | |||||
| widget.onPressed(widget.searchController.text); | |||||
| }, | }, | ||||
| ), | ), | ||||
| ), | ), | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| _blocContext = context; | |||||
| return Container(child: getSearchBarUI()); | return Container(child: getSearchBarUI()); | ||||
| } | } | ||||
| @override | @override | ||||
| void dispose() { | void dispose() { | ||||
| _searchController.dispose(); | |||||
| widget.searchController.dispose(); | |||||
| super.dispose(); | super.dispose(); | ||||
| } | } | ||||
| } | } |
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:farm_tpf/utils/helpers.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | |||||
| import '../../../../custom_model/TbCropDTO.dart'; | |||||
| import '../../../../themes/app_colors.dart'; | |||||
| import '../../../../themes/styles_text.dart'; | |||||
| import 'package:farm_tpf/utils/formatter.dart'; | |||||
| class ItemPlot extends StatelessWidget { | |||||
| final TbCropDTO item; | |||||
| final Function onPressed; | |||||
| ItemPlot({ | |||||
| Key? key, | |||||
| required this.item, | |||||
| required this.onPressed, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| var startDate = item.startDate?.format_DDMMYY().toString() ?? ''; | |||||
| var area = item.areaM2?.formatNumtoStringDecimal().toString() ?? ''; | |||||
| var backgroundColor; | |||||
| switch (item.status) { | |||||
| case "STATUS_ARE_ACTIVE": | |||||
| backgroundColor = Colors.white; | |||||
| break; | |||||
| case "STATUS_FINISHED": | |||||
| backgroundColor = AppColors.primary1; | |||||
| break; | |||||
| default: | |||||
| backgroundColor = Colors.white; | |||||
| } | |||||
| return GestureDetector( | |||||
| onTap: () { | |||||
| onPressed(); | |||||
| }, | |||||
| child: Container( | |||||
| padding: EdgeInsets.symmetric(vertical: 12, horizontal: 8), | |||||
| margin: EdgeInsets.symmetric(vertical: 4, horizontal: 8), | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| border: Border.all( | |||||
| color: Colors.grey.shade200, | |||||
| width: 1, | |||||
| ), | |||||
| color: backgroundColor, | |||||
| ), | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Text( | |||||
| "${item.code ?? ''} - ${item.suppliesName ?? ''}", | |||||
| style: StylesText.body4, | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| Text( | |||||
| '$startDate - $area m\u00B2', | |||||
| style: StylesText.body6, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } |
| String? code, | String? code, | ||||
| num? areaM2, | num? areaM2, | ||||
| }) { | }) { | ||||
| return Column( | |||||
| children: [ | |||||
| Container( | |||||
| padding: EdgeInsets.all(8), | |||||
| width: double.infinity, | |||||
| color: Colors.white, | |||||
| child: Row( | |||||
| children: [ | |||||
| SizedBox( | |||||
| width: 12, | |||||
| ), | |||||
| Expanded( | |||||
| child: Container( | |||||
| height: 75, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| mainAxisSize: MainAxisSize.min, | |||||
| children: [ | |||||
| Text('${suppliesName ?? ''}', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)), | |||||
| Expanded( | |||||
| child: SizedBox(), | |||||
| ), | |||||
| Text( | |||||
| 'Mã lô: ${code ?? ''}', | |||||
| style: TextStyle(color: Colors.grey), | |||||
| overflow: TextOverflow.clip, | |||||
| ), | |||||
| Text('Diện tích: ${areaM2?.formatNumtoStringDecimal() ?? '0'} m\u00B2', style: TextStyle(color: Colors.grey)) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| Image.asset( | |||||
| AppAssets.tempImage, | |||||
| width: 75, | |||||
| height: 75, | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| Expanded( | |||||
| child: HomeTabbarWidget( | |||||
| cropType: widget.cropType, | |||||
| cropId: widget.cropId, | |||||
| cropCode: widget.cropCode, | |||||
| initialIndex: widget.initialIndex, | |||||
| )) | |||||
| ], | |||||
| return HomeTabbarWidget( | |||||
| cropType: widget.cropType, | |||||
| cropId: widget.cropId, | |||||
| cropCode: widget.cropCode, | |||||
| initialIndex: widget.initialIndex, | |||||
| ); | ); | ||||
| } | } | ||||
| import 'package:farm_tpf/data/repository/user_repository.dart'; | import 'package:farm_tpf/data/repository/user_repository.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart'; | import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/account/sc_account.dart'; | import 'package:farm_tpf/presentation/screens/account/sc_account.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/code_detail_page.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/code_page.dart'; | import 'package:farm_tpf/presentation/screens/codes/code_page.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/control_device/sc_control_device.dart'; | import 'package:farm_tpf/presentation/screens/control_device/sc_control_device.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/notification/sc_notification.dart'; | import 'package:farm_tpf/presentation/screens/notification/sc_notification.dart'; | ||||
| ))); | ))); | ||||
| } | } | ||||
| _showAlertCheckCropCode(String cropCode) async { | |||||
| _showAlertCheckCropCode(String code) async { | |||||
| var repository = Repository(); | var repository = Repository(); | ||||
| Get.defaultDialog(title: "Kiểm tra thông tin lô ....", middleText: "", content: CircularProgressIndicator()); | Get.defaultDialog(title: "Kiểm tra thông tin lô ....", middleText: "", content: CircularProgressIndicator()); | ||||
| try { | try { | ||||
| await repository.getPlotDetailByCode(cropCode).then((value) { | |||||
| print("ok"); | |||||
| if (Get.isDialogOpen ?? false) Get.back(); | |||||
| Get.to(PlotDetailScreen(cropId: value.tbCropDTO?.id ?? -1, cropType: value.tbCropDTO?.tbCropTypeId ?? -1, initialIndex: 0)); | |||||
| }).catchError((onError) { | |||||
| Utils.showDialog( | |||||
| title: "Không tìm thấy lô", | |||||
| message: "Thử lại với mã tem khác?", | |||||
| textConfirm: "Thử lại", | |||||
| textCancel: "Huỷ", | |||||
| onConfirm: () { | |||||
| Get.back(); | |||||
| // scan(context); | |||||
| }); | |||||
| }); | |||||
| if (code.startsWith('LO')) { | |||||
| await repository.getPlotDetailByCode(code).then((value) { | |||||
| print("ok"); | |||||
| if (Get.isDialogOpen ?? false) Get.back(); | |||||
| Get.to( | |||||
| PlotDetailScreen( | |||||
| cropId: value.tbCropDTO?.id ?? -1, | |||||
| cropType: value.tbCropDTO?.tbCropTypeId ?? -1, | |||||
| initialIndex: 0, | |||||
| ), | |||||
| ); | |||||
| }).catchError((onError) { | |||||
| Utils.showDialog( | |||||
| title: "Không tìm thấy lô", | |||||
| message: "Thử lại với mã tem khác?", | |||||
| textConfirm: "Thử lại", | |||||
| textCancel: "Huỷ", | |||||
| onConfirm: () { | |||||
| Get.back(); | |||||
| // scan(context); | |||||
| }); | |||||
| }); | |||||
| } else if (code.startsWith('AC')) { | |||||
| var stamp = await repository.getStampDetailByCode(code: code); | |||||
| Get.to(() => CodeDetailPage(stampId: stamp.id ?? 0, stampCode: stamp.code ?? '')); | |||||
| } | |||||
| } catch (e) { | } catch (e) { | ||||
| Utils.showDialog( | Utils.showDialog( | ||||
| title: "Không tìm thấy lô", | |||||
| message: "Thử lại với mã tem khác?", | |||||
| textConfirm: "Thử lại", | |||||
| textCancel: "Huỷ", | |||||
| onConfirm: () { | |||||
| Get.back(); | |||||
| // scan(context); | |||||
| }); | |||||
| title: "Không tìm thấy lô", | |||||
| message: "Thử lại với mã tem khác?", | |||||
| textConfirm: "Thử lại", | |||||
| textCancel: "Huỷ", | |||||
| onConfirm: () { | |||||
| Get.back(); | |||||
| // scan(context); | |||||
| }, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| } | } | ||||
| enum CRUDStatus { unknown, add, edit, delete } | enum CRUDStatus { unknown, add, edit, delete } | ||||
| enum LocationType { country, province, district, ward } | enum LocationType { country, province, district, ward } | ||||
| enum StampStatus { | |||||
| NEW, | |||||
| ACTIVE, | |||||
| CANCELED, | |||||
| EXPIRED, | |||||
| } | |||||
| enum SortType { | |||||
| asc, | |||||
| desc, | |||||
| } |
| import 'package:farm_tpf/utils/const_common.dart'; | |||||
| import 'package:flutter/foundation.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| class Helpers { | class Helpers { | ||||
| return ''; | return ''; | ||||
| } | } | ||||
| } | } | ||||
| static String getStampStatus(String status) { | |||||
| if (status.toUpperCase() == describeEnum(StampStatus.NEW)) { | |||||
| return 'Mới'; | |||||
| } else if (status.toUpperCase() == describeEnum(StampStatus.ACTIVE)) { | |||||
| return 'Đã kích hoạt'; | |||||
| } else if (status.toUpperCase() == describeEnum(StampStatus.CANCELED)) { | |||||
| return 'Đã huỷ'; | |||||
| } else if (status.toUpperCase() == describeEnum(StampStatus.EXPIRED)) { | |||||
| return 'Hết hạn'; | |||||
| } | |||||
| return ''; | |||||
| } | |||||
| } | } |
| url: "https://pub.dev" | url: "https://pub.dev" | ||||
| source: hosted | source: hosted | ||||
| version: "3.0.0-pre" | version: "3.0.0-pre" | ||||
| multi_select_flutter: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| name: multi_select_flutter | |||||
| sha256: "503857b415d390d29159df8a9d92d83c6aac17aaf1c307fb7bcfc77d097d20ed" | |||||
| url: "https://pub.dev" | |||||
| source: hosted | |||||
| version: "4.1.3" | |||||
| nested: | nested: | ||||
| dependency: transitive | dependency: transitive | ||||
| description: | description: | ||||
| url: "https://pub.dev" | url: "https://pub.dev" | ||||
| source: hosted | source: hosted | ||||
| version: "1.0.2" | version: "1.0.2" | ||||
| open_filex: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| name: open_filex | |||||
| sha256: "74e2280754cf8161e860746c3181db2c996d6c1909c7057b738ede4a469816b8" | |||||
| url: "https://pub.dev" | |||||
| source: hosted | |||||
| version: "4.4.0" | |||||
| package_config: | package_config: | ||||
| dependency: transitive | dependency: transitive | ||||
| description: | description: |
| description: A new Flutter project. | description: A new Flutter project. | ||||
| publish_to: 'none' | publish_to: 'none' | ||||
| version: 1.1.5+20 | |||||
| version: 1.1.6+21 | |||||
| environment: | environment: | ||||
| sdk: ">=2.17.0 <=3.0.0" | sdk: ">=2.17.0 <=3.0.0" | ||||
| flutter_switch: ^0.3.2 | flutter_switch: ^0.3.2 | ||||
| image_picker: ^0.8.3+2 | image_picker: ^0.8.3+2 | ||||
| modal_bottom_sheet: ^3.0.0-pre | modal_bottom_sheet: ^3.0.0-pre | ||||
| open_filex: ^4.4.0 | |||||
| multi_select_flutter: ^4.1.3 | |||||
| dev_dependencies: | dev_dependencies: | ||||
| flutter_test: | flutter_test: |