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.

482 lines
19KB

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