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.

475 lines
20KB

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