import 'dart:developer'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:onufitness/constants/api_enum_constant.dart'; import 'package:onufitness/models/notification/get_all_notification_response_model.dart'; import 'package:onufitness/services/api_services/base_api_services.dart'; class NotificationController extends GetxController { // Observables var notificationResponse = Rxn(); var isLoading = true.obs; var isLoadingMore = false.obs; var errorMessage = RxnString(); var hasReachedEnd = false.obs; // Pagination variables var currentPage = 1.obs; static const int pageSize = 20; var allNotifications = [].obs; // Scroll controller for pagination final ScrollController scrollController = ScrollController(); @override void onInit() { super.onInit(); _setupScrollListener(); fetchNotifications(isRefresh: true); } @override void onClose() { scrollController.dispose(); super.onClose(); } void _setupScrollListener() { scrollController.addListener(() { if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 200) { if (!isLoadingMore.value && !hasReachedEnd.value) { loadMore(); } } }); } // Getters List get notifications => allNotifications; int get totalUnseenCount => notificationResponse.value?.data?.totalUnseenCount ?? 0; bool get hasUnreadNotifications => totalUnseenCount > 0; //fetch Notifications API Call ................................................................................ Future fetchNotifications({bool isRefresh = false}) async { try { if (isRefresh) { isLoading.value = true; currentPage.value = 1; hasReachedEnd.value = false; allNotifications.clear(); } errorMessage.value = null; final response = await ApiBase.getRequest( extendedURL: "/api/Notifications/get-notifications-by-userID?PageNumber=${currentPage.value}&PageSize=$pageSize", ); if (response.statusCode == 200) { final responseModel = getAllNotificationResponseModelFromJson( response.body, ); notificationResponse.value = responseModel; if (responseModel.data?.items != null) { if (isRefresh) { allNotifications.value = responseModel.data!.items!; } else { allNotifications.addAll(responseModel.data!.items!); } // Check if we've reached the end if (responseModel.data!.items!.length < pageSize) { hasReachedEnd.value = true; } } else { hasReachedEnd.value = true; } } else { errorMessage.value = 'Failed to load notifications'; } } catch (e) { errorMessage.value = 'Error: $e'; } finally { isLoading.value = false; isLoadingMore.value = false; } } //.............................................................................................................. //.............................................................................................................. Future loadMore() async { if (hasReachedEnd.value || isLoadingMore.value) return; isLoadingMore.value = true; currentPage.value++; await fetchNotifications(isRefresh: false); } Future refreshNotifications() async { await fetchNotifications(isRefresh: true); } Future markNotificationAsRead(int notificationId) async { log("Entered in markNotificationAsRead"); try { final response = await ApiBase.patchRequest( extendedURL: "/api/Notifications/update-notification/$notificationId", ); log(response.statusCode.toString()); log(response.body.toString()); if (response.statusCode == 200) { // Update local state final itemIndex = allNotifications.indexWhere( (item) => item.notificationId == notificationId, ); if (itemIndex != -1) { allNotifications[itemIndex].isSeen = true; // Update unseen count if (notificationResponse.value?.data != null) { notificationResponse.value!.data!.totalUnseenCount = (notificationResponse.value!.data!.totalUnseenCount ?? 1) - 1; } // Trigger reactive update allNotifications.refresh(); notificationResponse.refresh(); } } } catch (e) { log("Catch : Failed to Mark Read notification"); } } Future markAllAsRead() async { log("markAllAsRead"); try { final response = await ApiBase.patchRequest( extendedURL: "/api/Notifications/mark-all-as-read", ); log(response.statusCode.toString()); log(response.body.toString()); if (response.statusCode == 200) { // Update local state for (var item in allNotifications) { item.isSeen = true; } // Update unseen count if (notificationResponse.value?.data != null) { notificationResponse.value!.data!.totalUnseenCount = 0; } allNotifications.refresh(); notificationResponse.refresh(); } } catch (e) { log("Catch : Failed to Mark all Read notification"); } } // Utility Methods IconData getNotificationIcon(int? notificationType) { switch (notificationType) { case ApiEnum.Goal: return Icons.fitness_center; case ApiEnum.Challenge: return Icons.event; case ApiEnum.ConnectionRequest: return Icons.people; case ApiEnum.Post: return Icons.image; case ApiEnum.RequestAccepted: return Icons.person; case ApiEnum.CoachRequest: return Icons.notifications; case ApiEnum.ReportPost: return Icons.report; case ApiEnum.ChallengeCompleted: return Icons.event; case ApiEnum.GoalCompleted: return Icons.fitness_center; default: return Icons.notifications; } } Color getNotificationColor(int? notificationType) { switch (notificationType) { case ApiEnum.Goal: return Colors.blue; case ApiEnum.Challenge: return Colors.orange; case ApiEnum.ConnectionRequest: return Colors.green; case ApiEnum.Post: return Colors.red; case ApiEnum.RequestAccepted: return Colors.purple; case ApiEnum.CoachRequest: return Colors.brown; case ApiEnum.ReportPost: return Colors.grey; case ApiEnum.ChallengeCompleted: return Colors.purpleAccent; case ApiEnum.GoalCompleted: return Colors.deepPurple; default: return Colors.grey; } } }