import 'package:farm_tpf/custom_model/NotificationDTO.dart'; import 'package:farm_tpf/data/repository/repository.dart'; import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; import 'package:farm_tpf/presentation/custom_widgets/dash_line_widget.dart'; import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; import 'package:farm_tpf/presentation/screens/notification/update_count_noti_bloc.dart'; import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; import 'package:farm_tpf/presentation/screens/task/task_detail_page.dart'; import 'package:farm_tpf/utils/NotificationsBloc.dart'; import 'package:farm_tpf/utils/const_icons.dart'; import 'package:farm_tpf/utils/pref.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:farm_tpf/utils/formatter.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import '../actions/sc_action.dart'; import 'bloc/noti_bloc.dart'; class NotificationScreen extends StatefulWidget { @override _NotificationScreenState createState() => _NotificationScreenState(); } class _NotificationScreenState extends State { var notiBloc = NotiBloc(repository: Repository()); final _scrollController = ScrollController(); final _scrollThreshold = 250.0; List currentItems = []; int latestId = 0; int currentPage = 0; bool currentHasReachedMax = true; bool isUpdatingFromApi = true; Stream? _notificationsStream; var pref = LocalPref(); var token; Future getSharedPrefs() async { _scrollController.addListener(() { final maxScroll = _scrollController.position.maxScrollExtent; final currentScroll = _scrollController.position.pixels; if (maxScroll - currentScroll < _scrollThreshold) { notiBloc.add(DataFetched()); } }); token = await pref.getString(DATA_CONST.TOKEN_KEY); } @override void initState() { getSharedPrefs(); notiBloc.add(DataFetched()); _notificationsStream = NotificationsBloc.instance.notificationsStream; _notificationsStream?.listen((notification) { updateCountNotiBloc.getNotifications((data) {}, (err) {}); print('Notification: $notification'); notiBloc.add(OnRefresh()); }); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: BlocBuilder( bloc: notiBloc, builder: (context, state) { if (state is NotiFailure) { return Center(child: Text(state.errorString)); } else if (state is NotiSuccess) { updateCountNotiBloc.getNotifications((data) {}, (err) {}); if (state.items!.isEmpty) { return SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 8, ), Padding( padding: const EdgeInsets.all(8.0), child: Text('Thông báo', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22)), ), Expanded( child: Center(child: Text("Không có thông báo")), ), ], ), ); } currentItems = List.from(state.items!); currentPage = state.page ?? 1; currentHasReachedMax = state.hasReachedMax ?? false; return SafeArea( child: Column( children: [ Container( padding: EdgeInsets.all(8), color: Colors.white, child: Row( children: [ SizedBox( height: 8, ), Expanded( child: Text( 'Thông báo', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22), )), TextButton( onPressed: () { notiBloc.add(MarkAllNotificationUpdate(status: "1")); }, child: Text('Đánh dấu đã đọc tất cả', style: TextStyle(fontWeight: FontWeight.normal, fontSize: 14, color: Colors.blue))) ], )), Expanded( child: RefreshIndicator( child: ListView.builder( physics: AlwaysScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) { return index >= state.items!.length ? BottomLoader() : ItemInfinityWidget( notiBloc: notiBloc, unread: state.unread ?? 0, read: state.read ?? 0, currentItems: currentItems, item: state.items![index], currentPage: state.page ?? 1, currentReachedMax: state.hasReachedMax ?? false, ); }, itemCount: (state.hasReachedMax ?? false) ? state.items?.length : (state.items?.length ?? 0) + 1, controller: _scrollController, ), onRefresh: () async { notiBloc.add(OnRefresh()); })) ], ), ); } else if (state is NotiLoadding) { return Center( child: LoadingListPage(), ); } return Container(); }, ), ); } @override void dispose() { _scrollController.dispose(); super.dispose(); } } class ItemInfinityWidget extends StatelessWidget { final int unread; final int read; final NotificationDTO item; final List currentItems; final int currentPage; final bool currentReachedMax; final NotiBloc notiBloc; const ItemInfinityWidget( {Key? key, required this.unread, required this.read, required this.currentItems, required this.item, required this.currentPage, required this.currentReachedMax, required this.notiBloc}) : super(key: key); @override Widget build(BuildContext context) { var type; try { type = int.parse(item.type ?? '-1'); } catch (_) { type = -1; } return Column( children: [ GestureDetector( child: Container( margin: EdgeInsets.all(4.0), child: Column( children: [ ListTile( title: Text(item.subject ?? ''), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(item.message ?? ''), Row(children: [ Icon(Icons.access_time, color: item.isRead == 1 ? Colors.grey : Colors.blue, size: 18), SizedBox( width: 4, ), Text(item.sendDate?.fromUtcToLocal() ?? '', style: TextStyle(color: item.isRead == 1 ? Colors.grey : Colors.blue)) ]), ], ), leading: SvgPicture.asset(AppIcons.icNotificationItem)), ], )), onTap: () { if (item.contents == "ENV_UPDATE") { Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => PlotDetailScreen( cropType: type, cropId: item.tbCropId ?? -1, initialIndex: 0, ), ), ).then((value) { if (item.isRead == 0) { _updateReadNotification( context: context, unread: unread, read: read, item: item, currentItems: currentItems, currentPage: currentPage, currentReachedMax: currentReachedMax); } }); } else if (item.contents == "PIC_UPDATE") { Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => PlotDetailScreen( cropType: type, cropId: item.tbCropId ?? -1, initialIndex: 1, ))).then((value) { if (item.isRead == 0) { _updateReadNotification( context: context, unread: unread, read: read, item: item, currentItems: currentItems, currentPage: currentPage, currentReachedMax: currentReachedMax); } }); } else if (item.contents == "TODO_LIST_CREATE" || item.contents == 'TODO_LIST_UPDATE') { Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => TaskDetailPage( taskId: item.externalId ?? -1, ), ), ).then((value) { if (item.isRead == 0) { _updateReadNotification( context: context, unread: unread, read: read, item: item, currentItems: currentItems, currentPage: currentPage, currentReachedMax: currentReachedMax); } }); } else if (item.contents == 'ACTIVITY_CREATE' || item.contents == 'ACTIVITY_UPDATE') { Get.to(ActionScreen( isEdit: true, cropId: item.tbCropId ?? -1, activityId: item.externalId ?? -1, title: 'ActionScreen', idAction: item.activityTypeId ?? -1, )); } else {} }), Container(padding: EdgeInsets.only(left: 16, right: 16), child: DashLineWidget()) ], ); } _updateReadNotification( {BuildContext? context, int? unread, int? read, NotificationDTO? item, List? currentItems, int? currentPage, bool? currentReachedMax}) { List updatedItems = []; currentItems?.forEach((e) { if (e.id == (item?.id ?? -1)) { e.isRead = 1; } else {} updatedItems.add(NotificationDTO.clone(e)); }); notiBloc.add(OnUpdate( unread: (unread ?? 1) - 1, read: (read ?? 0) + 1, currentItemId: item?.id ?? -1, currentItems: updatedItems, currentPage: currentPage ?? 1, hasReachedMax: currentReachedMax ?? false, )); } }