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.

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