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.

476 lines
17KB

  1. import 'package:farm_tpf/custom_model/CropPlot.dart';
  2. import 'package:farm_tpf/data/repository/repository.dart';
  3. import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart';
  4. import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart';
  5. import 'package:farm_tpf/presentation/screens/actions/crop_status/sc_edit_action_crop_status.dart';
  6. import 'package:farm_tpf/presentation/screens/actions/disease/sc_edit_action_disease.dart';
  7. import 'package:farm_tpf/presentation/screens/actions/dung/sc_edit_action_dung.dart';
  8. import 'package:farm_tpf/presentation/screens/actions/end/sc_edit_action_end.dart';
  9. import 'package:farm_tpf/presentation/screens/actions/environment_update/sc_edit_action_environment_update.dart';
  10. import 'package:farm_tpf/presentation/screens/actions/harvest/sc_edit_action_harvest.dart';
  11. import 'package:farm_tpf/presentation/screens/actions/nursery/sc_edit_action_nursery.dart';
  12. import 'package:farm_tpf/presentation/screens/actions/other/sc_edit_action_other.dart';
  13. import 'package:farm_tpf/presentation/screens/actions/packing/sc_edit_action_packing.dart';
  14. import 'package:farm_tpf/presentation/screens/actions/plant/sc_edit_action_plant.dart';
  15. import 'package:farm_tpf/presentation/screens/actions/sell/sc_edit_action_sell.dart';
  16. import 'package:farm_tpf/presentation/screens/actions/spraying/sc_edit_action_spraying.dart';
  17. import 'package:farm_tpf/presentation/screens/actions/use_water/sc_edit_action_user_water.dart';
  18. import 'package:farm_tpf/presentation/screens/plot/sc_plot.dart';
  19. import 'package:farm_tpf/presentation/screens/plot_detail/bloc/plot_detail_bloc.dart';
  20. import 'package:farm_tpf/utils/const_color.dart';
  21. import 'package:farm_tpf/utils/const_string.dart';
  22. import 'package:flutter/material.dart';
  23. import 'package:flutter_bloc/flutter_bloc.dart';
  24. import 'package:farm_tpf/utils/formatter.dart';
  25. import 'package:get/get.dart';
  26. class PlotActionScreen extends StatefulWidget {
  27. int cropId;
  28. String cropCode;
  29. PlotActionScreen({this.cropId, this.cropCode});
  30. @override
  31. _PlotActionScreenState createState() => _PlotActionScreenState();
  32. }
  33. class _PlotActionScreenState extends State<PlotActionScreen> {
  34. List<ActionType> actions = new List<ActionType>();
  35. ScrollController _scrollController;
  36. var changeToRefresh = Get.put(ChangeToRefreshLists());
  37. @override
  38. void initState() {
  39. super.initState();
  40. changeToRefresh.initValue();
  41. _scrollController = ScrollController()..addListener(() => setState(() {}));
  42. _initActionButtons();
  43. }
  44. _initActionButtons() {
  45. actions.add(ActionType(
  46. plot_action_nursery,
  47. null,
  48. EditActionNurseryScreen(
  49. cropId: widget.cropId,
  50. )));
  51. actions.add(ActionType(plot_action_plant, null, EditActionPlantScreen()));
  52. actions.add(ActionType(
  53. plot_action_crop_status,
  54. null,
  55. EditActionCropStatusScreen(
  56. cropId: widget.cropId,
  57. )));
  58. actions.add(ActionType(
  59. plot_action_environment_update,
  60. null,
  61. EditActionEnvironmentUpdate(
  62. cropId: widget.cropId,
  63. )));
  64. actions.add(ActionType(plot_action_dung, null, EditActionDungScreen()));
  65. actions.add(
  66. ActionType(plot_action_spraying, null, EditActionSprayingScreen()));
  67. actions.add(ActionType(
  68. plot_action_disease,
  69. null,
  70. EditActionDiseaseScreen(
  71. cropId: widget.cropId,
  72. )));
  73. actions.add(ActionType(
  74. plot_action_use_water,
  75. null,
  76. EditActionUseWaterScreen(
  77. cropId: widget.cropId,
  78. )));
  79. actions.add(ActionType(plot_action_other, null, EditActionOtherScreen()));
  80. actions.add(ActionType(
  81. plot_action_harvest,
  82. null,
  83. EditActionHarvestScreen(
  84. cropId: widget.cropId,
  85. )));
  86. actions.add(ActionType(
  87. plot_action_finish,
  88. null,
  89. EditActionEndScreen(
  90. cropId: widget.cropId,
  91. )));
  92. }
  93. Widget _createActionButtons(ActionType actionType, BuildContext _context) {
  94. return BlocProvider<PlotDetailBloc>(
  95. create: (context) => PlotDetailBloc(repository: Repository()),
  96. child: GestureDetector(
  97. onTap: () {
  98. Navigator.of(context)
  99. .push(MaterialPageRoute(
  100. builder: (context) => actionType.listScreen))
  101. .then((value) {
  102. if (1 == 1) {
  103. try {
  104. //TODO: refresh list
  105. } catch (e) {
  106. print(e.toString());
  107. }
  108. }
  109. });
  110. },
  111. child: Container(
  112. height: 75,
  113. margin: EdgeInsets.all(4.0),
  114. padding: EdgeInsets.all(0.0),
  115. decoration: BoxDecoration(
  116. color: COLOR_CONST.WHITE,
  117. borderRadius: BorderRadius.only(
  118. topLeft: Radius.circular(8.0),
  119. bottomLeft: Radius.circular(8.0),
  120. bottomRight: Radius.circular(8.0),
  121. topRight: Radius.circular(8.0)),
  122. boxShadow: <BoxShadow>[
  123. BoxShadow(
  124. color: COLOR_CONST.GRAY1.withOpacity(0.2),
  125. offset: Offset(1.1, 1.1),
  126. blurRadius: 10.0),
  127. ],
  128. ),
  129. child: Stack(
  130. children: <Widget>[
  131. Positioned(
  132. top: -10,
  133. right: -3,
  134. child: (actionType.addScreen == null)
  135. ? Container()
  136. : IconButton(
  137. icon: Icon(
  138. Icons.add_circle,
  139. size: 40,
  140. color: Colors.green,
  141. ),
  142. onPressed: () {
  143. Navigator.of(context).push(MaterialPageRoute(
  144. builder: (context) => actionType.addScreen));
  145. })),
  146. Positioned.fill(
  147. child: Align(
  148. alignment: Alignment.center,
  149. child: Text(
  150. actionType.actionName,
  151. textAlign: TextAlign.center,
  152. style: TextStyle(
  153. fontWeight: FontWeight.w400,
  154. fontSize: 13,
  155. color: COLOR_CONST.BLACK2,
  156. ),
  157. )),
  158. ),
  159. ],
  160. ),
  161. )),
  162. );
  163. }
  164. bool _showTitle(BuildContext context) {
  165. var kExpandedHeight = MediaQuery.of(context).size.width * 1.125 + 32;
  166. return _scrollController.hasClients &&
  167. _scrollController.offset > kExpandedHeight - kToolbarHeight;
  168. }
  169. @override
  170. Widget build(BuildContext context) {
  171. return NestedScrollView(
  172. controller: _scrollController,
  173. headerSliverBuilder: (context, innerBoxScrolled) => [
  174. SliverAppBar(
  175. floating: false,
  176. pinned: false,
  177. backgroundColor: Colors.white,
  178. leading: Container(),
  179. title: null,
  180. // title: _showTitle(context) ? Text(plot_detail_title) : null,
  181. //Height flexibleSpace : WidthScreen /2 * 6/16 * 6(row) + 8(space) *4
  182. expandedHeight: MediaQuery.of(context).size.width * 1.125 + 32,
  183. flexibleSpace: _showTitle(context)
  184. ? null
  185. : BlocProvider<PlotDetailBloc>(
  186. create: (context) => PlotDetailBloc(repository: Repository()),
  187. child: BlocBuilder<PlotDetailBloc, PlotDetailState>(
  188. builder: (contextB, state) {
  189. return FlexibleSpaceBar(
  190. centerTitle: true,
  191. title: GridView.count(
  192. shrinkWrap: true,
  193. crossAxisCount: 2,
  194. childAspectRatio: 16 / 6,
  195. children: actions.map(
  196. (item) {
  197. return _createActionButtons(item, contextB);
  198. },
  199. ).toList()),
  200. );
  201. }),
  202. ),
  203. ),
  204. ],
  205. body: BlocProvider(
  206. create: (context) => PlotDetailBloc(repository: Repository())
  207. ..add(DataFetched(cropId: widget.cropId, cropCode: widget.cropCode)),
  208. child: HoldInfinityWidget(
  209. cropId: widget.cropId,
  210. cropCode: widget.cropCode,
  211. ),
  212. ),
  213. );
  214. }
  215. }
  216. class HoldInfinityWidget extends StatelessWidget {
  217. int cropId;
  218. String cropCode;
  219. HoldInfinityWidget({this.cropId, this.cropCode});
  220. final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  221. @override
  222. Widget build(BuildContext context) {
  223. return Scaffold(key: _scaffoldKey, body: InfinityView(cropId: cropId));
  224. }
  225. }
  226. class InfinityView extends StatefulWidget {
  227. int cropId;
  228. String cropCode;
  229. InfinityView({this.cropId, this.cropCode});
  230. @override
  231. _InfinityViewState createState() => _InfinityViewState();
  232. }
  233. class _InfinityViewState extends State<InfinityView> {
  234. final _scrollController = ScrollController();
  235. final _scrollThreshold = 250.0;
  236. PlotDetailBloc _plotDetailBloc;
  237. var a = Get.put(ChangeToRefreshLists());
  238. @override
  239. void initState() {
  240. _scrollController.addListener(() {
  241. final maxScroll = _scrollController.position.maxScrollExtent;
  242. final currentScroll = _scrollController.position.pixels;
  243. if (maxScroll - currentScroll < _scrollThreshold) {
  244. _plotDetailBloc
  245. .add(DataFetched(cropId: widget.cropId, cropCode: widget.cropCode));
  246. }
  247. });
  248. _plotDetailBloc = BlocProvider.of<PlotDetailBloc>(context);
  249. super.initState();
  250. }
  251. @override
  252. Widget build(BuildContext context) {
  253. return BlocBuilder<PlotDetailBloc, PlotDetailState>(
  254. builder: (context, state) {
  255. if (state is PlotDetailFailure) {
  256. return Center(child: Text(state.errorString));
  257. }
  258. if (state is PlotDetailSuccess) {
  259. if (state.items.isEmpty) {
  260. return Center(child: Text(label_list_empty));
  261. }
  262. List<Activities> currentItems = List<Activities>.from(state.items);
  263. Get.find<ChangeToRefreshLists>()
  264. .updateValue(currentItems, state.page, state.hasReachedMax);
  265. return RefreshIndicator(
  266. child: Column(
  267. children: [
  268. Container(
  269. height: 40,
  270. alignment: Alignment.center,
  271. decoration: BoxDecoration(
  272. color: COLOR_CONST.WHITE_50,
  273. border: Border(
  274. top: BorderSide(
  275. width: 0.5, color: COLOR_CONST.DEFAULT),
  276. bottom: BorderSide(
  277. width: 0.5, color: COLOR_CONST.DEFAULT)),
  278. ),
  279. child: Text(
  280. plot_detail_title,
  281. style: TextStyle(
  282. fontSize: 20, fontWeight: FontWeight.normal),
  283. )),
  284. Expanded(
  285. child: ListView.builder(
  286. physics: AlwaysScrollableScrollPhysics(),
  287. itemBuilder: (BuildContext context, int index) {
  288. return index >= state.items.length
  289. ? BottomLoader()
  290. : ItemInfinityWidget(
  291. currentItems: currentItems,
  292. item: state.items[index],
  293. currentPage: state.page,
  294. currentReachedMax: state.hasReachedMax);
  295. },
  296. itemCount: state.hasReachedMax
  297. ? state.items.length
  298. : state.items.length + 1,
  299. controller: _scrollController,
  300. ))
  301. ],
  302. ),
  303. onRefresh: () async {
  304. _plotDetailBloc.add(OnRefresh(
  305. cropId: widget.cropId, cropCode: widget.cropCode));
  306. });
  307. }
  308. return Center(
  309. child: LoadingListPage(),
  310. );
  311. },
  312. );
  313. }
  314. @override
  315. void dispose() {
  316. _scrollController.dispose();
  317. super.dispose();
  318. }
  319. }
  320. class ItemInfinityWidget extends StatelessWidget {
  321. final List<Activities> currentItems;
  322. final Activities item;
  323. final int currentPage;
  324. final bool currentReachedMax;
  325. const ItemInfinityWidget(
  326. {Key key,
  327. @required this.currentItems,
  328. @required this.item,
  329. @required this.currentPage,
  330. @required this.currentReachedMax})
  331. : super(key: key);
  332. @override
  333. Widget build(BuildContext context) {
  334. return GestureDetector(
  335. child: Card(
  336. child: ListTile(
  337. title: Text(item.activityTypeDescription ?? ''),
  338. subtitle: Text(item.executeDate.format_DDMMYY_HHmm()),
  339. trailing: Text(item.id.toString()),
  340. ),
  341. ),
  342. onTap: () {
  343. if (item.activityTypeName == "ACTIVE_TYPE_NURSERY") {
  344. Get.to(EditActionNurseryScreen(
  345. cropId: item.cropId,
  346. activityId: item.id,
  347. isEdit: true,
  348. )).then((value) {
  349. if (value != null) {
  350. try {
  351. //TODO: refresh when edit activity
  352. // BlocProvider.of<PlotDetailBloc>(context)
  353. // .add(OnRefresh(cropId: item.cropId));
  354. // var updatedItem = Activities.fromJson(value);
  355. // List<Activities> updatedItems = new List<Activities>();
  356. // currentItems.forEach((e) {
  357. // if (e.id == updatedItem.id) {
  358. // e.executeDate = updatedItem.executeDate;
  359. // } else {
  360. // //
  361. // }
  362. // updatedItems.add(Activities.clone(e));
  363. // });
  364. // BlocProvider.of<PlotDetailBloc>(context).add(
  365. // OnUpdate<Activities>(
  366. // currentItems: updatedItems,
  367. // currentPage: currentPage,
  368. // hasReachedMax: currentReachedMax));
  369. } catch (e) {
  370. print(e.toString());
  371. }
  372. }
  373. });
  374. } else if (item.activityTypeName == "ACTIVE_TYPE_STATUS_CROP") {
  375. Get.to(EditActionCropStatusScreen(
  376. cropId: item.cropId,
  377. activityId: item.id,
  378. isEdit: true,
  379. ));
  380. } else if (item.activityTypeName == "ACTIVE_TYPE_UPDATE_ENV") {
  381. Get.to(EditActionEnvironmentUpdate(
  382. cropId: item.cropId,
  383. activityId: item.id,
  384. isEdit: true,
  385. ));
  386. } else if (item.activityTypeName ==
  387. "ACTIVE_TYPE_PESTS_INVESTIGATION") {
  388. Get.to(EditActionDiseaseScreen(
  389. cropId: item.cropId,
  390. activityId: item.id,
  391. isEdit: true,
  392. ));
  393. } else if (item.activityTypeName == "ACTIVE_TYPE_USE_WATER") {
  394. Get.to(EditActionUseWaterScreen(
  395. cropId: item.cropId,
  396. activityId: item.id,
  397. isEdit: true,
  398. ));
  399. } else if (item.activityTypeName == "ACTIVE_TYPE_HARVEST") {
  400. Get.to(EditActionHarvestScreen(
  401. cropId: item.cropId,
  402. activityId: item.id,
  403. isEdit: true,
  404. ));
  405. } else if (item.activityTypeName == "ACTIVE_TYPE_PACKING") {
  406. Get.to(EditActionPackingScreen(
  407. cropId: item.cropId,
  408. activityId: item.id,
  409. isEdit: true,
  410. ));
  411. } else if (item.activityTypeName == "ACTIVE_TYPE_SELL") {
  412. Get.to(EditActionSellScreen(
  413. cropId: item.cropId,
  414. activityId: item.id,
  415. isEdit: true,
  416. ));
  417. } else if (item.activityTypeName == "ACTIVE_TYPE_END") {
  418. Get.to(EditActionEndScreen(
  419. cropId: item.cropId,
  420. activityId: item.id,
  421. isEdit: true,
  422. ));
  423. }
  424. });
  425. }
  426. }
  427. class ActionType {
  428. Widget addScreen;
  429. Widget listScreen;
  430. String actionName;
  431. ActionType(String actionName, Widget addScreen, Widget listScreen) {
  432. this.actionName = actionName;
  433. this.addScreen = addScreen;
  434. this.listScreen = listScreen;
  435. }
  436. }
  437. class ChangeToRefreshLists extends GetxController {
  438. List<Activities> currentItems;
  439. int currentPage;
  440. bool currentReachedMax;
  441. void initValue() {
  442. currentItems = List<Activities>();
  443. currentPage = 0;
  444. currentReachedMax = true;
  445. update();
  446. }
  447. void updateValue(List<Activities> updateItems, int page, bool reachedMax) {
  448. currentItems = updateItems;
  449. currentPage = page;
  450. currentReachedMax = reachedMax;
  451. update();
  452. }
  453. }