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.

420 lines
15KB

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