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.

335 lines
11KB

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