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.

629 lines
27KB

  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. _validateInputs();
  420. },
  421. );
  422. return <Widget>[iconButton];
  423. }
  424. return <Widget>[Container()];
  425. }
  426. @override
  427. Widget build(BuildContext context) => KeyboardDismisser(
  428. gestures: [
  429. GestureType.onTap,
  430. GestureType.onPanUpdateDownDirection,
  431. ],
  432. child: Scaffold(
  433. key: _scaffoldKey,
  434. appBar: AppBar(
  435. centerTitle: true,
  436. title: Text(plot_action_nursery),
  437. actions: _actionAppBar()),
  438. body: KeyboardDismisser(
  439. child: MultiBlocProvider(
  440. providers: [
  441. BlocProvider<ExpansionListBloc>(
  442. create: (context) => ExpansionListBloc(),
  443. ),
  444. BlocProvider<StatusAddFormBloc>(
  445. create: (context) => StatusAddFormBloc(),
  446. ),
  447. BlocProvider<ActionDetailBloc>(
  448. create: (context) =>
  449. ActionDetailBloc(repository: Repository())
  450. ..add(FetchData(
  451. isNeedFetchData: widget.isEdit,
  452. apiActivity: ConstCommon.apiDetailNursery,
  453. activityId: widget.activityId))),
  454. BlocProvider<MediaHelperBloc>(
  455. create: (context) =>
  456. MediaHelperBloc()..add(ChangeListMedia(items: [])),
  457. )
  458. ],
  459. child: Form(
  460. key: _formKey,
  461. autovalidate: _autoValidate,
  462. child: SingleChildScrollView(
  463. padding: EdgeInsets.all(8.0),
  464. child: BlocConsumer<ActionDetailBloc,
  465. ActionDetailState>(
  466. listener: (context, state) async {
  467. if (state is ActionDetailFailure) {
  468. print("fail");
  469. LoadingDialog.hideLoadingDialog(context);
  470. } else if (state is ActionDetailSuccess) {
  471. LoadingDialog.hideLoadingDialog(context);
  472. print("success");
  473. print(state.item);
  474. _nursery = Nursery.fromJson(state.item);
  475. _seedLengthController.text = _nursery
  476. .seedLength
  477. .formatNumtoStringDecimal();
  478. _quantityController.text = _nursery.quantity
  479. .formatNumtoStringDecimal();
  480. _seedIncubationTimeController.text = _nursery
  481. .seedIncubationTime
  482. .formatNumtoStringDecimal();
  483. _descriptionController.text =
  484. _nursery.description;
  485. _executeByController.text =
  486. _nursery.executeBy;
  487. Get.find<ChangeDateTimePicker>().change(_nursery
  488. .executeDate
  489. .convertStringServerDateTimeToLocalDateTime());
  490. //Show media
  491. if (Validators.stringNotNullOrEmpty(
  492. _nursery.media)) {
  493. BlocProvider.of<MediaHelperBloc>(context)
  494. .add(ChangeListMedia(
  495. items: UtilAction
  496. .convertFilePathToMedia(
  497. _nursery.media)));
  498. }
  499. //Show worker
  500. if (_nursery.nurseryDetail.length > 0) {
  501. BlocProvider.of<ExpansionListBloc>(context)
  502. .add(AddNew(
  503. items: _nursery.nurseryDetail));
  504. }
  505. //change subStrates
  506. if (_nursery.substratesId != null) {
  507. Get.find<ChangeSupply>().changeByIdAndName(
  508. _nursery.substratesId,
  509. _nursery.substrateName);
  510. }
  511. } else if (state is ActionDetailInitial) {
  512. print("init");
  513. } else if (state is ActionDetailLoading) {
  514. print("loading");
  515. LoadingDialog.showLoadingDialog(context);
  516. }
  517. },
  518. builder: (context, state) {
  519. return Column(
  520. children: <Widget>[
  521. Container(
  522. width: double.infinity,
  523. child: Text(
  524. "Ngày thực hiện *",
  525. style: TextStyle(
  526. color: Colors.black54,
  527. fontSize: 13.0),
  528. ),
  529. ),
  530. _btnExecuteTimePicker(),
  531. SizedBox(
  532. height: 8.0,
  533. ),
  534. Container(
  535. width: double.infinity,
  536. child: Text(
  537. "Loại giá thể",
  538. style: TextStyle(
  539. color: Colors.black54,
  540. fontSize: 13.0),
  541. ),
  542. ),
  543. _btnSelectSubstrates(),
  544. SizedBox(
  545. height: 8.0,
  546. ),
  547. _seedLengthField(),
  548. SizedBox(
  549. height: 8.0,
  550. ),
  551. _quantityField(),
  552. SizedBox(
  553. height: 8.0,
  554. ),
  555. _seedIncubationTimeField(),
  556. SizedBox(
  557. height: 8.0,
  558. ),
  559. _desciptionField(),
  560. SizedBox(
  561. height: 8.0,
  562. ),
  563. _executeByField(),
  564. SizedBox(
  565. height: 8.0,
  566. ),
  567. _buildListAddWorker(),
  568. SizedBox(
  569. height: 8.0,
  570. ),
  571. _btnAddWorker(),
  572. SizedBox(
  573. height: 8.0,
  574. ),
  575. BlocBuilder<MediaHelperBloc,
  576. MediaHelperState>(
  577. builder: (context, state) {
  578. if (state is MediaHelperSuccess) {
  579. print("length: " +
  580. state.items.length.toString());
  581. return WidgetMediaPicker(
  582. currentItems: state.items,
  583. onChangeFiles: (newPathFiles,
  584. deletePathFiles) async {
  585. Get.find<ChangeFileController>()
  586. .change(newPathFiles,
  587. deletePathFiles);
  588. });
  589. } else {
  590. return Center(
  591. child: CircularProgressIndicator());
  592. }
  593. }),
  594. ],
  595. );
  596. },
  597. ),
  598. ))))));
  599. @override
  600. void dispose() {
  601. _substrateController.dispose();
  602. _seedLengthController.dispose();
  603. _quantityController.dispose();
  604. _seedIncubationTimeController.dispose();
  605. _descriptionController.dispose();
  606. _executeByController.dispose();
  607. super.dispose();
  608. }
  609. }