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.

628 lines
25KB

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