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.

340 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. notiBloc: widget.notiBloc,
  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. final NotiBloc notiBloc;
  225. const ItemInfinityWidget(
  226. {Key key,
  227. @required this.unread,
  228. @required this.read,
  229. @required this.currentItems,
  230. @required this.item,
  231. @required this.currentPage,
  232. @required this.currentReachedMax,
  233. @required this.notiBloc})
  234. : super(key: key);
  235. @override
  236. Widget build(BuildContext context) {
  237. return GestureDetector(
  238. child: Card(
  239. margin: EdgeInsets.all(4.0),
  240. child: ListTile(
  241. title: Text(item.subject),
  242. subtitle: Column(
  243. crossAxisAlignment: CrossAxisAlignment.start,
  244. children: <Widget>[
  245. Text(item.message),
  246. Text(
  247. item.sendDate.format_DDMMYY_HHmm(),
  248. style: TextStyle(
  249. color: item.isRead == 1 ? Colors.grey : Colors.blue),
  250. ),
  251. ],
  252. ),
  253. leading: Icon(
  254. Icons.notifications_active,
  255. color: item.isRead == 1 ? Colors.grey : Colors.blue,
  256. ))),
  257. onTap: () {
  258. if (item.contents == "ENV_UPDATE") {
  259. Navigator.push(
  260. context,
  261. MaterialPageRoute(
  262. builder: (BuildContext context) => PlotDetailScreen(
  263. cropId: item.tbCropId,
  264. cropType: item.type,
  265. ))).then((value) {
  266. if (item.isRead == 0) {
  267. _updateReadNotification(
  268. context: context,
  269. unread: unread,
  270. read: read,
  271. item: item,
  272. currentItems: currentItems,
  273. currentPage: currentPage,
  274. currentReachedMax: currentReachedMax);
  275. }
  276. });
  277. } else if (item.contents == "PIC_UPDATE") {
  278. Navigator.push(
  279. context,
  280. MaterialPageRoute(
  281. builder: (BuildContext context) => PlotInformationScreen(
  282. cropId: item.tbCropId,
  283. ))).then((value) {
  284. if (item.isRead == 0) {
  285. _updateReadNotification(
  286. context: context,
  287. unread: unread,
  288. read: read,
  289. item: item,
  290. currentItems: currentItems,
  291. currentPage: currentPage,
  292. currentReachedMax: currentReachedMax);
  293. }
  294. });
  295. } else {}
  296. });
  297. }
  298. _updateReadNotification(
  299. {BuildContext context,
  300. int unread,
  301. int read,
  302. NotificationDTO item,
  303. List<NotificationDTO> currentItems,
  304. int currentPage,
  305. bool currentReachedMax}) {
  306. List<NotificationDTO> updatedItems = new List<NotificationDTO>();
  307. currentItems.forEach((e) {
  308. if (e.id == item.id) {
  309. e.isRead = 1;
  310. } else {}
  311. updatedItems.add(NotificationDTO.clone(e));
  312. });
  313. notiBloc.add(OnUpdate<NotificationDTO>(
  314. unread: unread - 1,
  315. read: read + 1,
  316. currentItemId: item.id,
  317. currentItems: updatedItems,
  318. currentPage: currentPage,
  319. hasReachedMax: currentReachedMax));
  320. }
  321. }