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.

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