337 lines
9.4 KiB
Dart
337 lines
9.4 KiB
Dart
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<void> 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<NotificationResponseModel>():
|
|
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<NotificationResponseModel>():
|
|
_errorMessage = result.error.toString();
|
|
break;
|
|
}
|
|
|
|
isLoadingAll = false;
|
|
isMoreLoadingAll = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> 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<NotificationResponseModel>():
|
|
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<NotificationResponseModel>():
|
|
_errorMessage = result.error.toString();
|
|
break;
|
|
}
|
|
|
|
isLoadingUnread = false;
|
|
isMoreLoadingUnread = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> 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<NotificationResponseModel>():
|
|
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<NotificationResponseModel>():
|
|
_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<void> jumpToPageAll(int page) async {
|
|
if (totalPagesAll == 0 || page < 1 || page > totalPagesAll) {
|
|
return;
|
|
}
|
|
await getNotifications(page: page);
|
|
}
|
|
|
|
Future<void> jumpToPageUnread(int page) async {
|
|
if (totalPagesUnread == 0 || page < 1 || page > totalPagesUnread) {
|
|
return;
|
|
}
|
|
await getUnreadNotifications(page: page);
|
|
}
|
|
|
|
Future<void> jumpToPageImportant(int page) async {
|
|
if (totalPagesImportant == 0 || page < 1 || page > totalPagesImportant) {
|
|
return;
|
|
}
|
|
await getImportantNotifications(page: page);
|
|
}
|
|
|
|
Future<void> markAllAsRead(BuildContext context) async {
|
|
isLoadingAll = true;
|
|
_errorMessage = null;
|
|
notifyListeners();
|
|
|
|
final result = await _repository.markAllAsRead();
|
|
|
|
if (!context.mounted) {
|
|
return;
|
|
}
|
|
|
|
switch (result) {
|
|
case Ok<Map<String, dynamic>>():
|
|
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>();
|
|
homeViewModel.serUnreadNotificationFalse();
|
|
} else {
|
|
_errorMessage = message;
|
|
if (context.mounted) {
|
|
AppToast.error(context, message);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Error<Map<String, dynamic>>():
|
|
_errorMessage = result.error.toString();
|
|
if (context.mounted) {
|
|
AppToast.error(context, _errorMessage!);
|
|
}
|
|
break;
|
|
}
|
|
|
|
isLoadingAll = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
String timeAgo(timestamp) {
|
|
final int ts = int.tryParse(timestamp.toString()) ?? 0;
|
|
final createdAt = DateTime.fromMillisecondsSinceEpoch(ts * 1000).toLocal();
|
|
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}';
|
|
}
|
|
}
|
|
}
|