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.

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