| List<Activities> activities; | List<Activities> activities; | ||||
| String sowingDate; | String sowingDate; | ||||
| int soakSeedsTime; | int soakSeedsTime; | ||||
| int seedIncubationTime; | |||||
| num seedIncubationTime; | |||||
| int numberPlants; | int numberPlants; | ||||
| int numberCurrentPlants; | int numberCurrentPlants; | ||||
| String endOfFarmingDate; | String endOfFarmingDate; |
| import 'package:farm_tpf/utils/validators.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| class DropdownSupplyWidget extends StatelessWidget { | |||||
| final String condition; | |||||
| final String hint; | |||||
| final String value; | |||||
| final Function onPressed; | |||||
| final String invalidMessage; | |||||
| DropdownSupplyWidget( | |||||
| {@required this.hint, | |||||
| this.value, | |||||
| @required this.condition, | |||||
| @required this.onPressed, | |||||
| this.invalidMessage}); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return SizedBox( | |||||
| width: double.infinity, | |||||
| height: Validators.stringNotNullOrEmpty(invalidMessage) ? 85 : 65, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Text( | |||||
| hint ?? '', | |||||
| style: TextStyle( | |||||
| color: Validators.stringNotNullOrEmpty(invalidMessage) | |||||
| ? Colors.red | |||||
| : Colors.black54, | |||||
| fontSize: 13.0), | |||||
| ), | |||||
| SizedBox( | |||||
| width: double.infinity, | |||||
| height: 44, | |||||
| child: FlatButton( | |||||
| padding: EdgeInsets.only( | |||||
| top: 0.0, right: 0.0, bottom: 0.0, left: 0.0), | |||||
| onPressed: onPressed, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Container( | |||||
| padding: EdgeInsets.only( | |||||
| top: 0.0, right: 0.0, bottom: 10.5, left: 0.0), | |||||
| decoration: BoxDecoration( | |||||
| border: Border( | |||||
| bottom: BorderSide( | |||||
| width: 0.5, | |||||
| color: Validators.stringNotNullOrEmpty( | |||||
| invalidMessage) | |||||
| ? Colors.red | |||||
| : Colors.black54)), | |||||
| ), | |||||
| child: Row( | |||||
| children: [ | |||||
| Expanded( | |||||
| child: Text(value ?? hint, | |||||
| style: TextStyle( | |||||
| fontSize: 16.0, | |||||
| color: Colors.black45))), | |||||
| Icon( | |||||
| Icons.arrow_drop_down, | |||||
| color: Colors.grey, | |||||
| ), | |||||
| ], | |||||
| )) | |||||
| ], | |||||
| )), | |||||
| ), | |||||
| Validators.stringNotNullOrEmpty(invalidMessage) | |||||
| ? Text( | |||||
| invalidMessage ?? '', | |||||
| style: TextStyle( | |||||
| fontSize: 12.0, | |||||
| color: Colors.red, | |||||
| fontWeight: FontWeight.normal), | |||||
| textAlign: TextAlign.left, | |||||
| ) | |||||
| : SizedBox(), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } |
| import 'package:farm_tpf/utils/validators.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| class FieldDateWidget extends StatelessWidget { | |||||
| final String hint; | |||||
| final String value; | |||||
| final Function onPressed; | |||||
| final String invalidMessage; | |||||
| FieldDateWidget( | |||||
| {@required this.hint, | |||||
| this.value, | |||||
| @required this.onPressed, | |||||
| this.invalidMessage}); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return SizedBox( | |||||
| width: double.infinity, | |||||
| height: Validators.stringNotNullOrEmpty(invalidMessage) ? 85 : 65, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Text( | |||||
| hint ?? '', | |||||
| style: TextStyle( | |||||
| color: Validators.stringNotNullOrEmpty(invalidMessage) | |||||
| ? Colors.red | |||||
| : Colors.black54, | |||||
| fontSize: 13.0), | |||||
| ), | |||||
| SizedBox( | |||||
| width: double.infinity, | |||||
| height: 44, | |||||
| child: FlatButton( | |||||
| padding: EdgeInsets.only( | |||||
| top: 0.0, right: 0.0, bottom: 0.0, left: 0.0), | |||||
| onPressed: onPressed, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Container( | |||||
| padding: EdgeInsets.only( | |||||
| top: 0.0, right: 0.0, bottom: 10.5, left: 0.0), | |||||
| decoration: BoxDecoration( | |||||
| border: Border( | |||||
| bottom: BorderSide( | |||||
| width: 0.5, | |||||
| color: Validators.stringNotNullOrEmpty( | |||||
| invalidMessage) | |||||
| ? Colors.red | |||||
| : Colors.black54)), | |||||
| ), | |||||
| child: Row( | |||||
| children: [ | |||||
| Expanded( | |||||
| child: Text(value ?? hint, | |||||
| style: TextStyle( | |||||
| fontSize: 16.0, | |||||
| color: Colors.black45))), | |||||
| Icon( | |||||
| Icons.date_range, | |||||
| color: Colors.grey, | |||||
| ), | |||||
| ], | |||||
| )) | |||||
| ], | |||||
| )), | |||||
| ), | |||||
| Validators.stringNotNullOrEmpty(invalidMessage) | |||||
| ? Text( | |||||
| invalidMessage ?? '', | |||||
| style: TextStyle( | |||||
| fontSize: 12.0, | |||||
| color: Colors.red, | |||||
| fontWeight: FontWeight.normal), | |||||
| textAlign: TextAlign.left, | |||||
| ) | |||||
| : SizedBox(), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } |
| import 'package:farm_tpf/utils/const_color.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| class TextFieldAreaWidget extends StatelessWidget { | |||||
| final String hint; | |||||
| final TextEditingController controller; | |||||
| final Function onSaved; | |||||
| TextFieldAreaWidget( | |||||
| {@required this.hint, @required this.onSaved, @required this.controller}); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Container( | |||||
| padding: EdgeInsets.all(8), | |||||
| decoration: BoxDecoration( | |||||
| color: AppColors.YELLOW.withOpacity(0.1), | |||||
| borderRadius: BorderRadius.circular(8)), | |||||
| child: TextFormField( | |||||
| keyboardType: TextInputType.text, | |||||
| controller: controller, | |||||
| decoration: InputDecoration( | |||||
| labelText: hint, hintText: hint, border: InputBorder.none), | |||||
| onSaved: onSaved, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } |
| import 'package:farm_tpf/custom_model/action_form/ActionUIField.dart'; | |||||
| import 'package:farm_tpf/custom_model/action_form/ActionUIForm.dart'; | |||||
| import 'package:farm_tpf/data/repository/repository.dart'; | import 'package:farm_tpf/data/repository/repository.dart'; | ||||
| 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/bloc/media_helper_bloc.dart'; | import 'package:farm_tpf/presentation/custom_widgets/bloc/media_helper_bloc.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/button_widget.dart'; | import 'package:farm_tpf/presentation/custom_widgets/button_widget.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/dropdown_supply_widget.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_action_field_date.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_field_time_picker.dart'; | import 'package:farm_tpf/presentation/custom_widgets/widget_field_time_picker.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_loading.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/custom_widgets/widget_media_picker.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_text_field_area.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_text_form_field.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/actions/cubit/action_ui_cubit.dart'; | import 'package:farm_tpf/presentation/screens/actions/cubit/action_ui_cubit.dart'; | ||||
| import 'package:farm_tpf/utils/pref.dart'; | import 'package:farm_tpf/utils/pref.dart'; | ||||
| import 'package:farm_tpf/utils/validators.dart'; | import 'package:farm_tpf/utils/validators.dart'; | ||||
| DateTime executeTime = DateTime.now(); | DateTime executeTime = DateTime.now(); | ||||
| List<String> filePaths = List<String>(); | List<String> filePaths = List<String>(); | ||||
| var changeFileController = Get.put(ChangeFileController()); | var changeFileController = Get.put(ChangeFileController()); | ||||
| Map<String, TextEditingController> textFieldControllers = {}; | |||||
| Future<Null> getSharedPrefs() async { | Future<Null> getSharedPrefs() async { | ||||
| var currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME); | var currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME); | ||||
| filePaths = Get.find<ChangeFileController>().newFiles; | filePaths = Get.find<ChangeFileController>().newFiles; | ||||
| //Create request general model | //Create request general model | ||||
| try { | try { | ||||
| LoadingDialog.hideLoadingDialog(context); | |||||
| //ADD NEW | //ADD NEW | ||||
| //Update | //Update | ||||
| textFieldControllers.forEach((key, value) { | |||||
| print(textFieldControllers[key].text); | |||||
| }); | |||||
| } catch (e) { | } catch (e) { | ||||
| LoadingDialog.hideLoadingDialog(context); | LoadingDialog.hideLoadingDialog(context); | ||||
| print(e.toString()); | print(e.toString()); | ||||
| ); | ); | ||||
| } | } | ||||
| // | |||||
| // GENERATE DYNAMIC FORM | |||||
| // | |||||
| Widget generateTextField(List<ActionUIField> fields) { | |||||
| return Container( | |||||
| height: fields.length * 70.0, | |||||
| child: ListView.separated( | |||||
| itemCount: fields.length, | |||||
| separatorBuilder: (context, index) { | |||||
| return SizedBox( | |||||
| height: 8, | |||||
| ); | |||||
| }, | |||||
| itemBuilder: (context, index) { | |||||
| var field = fields[index]; | |||||
| if (field.tbControlTypeName == 'text') { | |||||
| return TextFormField( | |||||
| keyboardType: TextInputType.text, | |||||
| decoration: InputDecoration(labelText: field.description), | |||||
| controller: textFieldControllers[field.id.toString()], | |||||
| onSaved: (newValue) {}, | |||||
| validator: field.isMandatory == 0 | |||||
| ? (String value) { | |||||
| return Validators.validateNotNullOrEmpty( | |||||
| value, 'Vui lòng nhập ${field.description}'); | |||||
| } | |||||
| : null, | |||||
| ); | |||||
| } else if (field.tbControlTypeName == 'number') { | |||||
| return WidgetTextFormFieldNumber( | |||||
| hintValue: field.description, | |||||
| textController: textFieldControllers[field.id.toString()], | |||||
| onSaved: (newValue) {}, | |||||
| validator: field.isMandatory == 1 | |||||
| ? (String value) { | |||||
| return Validators.validNumberOrEmpty( | |||||
| value, 'Vui lòng nhập ${field.description}'); | |||||
| } | |||||
| : null, | |||||
| ); | |||||
| } else if (field.tbControlTypeName == 'textarea') { | |||||
| return TextFieldAreaWidget( | |||||
| hint: field.description, | |||||
| controller: textFieldControllers[field.id.toString()], | |||||
| onSaved: (newValue) {}); | |||||
| } else if (field.tbControlTypeName == 'dropdown') { | |||||
| return DropdownSupplyWidget( | |||||
| value: field.description, | |||||
| hint: | |||||
| '${field.description} ${field.isMandatory == 1 ? '*' : ''}', | |||||
| condition: field.tbActivityExtendTypeCondition, | |||||
| invalidMessage: '', | |||||
| onPressed: () {}); | |||||
| } else if (field.tbControlTypeName == 'date') { | |||||
| return FieldDateWidget( | |||||
| value: field.description, | |||||
| hint: | |||||
| '${field.description} ${field.isMandatory == 1 ? '*' : ''}', | |||||
| invalidMessage: '', | |||||
| onPressed: () {}); | |||||
| } else if (field.tbControlTypeName == 'radiobutton') { | |||||
| return Text(field.tbControlTypeName); | |||||
| } else { | |||||
| return Text(field.tbControlTypeName); | |||||
| } | |||||
| }), | |||||
| ); | |||||
| } | |||||
| @override | @override | ||||
| Widget build(BuildContext context) => KeyboardDismisser( | Widget build(BuildContext context) => KeyboardDismisser( | ||||
| gestures: [ | gestures: [ | ||||
| style: TextStyle( | style: TextStyle( | ||||
| color: Colors.red, fontWeight: FontWeight.normal), | color: Colors.red, fontWeight: FontWeight.normal), | ||||
| ), | ), | ||||
| onTap: () {}, | |||||
| onTap: () { | |||||
| FocusScopeNode currentFocus = FocusScope.of(context); | |||||
| if (!currentFocus.hasPrimaryFocus) { | |||||
| currentFocus.unfocus(); | |||||
| } | |||||
| _validateInputs(); | |||||
| }, | |||||
| ), | ), | ||||
| ), | ), | ||||
| body: KeyboardDismisser( | body: KeyboardDismisser( | ||||
| print('loading...'); | print('loading...'); | ||||
| return Center(child: CircularProgressIndicator()); | return Center(child: CircularProgressIndicator()); | ||||
| } else if (state is ActionUiSuccess) { | } else if (state is ActionUiSuccess) { | ||||
| print('success'); | |||||
| var actionUiForm = state.item as ActionUIForm; | |||||
| actionUiForm.objectParameterDTOList | |||||
| .forEach((element) { | |||||
| var textEditingController = | |||||
| new TextEditingController(); | |||||
| textFieldControllers.putIfAbsent( | |||||
| element.id.toString(), | |||||
| () => textEditingController); | |||||
| }); | |||||
| return Column( | return Column( | ||||
| children: [ | children: [ | ||||
| Padding( | Padding( | ||||
| SizedBox( | SizedBox( | ||||
| height: 8.0, | height: 8.0, | ||||
| ), | ), | ||||
| generateTextField(actionUiForm | |||||
| .objectParameterDTOList), | |||||
| _executeByField(), | _executeByField(), | ||||
| SizedBox( | SizedBox( | ||||
| height: 8.0, | height: 8.0, |
| } | } | ||||
| if (state is PlotParameterSuccess) { | if (state is PlotParameterSuccess) { | ||||
| if (_periodicSubscription == null) { | if (_periodicSubscription == null) { | ||||
| _periodicSubscription ??= | |||||
| Stream.periodic(const Duration(seconds: 5), (x) => x).listen( | |||||
| (_) => add(OnRefresh(cropId: event.cropId)), | |||||
| onError: (error) => print("Do something with $error")); | |||||
| //TODO: open when release | |||||
| // _periodicSubscription ??= | |||||
| // Stream.periodic(const Duration(seconds: 5), (x) => x).listen( | |||||
| // (_) => add(OnRefresh(cropId: event.cropId)), | |||||
| // onError: (error) => print("Do something with $error")); | |||||
| } else { | } else { | ||||
| _periodicSubscription.resume(); | _periodicSubscription.resume(); | ||||
| } | } | ||||
| Future<void> close() async { | Future<void> close() async { | ||||
| await _periodicSubscription?.cancel(); | await _periodicSubscription?.cancel(); | ||||
| _periodicSubscription = null; | _periodicSubscription = null; | ||||
| print('closed subscription'); | |||||
| return super.close(); | return super.close(); | ||||
| } | } | ||||
| } | } |
| void getPlotInfo( | void getPlotInfo( | ||||
| int cropId, Function(dynamic) onSuccess, Function(String) onError) async { | int cropId, Function(dynamic) onSuccess, Function(String) onError) async { | ||||
| _repository.getPlotDetail(cropId).then((value) { | |||||
| _repository.getPlotDetail(cropId, page: 0, size: 20).then((value) { | |||||
| onSuccess(value); | onSuccess(value); | ||||
| _getPlotInfoFetcher.sink.add(value); | _getPlotInfoFetcher.sink.add(value); | ||||
| }).catchError((onError) { | }).catchError((onError) { |
| @override | @override | ||||
| void dispose() { | void dispose() { | ||||
| _descriptionController.dispose(); | |||||
| _descriptionController?.dispose(); | |||||
| super.dispose(); | super.dispose(); | ||||
| } | } | ||||
| } | } | ||||
| static String validNumberOrEmpty(String value, String errorMessage) { | static String validNumberOrEmpty(String value, String errorMessage) { | ||||
| if (value.isEmpty) return null; | |||||
| try { | try { | ||||
| if (value.isEmpty) return errorMessage; | |||||
| var doubleValue = value.parseDoubleThousand(); | var doubleValue = value.parseDoubleThousand(); | ||||
| if (doubleValue > 0) { | if (doubleValue > 0) { | ||||
| return null; | return null; |