import 'dart:convert'; import 'package:farm_tpf/custom_model/Media.dart'; import 'package:farm_tpf/custom_model/Nursery.dart'; import 'package:farm_tpf/custom_model/NurseryDetail.dart'; import 'package:farm_tpf/custom_model/Supply.dart'; import 'package:farm_tpf/data/api/app_exception.dart'; import 'package:farm_tpf/data/repository/repository.dart'; import 'package:farm_tpf/presentation/custom_widgets/bloc/media_helper_bloc.dart'; import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart'; import 'package:farm_tpf/presentation/custom_widgets/widget_media_picker.dart'; import 'package:farm_tpf/presentation/screens/actions/bloc/action_detail_bloc.dart'; import 'package:farm_tpf/presentation/screens/actions/nursery/bloc/expansion_list_bloc.dart'; import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_file_controller.dart'; import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_supply.dart'; import 'package:farm_tpf/presentation/screens/resources/sc_resource_helper.dart'; import 'package:farm_tpf/utils/bloc/bloc/status_add_form_bloc.dart'; import 'package:farm_tpf/utils/const_color.dart'; import 'package:farm_tpf/utils/const_common.dart'; import 'package:farm_tpf/utils/const_string.dart'; import 'package:farm_tpf/utils/const_style.dart'; import 'package:farm_tpf/utils/pref.dart'; import 'package:farm_tpf/utils/validators.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_datetime_picker/flutter_datetime_picker.dart'; import 'package:get/get.dart'; import 'package:get/state_manager.dart'; import 'package:intl/intl.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; import 'package:mime/mime.dart'; import 'package:pattern_formatter/pattern_formatter.dart'; import 'package:farm_tpf/utils/formatter.dart'; class EditActionNurseryScreen extends StatefulWidget { final int cropId; final bool isEdit; final int activityId; EditActionNurseryScreen( {@required this.cropId, this.isEdit = false, this.activityId}); @override _EditActionNurseryState createState() => _EditActionNurseryState(); } class _EditActionNurseryState extends State { final GlobalKey _scaffoldKey = new GlobalKey(); final _repository = Repository(); GlobalKey _formKey = GlobalKey(); bool _autoValidate = false; Nursery _nursery = Nursery(); var pref = LocalPref(); TextEditingController _substrateController = TextEditingController(); TextEditingController _seedLengthController = TextEditingController(); TextEditingController _quantityController = TextEditingController(); TextEditingController _seedIncubationTimeController = TextEditingController(); TextEditingController _descriptionController = TextEditingController(); TextEditingController _workerNameController = TextEditingController(); TextEditingController _trayNumberController = TextEditingController(); final _executeByController = TextEditingController(); String executeTimeView; DateTime executeTime = DateTime.now(); List currentNurseryDetail = List(); int currentIndexUpdate = -1; bool isResetForm = true; final changeSupply = Get.put(ChangeSupply()); int selectedSupplyId = -1; List filePaths = List(); var changeFileController = Get.put(ChangeFileController()); Future getSharedPrefs() async { var currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME); _executeByController.text = currentFullName ?? ""; } @override void initState() { super.initState(); getSharedPrefs(); changeSupply.initValue(); changeFileController.initValue(); _nursery.nurseryDetail = new List(); var parsedExecuteDate = DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(executeTime); _nursery.executeDate = "$parsedExecuteDate"; executeTimeView = DateFormat("dd/MM/yyyy HH:mm").format(executeTime); _nursery.cropId = widget.cropId; } _validateInputs() async { if (_formKey.currentState.validate()) { _formKey.currentState.save(); LoadingDialog.showLoadingDialog(context); _nursery.nurseryDetail = currentNurseryDetail; filePaths = Get.find().files; var activityNursery = jsonEncode(_nursery.toJson()).toString(); //ADD NEW if (_nursery.activityId == null) { _repository.createAction((value) { LoadingDialog.hideLoadingDialog(context); Get.back(result: value); Get.snackbar(label_add_success, "Hoạt động ươm", snackPosition: SnackPosition.BOTTOM); }, (error) { LoadingDialog.hideLoadingDialog(context); _scaffoldKey.currentState.showSnackBar(SnackBar( content: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible(child: Text(AppException.handleError(error))), Icon(Icons.error), ], ), backgroundColor: Colors.red, duration: Duration(seconds: 3), )); }, apiAddAction: ConstCommon.apiAddNursery, paramActivity: ConstCommon.paramsActionNursery, activityAction: activityNursery, filePaths: filePaths); } else { //UPDATE _repository.updateAction((value) { LoadingDialog.hideLoadingDialog(context); Get.back(result: value); Get.snackbar(label_update_success, "Hoạt động ươm", snackPosition: SnackPosition.BOTTOM); }, (error) { LoadingDialog.hideLoadingDialog(context); _scaffoldKey.currentState.showSnackBar(SnackBar( content: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible(child: Text(AppException.handleError(error))), Icon(Icons.error), ], ), backgroundColor: Colors.red, duration: Duration(seconds: 3), )); }, apiUpdateAction: ConstCommon.apiUpdateNursery, paramActivity: ConstCommon.paramsActionNursery, activityAction: activityNursery, filePaths: filePaths); } } else { _autoValidate = true; } } Widget _btnExecuteTimePicker() { return FlatButton( padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 0.0, left: 0.0), onPressed: () { DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {}, onConfirm: (date) { setState(() { var parsedDate = DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(date); _nursery.executeDate = "$parsedDate"; executeTimeView = DateFormat("dd/MM/yyyy HH:mm").format(date); }); }, currentTime: executeTime, locale: LocaleType.vi); }, child: Container( padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 10.5, left: 0.0), decoration: BoxDecoration( border: kBorderTextField, ), child: Row( children: [ Expanded( child: Text( //TODO: check condition executeTimeView == null ? "$executeTime" : executeTimeView, style: TextStyle(fontSize: 14.0, color: Colors.black87), )), Icon( Icons.date_range, color: Colors.blue, ), ], ))); } Widget _btnSelectSubstrates() { return FlatButton( padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 0.0, left: 0.0), onPressed: () { Navigator.of(context) .push(MaterialPageRoute( builder: (_) => ResourceHelperScreen( titleName: "Giá thể", type: ConstCommon.supplyTypeSubStrate, selectedId: Get.find().selectedSupplyId), fullscreenDialog: false)) .then((value) { if (value != null) { var result = value as Supply; _nursery.substratesId = result.id; changeSupply.change(result); print("Home: $value"); } }); }, child: Container( padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 10.5, left: 0.0), decoration: BoxDecoration( border: kBorderTextField, ), child: Row( children: [ GetBuilder( builder: (_) => Expanded( child: Text( changeSupply.selectedSupplyName == null ? "Loại giá thể" : changeSupply.selectedSupplyName.toString(), style: TextStyle( fontSize: 14.0, color: Colors.black87)))), Icon( Icons.arrow_drop_down, color: Colors.grey, ), ], ))); } Widget _seedLengthField() { return TextFormField( keyboardType: TextInputType.numberWithOptions(decimal: true), inputFormatters: [ ThousandsFormatter( formatter: NumberFormat("#,###.##", "es"), allowFraction: true) ], decoration: InputDecoration(labelText: "Chiều dài mần"), controller: _seedLengthController, onSaved: (newValue) { _nursery.seedLength = newValue.parseDoubleThousand(); }, ); } Widget _quantityField() { return TextFormField( keyboardType: TextInputType.numberWithOptions(decimal: true), inputFormatters: [ ThousandsFormatter( formatter: NumberFormat("#,###.##", "es"), allowFraction: true) ], decoration: InputDecoration(labelText: "Số lượng hạt gieo"), controller: _quantityController, onSaved: (newValue) { _nursery.quantity = newValue.parseDoubleThousand(); }, ); } Widget _seedIncubationTimeField() { return TextFormField( keyboardType: TextInputType.numberWithOptions(decimal: true), inputFormatters: [ ThousandsFormatter( formatter: NumberFormat("#,###.##", "es"), allowFraction: true) ], decoration: InputDecoration(labelText: "Thời gian ngâm hạt"), controller: _seedIncubationTimeController, onSaved: (newValue) { _nursery.seedIncubationTime = newValue.parseDoubleThousand(); }, ); } Widget _desciptionField() { return TextFormField( keyboardType: TextInputType.text, decoration: InputDecoration(labelText: "Ghi chú"), controller: _descriptionController, onSaved: (newValue) { _nursery.description = newValue; }, ); } Widget _executeByField() { return TextFormField( keyboardType: TextInputType.text, decoration: InputDecoration(labelText: "Người thực hiện"), enabled: false, controller: _executeByController, onSaved: (newValue) {}, ); } Widget _btnAddWorker() { //TODO :check flow error sua item -> xoa list -> bam nut them return Builder(builder: (context) { return BlocConsumer( listener: (context, state) { if (state is Edit) { isResetForm = false; _workerNameController.text = state.nurseryDetail.workerName; _trayNumberController.text = state.nurseryDetail.trayNumber; } else if (state is Delete) { if (currentIndexUpdate == state.index) { isResetForm = true; _workerNameController.text = ""; _trayNumberController.text = ""; } } else { isResetForm = true; _workerNameController.text = ""; _trayNumberController.text = ""; } }, builder: (context, state) { return Container( padding: EdgeInsets.all(8.0), decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(10), color: Colors.white, border: Border.all(color: COLOR_CONST.DEFAULT)), child: Column( children: [ TextFormField( keyboardType: TextInputType.text, controller: _workerNameController, decoration: InputDecoration(labelText: "Tên công nhân"), onSaved: (newValue) {}, ), TextFormField( keyboardType: TextInputType.text, controller: _trayNumberController, decoration: InputDecoration(labelText: "Ươm khây số"), onSaved: (newValue) {}, ), Align( alignment: Alignment.centerRight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ isResetForm ? Container() : OutlineButton( shape: RoundedRectangleBorder( borderRadius: new BorderRadius.circular(8.0)), child: Text("Huỷ"), onPressed: () { context.bloc().add(Reset()); }), FlatButton( color: COLOR_CONST.DEFAULT, shape: RoundedRectangleBorder( borderRadius: new BorderRadius.circular(8.0)), onPressed: () { if (_workerNameController.text.isEmpty || _trayNumberController.text.isEmpty) { return; } NurseryDetail _nurseryDetail = NurseryDetail() ..workerName = _workerNameController.text ..trayNumber = _trayNumberController.text; if (state is Edit) { context.bloc().add(Update( index: state.index, item: _nurseryDetail, items: state.items)); } else { currentNurseryDetail.insert(0, _nurseryDetail); BlocProvider.of(context) .add(AddNew(items: currentNurseryDetail)); } context.bloc().add(Reset()); }, child: Text( (state is Edit) ? "Sửa" : "Thêm", style: TextStyle(color: Colors.white), )) ], ), ), ], )); }); }); } Widget _buildListAddWorker() { return Builder(builder: (context) { return BlocBuilder( builder: (context, state) { if (state is ExpansionListSuccess) { currentNurseryDetail = state.items; if (currentNurseryDetail.isEmpty) { return Container(); } return Container( height: 70, child: ListView.builder( physics: ClampingScrollPhysics(), scrollDirection: Axis.horizontal, shrinkWrap: true, itemCount: currentNurseryDetail.length, itemBuilder: (context, index) { return GestureDetector( onTap: () { print("edit worker"); currentIndexUpdate = index; context.bloc().add(Changed( status: CRUDStatus.edit, index: index, nurseryDetail: currentNurseryDetail[index], items: currentNurseryDetail)); }, child: Card( child: Stack( alignment: Alignment.bottomCenter, overflow: Overflow.visible, children: [ Positioned( child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Container( padding: EdgeInsets.all(4), width: 120, child: Column( children: [ SizedBox( height: 12.0, ), Flexible( child: Text( currentNurseryDetail[index] .workerName ?? "", overflow: TextOverflow.ellipsis, maxLines: 1), ), Flexible( child: Text(currentNurseryDetail[index] .trayNumber ?? "")) ], ), ), )), Positioned( top: -10, right: -10, child: IconButton( icon: Icon( Icons.cancel, color: Colors.redAccent, ), onPressed: () { print("Delete worker"); context.bloc().add( DeleteItem( index: index, items: currentNurseryDetail)); context.bloc().add( Changed( status: CRUDStatus.delete, index: index, nurseryDetail: currentNurseryDetail[index], items: currentNurseryDetail)); }), ) ], ))); })); } else if (state is ExpansionListFailure) { return Container(); } else { return Container(); } }); }); } _actionAppBar() { IconButton iconButton; if (1 == 1) { iconButton = IconButton( icon: Icon( Icons.done, color: Colors.black, ), onPressed: () { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); } _validateInputs(); }, ); return [iconButton]; } return [Container()]; } @override Widget build(BuildContext context) => KeyboardDismisser( gestures: [ GestureType.onTap, GestureType.onPanUpdateDownDirection, ], child: Scaffold( key: _scaffoldKey, appBar: AppBar( centerTitle: true, title: Text(plot_action_nursery), actions: _actionAppBar()), body: KeyboardDismisser( child: MultiBlocProvider( providers: [ BlocProvider( create: (context) => ExpansionListBloc(), ), BlocProvider( create: (context) => StatusAddFormBloc(), ), BlocProvider( create: (context) => ActionDetailBloc(repository: Repository()) ..add(FetchData( isNeedFetchData: widget.isEdit, apiActivity: ConstCommon.apiDetailNursery, activityId: widget.activityId))), BlocProvider( create: (context) => MediaHelperBloc()..add(ChangeListMedia(items: [])), ) ], child: Form( key: _formKey, autovalidate: _autoValidate, child: SingleChildScrollView( padding: EdgeInsets.all(8.0), child: BlocConsumer( listener: (context, state) async { if (state is ActionDetailFailure) { print("fail"); LoadingDialog.hideLoadingDialog(context); } else if (state is ActionDetailSuccess) { LoadingDialog.hideLoadingDialog(context); print("success"); print(state.item); _nursery = Nursery.fromJson(state.item); _seedLengthController.text = _nursery .seedLength .formatNumtoStringDecimal(); _quantityController.text = _nursery.quantity .formatNumtoStringDecimal(); _seedIncubationTimeController.text = _nursery .seedIncubationTime .formatNumtoStringDecimal(); _descriptionController.text = _nursery.description; _executeByController.text = _nursery.executeBy; try { executeTime = DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") .parse(_nursery.executeDate); } catch (_) {} executeTimeView = DateFormat("dd/MM/yyyy HH:mm") .format(executeTime); //Show media if (_nursery.media != null) { await cacheFiles(_nursery.media) .then((value) { print("then: ${value.length}"); BlocProvider.of(context) .add(ChangeListMedia(items: value)); }).whenComplete(() { print("completed"); }); } //Show worker if (_nursery.nurseryDetail.length > 0) { BlocProvider.of(context) .add(AddNew( items: _nursery.nurseryDetail)); } //change subStrates if (_nursery.substratesId != null) { Get.find().changeByIdAndName( _nursery.substratesId, _nursery.substrateName); } } else if (state is ActionDetailInitial) { print("init"); } else if (state is ActionDetailLoading) { print("loading"); LoadingDialog.showLoadingDialog(context); } }, builder: (context, state) { return Column( children: [ Container( width: double.infinity, child: Text( "Ngày thực hiện *", style: TextStyle( color: Colors.black54, fontSize: 13.0), ), ), _btnExecuteTimePicker(), SizedBox( height: 8.0, ), Container( width: double.infinity, child: Text( "Loại giá thể", style: TextStyle( color: Colors.black54, fontSize: 13.0), ), ), _btnSelectSubstrates(), SizedBox( height: 8.0, ), _seedLengthField(), SizedBox( height: 8.0, ), _quantityField(), SizedBox( height: 8.0, ), _seedIncubationTimeField(), SizedBox( height: 8.0, ), _desciptionField(), SizedBox( height: 8.0, ), _executeByField(), SizedBox( height: 8.0, ), _btnAddWorker(), SizedBox( height: 8.0, ), _buildListAddWorker(), SizedBox( height: 8.0, ), BlocBuilder( builder: (context, state) { if (state is MediaHelperSuccess) { print("length: " + state.items.length.toString()); return WidgetMediaPicker( currentItems: state.items, onChangeFiles: (filePaths) async { Get.find() .addAllFile(filePaths); }); } else { return Center( child: CircularProgressIndicator()); } }), ], ); }, ), )))))); @override void dispose() { _substrateController.dispose(); _seedLengthController.dispose(); _quantityController.dispose(); _seedIncubationTimeController.dispose(); _descriptionController.dispose(); _executeByController.dispose(); super.dispose(); } Future> cacheFiles(String existedMedias) async { var medias = List(); var mediaPathsLocal = List(); var mediaPaths = existedMedias.split(";"); for (int i = 0; i < mediaPaths.length; i++) { var tempFile = await DefaultCacheManager() .getSingleFile(ConstCommon.baseImageUrl + mediaPaths[i]); print(tempFile.path); var isVideo = lookupMimeType(tempFile.path) == "video/mp4"; print("file type: " + lookupMimeType(tempFile.path)); Media media = Media() ..pathFile = tempFile.path ..isVideo = isVideo; medias.add(media); mediaPathsLocal.add(tempFile.path); } Get.find().addAllFile(filePaths); return medias; } }