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.

464 lines
19KB

  1. import 'dart:convert';
  2. import 'package:farm_tpf/custom_model/Harvest.dart';
  3. import 'package:farm_tpf/custom_model/Packing.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/bloc_get_harvest.dart';
  16. import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_file_controller.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 EditActionPackingScreen extends StatefulWidget {
  32. final int cropId;
  33. final bool isEdit;
  34. final int? activityId;
  35. final int? harvestId;
  36. EditActionPackingScreen({
  37. required this.cropId,
  38. this.isEdit = false,
  39. this.activityId,
  40. this.harvestId,
  41. });
  42. @override
  43. _EditActionPackingScreenState createState() => _EditActionPackingScreenState();
  44. }
  45. class _EditActionPackingScreenState extends State<EditActionPackingScreen> {
  46. final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  47. final _repository = Repository();
  48. GlobalKey<FormState> _formKey = GlobalKey();
  49. bool _autoValidate = false;
  50. Packing _packing = Packing();
  51. TextEditingController _l1Controller = TextEditingController();
  52. TextEditingController _l2Controller = TextEditingController();
  53. TextEditingController _l3Controller = TextEditingController();
  54. TextEditingController _removedQuantityController = TextEditingController();
  55. TextEditingController _descriptionController = TextEditingController();
  56. final _executeByController = TextEditingController();
  57. var pref = LocalPref();
  58. List<Harvest> _harvests = <Harvest>[];
  59. Harvest harvestValue = Harvest();
  60. String executeTimeView = '';
  61. DateTime executeTime = DateTime.now();
  62. List<String> filePaths = <String>[];
  63. var changeFileController = Get.put(ChangeFileController());
  64. Future<Null> getSharedPrefs() async {
  65. var currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME);
  66. _executeByController.text = currentFullName ?? "";
  67. }
  68. @override
  69. void initState() {
  70. super.initState();
  71. getSharedPrefs();
  72. changeFileController.initValue();
  73. _packing.executeDate = executeTime.convertLocalDateTimeToStringUtcDateTime();
  74. executeTimeView = executeTime.displayDateTime_DDMMYYYY_HHmm();
  75. _packing.cropId = widget.cropId;
  76. if (!widget.isEdit) {
  77. getHarvestBloc.getHarvests((data) {
  78. _harvests = data;
  79. for (var item in _harvests) {
  80. if (item.id == widget.harvestId) {
  81. harvestValue = item;
  82. break;
  83. }
  84. }
  85. }, (err) {});
  86. }
  87. }
  88. _validateInputs() async {
  89. if (_formKey.currentState!.validate()) {
  90. _formKey.currentState!.save();
  91. LoadingDialog.showLoadingDialog(context);
  92. filePaths = Get.find<ChangeFileController>().newFiles;
  93. try {
  94. _packing.mediaDel = Get.find<ChangeFileController>().deleteFiles;
  95. var activityPacking = jsonEncode(_packing.toJson()).toString();
  96. //ADD NEW
  97. if (_packing.activityId == null) {
  98. _repository.createAction((value) {
  99. LoadingDialog.hideLoadingDialog(context);
  100. Get.back(result: value);
  101. Utils.showSnackBarSuccess(message: label_add_success);
  102. }, (error) {
  103. LoadingDialog.hideLoadingDialog(context);
  104. Utils.showSnackBarError(message: AppException.handleError(error));
  105. },
  106. apiAddAction: ConstCommon.apiAddPacking,
  107. paramActivity: ConstCommon.paramsActionPacking,
  108. activityAction: activityPacking,
  109. filePaths: filePaths);
  110. } else {
  111. //UPDATE
  112. _repository.updateAction((value) {
  113. LoadingDialog.hideLoadingDialog(context);
  114. Get.back(result: value);
  115. Utils.showSnackBarSuccess(message: label_update_success);
  116. }, (error) {
  117. LoadingDialog.hideLoadingDialog(context);
  118. Utils.showSnackBarError(message: AppException.handleError(error));
  119. },
  120. apiUpdateAction: ConstCommon.apiUpdatePacking,
  121. paramActivity: ConstCommon.paramsActionPacking,
  122. activityAction: activityPacking,
  123. filePaths: filePaths);
  124. }
  125. } catch (e) {
  126. LoadingDialog.hideLoadingDialog(context);
  127. print(e.toString());
  128. }
  129. } else {
  130. _autoValidate = true;
  131. }
  132. }
  133. List<DropdownMenuItem<Harvest>> _buildDropMenu(List<Harvest> actions) {
  134. return actions
  135. .map((action) => DropdownMenuItem<Harvest>(
  136. child: Text("Mã thu hoạch " + action.id.toString()),
  137. value: action,
  138. ))
  139. .toList();
  140. }
  141. Widget _dropdownHarvest() {
  142. return StreamBuilder(
  143. stream: getHarvestBloc.actions,
  144. builder: (context, AsyncSnapshot<dynamic> snapshot) {
  145. if (snapshot.hasData) {
  146. return DropdownButtonFormField<Harvest>(
  147. value: harvestValue,
  148. hint: const Text("Mã thu hoạch"),
  149. onChanged: (Harvest? newValue) {
  150. setState(() {
  151. harvestValue = newValue = Harvest();
  152. _packing.harvestId = newValue?.id ?? -1;
  153. });
  154. },
  155. isExpanded: true,
  156. items: _buildDropMenu(_harvests));
  157. } else {
  158. return const Center(
  159. child: CircularProgressIndicator(),
  160. );
  161. }
  162. },
  163. );
  164. }
  165. Widget _btnExecuteTimePicker() {
  166. return FlatButton(
  167. padding: const EdgeInsets.only(top: 0.0, right: 0.0, bottom: 0.0, left: 0.0),
  168. onPressed: () {
  169. DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {}, onConfirm: (date) {
  170. setState(() {
  171. executeTime = date;
  172. _packing.executeDate = executeTime.convertLocalDateTimeToStringUtcDateTime();
  173. executeTimeView = executeTime.displayDateTime_DDMMYYYY_HHmm();
  174. });
  175. }, currentTime: executeTime, locale: LocaleType.vi);
  176. },
  177. child: Container(
  178. padding: const EdgeInsets.only(top: 0.0, right: 0.0, bottom: 10.5, left: 0.0),
  179. decoration: const BoxDecoration(
  180. border: kBorderTextField,
  181. ),
  182. child: Row(
  183. children: [
  184. Expanded(
  185. child: Text(
  186. //TODO: check condition
  187. executeTimeView == null ? "$executeTime" : executeTimeView,
  188. style: const TextStyle(fontSize: 14.0, color: Colors.black87),
  189. )),
  190. const Icon(
  191. Icons.date_range,
  192. color: Colors.grey,
  193. ),
  194. ],
  195. )));
  196. }
  197. Widget _l1Field() {
  198. return WidgetTextFormFieldNumber(
  199. hintValue: "Số lượng/khối lượng loại 1",
  200. textController: _l1Controller,
  201. onSaved: (newValue) {
  202. _packing.quantityLv1 = (newValue ?? '0').parseDoubleThousand();
  203. },
  204. onChanged: (_) {},
  205. validator: (_) {},
  206. );
  207. }
  208. Widget _l2Field() {
  209. return WidgetTextFormFieldNumber(
  210. hintValue: "Số lượng/khối lượng loại 2",
  211. textController: _l2Controller,
  212. onSaved: (newValue) {
  213. _packing.quantityLv2 = (newValue ?? '0').parseDoubleThousand();
  214. },
  215. onChanged: (_) {},
  216. validator: (_) {},
  217. );
  218. }
  219. Widget _l3Field() {
  220. return WidgetTextFormFieldNumber(
  221. hintValue: "Số lượng/khối lượng loại 3",
  222. textController: _l3Controller,
  223. onSaved: (newValue) {
  224. _packing.quantityLv3 = (newValue ?? '0').parseDoubleThousand();
  225. },
  226. onChanged: (_) {},
  227. validator: (_) {},
  228. );
  229. }
  230. Widget _removedQuantityField() {
  231. return WidgetTextFormFieldNumber(
  232. hintValue: "Số lượng/khối lượng loại bỏ",
  233. textController: _removedQuantityController,
  234. onSaved: (newValue) {
  235. _packing.removedQuantity = (newValue ?? '0').parseDoubleThousand();
  236. },
  237. onChanged: (_) {},
  238. validator: (_) {},
  239. );
  240. }
  241. Widget _descriptionField() {
  242. return TextFieldDescriptionWidget(
  243. controller: _descriptionController,
  244. onSaved: (newValue) {
  245. _packing.description = newValue;
  246. },
  247. );
  248. }
  249. Widget _executeByField() {
  250. return TextFormField(
  251. keyboardType: TextInputType.text,
  252. decoration: const InputDecoration(labelText: "Người thực hiện"),
  253. enabled: false,
  254. controller: _executeByController,
  255. onSaved: (newValue) {},
  256. );
  257. }
  258. @override
  259. Widget build(BuildContext context) => KeyboardDismisser(
  260. gestures: [
  261. GestureType.onTap,
  262. GestureType.onPanUpdateDownDirection,
  263. ],
  264. child: Scaffold(
  265. backgroundColor: Colors.white,
  266. key: _scaffoldKey,
  267. appBar: AppBarWidget(
  268. isBack: true,
  269. action: InkWell(
  270. child: const Text(
  271. 'Huỷ',
  272. style: TextStyle(color: Colors.red, fontWeight: FontWeight.normal),
  273. ),
  274. onTap: () {
  275. if (Get.isSnackbarOpen) Get.back();
  276. Get.back();
  277. },
  278. ),
  279. ),
  280. body: KeyboardDismisser(
  281. child: MultiBlocProvider(
  282. providers: [
  283. BlocProvider<ActionDetailBloc>(
  284. create: (context) => ActionDetailBloc(repository: Repository())
  285. ..add(
  286. FetchData(
  287. isNeedFetchData: widget.isEdit,
  288. apiActivity: ConstCommon.apiDetailPacking,
  289. activityId: widget.activityId ?? -1,
  290. ),
  291. ),
  292. ),
  293. BlocProvider<MediaHelperBloc>(
  294. create: (context) => MediaHelperBloc()..add(ChangeListMedia(items: [])),
  295. )
  296. ],
  297. child: Form(
  298. key: _formKey,
  299. // autovalidate: _autoValidate,
  300. child: SafeArea(
  301. child: SingleChildScrollView(
  302. child: BlocConsumer<ActionDetailBloc, ActionDetailState>(
  303. listener: (context, state) async {
  304. if (state is ActionDetailFailure) {
  305. LoadingDialog.hideLoadingDialog(context);
  306. } else if (state is ActionDetailSuccess) {
  307. LoadingDialog.hideLoadingDialog(context);
  308. print(state.item);
  309. _packing = Packing.fromJson(state.item);
  310. _packing.activityId = widget.activityId ?? -1;
  311. _l1Controller.text = _packing.quantityLv1?.formatNumtoStringDecimal() ?? '';
  312. _l2Controller.text = _packing.quantityLv2?.formatNumtoStringDecimal() ?? '';
  313. _l3Controller.text = _packing.quantityLv3?.formatNumtoStringDecimal() ?? '';
  314. _removedQuantityController.text = _packing.removedQuantity?.formatNumtoStringDecimal() ?? '';
  315. _descriptionController.text = _packing.description ?? "";
  316. _executeByController.text = _packing.executeBy ?? '';
  317. //select harvest
  318. getHarvestBloc.getHarvests((data) {
  319. _harvests = data;
  320. for (var item in _harvests) {
  321. if (item.id == _packing.harvestId) {
  322. harvestValue = item;
  323. break;
  324. }
  325. }
  326. }, (err) {});
  327. executeTime = _packing.executeDate?.convertStringServerDateTimeToLocalDateTime() ?? DateTime.now();
  328. executeTimeView = executeTime.displayDateTime_DDMMYYYY_HHmm();
  329. //Show media
  330. if (Validators.stringNotNullOrEmpty(_packing.media ?? '')) {
  331. BlocProvider.of<MediaHelperBloc>(context)
  332. .add(ChangeListMedia(items: UtilAction.convertFilePathToMedia(_packing.media ?? '')));
  333. }
  334. } else if (state is ActionDetailInitial) {
  335. } else if (state is ActionDetailLoading) {
  336. LoadingDialog.showLoadingDialog(context);
  337. }
  338. },
  339. builder: (context, state) {
  340. return Column(
  341. children: [
  342. Padding(
  343. padding: const EdgeInsets.all(8.0),
  344. child: Column(
  345. crossAxisAlignment: CrossAxisAlignment.start,
  346. children: <Widget>[
  347. const Text(
  348. plot_action_packing,
  349. style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22),
  350. ),
  351. const SizedBox(
  352. height: 8.0,
  353. ),
  354. Container(
  355. width: double.infinity,
  356. child: const Text(
  357. "Ngày thực hiện *",
  358. style: TextStyle(color: Colors.black54, fontSize: 13.0),
  359. ),
  360. ),
  361. _btnExecuteTimePicker(),
  362. const SizedBox(
  363. height: 8.0,
  364. ),
  365. _dropdownHarvest(),
  366. const SizedBox(
  367. height: 8.0,
  368. ),
  369. _l1Field(),
  370. const SizedBox(
  371. height: 8.0,
  372. ),
  373. _l2Field(),
  374. const SizedBox(
  375. height: 8.0,
  376. ),
  377. _l3Field(),
  378. const SizedBox(
  379. height: 8.0,
  380. ),
  381. _removedQuantityField(),
  382. const SizedBox(
  383. height: 8.0,
  384. ),
  385. _descriptionField(),
  386. const SizedBox(
  387. height: 8.0,
  388. ),
  389. _executeByField(),
  390. const SizedBox(
  391. height: 8.0,
  392. ),
  393. ],
  394. ),
  395. ),
  396. Container(
  397. width: double.infinity,
  398. height: 16,
  399. color: Colors.grey[200],
  400. ),
  401. BlocBuilder<MediaHelperBloc, MediaHelperState>(builder: (context, state) {
  402. if (state is MediaHelperSuccess) {
  403. return WidgetMediaPicker(
  404. currentItems: state.items,
  405. onChangeFiles: (newPathFiles, deletePathFiles) async {
  406. Get.find<ChangeFileController>().change(newPathFiles, deletePathFiles);
  407. });
  408. } else {
  409. return const Center(child: CircularProgressIndicator());
  410. }
  411. }),
  412. Padding(
  413. padding: const EdgeInsets.all(8.0),
  414. child: ButtonWidget(
  415. title: 'CẬP NHẬT',
  416. onPressed: () {
  417. var currentFocus = FocusScope.of(context);
  418. if (!currentFocus.hasPrimaryFocus) {
  419. currentFocus.unfocus();
  420. }
  421. _validateInputs();
  422. }),
  423. )
  424. ],
  425. );
  426. },
  427. ),
  428. ),
  429. )),
  430. ))));
  431. @override
  432. void dispose() {
  433. _l1Controller.dispose();
  434. _l2Controller.dispose();
  435. _l3Controller.dispose();
  436. _removedQuantityController.dispose();
  437. _descriptionController.dispose();
  438. _executeByController.dispose();
  439. super.dispose();
  440. }
  441. }