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
31KB

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