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.

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