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.

512 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/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/state_management_helper/change_file_controller.dart';
  11. import 'package:farm_tpf/utils/const_common.dart';
  12. import 'package:farm_tpf/utils/const_string.dart';
  13. import 'package:farm_tpf/utils/const_style.dart';
  14. import 'package:farm_tpf/utils/pref.dart';
  15. import 'package:farm_tpf/utils/validators.dart';
  16. import 'package:flutter/material.dart';
  17. import 'package:flutter_bloc/flutter_bloc.dart';
  18. import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
  19. import 'package:get/get.dart';
  20. import 'package:intl/intl.dart';
  21. import 'package:keyboard_dismisser/keyboard_dismisser.dart';
  22. import 'package:pattern_formatter/pattern_formatter.dart';
  23. import 'package:farm_tpf/utils/formatter.dart';
  24. import '../bloc_get_harvest.dart';
  25. import '../util_action.dart';
  26. class EditActionSellScreen extends StatefulWidget {
  27. final int cropId;
  28. final bool isEdit;
  29. final int activityId;
  30. final int harvestId;
  31. EditActionSellScreen(
  32. {@required this.cropId,
  33. this.isEdit = false,
  34. this.activityId,
  35. this.harvestId});
  36. @override
  37. _EditActionSellScreenState createState() => _EditActionSellScreenState();
  38. }
  39. class _EditActionSellScreenState extends State<EditActionSellScreen> {
  40. final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  41. final _repository = Repository();
  42. GlobalKey<FormState> _formKey = GlobalKey();
  43. bool _autoValidate = false;
  44. Sell _sell = Sell();
  45. TextEditingController _l1Controller = TextEditingController();
  46. TextEditingController _l2Controller = TextEditingController();
  47. TextEditingController _l3Controller = TextEditingController();
  48. TextEditingController _removedQuantityController = TextEditingController();
  49. TextEditingController _descriptionController = TextEditingController();
  50. final _buyerController = TextEditingController();
  51. final _executeByController = TextEditingController();
  52. var pref = LocalPref();
  53. List<Harvest> _harvests = List<Harvest>();
  54. Harvest harvestValue;
  55. String executeTimeView;
  56. DateTime executeTime = DateTime.now();
  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. var parsedExecuteDate =
  69. DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(executeTime);
  70. _sell.executeDate = "$parsedExecuteDate";
  71. executeTimeView = DateFormat("dd/MM/yyyy HH:mm").format(executeTime);
  72. _sell.cropId = widget.cropId;
  73. if (!widget.isEdit) {
  74. getHarvestBloc.getHarvests((data) {
  75. _harvests = data;
  76. for (var item in _harvests) {
  77. if (item.id == widget.harvestId) {
  78. harvestValue = item;
  79. break;
  80. }
  81. }
  82. }, (err) {});
  83. }
  84. }
  85. _validateInputs() async {
  86. if (_formKey.currentState.validate()) {
  87. _formKey.currentState.save();
  88. LoadingDialog.showLoadingDialog(context);
  89. filePaths = Get.find<ChangeFileController>().files;
  90. try {
  91. var activitySell = jsonEncode(_sell.toJson()).toString();
  92. //ADD NEW
  93. if (_sell.activityId == null) {
  94. _repository.createAction((value) {
  95. LoadingDialog.hideLoadingDialog(context);
  96. Get.back(result: value);
  97. Get.snackbar(label_add_success, "Hoạt động xuất bán",
  98. snackPosition: SnackPosition.BOTTOM);
  99. }, (error) {
  100. LoadingDialog.hideLoadingDialog(context);
  101. _scaffoldKey.currentState.showSnackBar(SnackBar(
  102. content: Row(
  103. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  104. children: <Widget>[
  105. Flexible(child: Text(AppException.handleError(error))),
  106. Icon(Icons.error),
  107. ],
  108. ),
  109. backgroundColor: Colors.red,
  110. duration: Duration(seconds: 3),
  111. ));
  112. },
  113. apiAddAction: ConstCommon.apiAddSell,
  114. paramActivity: ConstCommon.paramsActionSell,
  115. activityAction: activitySell,
  116. filePaths: filePaths);
  117. } else {
  118. //UPDATE
  119. _repository.updateAction((value) {
  120. LoadingDialog.hideLoadingDialog(context);
  121. Get.back(result: value);
  122. Get.snackbar(label_update_success, "Hoạt động xuất bán",
  123. snackPosition: SnackPosition.BOTTOM);
  124. }, (error) {
  125. LoadingDialog.hideLoadingDialog(context);
  126. _scaffoldKey.currentState.showSnackBar(SnackBar(
  127. content: Row(
  128. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  129. children: <Widget>[
  130. Flexible(child: Text(AppException.handleError(error))),
  131. Icon(Icons.error),
  132. ],
  133. ),
  134. backgroundColor: Colors.red,
  135. duration: Duration(seconds: 3),
  136. ));
  137. },
  138. apiUpdateAction: ConstCommon.apiUpdateSell,
  139. paramActivity: ConstCommon.paramsActionSell,
  140. activityAction: activitySell,
  141. filePaths: filePaths);
  142. }
  143. } catch (e) {
  144. LoadingDialog.hideLoadingDialog(context);
  145. print(e.toString());
  146. }
  147. } else {
  148. _autoValidate = true;
  149. }
  150. }
  151. List<DropdownMenuItem<Harvest>> _buildDropMenu(List<Harvest> actions) {
  152. return actions
  153. .map((action) => DropdownMenuItem<Harvest>(
  154. child: Text("Mã thu hoạch " + action.id.toString()),
  155. value: action,
  156. ))
  157. .toList();
  158. }
  159. Widget _dropdownHarvest() {
  160. return StreamBuilder(
  161. stream: getHarvestBloc.actions,
  162. builder: (context, AsyncSnapshot<dynamic> snapshot) {
  163. if (snapshot.hasData) {
  164. return DropdownButtonFormField<Harvest>(
  165. value: harvestValue,
  166. hint: Text("Mã thu hoạch *"),
  167. onChanged: (Harvest newValue) {
  168. setState(() {
  169. harvestValue = newValue;
  170. _sell.harvestId = newValue.id;
  171. });
  172. },
  173. validator: (value) => value == null ? "Mã thu hoạch" : null,
  174. isExpanded: true,
  175. items: _buildDropMenu(_harvests));
  176. } else {
  177. return Center(
  178. child: CircularProgressIndicator(),
  179. );
  180. }
  181. },
  182. );
  183. }
  184. Widget _btnExecuteTimePicker() {
  185. return FlatButton(
  186. padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 0.0, left: 0.0),
  187. onPressed: () {
  188. DatePicker.showDateTimePicker(context,
  189. showTitleActions: true, onChanged: (date) {}, onConfirm: (date) {
  190. setState(() {
  191. var parsedDate =
  192. DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(date);
  193. _sell.executeDate = "$parsedDate";
  194. executeTimeView = DateFormat("dd/MM/yyyy HH:mm").format(date);
  195. });
  196. }, currentTime: executeTime, locale: LocaleType.vi);
  197. },
  198. child: Container(
  199. padding:
  200. EdgeInsets.only(top: 0.0, right: 0.0, bottom: 10.5, left: 0.0),
  201. decoration: BoxDecoration(
  202. border: kBorderTextField,
  203. ),
  204. child: Row(
  205. children: [
  206. Expanded(
  207. child: Text(
  208. //TODO: check condition
  209. executeTimeView == null ? "$executeTime" : executeTimeView,
  210. style: TextStyle(fontSize: 14.0, color: Colors.black87),
  211. )),
  212. Icon(
  213. Icons.date_range,
  214. color: Colors.blue,
  215. ),
  216. ],
  217. )));
  218. }
  219. Widget _l1Field() {
  220. return TextFormField(
  221. keyboardType: TextInputType.numberWithOptions(decimal: true),
  222. inputFormatters: [
  223. ThousandsFormatter(
  224. formatter: NumberFormat("#,###.##", "es"), allowFraction: true)
  225. ],
  226. decoration: InputDecoration(labelText: "Số lượng/khối lượng loại 1"),
  227. controller: _l1Controller,
  228. onSaved: (newValue) {
  229. _sell.quantityLv1 = newValue.parseDoubleThousand();
  230. },
  231. );
  232. }
  233. Widget _l2Field() {
  234. return TextFormField(
  235. keyboardType: TextInputType.numberWithOptions(decimal: true),
  236. inputFormatters: [
  237. ThousandsFormatter(
  238. formatter: NumberFormat("#,###.##", "es"), allowFraction: true)
  239. ],
  240. decoration: InputDecoration(labelText: "Số lượng/khối lượng loại 2"),
  241. controller: _l2Controller,
  242. onSaved: (newValue) {
  243. _sell.quantityLv2 = newValue.parseDoubleThousand();
  244. },
  245. );
  246. }
  247. Widget _l3Field() {
  248. return TextFormField(
  249. keyboardType: TextInputType.numberWithOptions(decimal: true),
  250. inputFormatters: [
  251. ThousandsFormatter(
  252. formatter: NumberFormat("#,###.##", "es"), allowFraction: true)
  253. ],
  254. decoration: InputDecoration(labelText: "Số lượng/khối lượng loại 3"),
  255. controller: _l3Controller,
  256. onSaved: (newValue) {
  257. _sell.quantityLv3 = newValue.parseDoubleThousand();
  258. },
  259. );
  260. }
  261. Widget _removedQuantityField() {
  262. return TextFormField(
  263. keyboardType: TextInputType.numberWithOptions(decimal: true),
  264. inputFormatters: [
  265. ThousandsFormatter(
  266. formatter: NumberFormat("#,###.##", "es"), allowFraction: true)
  267. ],
  268. decoration: InputDecoration(labelText: "Số lượng/khối lượng loại bỏ"),
  269. controller: _removedQuantityController,
  270. onSaved: (newValue) {
  271. _sell.removedQuantity = newValue.parseDoubleThousand();
  272. },
  273. );
  274. }
  275. Widget _buyerField() {
  276. return TextFormField(
  277. keyboardType: TextInputType.text,
  278. decoration: InputDecoration(labelText: "Khách hàng"),
  279. controller: _buyerController,
  280. onSaved: (newValue) {
  281. _sell.buyer = newValue;
  282. },
  283. );
  284. }
  285. Widget _descriptionField() {
  286. return TextFormField(
  287. keyboardType: TextInputType.text,
  288. decoration: InputDecoration(labelText: "Ghi chú"),
  289. controller: _descriptionController,
  290. onSaved: (newValue) {
  291. _sell.description = newValue;
  292. },
  293. );
  294. }
  295. Widget _executeByField() {
  296. return TextFormField(
  297. keyboardType: TextInputType.text,
  298. decoration: InputDecoration(labelText: "Người thực hiện"),
  299. enabled: false,
  300. controller: _executeByController,
  301. onSaved: (newValue) {},
  302. );
  303. }
  304. _actionAppBar() {
  305. IconButton iconButton;
  306. if (1 == 1) {
  307. iconButton = IconButton(
  308. icon: Icon(
  309. Icons.done,
  310. color: Colors.black,
  311. ),
  312. onPressed: () {
  313. FocusScopeNode currentFocus = FocusScope.of(context);
  314. if (!currentFocus.hasPrimaryFocus) {
  315. currentFocus.unfocus();
  316. }
  317. _validateInputs();
  318. },
  319. );
  320. return <Widget>[iconButton];
  321. }
  322. return <Widget>[Container()];
  323. }
  324. @override
  325. Widget build(BuildContext context) => KeyboardDismisser(
  326. gestures: [
  327. GestureType.onTap,
  328. GestureType.onPanUpdateDownDirection,
  329. ],
  330. child: Scaffold(
  331. key: _scaffoldKey,
  332. appBar: AppBar(
  333. centerTitle: true,
  334. title: Text(plot_action_sell),
  335. actions: _actionAppBar()),
  336. body: KeyboardDismisser(
  337. child: MultiBlocProvider(
  338. providers: [
  339. BlocProvider<ActionDetailBloc>(
  340. create: (context) =>
  341. ActionDetailBloc(repository: Repository())
  342. ..add(FetchData(
  343. isNeedFetchData: widget.isEdit,
  344. apiActivity: ConstCommon.apiDetailSell,
  345. activityId: widget.activityId))),
  346. BlocProvider<MediaHelperBloc>(
  347. create: (context) =>
  348. MediaHelperBloc()..add(ChangeListMedia(items: [])),
  349. )
  350. ],
  351. child: Form(
  352. key: _formKey,
  353. autovalidate: _autoValidate,
  354. child: SingleChildScrollView(
  355. padding: EdgeInsets.all(8.0),
  356. child: BlocConsumer<ActionDetailBloc, ActionDetailState>(
  357. listener: (context, state) async {
  358. if (state is ActionDetailFailure) {
  359. LoadingDialog.hideLoadingDialog(context);
  360. } else if (state is ActionDetailSuccess) {
  361. LoadingDialog.hideLoadingDialog(context);
  362. print(state.item);
  363. _sell = Sell.fromJson(state.item);
  364. _sell.activityId = widget.activityId;
  365. _l1Controller.text =
  366. _sell.quantityLv1.formatNumtoStringDecimal();
  367. _l2Controller.text =
  368. _sell.quantityLv2.formatNumtoStringDecimal();
  369. _l3Controller.text =
  370. _sell.quantityLv3.formatNumtoStringDecimal();
  371. _removedQuantityController.text = _sell
  372. .removedQuantity
  373. .formatNumtoStringDecimal();
  374. _buyerController.text = _sell.buyer ?? "";
  375. _descriptionController.text =
  376. _sell.description ?? "";
  377. _executeByController.text = _sell.executeBy;
  378. //select harvest
  379. getHarvestBloc.getHarvests((data) {
  380. _harvests = data;
  381. for (var item in _harvests) {
  382. if (item.id == _sell.harvestId) {
  383. harvestValue = item;
  384. break;
  385. }
  386. }
  387. }, (err) {});
  388. try {
  389. executeTime =
  390. DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
  391. .parse(_sell.executeDate);
  392. executeTimeView = DateFormat("dd/MM/yyyy HH:mm")
  393. .format(executeTime);
  394. } catch (_) {}
  395. //Show media
  396. if (_sell.media != null) {
  397. await UtilAction.cacheFiles(_sell.media)
  398. .then((value) {
  399. BlocProvider.of<MediaHelperBloc>(context)
  400. .add(ChangeListMedia(items: value));
  401. }).whenComplete(() {
  402. print("completed");
  403. });
  404. }
  405. } else if (state is ActionDetailInitial) {
  406. } else if (state is ActionDetailLoading) {
  407. LoadingDialog.showLoadingDialog(context);
  408. }
  409. },
  410. builder: (context, state) {
  411. return Column(
  412. children: <Widget>[
  413. Container(
  414. width: double.infinity,
  415. child: Text(
  416. "Ngày thực hiện *",
  417. style: TextStyle(
  418. color: Colors.black54, fontSize: 13.0),
  419. ),
  420. ),
  421. _btnExecuteTimePicker(),
  422. SizedBox(
  423. height: 8.0,
  424. ),
  425. _dropdownHarvest(),
  426. SizedBox(
  427. height: 8.0,
  428. ),
  429. _l1Field(),
  430. SizedBox(
  431. height: 8.0,
  432. ),
  433. _l2Field(),
  434. SizedBox(
  435. height: 8.0,
  436. ),
  437. _l3Field(),
  438. SizedBox(
  439. height: 8.0,
  440. ),
  441. _removedQuantityField(),
  442. SizedBox(
  443. height: 8.0,
  444. ),
  445. _buyerField(),
  446. SizedBox(
  447. height: 8.0,
  448. ),
  449. _descriptionField(),
  450. SizedBox(
  451. height: 8.0,
  452. ),
  453. _executeByField(),
  454. SizedBox(
  455. height: 8.0,
  456. ),
  457. BlocBuilder<MediaHelperBloc, MediaHelperState>(
  458. builder: (context, state) {
  459. if (state is MediaHelperSuccess) {
  460. return WidgetMediaPicker(
  461. currentItems: state.items,
  462. onChangeFiles: (filePaths) async {
  463. Get.find<ChangeFileController>()
  464. .addAllFile(filePaths);
  465. });
  466. } else {
  467. return Center(
  468. child: CircularProgressIndicator());
  469. }
  470. }),
  471. ],
  472. );
  473. },
  474. ),
  475. )),
  476. ))));
  477. @override
  478. void dispose() {
  479. _l1Controller.dispose();
  480. _l2Controller.dispose();
  481. _l3Controller.dispose();
  482. _removedQuantityController.dispose();
  483. _descriptionController.dispose();
  484. _buyerController.dispose();
  485. _executeByController.dispose();
  486. super.dispose();
  487. }
  488. }