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.

324 lines
12KB

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