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
19KB

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