Merge pull request 'mark single notification as read' (#186) from seen_notification into main
Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/186
This commit is contained in:
@@ -159,8 +159,10 @@ List<SingleChildWidget> get viewModels {
|
|||||||
),
|
),
|
||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create:
|
create:
|
||||||
(context) =>
|
(context) => NotificationViewModel(
|
||||||
NotificationViewModel(repositoryViewModel: context.read()),
|
repositoryViewModel: context.read(),
|
||||||
|
homeViewModel: context.read(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,4 +39,10 @@ class NotificationsRepository {
|
|||||||
offset: offset,
|
offset: offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Result<NotificationResponseModel>> markAsRead({
|
||||||
|
required String notificationId,
|
||||||
|
}) {
|
||||||
|
return _notificationsService.markAsRead(notificationId: notificationId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,20 @@ class NotificationApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const String markAllAsRead = '/api/v1/notifications/mark';
|
static const String markAllAsRead = '/api/v1/notifications/mark';
|
||||||
static const String markAsRead = '/api/v1/notifications/mark-as-read';
|
static const String markAsRead = '/api/v1/notifications/mark';
|
||||||
|
|
||||||
static const String unreadNotifications = '/api/v1/notifications?seen=false';
|
static const String unreadNotifications = '/api/v1/notifications?seen=false';
|
||||||
static String getUnreadNotifications({required int limit, required int offset}) {
|
static String getUnreadNotifications({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
}) {
|
||||||
return '/api/v1/notifications?seen=false&limit=$limit&offset=$offset';
|
return '/api/v1/notifications?seen=false&limit=$limit&offset=$offset';
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getImportantNotifications({required int limit, required int offset}) {
|
static String getImportantNotifications({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
}) {
|
||||||
return '/api/v1/notifications?priority=important&limit=$limit&offset=$offset';
|
return '/api/v1/notifications?priority=important&limit=$limit&offset=$offset';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// notification_service.dart
|
// notification_service.dart
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
import 'package:tm_app/data/services/api/notification_api.dart';
|
import 'package:tm_app/data/services/api/notification_api.dart';
|
||||||
import 'package:tm_app/data/services/model/notification__response/notification_response_model.dart';
|
import 'package:tm_app/data/services/model/notification__response/notification_response_model.dart';
|
||||||
|
|
||||||
import '../../core/network/network_manager.dart';
|
import '../../core/network/network_manager.dart';
|
||||||
|
|
||||||
class NotificationsService {
|
class NotificationsService {
|
||||||
@@ -34,13 +34,11 @@ class NotificationsService {
|
|||||||
Future<Result<NotificationResponseModel>> markAsRead({
|
Future<Result<NotificationResponseModel>> markAsRead({
|
||||||
required String notificationId,
|
required String notificationId,
|
||||||
}) async {
|
}) async {
|
||||||
final data = jsonEncode({'notification_id': notificationId});
|
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
NotificationApi.markAsRead,
|
'${NotificationApi.markAsRead}/$notificationId',
|
||||||
method: 'POST',
|
method: 'GET',
|
||||||
(json) => NotificationResponseModel.fromJson(json),
|
(json) => NotificationResponseModel.fromJson(json),
|
||||||
data: data,
|
);
|
||||||
);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// notification_view_model.dart
|
// notification_view_model.dart
|
||||||
import 'package:flutter/material.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/app_toast.dart';
|
||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
import 'package:tm_app/data/repositories/notification_repository.dart';
|
import 'package:tm_app/data/repositories/notification_repository.dart';
|
||||||
@@ -10,9 +9,13 @@ import 'package:tm_app/views/notification/strings/notification_strings.dart';
|
|||||||
|
|
||||||
class NotificationViewModel with ChangeNotifier {
|
class NotificationViewModel with ChangeNotifier {
|
||||||
final NotificationsRepository _repository;
|
final NotificationsRepository _repository;
|
||||||
|
final HomeViewModel _homeViewModel;
|
||||||
|
|
||||||
NotificationViewModel({required NotificationsRepository repositoryViewModel})
|
NotificationViewModel({
|
||||||
: _repository = repositoryViewModel {
|
required NotificationsRepository repositoryViewModel,
|
||||||
|
required HomeViewModel homeViewModel,
|
||||||
|
}) : _repository = repositoryViewModel,
|
||||||
|
_homeViewModel = homeViewModel {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
init();
|
init();
|
||||||
});
|
});
|
||||||
@@ -214,10 +217,10 @@ class NotificationViewModel with ChangeNotifier {
|
|||||||
void _updateImportantFromAll() {
|
void _updateImportantFromAll() {
|
||||||
final all = allNotificationResponse?.data ?? [];
|
final all = allNotificationResponse?.data ?? [];
|
||||||
final filtered =
|
final filtered =
|
||||||
(all.where((n) {
|
all.where((n) {
|
||||||
final p = n.priority ?? '';
|
final p = n.priority ?? '';
|
||||||
return p.toLowerCase() == 'important';
|
return p.toLowerCase() == 'important';
|
||||||
}).toList());
|
}).toList();
|
||||||
|
|
||||||
if (allNotificationResponse != null) {
|
if (allNotificationResponse != null) {
|
||||||
importantNotificationResponse = allNotificationResponse!.copyWith(
|
importantNotificationResponse = allNotificationResponse!.copyWith(
|
||||||
@@ -294,6 +297,9 @@ class NotificationViewModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure unread list is empty after marking all as read
|
||||||
|
_checkAndUpdateUnreadState();
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
AppToast.success(
|
AppToast.success(
|
||||||
context,
|
context,
|
||||||
@@ -341,12 +347,100 @@ class NotificationViewModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setNotificationFalse(BuildContext context) {
|
void setNotificationFalse(BuildContext context) {
|
||||||
final homeViewModel = context.read<HomeViewModel>();
|
_homeViewModel.setUnreadNotificationFalse();
|
||||||
homeViewModel.setUnreadNotificationFalse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkNotifications(BuildContext context) {
|
void _checkAndUpdateUnreadState() {
|
||||||
final homeViewModel = context.read<HomeViewModel>();
|
// Check if all notifications are read
|
||||||
homeViewModel.checkUnreadNotifications();
|
final allNotifications = allNotificationResponse?.data ?? [];
|
||||||
|
final hasUnreadNotifications = allNotifications.any((n) => n.seen != true);
|
||||||
|
|
||||||
|
if (!hasUnreadNotifications) {
|
||||||
|
// Clear unread list if all notifications are read
|
||||||
|
unreadNotificationResponse = unreadNotificationResponse?.copyWith(
|
||||||
|
data: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get unreadCount {
|
||||||
|
return unreadNotificationResponse?.data?.length ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get importantCount {
|
||||||
|
return importantNotificationResponse?.data?.length ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasUnreadNotifications {
|
||||||
|
return unreadCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasImportantNotifications {
|
||||||
|
return importantCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkNotifications() {
|
||||||
|
_homeViewModel.checkUnreadNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> markAsRead({required String notificationId}) async {
|
||||||
|
final result = await _repository.markAsRead(notificationId: notificationId);
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case Ok<NotificationResponseModel>():
|
||||||
|
// Find and update only the specific notification that matches the ID
|
||||||
|
final updatedNotifications =
|
||||||
|
allNotificationResponse?.data?.map((n) {
|
||||||
|
if (n.id == notificationId) {
|
||||||
|
return n.copyWith(seen: true);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
if (updatedNotifications != null) {
|
||||||
|
allNotificationResponse = allNotificationResponse!.copyWith(
|
||||||
|
data: updatedNotifications,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update unread list - remove the notification that was marked as read
|
||||||
|
if (unreadNotificationResponse?.data != null) {
|
||||||
|
final updatedUnreadList =
|
||||||
|
unreadNotificationResponse!.data!
|
||||||
|
.where((n) => n.id != notificationId)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
unreadNotificationResponse = unreadNotificationResponse!.copyWith(
|
||||||
|
data: updatedUnreadList,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update important list - mark the notification as seen if it exists
|
||||||
|
if (importantNotificationResponse?.data != null) {
|
||||||
|
final updatedImportantList =
|
||||||
|
importantNotificationResponse!.data!.map((n) {
|
||||||
|
if (n.id == notificationId) {
|
||||||
|
return n.copyWith(seen: true);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
importantNotificationResponse = importantNotificationResponse!
|
||||||
|
.copyWith(data: updatedImportantList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all notifications are now read
|
||||||
|
_checkAndUpdateUnreadState();
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
checkNotifications();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Error<NotificationResponseModel>():
|
||||||
|
_errorMessage = result.error.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ class NotificationCard extends StatelessWidget {
|
|||||||
const Spacer(),
|
const Spacer(),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
viewModel.markAsRead(notificationId: notification.id!);
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@@ -131,11 +132,7 @@ class NotificationCard extends StatelessWidget {
|
|||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).then((value) {
|
);
|
||||||
if (context.mounted) {
|
|
||||||
viewModel.checkNotifications(context);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
Reference in New Issue
Block a user