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.

350 lines
15KB

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