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.

721 lines
33KB

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