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
19KB

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