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.

455 lines
18KB

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