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.

461 lines
18KB

  1. import 'dart:convert';
  2. import 'package:farm_tpf/custom_model/Disease.dart';
  3. import 'package:farm_tpf/custom_model/RequestDisease.dart';
  4. import 'package:farm_tpf/data/api/app_exception.dart';
  5. import 'package:farm_tpf/data/repository/repository.dart';
  6. import 'package:farm_tpf/presentation/custom_widgets/bloc/media_helper_bloc.dart';
  7. import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart';
  8. import 'package:farm_tpf/presentation/custom_widgets/widget_media_picker.dart';
  9. import 'package:farm_tpf/presentation/screens/actions/bloc/action_detail_bloc.dart';
  10. import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_file_controller.dart';
  11. import 'package:farm_tpf/utils/const_common.dart';
  12. import 'package:farm_tpf/utils/const_string.dart';
  13. import 'package:farm_tpf/utils/const_style.dart';
  14. import 'package:farm_tpf/utils/pref.dart';
  15. import 'package:farm_tpf/utils/validators.dart';
  16. import 'package:flutter/material.dart';
  17. import 'package:flutter_bloc/flutter_bloc.dart';
  18. import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
  19. import 'package:get/get.dart';
  20. import 'package:intl/intl.dart';
  21. import 'package:keyboard_dismisser/keyboard_dismisser.dart';
  22. import 'package:pattern_formatter/pattern_formatter.dart';
  23. import 'package:farm_tpf/utils/formatter.dart';
  24. import '../util_action.dart';
  25. class EditActionDiseaseScreen extends StatefulWidget {
  26. final int cropId;
  27. final bool isEdit;
  28. final int activityId;
  29. EditActionDiseaseScreen(
  30. {@required this.cropId, this.isEdit = false, this.activityId});
  31. @override
  32. _EditActionDiseaseScreenState createState() =>
  33. _EditActionDiseaseScreenState();
  34. }
  35. class _EditActionDiseaseScreenState extends State<EditActionDiseaseScreen> {
  36. final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  37. final _repository = Repository();
  38. GlobalKey<FormState> _formKey = GlobalKey();
  39. bool _autoValidate = false;
  40. Disease _disease = Disease();
  41. var pref = LocalPref();
  42. TextEditingController _typesOfPestController = TextEditingController();
  43. TextEditingController _numTreeController = TextEditingController();
  44. TextEditingController _harmLevelController = TextEditingController();
  45. TextEditingController _treePercentController = TextEditingController();
  46. TextEditingController _locationController = TextEditingController();
  47. TextEditingController _naturalEnemyController = TextEditingController();
  48. TextEditingController _treatmentMeasuresController = TextEditingController();
  49. TextEditingController _descriptionController = TextEditingController();
  50. String executeTimeView;
  51. DateTime executeTime = DateTime.now();
  52. List<String> filePaths = List<String>();
  53. var changeFileController = Get.put(ChangeFileController());
  54. @override
  55. void initState() {
  56. super.initState();
  57. changeFileController.initValue();
  58. var parsedExecuteDate =
  59. DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(executeTime);
  60. _disease.executeDate = "$parsedExecuteDate";
  61. executeTimeView = DateFormat("dd/MM/yyyy HH:mm").format(executeTime);
  62. _disease.cropId = widget.cropId;
  63. }
  64. _validateInputs() async {
  65. if (_formKey.currentState.validate()) {
  66. _formKey.currentState.save();
  67. LoadingDialog.showLoadingDialog(context);
  68. filePaths = Get.find<ChangeFileController>().files;
  69. //Create request general model
  70. try {
  71. RequestDisease requestDisease = RequestDisease()
  72. ..cropId = _disease.cropId
  73. ..activityId = _disease.activityId
  74. ..description = _disease.description
  75. ..executeDate = _disease.executeDate;
  76. var generalDetail = List<ObjectUpdateDetail>();
  77. generalDetail.add(ObjectUpdateDetail()
  78. ..name = "LOAI_DICH_HAI"
  79. ..index = _disease.typesOfPest);
  80. generalDetail.add(ObjectUpdateDetail()
  81. ..name = "MUC_DO_GAY_HAI"
  82. ..index = _disease.harmLevel);
  83. generalDetail.add(ObjectUpdateDetail()
  84. ..name = "PHAN_TRAM_CAY"
  85. ..index = _disease.treePercent);
  86. generalDetail.add(ObjectUpdateDetail()
  87. ..name = "VI_TRI"
  88. ..index = _disease.location);
  89. generalDetail.add(ObjectUpdateDetail()
  90. ..name = "THIEN_DICH"
  91. ..index = _disease.naturalEnemy);
  92. generalDetail.add(ObjectUpdateDetail()
  93. ..name = "BIEN_PHAP_XU_LY"
  94. ..index = _disease.treatmentMeasures);
  95. requestDisease.objectUpdateDetail = generalDetail;
  96. var activityDisease = jsonEncode(requestDisease.toJson()).toString();
  97. //ADD NEW
  98. if (_disease.activityId == null) {
  99. _repository.createAction((value) {
  100. LoadingDialog.hideLoadingDialog(context);
  101. Get.back(result: value);
  102. Get.snackbar(label_add_success, "Hoạt động điều tra dịch hại",
  103. snackPosition: SnackPosition.BOTTOM);
  104. }, (error) {
  105. LoadingDialog.hideLoadingDialog(context);
  106. _scaffoldKey.currentState.showSnackBar(SnackBar(
  107. content: Row(
  108. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  109. children: <Widget>[
  110. Flexible(child: Text(AppException.handleError(error))),
  111. Icon(Icons.error),
  112. ],
  113. ),
  114. backgroundColor: Colors.red,
  115. duration: Duration(seconds: 3),
  116. ));
  117. },
  118. apiAddAction: ConstCommon.apiAddDisease,
  119. paramActivity: ConstCommon.paramsActionDisease,
  120. activityAction: activityDisease,
  121. filePaths: filePaths);
  122. } else {
  123. //UPDATE
  124. _repository.updateAction((value) {
  125. LoadingDialog.hideLoadingDialog(context);
  126. Get.back(result: value);
  127. Get.snackbar(label_update_success, "Hoạt động điều tra dịch hại",
  128. snackPosition: SnackPosition.BOTTOM);
  129. }, (error) {
  130. LoadingDialog.hideLoadingDialog(context);
  131. _scaffoldKey.currentState.showSnackBar(SnackBar(
  132. content: Row(
  133. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  134. children: <Widget>[
  135. Flexible(child: Text(AppException.handleError(error))),
  136. Icon(Icons.error),
  137. ],
  138. ),
  139. backgroundColor: Colors.red,
  140. duration: Duration(seconds: 3),
  141. ));
  142. },
  143. apiUpdateAction: ConstCommon.apiUpdateDisease,
  144. paramActivity: ConstCommon.paramsActionDisease,
  145. activityAction: activityDisease,
  146. filePaths: filePaths);
  147. }
  148. } catch (e) {
  149. LoadingDialog.hideLoadingDialog(context);
  150. print(e.toString());
  151. }
  152. } else {
  153. _autoValidate = true;
  154. }
  155. }
  156. Widget _btnExecuteTimePicker() {
  157. return FlatButton(
  158. padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 0.0, left: 0.0),
  159. onPressed: () {
  160. DatePicker.showDateTimePicker(context,
  161. showTitleActions: true, onChanged: (date) {}, onConfirm: (date) {
  162. setState(() {
  163. var parsedDate =
  164. DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(date);
  165. _disease.executeDate = "$parsedDate";
  166. executeTimeView = DateFormat("dd/MM/yyyy HH:mm").format(date);
  167. });
  168. }, currentTime: executeTime, locale: LocaleType.vi);
  169. },
  170. child: Container(
  171. padding:
  172. EdgeInsets.only(top: 0.0, right: 0.0, bottom: 10.5, left: 0.0),
  173. decoration: BoxDecoration(
  174. border: kBorderTextField,
  175. ),
  176. child: Row(
  177. children: [
  178. Expanded(
  179. child: Text(
  180. //TODO: check condition
  181. executeTimeView == null ? "$executeTime" : executeTimeView,
  182. style: TextStyle(fontSize: 14.0, color: Colors.black87),
  183. )),
  184. Icon(
  185. Icons.date_range,
  186. color: Colors.blue,
  187. ),
  188. ],
  189. )));
  190. }
  191. Widget _typeOfPestField() {
  192. return TextFormField(
  193. keyboardType: TextInputType.text,
  194. decoration: InputDecoration(labelText: "Loại dịch hại"),
  195. controller: _typesOfPestController,
  196. validator: (String value) {
  197. return Validators.validateNotNullOrEmpty(value, "Loại dịch hại");
  198. },
  199. onSaved: (newValue) {
  200. _disease.typesOfPest = newValue;
  201. },
  202. );
  203. }
  204. Widget _harmLevelField() {
  205. return TextFormField(
  206. keyboardType: TextInputType.text,
  207. decoration: InputDecoration(labelText: "Mức độ gây hại"),
  208. controller: _harmLevelController,
  209. onSaved: (newValue) {
  210. _disease.harmLevel = newValue;
  211. },
  212. );
  213. }
  214. Widget _treePercentField() {
  215. return TextFormField(
  216. keyboardType: TextInputType.numberWithOptions(decimal: true),
  217. inputFormatters: [
  218. ThousandsFormatter(
  219. formatter: NumberFormat("#,###.##", "es"), allowFraction: true)
  220. ],
  221. decoration: InputDecoration(labelText: "% cây"),
  222. controller: _treePercentController,
  223. validator: (String value) {
  224. return Validators.validNumber(value, "% cây");
  225. },
  226. onSaved: (newValue) {
  227. _disease.treePercent = newValue;
  228. },
  229. );
  230. }
  231. Widget _locationField() {
  232. return TextFormField(
  233. keyboardType: TextInputType.text,
  234. decoration: InputDecoration(labelText: "Vị trí"),
  235. controller: _locationController,
  236. onSaved: (newValue) {
  237. _disease.location = newValue;
  238. },
  239. );
  240. }
  241. Widget _naturalEnemyField() {
  242. return TextFormField(
  243. keyboardType: TextInputType.text,
  244. decoration: InputDecoration(labelText: "Thiên địch"),
  245. controller: _naturalEnemyController,
  246. onSaved: (newValue) {
  247. _disease.naturalEnemy = newValue;
  248. },
  249. );
  250. }
  251. Widget _treatmentMeasuresField() {
  252. return TextFormField(
  253. keyboardType: TextInputType.text,
  254. decoration: InputDecoration(labelText: "Biện pháp xử lý"),
  255. controller: _treatmentMeasuresController,
  256. onSaved: (newValue) {
  257. _disease.treatmentMeasures = newValue;
  258. },
  259. );
  260. }
  261. Widget _descriptionField() {
  262. return TextFormField(
  263. keyboardType: TextInputType.text,
  264. decoration: InputDecoration(labelText: "Ghi chú"),
  265. controller: _descriptionController,
  266. onSaved: (newValue) {
  267. _disease.description = newValue;
  268. },
  269. );
  270. }
  271. _actionAppBar() {
  272. IconButton iconButton;
  273. if (1 == 1) {
  274. iconButton = IconButton(
  275. icon: Icon(
  276. Icons.done,
  277. color: Colors.black,
  278. ),
  279. onPressed: () {
  280. FocusScopeNode currentFocus = FocusScope.of(context);
  281. if (!currentFocus.hasPrimaryFocus) {
  282. currentFocus.unfocus();
  283. }
  284. _validateInputs();
  285. },
  286. );
  287. return <Widget>[iconButton];
  288. }
  289. return <Widget>[Container()];
  290. }
  291. @override
  292. Widget build(BuildContext context) => KeyboardDismisser(
  293. gestures: [
  294. GestureType.onTap,
  295. GestureType.onPanUpdateDownDirection,
  296. ],
  297. child: Scaffold(
  298. key: _scaffoldKey,
  299. appBar: AppBar(
  300. centerTitle: true,
  301. title: Text(plot_action_disease),
  302. actions: _actionAppBar()),
  303. body: KeyboardDismisser(
  304. child: MultiBlocProvider(
  305. providers: [
  306. BlocProvider<ActionDetailBloc>(
  307. create: (context) =>
  308. ActionDetailBloc(repository: Repository())
  309. ..add(FetchData(
  310. isNeedFetchData: widget.isEdit,
  311. apiActivity: ConstCommon.apiDetailDisease,
  312. activityId: widget.activityId))),
  313. BlocProvider<MediaHelperBloc>(
  314. create: (context) =>
  315. MediaHelperBloc()..add(ChangeListMedia(items: [])),
  316. )
  317. ],
  318. child: Form(
  319. key: _formKey,
  320. autovalidate: _autoValidate,
  321. child: SingleChildScrollView(
  322. padding: EdgeInsets.all(8.0),
  323. child: BlocConsumer<ActionDetailBloc, ActionDetailState>(
  324. listener: (context, state) async {
  325. if (state is ActionDetailFailure) {
  326. LoadingDialog.hideLoadingDialog(context);
  327. } else if (state is ActionDetailSuccess) {
  328. LoadingDialog.hideLoadingDialog(context);
  329. print(state.item);
  330. _disease = Disease.fromJson(state.item);
  331. _disease.activityId = widget.activityId;
  332. _typesOfPestController.text =
  333. _disease.typesOfPest ?? "";
  334. _harmLevelController.text =
  335. _disease.harmLevel ?? "";
  336. _treePercentController.text = _disease.treePercent
  337. .formatStringToStringDecimal();
  338. _locationController.text =
  339. _disease.location.formatStringToStringDecimal();
  340. _naturalEnemyController.text =
  341. _disease.naturalEnemy ?? "";
  342. _treatmentMeasuresController.text =
  343. _disease.treatmentMeasures ?? "";
  344. _descriptionController.text =
  345. _disease.description ?? "";
  346. try {
  347. executeTime =
  348. DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
  349. .parse(_disease.executeDate);
  350. } catch (_) {}
  351. executeTimeView = DateFormat("dd/MM/yyyy HH:mm")
  352. .format(executeTime);
  353. //Show media
  354. if (_disease.media != null) {
  355. await UtilAction.cacheFiles(_disease.media)
  356. .then((value) {
  357. BlocProvider.of<MediaHelperBloc>(context)
  358. .add(ChangeListMedia(items: value));
  359. }).whenComplete(() {
  360. print("completed");
  361. });
  362. }
  363. } else if (state is ActionDetailInitial) {
  364. } else if (state is ActionDetailLoading) {
  365. LoadingDialog.showLoadingDialog(context);
  366. }
  367. },
  368. builder: (context, state) {
  369. return Column(
  370. children: <Widget>[
  371. Container(
  372. width: double.infinity,
  373. child: Text(
  374. "Ngày thực hiện",
  375. style: TextStyle(
  376. color: Colors.black54, fontSize: 13.0),
  377. ),
  378. ),
  379. _btnExecuteTimePicker(),
  380. SizedBox(
  381. height: 8.0,
  382. ),
  383. _typeOfPestField(),
  384. SizedBox(
  385. height: 8.0,
  386. ),
  387. _harmLevelField(),
  388. SizedBox(
  389. height: 8.0,
  390. ),
  391. _treePercentField(),
  392. SizedBox(
  393. height: 8.0,
  394. ),
  395. _locationField(),
  396. SizedBox(
  397. height: 8.0,
  398. ),
  399. _naturalEnemyField(),
  400. SizedBox(
  401. height: 8.0,
  402. ),
  403. _treatmentMeasuresField(),
  404. SizedBox(
  405. height: 8.0,
  406. ),
  407. _descriptionField(),
  408. SizedBox(
  409. height: 8.0,
  410. ),
  411. BlocBuilder<MediaHelperBloc, MediaHelperState>(
  412. builder: (context, state) {
  413. if (state is MediaHelperSuccess) {
  414. return WidgetMediaPicker(
  415. currentItems: state.items,
  416. onChangeFiles: (filePaths) async {
  417. Get.find<ChangeFileController>()
  418. .addAllFile(filePaths);
  419. });
  420. } else {
  421. return Center(
  422. child: CircularProgressIndicator());
  423. }
  424. }),
  425. ],
  426. );
  427. },
  428. ),
  429. )),
  430. ))));
  431. @override
  432. void dispose() {
  433. _typesOfPestController.dispose();
  434. _harmLevelController.dispose();
  435. _treePercentController.dispose();
  436. _locationController.dispose();
  437. _naturalEnemyController.dispose();
  438. _treatmentMeasuresController.dispose();
  439. _descriptionController.dispose();
  440. super.dispose();
  441. }
  442. }