You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

684 lines
26KB

  1. import 'dart:convert';
  2. import 'package:farm_tpf/custom_model/SuppliesUsing.dart';
  3. import 'package:farm_tpf/custom_model/action_form/ActionUIField.dart';
  4. import 'package:farm_tpf/custom_model/action_form/ActionUIForm.dart';
  5. import 'package:farm_tpf/custom_model/action_form/CommonData.dart';
  6. import 'package:farm_tpf/custom_model/action_form/RequestActivity.dart';
  7. import 'package:farm_tpf/data/api/app_exception.dart';
  8. import 'package:farm_tpf/data/repository/repository.dart';
  9. import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart';
  10. import 'package:farm_tpf/presentation/custom_widgets/bloc/media_helper_bloc.dart';
  11. import 'package:farm_tpf/presentation/custom_widgets/button_widget.dart';
  12. import 'package:farm_tpf/presentation/custom_widgets/dropdown_supply_widget.dart';
  13. import 'package:farm_tpf/presentation/custom_widgets/widget_action_field_date.dart';
  14. import 'package:farm_tpf/presentation/custom_widgets/widget_field_time_picker.dart';
  15. import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart';
  16. import 'package:farm_tpf/presentation/custom_widgets/widget_media_picker.dart';
  17. import 'package:farm_tpf/presentation/custom_widgets/widget_text_field_area.dart';
  18. import 'package:farm_tpf/presentation/custom_widgets/widget_text_form_field.dart';
  19. import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
  20. import 'package:farm_tpf/presentation/screens/actions/cubit/action_ui_cubit.dart';
  21. import 'package:farm_tpf/utils/const_string.dart';
  22. import 'package:farm_tpf/utils/pref.dart';
  23. import 'package:farm_tpf/utils/validators.dart';
  24. import 'package:flutter/material.dart';
  25. import 'package:flutter/scheduler.dart';
  26. import 'package:flutter_bloc/flutter_bloc.dart';
  27. import 'package:get/get.dart';
  28. import 'package:keyboard_dismisser/keyboard_dismisser.dart';
  29. import 'package:farm_tpf/utils/formatter.dart';
  30. import 'controller/ChangeFieldInForm.dart';
  31. import 'controller/ChangeSupplyUsing.dart';
  32. import 'controller/ChangeWorker.dart';
  33. import 'dung/widget_dung_supply.dart';
  34. import 'nursery/widget_worker.dart';
  35. import 'plant/widget_plant_supply.dart';
  36. import 'spraying/widget_spraying_supply.dart';
  37. import 'state_management_helper/change_dropdown_controller.dart';
  38. import 'state_management_helper/change_file_controller.dart';
  39. import 'util_action.dart';
  40. class ActionScreen extends StatefulWidget {
  41. final bool isEdit;
  42. final int cropId;
  43. final int idAction;
  44. final String activityType;
  45. final String title;
  46. final int activityId;
  47. ActionScreen(
  48. {@required this.isEdit,
  49. @required this.cropId,
  50. @required this.idAction,
  51. @required this.title,
  52. @required this.activityType,
  53. @required this.activityId});
  54. @override
  55. _ActionScreenState createState() => _ActionScreenState();
  56. }
  57. class _ActionScreenState extends State<ActionScreen> {
  58. var _formKey = GlobalKey<FormState>();
  59. var pref = LocalPref();
  60. final _executeByController = TextEditingController();
  61. DateTime executeTime = DateTime.now();
  62. List<String> filePaths = <String>[];
  63. var changeFileController = Get.put(ChangeFileController());
  64. Map<String, TextEditingController> textFieldControllers = {};
  65. Map<String, String> valueObjects = {};
  66. var _requestActivity = RequestActivity();
  67. final _repository = Repository();
  68. var _actionUIForm = ActionUIForm();
  69. var _nurseryDetails = <TbNurseryDetailsDTO>[];
  70. var _supplyUsings = <SuppliesUsing>[];
  71. var _previousGroupFieldName = '';
  72. Future<Null> getSharedPrefs() async {
  73. var currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME);
  74. _executeByController.text = currentFullName ?? "";
  75. }
  76. @override
  77. void initState() {
  78. super.initState();
  79. getSharedPrefs();
  80. changeFileController.initValue();
  81. }
  82. _submitForm() async {
  83. switch (widget.activityType) {
  84. case 'ACTIVE_TYPE_NURSERY':
  85. if (Get.find<ChangeFieldFormSupply>().isChanged) {
  86. Utils.showDialog(
  87. title: 'Thông tin người thực hiện chưa cập nhật',
  88. message: 'Bạn có muốn cập nhật',
  89. textConfirm: 'Tiếp tục',
  90. textCancel: 'Xem lại',
  91. onConfirm: () {
  92. Get.back();
  93. _validateInputs();
  94. });
  95. } else {
  96. _validateInputs();
  97. }
  98. break;
  99. case 'ACTIVE_TYPE_PLANTING':
  100. case 'ACTIVE_TYPE_FERTILIZE':
  101. case 'ACTIVE_TYPE_SPRAYING_PESTICIDES':
  102. if (Get.find<ChangeFieldFormSupply>().isChanged) {
  103. Utils.showDialogConfirmSupply(onConfirm: () {
  104. Get.back();
  105. _validateInputs();
  106. });
  107. } else {
  108. _validateInputs();
  109. }
  110. break;
  111. default:
  112. _validateInputs();
  113. break;
  114. }
  115. }
  116. _validateInputs() async {
  117. if (_formKey.currentState.validate()) {
  118. _formKey.currentState.save();
  119. try {
  120. LoadingDialog.showLoadingDialog(context);
  121. filePaths = Get.find<ChangeFileController>().newFiles;
  122. //Create request general model
  123. _requestActivity
  124. ..tbActivityTypeId = widget.idAction
  125. ..tbCropId = widget.cropId;
  126. if (_actionUIForm.activityExtendTypeDTOList.isNotEmpty) {
  127. _requestActivity
  128. ..externalTable = _actionUIForm
  129. ?.activityExtendTypeDTOList?.first?.externalTable ??
  130. '';
  131. }
  132. filePaths = Get.find<ChangeFileController>().newFiles;
  133. textFieldControllers.forEach((key, value) {
  134. print(textFieldControllers[key].text);
  135. valueObjects[key] = textFieldControllers[key].text;
  136. });
  137. //tbObjectUpdateDTOList
  138. var _objectPrameters = <TbObjectUpdateDTO>[];
  139. valueObjects.forEach((key, value) {
  140. var objectUpdate = TbObjectUpdateDTO()
  141. ..tbObjectParameterId = int.tryParse(key)
  142. ..index = value;
  143. _objectPrameters.add(objectUpdate);
  144. });
  145. _requestActivity.tbObjectUpdateDTOList = _objectPrameters;
  146. //CHECK NURSERY
  147. if (widget.activityType == 'ACTIVE_TYPE_NURSERY') {
  148. _requestActivity.tbNurseryDetailsDTOList = _nurseryDetails;
  149. } else if (widget.activityType == 'ACTIVE_TYPE_PLANTING' ||
  150. widget.activityType == 'ACTIVE_TYPE_FERTILIZE' ||
  151. widget.activityType == 'ACTIVE_TYPE_SPRAYING_PESTICIDES') {
  152. _requestActivity.tbSuppliesUsingDetailsDTOs = _supplyUsings;
  153. }
  154. //delete images
  155. _requestActivity.deletedImages =
  156. Get.find<ChangeFileController>().deleteFiles;
  157. //convert data to json
  158. var activityCommonData =
  159. jsonEncode(_requestActivity.toJson()).toString();
  160. print(activityCommonData);
  161. if (widget.activityId < 0) {
  162. //ADD New
  163. _repository.createActionCommon((data) {
  164. LoadingDialog.hideLoadingDialog(context);
  165. Get.back(result: 'ok');
  166. Utils.showSnackBarSuccess(message: label_add_success);
  167. }, (error) {
  168. LoadingDialog.hideLoadingDialog(context);
  169. Utils.showSnackBarError(message: AppException.handleError(error));
  170. },
  171. activityType: widget.activityType,
  172. activityData: activityCommonData,
  173. filePaths: filePaths);
  174. } else {
  175. //UPDATE
  176. _repository.updateActionCommon((data) {
  177. LoadingDialog.hideLoadingDialog(context);
  178. Get.back(result: 'ok');
  179. Utils.showSnackBarSuccess(message: label_update_success);
  180. }, (error) {
  181. LoadingDialog.hideLoadingDialog(context);
  182. Utils.showSnackBarError(message: AppException.handleError(error));
  183. },
  184. activityType: widget.activityType,
  185. activityData: activityCommonData,
  186. filePaths: filePaths);
  187. }
  188. //ADD NEW
  189. //Update
  190. } catch (e) {
  191. LoadingDialog.hideLoadingDialog(context);
  192. print(e.toString());
  193. }
  194. } else {
  195. //
  196. }
  197. }
  198. Widget _btnExecuteTimePicker() {
  199. return WidgetFieldDateTimePicker(
  200. initDateTime: executeTime,
  201. onUpdateDateTime: (selectedDate) {
  202. _requestActivity.executeDate =
  203. selectedDate.convertLocalDateTimeToStringUtcDateTime();
  204. });
  205. }
  206. Widget _executeByField() {
  207. return TextFormField(
  208. keyboardType: TextInputType.text,
  209. decoration: InputDecoration(labelText: "Người thực hiện"),
  210. enabled: false,
  211. controller: _executeByController,
  212. onSaved: (newValue) {},
  213. );
  214. }
  215. //
  216. // GENERATE DYNAMIC FORM
  217. //
  218. Widget groupName(String name) {
  219. if (_previousGroupFieldName == name ||
  220. !Validators.stringNotNullOrEmpty(name)) {
  221. return SizedBox();
  222. } else {
  223. var isShowEndline = false;
  224. if (Validators.stringNotNullOrEmpty(_previousGroupFieldName)) {
  225. isShowEndline = true;
  226. } else {
  227. //isShowEndline = false;
  228. }
  229. _previousGroupFieldName = name ?? '';
  230. return Container(
  231. child: Column(
  232. children: [
  233. isShowEndline
  234. ? Container(
  235. width: double.infinity,
  236. height: 0.35,
  237. color: Colors.grey[300],
  238. )
  239. : SizedBox(),
  240. Row(
  241. children: [
  242. Container(
  243. width: 24,
  244. height: 0.35,
  245. color: Colors.grey[300],
  246. ),
  247. Text(' ${name ?? ''} '),
  248. Expanded(
  249. child: Container(
  250. width: 5,
  251. height: 0.35,
  252. color: Colors.grey[300],
  253. ),
  254. ),
  255. ],
  256. ),
  257. ],
  258. ),
  259. );
  260. }
  261. }
  262. Widget generateField(List<ActionUIField> fields) {
  263. return Wrap(
  264. children: [
  265. ListView.separated(
  266. shrinkWrap: true,
  267. physics: NeverScrollableScrollPhysics(),
  268. itemCount: fields.length,
  269. separatorBuilder: (context, index) {
  270. return SizedBox(
  271. height: 8,
  272. );
  273. },
  274. itemBuilder: (context, index) {
  275. var field = fields[index];
  276. if (field.tbControlTypeName == 'text') {
  277. return Column(
  278. children: [
  279. groupName(field.groupName),
  280. TextFormField(
  281. keyboardType: TextInputType.text,
  282. decoration: InputDecoration(labelText: field.description),
  283. controller: textFieldControllers[field.id.toString()],
  284. onSaved: (newValue) {},
  285. validator: field.isMandatory
  286. ? (String value) {
  287. return Validators.validateNotNullOrEmpty(
  288. value, 'Vui lòng nhập ${field.description}');
  289. }
  290. : null,
  291. ),
  292. ],
  293. );
  294. } else if (field.tbControlTypeName == 'number') {
  295. return Column(
  296. children: [
  297. groupName(field.groupName),
  298. WidgetTextFormFieldNumber(
  299. hintValue: field.description,
  300. textController: textFieldControllers[field.id.toString()],
  301. onSaved: (newValue) {},
  302. validator: field.isMandatory
  303. ? (String value) {
  304. return Validators.validNumberOrEmpty(
  305. value, 'Vui lòng nhập ${field.description}');
  306. }
  307. : null,
  308. ),
  309. ],
  310. );
  311. } else if (field.tbControlTypeName == 'textarea') {
  312. return Column(
  313. children: [
  314. groupName(field.groupName),
  315. TextFieldAreaWidget(
  316. hint: field.description,
  317. controller: textFieldControllers[field.id.toString()],
  318. onSaved: (newValue) {}),
  319. ],
  320. );
  321. } else if (field.tbControlTypeName == 'dropdown' ||
  322. field.tbControlTypeName == 'radiobutton') {
  323. return Column(
  324. children: [
  325. groupName(field.groupName),
  326. DropdownSupplyWidget(
  327. titleName: field.description ?? '',
  328. tbSupply: field.tbActivityExtendTypeExternalTable ?? '',
  329. tag: field.name,
  330. value: field.description,
  331. hint:
  332. '${field.description} ${field.isMandatory ? '*' : ''}',
  333. condition: field.tbActivityExtendTypeCondition,
  334. invalidMessage: '',
  335. onPressed: (commonData) {
  336. valueObjects[field.id.toString()] =
  337. commonData.id.toString();
  338. }),
  339. ],
  340. );
  341. } else if (field.tbControlTypeName == 'date') {
  342. return Column(
  343. children: [
  344. groupName(field.groupName),
  345. FieldDateWidget(
  346. tag: field.name,
  347. value: field.description,
  348. hint:
  349. '${field.description} ${field.isMandatory ? '*' : ''}',
  350. invalidMessage: '',
  351. onPressed: (selectedDate) {
  352. valueObjects[field.id.toString()] = selectedDate
  353. .convertLocalDateTimeToStringUtcDateTime();
  354. }),
  355. ],
  356. );
  357. } else {
  358. return Container();
  359. }
  360. })
  361. ],
  362. );
  363. }
  364. //
  365. // GENERATE SUPPLY
  366. //
  367. Widget generateSupply(String activityType) {
  368. switch (activityType) {
  369. case 'ACTIVE_TYPE_NURSERY':
  370. return WidgetWorker(onChangeWorkers: (nurseryDetails) {
  371. _nurseryDetails = nurseryDetails;
  372. });
  373. break;
  374. case 'ACTIVE_TYPE_PLANTING':
  375. return Column(
  376. children: [
  377. Container(
  378. width: double.infinity,
  379. height: 16,
  380. color: Colors.grey[200],
  381. ),
  382. WidgetPlantSupply(
  383. currentItems: [],
  384. onChangeSupplies: (value) {
  385. _supplyUsings = value;
  386. }),
  387. ],
  388. );
  389. break;
  390. case 'ACTIVE_TYPE_FERTILIZE':
  391. return Column(
  392. children: [
  393. Container(
  394. width: double.infinity,
  395. height: 16,
  396. color: Colors.grey[200],
  397. ),
  398. WidgetDungSupply(
  399. currentItems: [],
  400. onChangeSupplies: (value) {
  401. _supplyUsings = value;
  402. }),
  403. ],
  404. );
  405. break;
  406. case 'ACTIVE_TYPE_SPRAYING_PESTICIDES':
  407. return Column(
  408. children: [
  409. Container(
  410. width: double.infinity,
  411. height: 16,
  412. color: Colors.grey[200],
  413. ),
  414. WidgetSprayingSupply(
  415. currentItems: [],
  416. onChangeSupplies: (value) {
  417. _supplyUsings = value;
  418. }),
  419. ],
  420. );
  421. break;
  422. default:
  423. return Container();
  424. break;
  425. }
  426. }
  427. void showDataWhenEdit() {
  428. //Show media
  429. if (Validators.stringNotNullOrEmpty(_requestActivity.media)) {
  430. BlocProvider.of<MediaHelperBloc>(context).add(ChangeListMedia(
  431. items: UtilAction.convertFilePathToMedia(_requestActivity.media)));
  432. }
  433. SchedulerBinding.instance.addPostFrameCallback((_) {
  434. if (widget.activityType == 'ACTIVE_TYPE_PLANTING' ||
  435. widget.activityType == 'ACTIVE_TYPE_FERTILIZE' ||
  436. widget.activityType == 'ACTIVE_TYPE_SPRAYING_PESTICIDES') {
  437. //list supply
  438. Get.find<ChangeSupplyUsing>()
  439. .changeInitList(_requestActivity.tbSuppliesUsingDetailsDTOs);
  440. } else if (widget.activityType == 'ACTIVE_TYPE_NURSERY') {
  441. //list nursery
  442. Get.find<ChangeWorker>()
  443. .changeInitList(_requestActivity.tbNurseryDetailsDTOList);
  444. }
  445. });
  446. //Show value textfield
  447. if (_requestActivity.tbObjectUpdateDTOList != null) {
  448. print(textFieldControllers.keys.toList());
  449. _requestActivity.tbObjectUpdateDTOList.forEach((element) {
  450. if (element.tbObjectParameterDTO?.tbControlTypeName == 'text' ||
  451. element.tbObjectParameterDTO?.tbControlTypeName == 'textarea') {
  452. SchedulerBinding.instance.addPostFrameCallback((_) {
  453. textFieldControllers[element.tbObjectParameterId.toString()].text =
  454. element.index;
  455. });
  456. } else if (element.tbObjectParameterDTO?.tbControlTypeName ==
  457. 'number') {
  458. SchedulerBinding.instance.addPostFrameCallback((_) {
  459. textFieldControllers[element.tbObjectParameterId.toString()].text =
  460. element.index.formatStringToStringDecimal();
  461. });
  462. } else {
  463. SchedulerBinding.instance.addPostFrameCallback((_) {
  464. if (element.tbObjectParameterDTO?.tbControlTypeName == 'dropdown' ||
  465. element.tbObjectParameterDTO?.tbControlTypeName == 'radio') {
  466. var dropdownValueName = '';
  467. if (element.tbObjectParameterDTO
  468. ?.tbActivityExtendTypeDropDownDTOList?.isNotEmpty ||
  469. element.tbObjectParameterDTO
  470. ?.tbActivityExtendTypeDropDownDTOList !=
  471. null) {
  472. element
  473. .tbObjectParameterDTO?.tbActivityExtendTypeDropDownDTOList
  474. .forEach((dropdownData) {
  475. if (dropdownData.id == int.tryParse(element.index)) {
  476. dropdownValueName = dropdownData.name;
  477. }
  478. });
  479. }
  480. var commonData = CommonData()
  481. ..id = int.tryParse(element.index)
  482. ..name = dropdownValueName;
  483. Get.find<ChangeDropdownController>(
  484. tag: element.tbObjectParameterDTO?.name)
  485. .change(commonData);
  486. } else if (element.tbObjectParameterDTO?.tbControlTypeName ==
  487. 'date') {
  488. Get.find<ChangeDateTimePicker>(
  489. tag: element.tbObjectParameterDTO?.name)
  490. .change(element.index
  491. .convertStringServerDateTimeToLocalDateTime());
  492. }
  493. });
  494. }
  495. });
  496. } else {
  497. //
  498. }
  499. }
  500. @override
  501. Widget build(BuildContext context) => KeyboardDismisser(
  502. gestures: [
  503. GestureType.onTap,
  504. GestureType.onPanUpdateDownDirection,
  505. ],
  506. child: Scaffold(
  507. backgroundColor: Colors.white,
  508. appBar: AppBarWidget(
  509. isBack: true,
  510. action: InkWell(
  511. child: Text(
  512. 'Lưu',
  513. style: TextStyle(
  514. color: Colors.red, fontWeight: FontWeight.normal),
  515. ),
  516. onTap: () {
  517. FocusScopeNode currentFocus = FocusScope.of(context);
  518. if (!currentFocus.hasPrimaryFocus) {
  519. currentFocus.unfocus();
  520. }
  521. _submitForm();
  522. },
  523. ),
  524. ),
  525. body: MultiBlocProvider(
  526. providers: [
  527. BlocProvider<ActionUiCubit>(
  528. create: (context) =>
  529. ActionUiCubit(repository: Repository())
  530. ..getActionUIForm(
  531. actionId: widget.idAction,
  532. actionType: widget.activityType,
  533. isEdit: widget.isEdit,
  534. activityId: widget.activityId)),
  535. BlocProvider<MediaHelperBloc>(
  536. create: (context) =>
  537. MediaHelperBloc()..add(ChangeListMedia(items: [])),
  538. )
  539. ],
  540. child: Form(
  541. key: _formKey,
  542. child: SafeArea(
  543. child: SingleChildScrollView(
  544. child: BlocBuilder<ActionUiCubit, ActionUiState>(
  545. builder: (context, state) {
  546. if (state is ActionUiLoading) {
  547. print('loading...');
  548. return Center(child: CircularProgressIndicator());
  549. } else if (state is ActionUiSuccess) {
  550. _actionUIForm = state.actionUIForm;
  551. _requestActivity = state.activityDetail;
  552. //CREATE UI
  553. _actionUIForm.objectParameterDTOList
  554. .forEach((element) {
  555. //generate controller
  556. if (element.tbControlTypeName == 'text' ||
  557. element.tbControlTypeName == 'number' ||
  558. element.tbControlTypeName == 'textarea') {
  559. var textEditingController =
  560. new TextEditingController();
  561. textFieldControllers.putIfAbsent(
  562. element.id.toString(),
  563. () => textEditingController);
  564. }
  565. // generate value each parameter
  566. valueObjects.putIfAbsent(
  567. element.id.toString(), () => '');
  568. });
  569. //SHOW EDIT DATA
  570. if (widget.isEdit) {
  571. showDataWhenEdit();
  572. }
  573. return Column(
  574. children: [
  575. Padding(
  576. padding: const EdgeInsets.all(8.0),
  577. child: Column(
  578. children: <Widget>[
  579. Container(
  580. width: double.infinity,
  581. child: Text(
  582. "Ngày thực hiện *",
  583. style: TextStyle(
  584. color: Colors.black54,
  585. fontSize: 13.0),
  586. ),
  587. ),
  588. _btnExecuteTimePicker(),
  589. SizedBox(
  590. height: 8.0,
  591. ),
  592. generateField(_actionUIForm
  593. .objectParameterDTOList),
  594. _executeByField(),
  595. SizedBox(
  596. height: 8.0,
  597. ),
  598. ],
  599. ),
  600. ),
  601. generateSupply(widget.activityType),
  602. Container(
  603. width: double.infinity,
  604. height: 16,
  605. color: Colors.grey[200],
  606. ),
  607. BlocBuilder<MediaHelperBloc,
  608. MediaHelperState>(
  609. builder: (context, state) {
  610. if (state is MediaHelperSuccess) {
  611. return WidgetMediaPicker(
  612. currentItems: state.items,
  613. onChangeFiles: (newPathFiles,
  614. deletePathFiles) async {
  615. Get.find<ChangeFileController>()
  616. .change(newPathFiles,
  617. deletePathFiles);
  618. });
  619. } else {
  620. return Center(
  621. child: CircularProgressIndicator());
  622. }
  623. }),
  624. Padding(
  625. padding: const EdgeInsets.all(8.0),
  626. child: ButtonWidget(
  627. title: 'CẬP NHẬT',
  628. onPressed: () {
  629. FocusScopeNode currentFocus =
  630. FocusScope.of(context);
  631. if (!currentFocus.hasPrimaryFocus) {
  632. currentFocus.unfocus();
  633. }
  634. _submitForm();
  635. }),
  636. ),
  637. ],
  638. );
  639. } else if (state is ActionUiFailure) {
  640. return Text(state.errorString);
  641. }
  642. return Container();
  643. },
  644. ),
  645. ),
  646. )),
  647. )));
  648. @override
  649. void dispose() {
  650. _executeByController.dispose();
  651. textFieldControllers.forEach((key, value) {
  652. textFieldControllers[key].dispose();
  653. });
  654. super.dispose();
  655. }
  656. }