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.

642 lines
28KB

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