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.

575 lines
23KB

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