import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/utils/app_toast.dart'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/repositories/notification_repository.dart'; import 'package:tm_app/data/services/model/notification__response/notification_response_model.dart'; import 'package:tm_app/view_models/home_view_model.dart'; import 'package:tm_app/views/notification/strings/notification_strings.dart'; class NotificationViewModel with ChangeNotifier { final NotificationsRepository _repository; NotificationViewModel({required NotificationsRepository repositoryViewModel}) : _repository = repositoryViewModel { WidgetsBinding.instance.addPostFrameCallback((_) { init(); }); } void init() async { clearData(); await getNotifications(); await getUnreadNotifications(); await getImportantNotifications(); } void clearData() { allNotificationResponse = null; unreadNotificationResponse = null; importantNotificationResponse = null; _errorMessage = null; currentPageAll = 1; totalPagesAll = 0; currentPageUnread = 1; totalPagesUnread = 0; currentPageImportant = 1; totalPagesImportant = 0; notifyListeners(); } static const int _pageSize = 10; String? _errorMessage; String? get errorMessage => _errorMessage; // All NotificationResponseModel? allNotificationResponse; bool isLoadingAll = false; bool isMoreLoadingAll = false; bool hasMoreAll = true; int currentPageAll = 1; int totalPagesAll = 0; // Unread NotificationResponseModel? unreadNotificationResponse; bool isLoadingUnread = false; bool isMoreLoadingUnread = false; bool hasMoreUnread = true; int currentPageUnread = 1; int totalPagesUnread = 0; // Important NotificationResponseModel? importantNotificationResponse; bool isLoadingImportant = false; bool isMoreLoadingImportant = false; bool hasMoreImportant = true; int currentPageImportant = 1; int totalPagesImportant = 0; Future getNotifications({ int page = 1, bool isPagination = false, }) async { if (isPagination) { isMoreLoadingAll = true; } else { isLoadingAll = true; } notifyListeners(); final int offset = (page - 1) * _pageSize; final result = await _repository.getNotifications( limit: _pageSize, offset: offset, ); switch (result) { case Ok(): final data = result.value; if (isPagination && allNotificationResponse != null) { final old = allNotificationResponse?.data ?? []; final fresh = data.data ?? []; allNotificationResponse = data.copyWith(data: [...old, ...fresh]); } else { allNotificationResponse = data; } _updateImportantFromAll(); currentPageAll = page; totalPagesAll = data.meta?.pages ?? 1; hasMoreAll = (data.data?.length ?? 0) >= _pageSize; break; case Error(): _errorMessage = result.error.toString(); break; } isLoadingAll = false; isMoreLoadingAll = false; notifyListeners(); } Future getUnreadNotifications({ int page = 1, bool isPagination = false, }) async { if (isPagination) { isMoreLoadingUnread = true; } else { isLoadingUnread = true; } notifyListeners(); final int offset = (page - 1) * _pageSize; final result = await _repository.getUnreadNotifications( limit: _pageSize, offset: offset, ); switch (result) { case Ok(): final data = result.value; if (isPagination && unreadNotificationResponse != null) { final old = unreadNotificationResponse?.data ?? []; final fresh = data.data ?? []; unreadNotificationResponse = data.copyWith(data: [...old, ...fresh]); } else { unreadNotificationResponse = data; } currentPageUnread = page; totalPagesUnread = data.meta?.pages ?? 1; hasMoreUnread = (data.data?.length ?? 0) >= _pageSize; break; case Error(): _errorMessage = result.error.toString(); break; } isLoadingUnread = false; isMoreLoadingUnread = false; notifyListeners(); } Future getImportantNotifications({ int page = 1, bool isPagination = false, }) async { if (isPagination) { isMoreLoadingImportant = true; } else { isLoadingImportant = true; } notifyListeners(); final int offset = (page - 1) * _pageSize; final result = await _repository.getUnreadNotifications( limit: _pageSize, offset: offset, ); switch (result) { case Ok(): final data = result.value; if (isPagination && importantNotificationResponse != null) { final old = importantNotificationResponse?.data ?? []; final fresh = data.data ?? []; importantNotificationResponse = data.copyWith( data: [...old, ...fresh], ); } else { importantNotificationResponse = data; } currentPageImportant = page; totalPagesImportant = data.meta?.pages ?? 1; hasMoreImportant = (data.data?.length ?? 0) >= _pageSize; break; case Error(): _errorMessage = result.error.toString(); _updateImportantFromAll(); break; } isLoadingImportant = false; isMoreLoadingImportant = false; notifyListeners(); } void _updateImportantFromAll() { final all = allNotificationResponse?.data ?? []; final filtered = (all.where((n) { final p = n.priority ?? ''; return p.toLowerCase() == 'important'; }).toList()); if (allNotificationResponse != null) { importantNotificationResponse = allNotificationResponse!.copyWith( data: filtered, ); } else { importantNotificationResponse = null; } } Future jumpToPageAll(int page) async { if (totalPagesAll == 0 || page < 1 || page > totalPagesAll) { return; } await getNotifications(page: page); } Future jumpToPageUnread(int page) async { if (totalPagesUnread == 0 || page < 1 || page > totalPagesUnread) { return; } await getUnreadNotifications(page: page); } Future jumpToPageImportant(int page) async { if (totalPagesImportant == 0 || page < 1 || page > totalPagesImportant) { return; } await getImportantNotifications(page: page); } Future markAllAsRead(BuildContext context) async { isLoadingAll = true; _errorMessage = null; notifyListeners(); final result = await _repository.markAllAsRead(); if (!context.mounted) { return; } switch (result) { case Ok>(): final response = result.value; final success = response['success'] as bool? ?? false; final message = response['message'] as String? ?? NotificationStrings.unknownResponse; if (success) { if (allNotificationResponse?.data != null) { final updatedNotifications = allNotificationResponse!.data! .map((n) => n.copyWith(seen: true)) .toList(); allNotificationResponse = allNotificationResponse!.copyWith( data: updatedNotifications, ); unreadNotificationResponse = unreadNotificationResponse?.copyWith( data: [], ); if (importantNotificationResponse?.data != null) { final updatedImportant = importantNotificationResponse!.data! .map((n) => n.copyWith(seen: true)) .toList(); importantNotificationResponse = importantNotificationResponse! .copyWith(data: updatedImportant); } } if (context.mounted) { AppToast.success( context, NotificationStrings.allNotificationMarkedAsRead, ); } final homeViewModel = context.read(); homeViewModel.serUnreadNotificationFalse(); } else { _errorMessage = message; if (context.mounted) { AppToast.error(context, message); } } break; case Error>(): _errorMessage = result.error.toString(); if (context.mounted) { AppToast.error(context, _errorMessage!); } break; } isLoadingAll = false; notifyListeners(); } String timeAgo(String dateTimeString) { final createdAt = DateTime.parse(dateTimeString); final now = DateTime.now(); final difference = now.difference(createdAt); if (difference.inMinutes < 1) { return NotificationStrings.now; } else if (difference.inMinutes < 60) { return '${difference.inMinutes} ${NotificationStrings.min} '; } else if (difference.inHours < 24) { return '${difference.inHours} ${NotificationStrings.hour} '; } else if (difference.inDays == 1) { return NotificationStrings.yesterday; } else { return '${difference.inDays} ${NotificationStrings.daysAgo}'; } } }