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.

504 lines
23KB

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