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.

664 lines
29KB

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