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.

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