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.

654 lines
28KB

  1. import 'dart:convert';
  2. import 'package:farm_tpf/custom_model/Nursery.dart';
  3. import 'package:farm_tpf/custom_model/NurseryDetail.dart';
  4. import 'package:farm_tpf/custom_model/Supply.dart';
  5. import 'package:farm_tpf/data/api/app_exception.dart';
  6. import 'package:farm_tpf/data/repository/repository.dart';
  7. import 'package:farm_tpf/presentation/custom_widgets/bloc/media_helper_bloc.dart';
  8. import 'package:farm_tpf/presentation/custom_widgets/widget_field_time_picker.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_form_field.dart';
  12. import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
  13. import 'package:farm_tpf/presentation/screens/actions/bloc/action_detail_bloc.dart';
  14. import 'package:farm_tpf/presentation/screens/actions/nursery/bloc/expansion_list_bloc.dart';
  15. import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_file_controller.dart';
  16. import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_supply.dart';
  17. import 'package:farm_tpf/presentation/screens/resources/sc_resource_helper.dart';
  18. import 'package:farm_tpf/utils/bloc/bloc/status_add_form_bloc.dart';
  19. import 'package:farm_tpf/utils/const_color.dart';
  20. import 'package:farm_tpf/utils/const_common.dart';
  21. import 'package:farm_tpf/utils/const_string.dart';
  22. import 'package:farm_tpf/utils/const_style.dart';
  23. import 'package:farm_tpf/utils/pref.dart';
  24. import 'package:farm_tpf/utils/validators.dart';
  25. import 'package:flutter/material.dart';
  26. import 'package:flutter_bloc/flutter_bloc.dart';
  27. import 'package:get/get.dart';
  28. import 'package:get/state_manager.dart';
  29. import 'package:keyboard_dismisser/keyboard_dismisser.dart';
  30. import 'package:farm_tpf/utils/formatter.dart';
  31. import '../util_action.dart';
  32. class EditActionNurseryScreen extends StatefulWidget {
  33. final int cropId;
  34. final bool isEdit;
  35. final int activityId;
  36. EditActionNurseryScreen(
  37. {@required this.cropId, this.isEdit = false, this.activityId});
  38. @override
  39. _EditActionNurseryState createState() => _EditActionNurseryState();
  40. }
  41. class _EditActionNurseryState extends State<EditActionNurseryScreen> {
  42. final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  43. final _repository = Repository();
  44. GlobalKey<FormState> _formKey = GlobalKey();
  45. bool _autoValidate = false;
  46. Nursery _nursery = Nursery();
  47. var pref = LocalPref();
  48. TextEditingController _substrateController = TextEditingController();
  49. TextEditingController _seedLengthController = TextEditingController();
  50. TextEditingController _quantityController = TextEditingController();
  51. TextEditingController _seedIncubationTimeController = TextEditingController();
  52. TextEditingController _descriptionController = TextEditingController();
  53. TextEditingController _workerNameController = TextEditingController();
  54. TextEditingController _trayNumberController = TextEditingController();
  55. final _executeByController = TextEditingController();
  56. DateTime executeTime = DateTime.now();
  57. List<NurseryDetail> currentNurseryDetail = List<NurseryDetail>();
  58. int currentIndexUpdate = -1;
  59. bool isResetForm = true;
  60. final changeSupply = Get.put(ChangeSupply());
  61. int selectedSupplyId = -1;
  62. List<String> filePaths = List<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. changeSupply.initValue();
  73. changeFileController.initValue();
  74. _nursery.nurseryDetail = new List<NurseryDetail>();
  75. _nursery.cropId = widget.cropId;
  76. }
  77. _validateInputs() async {
  78. if (_formKey.currentState.validate()) {
  79. _formKey.currentState.save();
  80. LoadingDialog.showLoadingDialog(context);
  81. _nursery.nurseryDetail = currentNurseryDetail;
  82. filePaths = Get.find<ChangeFileController>().newFiles;
  83. _nursery.mediaDel = Get.find<ChangeFileController>().deleteFiles;
  84. var activityNursery = jsonEncode(_nursery.toJson()).toString();
  85. //ADD NEW
  86. if (_nursery.activityId == null) {
  87. _repository.createAction((value) {
  88. LoadingDialog.hideLoadingDialog(context);
  89. Get.back(result: value);
  90. Utils.showSnackBarSuccess(message: label_add_success);
  91. }, (error) {
  92. LoadingDialog.hideLoadingDialog(context);
  93. Utils.showSnackBarError(message: AppException.handleError(error));
  94. },
  95. apiAddAction: ConstCommon.apiAddNursery,
  96. paramActivity: ConstCommon.paramsActionNursery,
  97. activityAction: activityNursery,
  98. filePaths: filePaths);
  99. } else {
  100. //UPDATE
  101. _repository.updateAction((value) {
  102. LoadingDialog.hideLoadingDialog(context);
  103. Get.back(result: value);
  104. Utils.showSnackBarSuccess(message: label_update_success);
  105. }, (error) {
  106. LoadingDialog.hideLoadingDialog(context);
  107. Utils.showSnackBarError(message: AppException.handleError(error));
  108. },
  109. apiUpdateAction: ConstCommon.apiUpdateNursery,
  110. paramActivity: ConstCommon.paramsActionNursery,
  111. activityAction: activityNursery,
  112. filePaths: filePaths);
  113. }
  114. } else {
  115. _autoValidate = true;
  116. }
  117. }
  118. Widget _btnExecuteTimePicker() {
  119. return WidgetFieldDateTimePicker(
  120. initDateTime: executeTime,
  121. onUpdateDateTime: (selectedDate) {
  122. _nursery.executeDate =
  123. selectedDate.convertLocalDateTimeToStringUtcDateTime();
  124. });
  125. }
  126. Widget _btnSelectSubstrates() {
  127. return FlatButton(
  128. padding: EdgeInsets.only(top: 0.0, right: 0.0, bottom: 0.0, left: 0.0),
  129. onPressed: () {
  130. Navigator.of(context)
  131. .push(MaterialPageRoute(
  132. builder: (_) => ResourceHelperScreen(
  133. titleName: "Giá thể",
  134. type: ConstCommon.supplyTypeSubStrate,
  135. selectedId: Get.find<ChangeSupply>().selectedSupplyId),
  136. fullscreenDialog: false))
  137. .then((value) {
  138. if (value != null) {
  139. var result = value as Supply;
  140. _nursery.substratesId = result.id;
  141. changeSupply.change(result);
  142. print("Home: $value");
  143. }
  144. });
  145. },
  146. child: Container(
  147. padding:
  148. EdgeInsets.only(top: 0.0, right: 0.0, bottom: 10.5, left: 0.0),
  149. decoration: BoxDecoration(
  150. border: kBorderTextField,
  151. ),
  152. child: Row(
  153. children: [
  154. GetBuilder<ChangeSupply>(
  155. builder: (_) => Expanded(
  156. child: Text(
  157. changeSupply.selectedSupplyName == null
  158. ? "Loại giá thể"
  159. : changeSupply.selectedSupplyName.toString(),
  160. style: TextStyle(
  161. fontSize: 14.0, color: Colors.black87)))),
  162. Icon(
  163. Icons.arrow_drop_down,
  164. color: Colors.grey,
  165. ),
  166. ],
  167. )));
  168. }
  169. Widget _seedLengthField() {
  170. return WidgetTextFormFieldNumber(
  171. hintValue: "Chiều dài mầm",
  172. textController: _seedLengthController,
  173. onSaved: (newValue) {
  174. _nursery.seedLength = newValue.parseDoubleThousand();
  175. },
  176. );
  177. }
  178. Widget _quantityField() {
  179. return WidgetTextFormFieldNumber(
  180. hintValue: "Số lượng hạt gieo",
  181. textController: _quantityController,
  182. onSaved: (newValue) {
  183. _nursery.quantity = newValue.parseDoubleThousand();
  184. },
  185. );
  186. }
  187. Widget _seedIncubationTimeField() {
  188. return WidgetTextFormFieldNumber(
  189. hintValue: "Thời gian ngâm hạt",
  190. textController: _seedIncubationTimeController,
  191. onSaved: (newValue) {
  192. _nursery.seedIncubationTime = newValue.parseDoubleThousand();
  193. },
  194. );
  195. }
  196. Widget _desciptionField() {
  197. return TextFormField(
  198. keyboardType: TextInputType.text,
  199. decoration: InputDecoration(labelText: "Ghi chú"),
  200. controller: _descriptionController,
  201. onSaved: (newValue) {
  202. _nursery.description = newValue;
  203. },
  204. );
  205. }
  206. Widget _executeByField() {
  207. return TextFormField(
  208. keyboardType: TextInputType.text,
  209. decoration: InputDecoration(labelText: "Người thực hiện"),
  210. enabled: false,
  211. controller: _executeByController,
  212. onSaved: (newValue) {},
  213. );
  214. }
  215. Widget _btnAddWorker() {
  216. //TODO :check flow error sua item -> xoa list -> bam nut them
  217. return Builder(builder: (context) {
  218. return BlocConsumer<StatusAddFormBloc, StatusAddFormState>(
  219. listener: (context, state) {
  220. if (state is Edit) {
  221. isResetForm = false;
  222. _workerNameController.text = state.nurseryDetail.workerName;
  223. _trayNumberController.text = state.nurseryDetail.trayNumber;
  224. } else if (state is Delete) {
  225. if (currentIndexUpdate == state.index) {
  226. isResetForm = true;
  227. _workerNameController.text = "";
  228. _trayNumberController.text = "";
  229. }
  230. } else {
  231. isResetForm = true;
  232. _workerNameController.text = "";
  233. _trayNumberController.text = "";
  234. }
  235. }, builder: (context, state) {
  236. return Container(
  237. padding: EdgeInsets.all(8.0),
  238. decoration: BoxDecoration(
  239. shape: BoxShape.rectangle,
  240. borderRadius: BorderRadius.circular(10),
  241. color: Colors.white,
  242. border: Border.all(color: COLOR_CONST.DEFAULT)),
  243. child: Form(
  244. child: Column(
  245. children: [
  246. TextFormField(
  247. keyboardType: TextInputType.text,
  248. controller: _workerNameController,
  249. decoration: InputDecoration(labelText: "Tên công nhân *"),
  250. validator: (value) {
  251. return Validators.validateNotNullOrEmpty(
  252. value, "Tên công nhân");
  253. },
  254. onSaved: (newValue) {},
  255. ),
  256. TextFormField(
  257. keyboardType: TextInputType.text,
  258. controller: _trayNumberController,
  259. decoration: InputDecoration(labelText: "Ươm khây số"),
  260. onSaved: (newValue) {},
  261. ),
  262. Align(
  263. alignment: Alignment.centerRight,
  264. child: Row(
  265. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  266. children: [
  267. isResetForm
  268. ? Container()
  269. : OutlineButton(
  270. shape: RoundedRectangleBorder(
  271. borderRadius:
  272. new BorderRadius.circular(8.0)),
  273. child: Text("Huỷ"),
  274. onPressed: () {
  275. context
  276. .bloc<StatusAddFormBloc>()
  277. .add(Reset());
  278. }),
  279. FlatButton(
  280. color: COLOR_CONST.DEFAULT,
  281. shape: RoundedRectangleBorder(
  282. borderRadius: new BorderRadius.circular(8.0)),
  283. onPressed: () {
  284. if (Validators.stringNotNullOrEmpty(
  285. _workerNameController.text)) {
  286. NurseryDetail _nurseryDetail = NurseryDetail()
  287. ..workerName = _workerNameController.text
  288. ..trayNumber = _trayNumberController.text;
  289. if (state is Edit) {
  290. context.bloc<ExpansionListBloc>().add(Update(
  291. index: state.index,
  292. item: _nurseryDetail,
  293. items: state.items));
  294. } else {
  295. currentNurseryDetail.insert(
  296. 0, _nurseryDetail);
  297. BlocProvider.of<ExpansionListBloc>(context)
  298. .add(AddNew(items: currentNurseryDetail));
  299. }
  300. context.bloc<StatusAddFormBloc>().add(Reset());
  301. } else {
  302. Utils.showSnackBarWarning(
  303. message: "Vui lòng nhập tên công nhân");
  304. }
  305. },
  306. child: Text(
  307. (state is Edit) ? "Sửa" : "Thêm",
  308. style: TextStyle(color: Colors.white),
  309. ))
  310. ],
  311. ),
  312. ),
  313. ],
  314. ),
  315. ));
  316. });
  317. });
  318. }
  319. Widget _buildListAddWorker() {
  320. return Builder(builder: (context) {
  321. return BlocBuilder<ExpansionListBloc, ExpansionListState>(
  322. builder: (context, state) {
  323. if (state is ExpansionListSuccess) {
  324. currentNurseryDetail = state.items;
  325. if (currentNurseryDetail.isEmpty) {
  326. return Container();
  327. }
  328. return Container(
  329. height: 70,
  330. child: ListView.builder(
  331. physics: ClampingScrollPhysics(),
  332. scrollDirection: Axis.horizontal,
  333. shrinkWrap: true,
  334. itemCount: currentNurseryDetail.length,
  335. itemBuilder: (context, index) {
  336. return GestureDetector(
  337. onTap: () {
  338. print("edit worker");
  339. currentIndexUpdate = index;
  340. context.bloc<StatusAddFormBloc>().add(Changed(
  341. status: CRUDStatus.edit,
  342. index: index,
  343. nurseryDetail: currentNurseryDetail[index],
  344. items: currentNurseryDetail));
  345. },
  346. child: Card(
  347. child: Stack(
  348. alignment: Alignment.bottomCenter,
  349. overflow: Overflow.visible,
  350. children: <Widget>[
  351. Positioned(
  352. child: ClipRRect(
  353. borderRadius: BorderRadius.circular(8),
  354. child: Container(
  355. padding: EdgeInsets.all(4),
  356. width: 120,
  357. child: Column(
  358. mainAxisAlignment: MainAxisAlignment.center,
  359. children: [
  360. SizedBox(
  361. height: 12.0,
  362. ),
  363. Flexible(
  364. child: Text(
  365. currentNurseryDetail[index]
  366. .workerName ??
  367. "",
  368. overflow: TextOverflow.ellipsis,
  369. maxLines: 1),
  370. ),
  371. Validators.stringNotNullOrEmpty(
  372. currentNurseryDetail[index]
  373. .trayNumber)
  374. ? Flexible(
  375. child: Text(
  376. currentNurseryDetail[index]
  377. .trayNumber ??
  378. ""))
  379. : SizedBox()
  380. ],
  381. ),
  382. ),
  383. )),
  384. Positioned(
  385. top: -10,
  386. right: -10,
  387. child: IconButton(
  388. icon: Icon(
  389. Icons.cancel,
  390. color: Colors.redAccent,
  391. ),
  392. onPressed: () {
  393. print("Delete worker");
  394. context.bloc<ExpansionListBloc>().add(
  395. DeleteItem(
  396. index: index,
  397. items: currentNurseryDetail));
  398. context.bloc<StatusAddFormBloc>().add(
  399. Changed(
  400. status: CRUDStatus.delete,
  401. index: index,
  402. nurseryDetail:
  403. currentNurseryDetail[index],
  404. items: currentNurseryDetail));
  405. }),
  406. )
  407. ],
  408. )));
  409. }));
  410. } else if (state is ExpansionListFailure) {
  411. return Container();
  412. } else {
  413. return Container();
  414. }
  415. });
  416. });
  417. }
  418. _actionAppBar() {
  419. IconButton iconButton;
  420. if (1 == 1) {
  421. iconButton = IconButton(
  422. icon: Icon(
  423. Icons.done,
  424. color: Colors.black,
  425. ),
  426. onPressed: () {
  427. FocusScopeNode currentFocus = FocusScope.of(context);
  428. if (!currentFocus.hasPrimaryFocus) {
  429. currentFocus.unfocus();
  430. }
  431. if (!Validators.stringNotNullOrEmpty(_workerNameController.text) &&
  432. !Validators.stringNotNullOrEmpty(_trayNumberController.text)) {
  433. _validateInputs();
  434. } else {
  435. Utils.showDialog(
  436. title: "Tên công nhân hoặc khây trồng đang cập nhật",
  437. message: "Bạn có muốn cập nhật?",
  438. textConfirm: "Tiếp tục",
  439. textCancel: "Xem lại",
  440. onConfirm: () {
  441. Get.back();
  442. _validateInputs();
  443. });
  444. }
  445. },
  446. );
  447. return <Widget>[iconButton];
  448. }
  449. return <Widget>[Container()];
  450. }
  451. @override
  452. Widget build(BuildContext context) => KeyboardDismisser(
  453. gestures: [
  454. GestureType.onTap,
  455. GestureType.onPanUpdateDownDirection,
  456. ],
  457. child: Scaffold(
  458. key: _scaffoldKey,
  459. appBar: AppBar(
  460. centerTitle: true,
  461. title: Text(plot_action_nursery),
  462. actions: _actionAppBar()),
  463. body: KeyboardDismisser(
  464. child: MultiBlocProvider(
  465. providers: [
  466. BlocProvider<ExpansionListBloc>(
  467. create: (context) => ExpansionListBloc(),
  468. ),
  469. BlocProvider<StatusAddFormBloc>(
  470. create: (context) => StatusAddFormBloc(),
  471. ),
  472. BlocProvider<ActionDetailBloc>(
  473. create: (context) =>
  474. ActionDetailBloc(repository: Repository())
  475. ..add(FetchData(
  476. isNeedFetchData: widget.isEdit,
  477. apiActivity: ConstCommon.apiDetailNursery,
  478. activityId: widget.activityId))),
  479. BlocProvider<MediaHelperBloc>(
  480. create: (context) =>
  481. MediaHelperBloc()..add(ChangeListMedia(items: [])),
  482. )
  483. ],
  484. child: Form(
  485. key: _formKey,
  486. autovalidate: _autoValidate,
  487. child: SingleChildScrollView(
  488. padding: EdgeInsets.all(8.0),
  489. child: BlocConsumer<ActionDetailBloc,
  490. ActionDetailState>(
  491. listener: (context, state) async {
  492. if (state is ActionDetailFailure) {
  493. print("fail");
  494. LoadingDialog.hideLoadingDialog(context);
  495. } else if (state is ActionDetailSuccess) {
  496. LoadingDialog.hideLoadingDialog(context);
  497. print("success");
  498. print(state.item);
  499. _nursery = Nursery.fromJson(state.item);
  500. _seedLengthController.text = _nursery
  501. .seedLength
  502. .formatNumtoStringDecimal();
  503. _quantityController.text = _nursery.quantity
  504. .formatNumtoStringDecimal();
  505. _seedIncubationTimeController.text = _nursery
  506. .seedIncubationTime
  507. .formatNumtoStringDecimal();
  508. _descriptionController.text =
  509. _nursery.description;
  510. _executeByController.text =
  511. _nursery.executeBy;
  512. Get.find<ChangeDateTimePicker>().change(_nursery
  513. .executeDate
  514. .convertStringServerDateTimeToLocalDateTime());
  515. //Show media
  516. if (Validators.stringNotNullOrEmpty(
  517. _nursery.media)) {
  518. BlocProvider.of<MediaHelperBloc>(context)
  519. .add(ChangeListMedia(
  520. items: UtilAction
  521. .convertFilePathToMedia(
  522. _nursery.media)));
  523. }
  524. //Show worker
  525. if (_nursery.nurseryDetail.length > 0) {
  526. BlocProvider.of<ExpansionListBloc>(context)
  527. .add(AddNew(
  528. items: _nursery.nurseryDetail));
  529. }
  530. //change subStrates
  531. if (_nursery.substratesId != null) {
  532. Get.find<ChangeSupply>().changeByIdAndName(
  533. _nursery.substratesId,
  534. _nursery.substrateName);
  535. }
  536. } else if (state is ActionDetailInitial) {
  537. print("init");
  538. } else if (state is ActionDetailLoading) {
  539. print("loading");
  540. LoadingDialog.showLoadingDialog(context);
  541. }
  542. },
  543. builder: (context, state) {
  544. return Column(
  545. children: <Widget>[
  546. Container(
  547. width: double.infinity,
  548. child: Text(
  549. "Ngày thực hiện *",
  550. style: TextStyle(
  551. color: Colors.black54,
  552. fontSize: 13.0),
  553. ),
  554. ),
  555. _btnExecuteTimePicker(),
  556. SizedBox(
  557. height: 8.0,
  558. ),
  559. Container(
  560. width: double.infinity,
  561. child: Text(
  562. "Loại giá thể",
  563. style: TextStyle(
  564. color: Colors.black54,
  565. fontSize: 13.0),
  566. ),
  567. ),
  568. _btnSelectSubstrates(),
  569. SizedBox(
  570. height: 8.0,
  571. ),
  572. _seedLengthField(),
  573. SizedBox(
  574. height: 8.0,
  575. ),
  576. _quantityField(),
  577. SizedBox(
  578. height: 8.0,
  579. ),
  580. _seedIncubationTimeField(),
  581. SizedBox(
  582. height: 8.0,
  583. ),
  584. _desciptionField(),
  585. SizedBox(
  586. height: 8.0,
  587. ),
  588. _executeByField(),
  589. SizedBox(
  590. height: 8.0,
  591. ),
  592. _buildListAddWorker(),
  593. SizedBox(
  594. height: 8.0,
  595. ),
  596. _btnAddWorker(),
  597. SizedBox(
  598. height: 8.0,
  599. ),
  600. BlocBuilder<MediaHelperBloc,
  601. MediaHelperState>(
  602. builder: (context, state) {
  603. if (state is MediaHelperSuccess) {
  604. print("length: " +
  605. state.items.length.toString());
  606. return WidgetMediaPicker(
  607. currentItems: state.items,
  608. onChangeFiles: (newPathFiles,
  609. deletePathFiles) async {
  610. Get.find<ChangeFileController>()
  611. .change(newPathFiles,
  612. deletePathFiles);
  613. });
  614. } else {
  615. return Center(
  616. child: CircularProgressIndicator());
  617. }
  618. }),
  619. ],
  620. );
  621. },
  622. ),
  623. ))))));
  624. @override
  625. void dispose() {
  626. _substrateController.dispose();
  627. _seedLengthController.dispose();
  628. _quantityController.dispose();
  629. _seedIncubationTimeController.dispose();
  630. _descriptionController.dispose();
  631. _executeByController.dispose();
  632. super.dispose();
  633. }
  634. }