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.

361 lines
17KB

  1. import 'dart:convert';
  2. import 'package:farm_tpf/custom_model/Plant.dart';
  3. import 'package:farm_tpf/custom_model/SuppliesUsing.dart';
  4. import 'package:farm_tpf/data/api/app_exception.dart';
  5. import 'package:farm_tpf/data/repository/repository.dart';
  6. import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart';
  7. import 'package:farm_tpf/presentation/custom_widgets/bloc/media_helper_bloc.dart';
  8. import 'package:farm_tpf/presentation/custom_widgets/button_widget.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_field_description.dart';
  13. import 'package:farm_tpf/presentation/custom_widgets/widget_text_form_field.dart';
  14. import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
  15. import 'package:farm_tpf/presentation/screens/actions/bloc/action_detail_bloc.dart';
  16. import 'package:farm_tpf/presentation/screens/actions/controller/ChangeFieldInForm.dart';
  17. import 'package:farm_tpf/presentation/screens/actions/controller/ChangeSupplyUsing.dart';
  18. import 'package:farm_tpf/presentation/screens/actions/plant/widget_plant_supply.dart';
  19. import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_file_controller.dart';
  20. import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_supply.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/services.dart';
  28. import 'package:flutter_bloc/flutter_bloc.dart';
  29. import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
  30. import 'package:get/get.dart';
  31. import 'package:intl/intl.dart';
  32. import 'package:keyboard_dismisser/keyboard_dismisser.dart';
  33. import 'package:pattern_formatter/pattern_formatter.dart';
  34. import 'package:farm_tpf/utils/formatter.dart';
  35. import '../util_action.dart';
  36. class EditActionPlantScreen extends StatefulWidget {
  37. final int cropId;
  38. final bool isEdit;
  39. final int? activityId;
  40. EditActionPlantScreen({required this.cropId, this.isEdit = false, this.activityId});
  41. @override
  42. _EditActionPlantScreenState createState() => _EditActionPlantScreenState();
  43. }
  44. class _EditActionPlantScreenState extends State<EditActionPlantScreen> {
  45. final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  46. final _repository = Repository();
  47. GlobalKey<FormState> _formKey = GlobalKey();
  48. bool _autoValidate = false;
  49. Plant _plant = Plant();
  50. var pref = LocalPref();
  51. final _descriptionController = TextEditingController();
  52. final _quantityController = TextEditingController();
  53. final _densityController = TextEditingController();
  54. final _executeByController = TextEditingController();
  55. List<SuppliesUsing> suppliesUsing = <SuppliesUsing>[];
  56. String executeTimeView = '';
  57. DateTime executeTime = DateTime.now();
  58. List<String> filePaths = <String>[];
  59. var changeFileController = Get.put(ChangeFileController());
  60. Future<Null> getSharedPrefs() async {
  61. var currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME);
  62. _executeByController.text = currentFullName ?? "";
  63. }
  64. @override
  65. void initState() {
  66. super.initState();
  67. getSharedPrefs();
  68. changeFileController.initValue();
  69. _plant.suppliesUsing = <SuppliesUsing>[];
  70. _plant.cropId = widget.cropId;
  71. }
  72. _validateInputs() async {
  73. if (_formKey.currentState!.validate()) {
  74. _formKey.currentState!.save();
  75. LoadingDialog.showLoadingDialog(context);
  76. filePaths = Get.find<ChangeFileController>().newFiles;
  77. var newSups = <SuppliesUsing>[];
  78. suppliesUsing.forEach((sup) {
  79. var newSup = sup;
  80. newSup.suppliesInWarehouseId = sup.tbSuppliesInWarehouseId;
  81. newSups.add(newSup);
  82. });
  83. _plant.suppliesUsing = newSups;
  84. _plant.mediaDel = Get.find<ChangeFileController>().deleteFiles;
  85. var activityPlant = jsonEncode(_plant.toJson()).toString();
  86. //ADD NEW
  87. if (_plant.activityId == null) {
  88. _repository.createAction((value) {
  89. LoadingDialog.hideLoadingDialog(context);
  90. Get.back(result: value);
  91. Utils.showSnackBarSuccess(message: label_add_success);
  92. }, (error) {
  93. LoadingDialog.hideLoadingDialog(context);
  94. Utils.showSnackBarError(message: AppException.handleError(error));
  95. }, apiAddAction: ConstCommon.apiAddPlant, paramActivity: ConstCommon.paramsActionPlant, activityAction: activityPlant, filePaths: filePaths);
  96. } else {
  97. //UPDATE
  98. _repository.updateAction((value) {
  99. LoadingDialog.hideLoadingDialog(context);
  100. Get.back(result: value);
  101. Utils.showSnackBarSuccess(message: label_update_success);
  102. }, (error) {
  103. LoadingDialog.hideLoadingDialog(context);
  104. Utils.showSnackBarError(message: AppException.handleError(error));
  105. },
  106. apiUpdateAction: ConstCommon.apiUpdatePlant,
  107. paramActivity: ConstCommon.paramsActionPlant,
  108. activityAction: activityPlant,
  109. filePaths: filePaths);
  110. }
  111. } else {
  112. _autoValidate = true;
  113. }
  114. }
  115. Widget _btnExecuteTimePicker() {
  116. return WidgetFieldDateTimePicker(
  117. initDateTime: executeTime,
  118. onUpdateDateTime: (selectedDate) {
  119. _plant.executeDate = selectedDate.convertLocalDateTimeToStringUtcDateTime();
  120. });
  121. }
  122. Widget _quantityField() {
  123. return WidgetTextFormFieldNumber(
  124. hintValue: "Số lượng cây trồng",
  125. textController: _quantityController,
  126. onSaved: (newValue) {
  127. _plant.quantity = (newValue ?? '0').parseDoubleThousand();
  128. },
  129. onChanged: (_) {},
  130. validator: (_) {},
  131. );
  132. }
  133. Widget _densityField() {
  134. return TextFormField(
  135. keyboardType: TextInputType.text,
  136. decoration: const InputDecoration(labelText: "Mật độ"),
  137. controller: _densityController,
  138. onSaved: (newValue) {
  139. _plant.density = newValue ?? '';
  140. },
  141. );
  142. }
  143. Widget _desciptionField() {
  144. return TextFieldDescriptionWidget(
  145. controller: _descriptionController,
  146. onSaved: (newValue) {
  147. _plant.description = newValue;
  148. },
  149. );
  150. }
  151. Widget _executeByField() {
  152. return TextFormField(
  153. keyboardType: TextInputType.text,
  154. decoration: const InputDecoration(labelText: "Người thực hiện"),
  155. enabled: false,
  156. controller: _executeByController,
  157. onSaved: (newValue) {},
  158. );
  159. }
  160. @override
  161. Widget build(BuildContext context) => KeyboardDismisser(
  162. gestures: [
  163. GestureType.onTap,
  164. GestureType.onPanUpdateDownDirection,
  165. ],
  166. child: Scaffold(
  167. backgroundColor: Colors.white,
  168. key: _scaffoldKey,
  169. appBar: AppBarWidget(
  170. isBack: true,
  171. action: InkWell(
  172. child: const Text(
  173. 'Huỷ',
  174. style: TextStyle(color: Colors.red, fontWeight: FontWeight.normal),
  175. ),
  176. onTap: () {
  177. if (Get.isSnackbarOpen) Get.back();
  178. Get.back();
  179. },
  180. ),
  181. ),
  182. body: KeyboardDismisser(
  183. child: MultiBlocProvider(
  184. providers: [
  185. BlocProvider<ActionDetailBloc>(
  186. create: (context) => ActionDetailBloc(repository: Repository())
  187. ..add(
  188. FetchData(
  189. isNeedFetchData: widget.isEdit,
  190. apiActivity: ConstCommon.apiDetailPlant,
  191. activityId: widget.activityId ?? -1,
  192. ),
  193. ),
  194. ),
  195. BlocProvider<MediaHelperBloc>(
  196. create: (context) => MediaHelperBloc()..add(ChangeListMedia(items: [])),
  197. )
  198. ],
  199. child: Form(
  200. key: _formKey,
  201. // autovalidate: _autoValidate,
  202. child: SafeArea(
  203. child: SingleChildScrollView(
  204. child: BlocConsumer<ActionDetailBloc, ActionDetailState>(
  205. listener: (context, state) async {
  206. if (state is ActionDetailFailure) {
  207. LoadingDialog.hideLoadingDialog(context);
  208. } else if (state is ActionDetailSuccess) {
  209. LoadingDialog.hideLoadingDialog(context);
  210. _plant = Plant.fromJson(state.item);
  211. _plant.activityId = widget.activityId ?? -1;
  212. _quantityController.text = _plant.quantity?.formatNumtoStringDecimal() ?? '';
  213. _densityController.text = _plant.density ?? '';
  214. _descriptionController.text = _plant.description ?? '';
  215. _executeByController.text = _plant.executeBy ?? '';
  216. Get.find<ChangeDateTimePicker>().change(
  217. _plant.executeDate?.convertStringServerDateTimeToLocalDateTime() ?? DateTime.now(),
  218. );
  219. //Show media
  220. if (Validators.stringNotNullOrEmpty(_plant.media ?? '')) {
  221. BlocProvider.of<MediaHelperBloc>(context)
  222. .add(ChangeListMedia(items: UtilAction.convertFilePathToMedia(_plant.media ?? '')));
  223. }
  224. //list supply
  225. suppliesUsing = _plant.suppliesUsing ?? <SuppliesUsing>[];
  226. Get.find<ChangeSupplyUsing>().changeInitList(suppliesUsing);
  227. } else if (state is ActionDetailInitial) {
  228. print("init");
  229. } else if (state is ActionDetailLoading) {
  230. print("loading");
  231. LoadingDialog.showLoadingDialog(context);
  232. }
  233. },
  234. builder: (context, state) {
  235. return Column(
  236. children: [
  237. Padding(
  238. padding: const EdgeInsets.all(8.0),
  239. child: Column(
  240. crossAxisAlignment: CrossAxisAlignment.start,
  241. children: <Widget>[
  242. const Text(
  243. 'Trồng',
  244. style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22),
  245. ),
  246. const SizedBox(
  247. height: 8.0,
  248. ),
  249. Container(
  250. width: double.infinity,
  251. child: const Text(
  252. "Ngày thực hiện *",
  253. style: TextStyle(color: Colors.black54, fontSize: 13.0),
  254. ),
  255. ),
  256. _btnExecuteTimePicker(),
  257. const SizedBox(
  258. height: 8.0,
  259. ),
  260. _quantityField(),
  261. const SizedBox(
  262. height: 8.0,
  263. ),
  264. _densityField(),
  265. const SizedBox(
  266. height: 8.0,
  267. ),
  268. _desciptionField(),
  269. const SizedBox(
  270. height: 8.0,
  271. ),
  272. _executeByField(),
  273. const SizedBox(
  274. height: 8.0,
  275. ),
  276. ],
  277. ),
  278. ),
  279. Container(
  280. width: double.infinity,
  281. height: 16,
  282. color: Colors.grey[200],
  283. ),
  284. WidgetPlantSupply(
  285. currentItems: [],
  286. onChangeSupplies: (value) {
  287. suppliesUsing = value;
  288. }),
  289. const SizedBox(
  290. height: 8.0,
  291. ),
  292. Container(
  293. width: double.infinity,
  294. height: 16,
  295. color: Colors.grey[200],
  296. ),
  297. BlocBuilder<MediaHelperBloc, MediaHelperState>(builder: (context, state) {
  298. if (state is MediaHelperSuccess) {
  299. return WidgetMediaPicker(
  300. currentItems: state.items,
  301. onChangeFiles: (newPathFiles, deletePathFiles) async {
  302. Get.find<ChangeFileController>().change(newPathFiles, deletePathFiles);
  303. });
  304. } else {
  305. return const Center(child: CircularProgressIndicator());
  306. }
  307. }),
  308. const SizedBox(
  309. height: 8,
  310. ),
  311. Padding(
  312. padding: const EdgeInsets.all(8.0),
  313. child: ButtonWidget(
  314. title: 'CẬP NHẬT',
  315. onPressed: () {
  316. var currentFocus = FocusScope.of(context);
  317. if (!currentFocus.hasPrimaryFocus) {
  318. currentFocus.unfocus();
  319. }
  320. if (Get.find<ChangeFieldFormSupply>().isChanged) {
  321. Utils.showDialogConfirmSupply(onConfirm: () {
  322. Get.back();
  323. _validateInputs();
  324. });
  325. } else {
  326. _validateInputs();
  327. }
  328. }),
  329. )
  330. ],
  331. );
  332. },
  333. ),
  334. ),
  335. ))))));
  336. @override
  337. void dispose() {
  338. _quantityController.dispose();
  339. _densityController.dispose();
  340. _descriptionController.dispose();
  341. _executeByController.dispose();
  342. super.dispose();
  343. }
  344. }