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.

544 lines
22KB

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