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.

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