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.

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