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.

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