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.

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