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.

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