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.

338 lines
12KB

  1. import 'package:farm_tpf/custom_model/NotificationDTO.dart';
  2. import 'package:farm_tpf/data/repository/repository.dart';
  3. import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart';
  4. import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart';
  5. import 'package:farm_tpf/presentation/custom_widgets/dash_line_widget.dart';
  6. import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart';
  7. import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart';
  8. import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_information.dart';
  9. import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_parameter.dart';
  10. import 'package:farm_tpf/utils/const_icons.dart';
  11. import 'package:farm_tpf/utils/pref.dart';
  12. import 'package:firebase_messaging/firebase_messaging.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:flutter_bloc/flutter_bloc.dart';
  15. import 'package:farm_tpf/utils/formatter.dart';
  16. import 'package:flutter_svg/svg.dart';
  17. import 'bloc/noti_bloc.dart';
  18. class NotificationScreen extends StatefulWidget {
  19. @override
  20. _NotificationScreenState createState() => _NotificationScreenState();
  21. }
  22. class _NotificationScreenState extends State<NotificationScreen> {
  23. final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  24. var notiBloc = NotiBloc(repository: Repository());
  25. @override
  26. void initState() {
  27. super.initState();
  28. _firebaseMessaging.configure(
  29. onMessage: (Map<String, dynamic> message) async {
  30. print("onMessage: $message");
  31. try {
  32. notiBloc.add(OnRefreshFromNotification());
  33. } catch (e) {
  34. print(e);
  35. }
  36. });
  37. }
  38. @override
  39. Widget build(BuildContext context) {
  40. return BlocBuilder(
  41. cubit: notiBloc,
  42. builder: (context, state) {
  43. return HoldInfinityWidget(
  44. notiBloc: notiBloc,
  45. );
  46. });
  47. }
  48. }
  49. class HoldInfinityWidget extends StatelessWidget {
  50. final NotiBloc notiBloc;
  51. HoldInfinityWidget({@required this.notiBloc});
  52. final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  53. @override
  54. Widget build(BuildContext context) {
  55. return Scaffold(
  56. key: _scaffoldKey,
  57. backgroundColor: Colors.white,
  58. appBar: AppBarWidget(
  59. isBack: false,
  60. ),
  61. body: BlocBuilder<NotiBloc, NotiState>(
  62. cubit: notiBloc,
  63. builder: (context, state) {
  64. return InfinityView(
  65. notiBloc: notiBloc,
  66. );
  67. },
  68. ));
  69. }
  70. }
  71. class InfinityView extends StatefulWidget {
  72. final NotiBloc notiBloc;
  73. InfinityView({@required this.notiBloc});
  74. @override
  75. _InfinityViewState createState() => _InfinityViewState();
  76. }
  77. class _InfinityViewState extends State<InfinityView> {
  78. final _scrollController = ScrollController();
  79. final _scrollThreshold = 250.0;
  80. List<NotificationDTO> currentItems = new List<NotificationDTO>();
  81. int latestId = 0;
  82. int currentPage = 0;
  83. bool currentHasReachedMax = true;
  84. bool isUpdatingFromApi = true;
  85. var pref = LocalPref();
  86. var token;
  87. Future<Null> getSharedPrefs() async {
  88. _scrollController.addListener(() {
  89. final maxScroll = _scrollController.position.maxScrollExtent;
  90. final currentScroll = _scrollController.position.pixels;
  91. if (maxScroll - currentScroll < _scrollThreshold) {
  92. widget.notiBloc.add(DataFetched());
  93. }
  94. });
  95. token = await pref.getString(DATA_CONST.TOKEN_KEY);
  96. }
  97. @override
  98. void initState() {
  99. getSharedPrefs();
  100. widget.notiBloc.add(DataFetched());
  101. super.initState();
  102. }
  103. @override
  104. Widget build(BuildContext context) {
  105. return BlocBuilder<NotiBloc, NotiState>(
  106. cubit: widget.notiBloc,
  107. builder: (context, state) {
  108. if (state is NotiFailure) {
  109. return Center(child: Text(state.errorString));
  110. } else if (state is NotiSuccess) {
  111. if (state.items.isEmpty) {
  112. return Center(child: Text("Không có thông báo"));
  113. }
  114. currentItems = List<NotificationDTO>.from(state.items);
  115. currentPage = state.page;
  116. currentHasReachedMax = state.hasReachedMax;
  117. return Column(
  118. children: <Widget>[
  119. Container(
  120. padding: EdgeInsets.all(8),
  121. color: Colors.white,
  122. child: Row(
  123. children: [
  124. Expanded(
  125. child: Text(
  126. 'Thông báo',
  127. style: TextStyle(
  128. fontWeight: FontWeight.w500, fontSize: 22),
  129. )),
  130. BlocBuilder<NotiBloc, NotiState>(
  131. cubit: widget.notiBloc,
  132. builder: (context, state) {
  133. if (state is NotiSuccess) {
  134. if (state.items.length > 0) {
  135. return FlatButton(
  136. onPressed: () {
  137. widget.notiBloc.add(
  138. MarkAllNotificationUpdate(status: "1"));
  139. },
  140. child: Text('Đánh dấu đã đọc tất cả',
  141. style: TextStyle(
  142. fontWeight: FontWeight.normal,
  143. fontSize: 14,
  144. color: Colors.blue)));
  145. } else {
  146. return SizedBox();
  147. }
  148. } else {
  149. return SizedBox();
  150. }
  151. },
  152. )
  153. ],
  154. )),
  155. Expanded(
  156. child: RefreshIndicator(
  157. child: ListView.builder(
  158. itemBuilder: (BuildContext context, int index) {
  159. return index >= state.items.length
  160. ? BottomLoader()
  161. : ItemInfinityWidget(
  162. notiBloc: widget.notiBloc,
  163. unread: state.unread,
  164. read: state.read,
  165. currentItems: currentItems,
  166. item: state.items[index],
  167. currentPage: state.page,
  168. currentReachedMax: state.hasReachedMax,
  169. );
  170. },
  171. itemCount: state.hasReachedMax
  172. ? state.items.length
  173. : state.items.length + 1,
  174. controller: _scrollController,
  175. ),
  176. onRefresh: () async {
  177. widget.notiBloc.add(OnRefresh());
  178. }))
  179. ],
  180. );
  181. } else if (state is NotiLoadding) {
  182. return Center(
  183. child: LoadingListPage(),
  184. );
  185. }
  186. return Container();
  187. },
  188. );
  189. }
  190. @override
  191. void dispose() {
  192. _scrollController.dispose();
  193. super.dispose();
  194. }
  195. }
  196. class ItemInfinityWidget extends StatelessWidget {
  197. final int unread;
  198. final int read;
  199. final NotificationDTO item;
  200. final List<NotificationDTO> currentItems;
  201. final int currentPage;
  202. final bool currentReachedMax;
  203. final NotiBloc notiBloc;
  204. const ItemInfinityWidget(
  205. {Key key,
  206. @required this.unread,
  207. @required this.read,
  208. @required this.currentItems,
  209. @required this.item,
  210. @required this.currentPage,
  211. @required this.currentReachedMax,
  212. @required this.notiBloc})
  213. : super(key: key);
  214. @override
  215. Widget build(BuildContext context) {
  216. return Column(
  217. children: [
  218. GestureDetector(
  219. child: Container(
  220. margin: EdgeInsets.all(4.0),
  221. child: Column(
  222. children: [
  223. ListTile(
  224. title: Text(item.subject),
  225. subtitle: Column(
  226. crossAxisAlignment: CrossAxisAlignment.start,
  227. children: <Widget>[
  228. Text(item.message),
  229. Row(children: [
  230. Icon(Icons.access_time,
  231. color: item.isRead == 1
  232. ? Colors.grey
  233. : Colors.blue,
  234. size: 18),
  235. SizedBox(
  236. width: 4,
  237. ),
  238. Text(item.sendDate.format_DDMMYY_HHmm(),
  239. style: TextStyle(
  240. color: item.isRead == 1
  241. ? Colors.grey
  242. : Colors.blue))
  243. ]),
  244. ],
  245. ),
  246. leading: SvgPicture.asset(AppIcons.icNotificationItem)),
  247. ],
  248. )),
  249. onTap: () {
  250. if (item.contents == "ENV_UPDATE") {
  251. Navigator.push(
  252. context,
  253. MaterialPageRoute(
  254. builder: (BuildContext context) => PlotParameterScreen(
  255. cropId: item.tbCropId,
  256. isShowAppbar: true,
  257. ))).then((value) {
  258. if (item.isRead == 0) {
  259. _updateReadNotification(
  260. context: context,
  261. unread: unread,
  262. read: read,
  263. item: item,
  264. currentItems: currentItems,
  265. currentPage: currentPage,
  266. currentReachedMax: currentReachedMax);
  267. }
  268. });
  269. } else if (item.contents == "PIC_UPDATE") {
  270. Navigator.push(
  271. context,
  272. MaterialPageRoute(
  273. builder: (BuildContext context) =>
  274. PlotInformationScreen(
  275. cropId: item.tbCropId,
  276. isShowAppbar: true,
  277. ))).then((value) {
  278. if (item.isRead == 0) {
  279. _updateReadNotification(
  280. context: context,
  281. unread: unread,
  282. read: read,
  283. item: item,
  284. currentItems: currentItems,
  285. currentPage: currentPage,
  286. currentReachedMax: currentReachedMax);
  287. }
  288. });
  289. } else {}
  290. }),
  291. Container(
  292. padding: EdgeInsets.only(left: 16, right: 16),
  293. child: DashLineWidget())
  294. ],
  295. );
  296. }
  297. _updateReadNotification(
  298. {BuildContext context,
  299. int unread,
  300. int read,
  301. NotificationDTO item,
  302. List<NotificationDTO> currentItems,
  303. int currentPage,
  304. bool currentReachedMax}) {
  305. List<NotificationDTO> updatedItems = new List<NotificationDTO>();
  306. currentItems.forEach((e) {
  307. if (e.id == item.id) {
  308. e.isRead = 1;
  309. } else {}
  310. updatedItems.add(NotificationDTO.clone(e));
  311. });
  312. notiBloc.add(OnUpdate<NotificationDTO>(
  313. unread: unread - 1,
  314. read: read + 1,
  315. currentItemId: item.id,
  316. currentItems: updatedItems,
  317. currentPage: currentPage,
  318. hasReachedMax: currentReachedMax));
  319. }
  320. }