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.

417 lines
17KB

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