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.

511 lines
18KB

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