Merge pull request 'update notification tab data when clicking on navigation bars' (#169) from navigate_notification_update into main

Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/169
This commit is contained in:
a.ghabeli
2025-09-27 10:47:52 +03:30
6 changed files with 139 additions and 90 deletions
@@ -8,6 +8,8 @@ import 'package:tm_app/view_models/home_view_model.dart';
import 'package:tm_app/view_models/tenders_view_model.dart';
import 'package:tm_app/views/shared/responsive_builder.dart';
import '../../../view_models/notification_view_model.dart';
class AppShellScreen extends StatelessWidget {
const AppShellScreen({required this.navigationShell, super.key});
@@ -32,6 +34,9 @@ class AppShellScreen extends StatelessWidget {
if (index == 1) {
context.read<TendersViewModel>().init(context);
}
if (index == 3) {
context.read<NotificationViewModel>().init();
}
});
}
+80 -40
View File
@@ -5,19 +5,38 @@ 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/views/notification/strings/notification_strings.dart';
class NotificationViewModel with ChangeNotifier {
final NotificationsRepository _repository;
NotificationViewModel({required NotificationsRepository repositoryViewModel})
: _repository = repositoryViewModel {
: _repository = repositoryViewModel {
WidgetsBinding.instance.addPostFrameCallback((_) {
getNotifications();
getUnreadNotifications();
getImportantNotifications();
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;
@@ -47,8 +66,10 @@ class NotificationViewModel with ChangeNotifier {
int currentPageImportant = 1;
int totalPagesImportant = 0;
Future<void> getNotifications({int page = 1, bool isPagination = false}) async {
Future<void> getNotifications({
int page = 1,
bool isPagination = false,
}) async {
if (isPagination) {
isMoreLoadingAll = true;
} else {
@@ -57,7 +78,10 @@ class NotificationViewModel with ChangeNotifier {
notifyListeners();
final int offset = (page - 1) * _pageSize;
final result = await _repository.getNotifications(limit: _pageSize, offset: offset);
final result = await _repository.getNotifications(
limit: _pageSize,
offset: offset,
);
switch (result) {
case Ok<NotificationResponseModel>():
@@ -66,9 +90,7 @@ class NotificationViewModel with ChangeNotifier {
final old = allNotificationResponse?.data?.notifications ?? [];
final fresh = data.data?.notifications ?? [];
allNotificationResponse = data.copyWith(
data: data.data?.copyWith(
notifications: [...old, ...fresh],
),
data: data.data?.copyWith(notifications: [...old, ...fresh]),
);
} else {
allNotificationResponse = data;
@@ -91,7 +113,10 @@ class NotificationViewModel with ChangeNotifier {
notifyListeners();
}
Future<void> getUnreadNotifications({int page = 1, bool isPagination = false}) async {
Future<void> getUnreadNotifications({
int page = 1,
bool isPagination = false,
}) async {
if (isPagination) {
isMoreLoadingUnread = true;
} else {
@@ -100,7 +125,10 @@ class NotificationViewModel with ChangeNotifier {
notifyListeners();
final int offset = (page - 1) * _pageSize;
final result = await _repository.getUnreadNotifications(limit: _pageSize, offset: offset);
final result = await _repository.getUnreadNotifications(
limit: _pageSize,
offset: offset,
);
switch (result) {
case Ok<NotificationResponseModel>():
@@ -109,9 +137,7 @@ class NotificationViewModel with ChangeNotifier {
final old = unreadNotificationResponse?.data?.notifications ?? [];
final fresh = data.data?.notifications ?? [];
unreadNotificationResponse = data.copyWith(
data: data.data?.copyWith(
notifications: [...old, ...fresh],
),
data: data.data?.copyWith(notifications: [...old, ...fresh]),
);
} else {
unreadNotificationResponse = data;
@@ -132,7 +158,10 @@ class NotificationViewModel with ChangeNotifier {
notifyListeners();
}
Future<void> getImportantNotifications({int page = 1, bool isPagination = false}) async {
Future<void> getImportantNotifications({
int page = 1,
bool isPagination = false,
}) async {
if (isPagination) {
isMoreLoadingImportant = true;
} else {
@@ -142,7 +171,10 @@ class NotificationViewModel with ChangeNotifier {
final int offset = (page - 1) * _pageSize;
final result = await _repository.getUnreadNotifications(limit: _pageSize, offset: offset);
final result = await _repository.getUnreadNotifications(
limit: _pageSize,
offset: offset,
);
switch (result) {
case Ok<NotificationResponseModel>():
@@ -151,9 +183,7 @@ class NotificationViewModel with ChangeNotifier {
final old = importantNotificationResponse?.data?.notifications ?? [];
final fresh = data.data?.notifications ?? [];
importantNotificationResponse = data.copyWith(
data: data.data?.copyWith(
notifications: [...old, ...fresh],
),
data: data.data?.copyWith(notifications: [...old, ...fresh]),
);
} else {
importantNotificationResponse = data;
@@ -165,7 +195,6 @@ class NotificationViewModel with ChangeNotifier {
break;
case Error<NotificationResponseModel>():
_errorMessage = result.error.toString();
_updateImportantFromAll();
@@ -179,10 +208,11 @@ class NotificationViewModel with ChangeNotifier {
void _updateImportantFromAll() {
final all = allNotificationResponse?.data?.notifications ?? [];
final filtered = (all.where((n) {
final p = n.priority ?? '';
return p.toLowerCase() == 'important';
}).toList());
final filtered =
(all.where((n) {
final p = n.priority ?? '';
return p.toLowerCase() == 'important';
}).toList());
if (allNotificationResponse != null) {
importantNotificationResponse = allNotificationResponse!.copyWith(
@@ -229,13 +259,16 @@ class NotificationViewModel with ChangeNotifier {
case Ok<Map<String, dynamic>>():
final response = result.value;
final success = response['success'] as bool? ?? false;
final message = response['message'] as String? ?? NotificationStrings.unknownResponse;
final message =
response['message'] as String? ??
NotificationStrings.unknownResponse;
if (success) {
if (allNotificationResponse?.data?.notifications != null) {
final updatedNotifications = allNotificationResponse!.data!.notifications!
.map((n) => n.copyWith(seen: true))
.toList();
final updatedNotifications =
allNotificationResponse!.data!.notifications!
.map((n) => n.copyWith(seen: true))
.toList();
allNotificationResponse = allNotificationResponse!.copyWith(
data: allNotificationResponse!.data!.copyWith(
@@ -244,24 +277,31 @@ class NotificationViewModel with ChangeNotifier {
);
unreadNotificationResponse = unreadNotificationResponse?.copyWith(
data: unreadNotificationResponse?.data?.copyWith(notifications: []),
data: unreadNotificationResponse?.data?.copyWith(
notifications: [],
),
);
if (importantNotificationResponse?.data?.notifications != null) {
final updatedImportant = importantNotificationResponse!.data!.notifications!
.map((n) => n.copyWith(seen: true))
.toList();
final updatedImportant =
importantNotificationResponse!.data!.notifications!
.map((n) => n.copyWith(seen: true))
.toList();
importantNotificationResponse = importantNotificationResponse!.copyWith(
data: importantNotificationResponse!.data!.copyWith(
notifications: updatedImportant,
),
);
importantNotificationResponse = importantNotificationResponse!
.copyWith(
data: importantNotificationResponse!.data!.copyWith(
notifications: updatedImportant,
),
);
}
}
if (context.mounted) {
AppToast.success(context, NotificationStrings.allNotificationMarkedAsRead);
AppToast.success(
context,
NotificationStrings.allNotificationMarkedAsRead,
);
}
} else {
_errorMessage = message;
+2
View File
@@ -126,6 +126,8 @@ class TendersViewModel with ChangeNotifier {
}
void init(BuildContext context) async {
_isLoading = true;
notifyListeners();
clearAll();
await getTenders(context: context);
}
@@ -53,7 +53,7 @@ class NotificationCard extends StatelessWidget {
Visibility(
visible:
notification.priority ==
NotificationStrings.important,
NotificationStrings.important.toLowerCase(),
child: Container(
width: 86.0.w(),
height: 24.0.h(),
+49 -49
View File
@@ -11,6 +11,7 @@ import 'package:tm_app/views/profile/strings/profile_strings.dart';
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
import '../../core/routes/app_routes.dart';
import '../../view_models/notification_view_model.dart';
class DesktopNavigationWidget extends StatelessWidget {
const DesktopNavigationWidget({
@@ -103,7 +104,7 @@ class DesktopNavigationWidget extends StatelessWidget {
context,
() => const NotificationRouteData().go(context),
);
//context.read<notificationViewModel>().getTenders();
context.read<NotificationViewModel>().init();
}
},
iconPath: AssetsManager.notify,
@@ -148,57 +149,56 @@ class DesktopNavigationWidget extends StatelessWidget {
);
}
Widget _navigationItem({
required BuildContext context,
required String text,
required bool isActive,
required VoidCallback onTap,
required String iconPath,
required String activeIconPath,
}) {
final hasUnread = context.watch<HomeViewModel>().hasUnreadNotification;
Widget _navigationItem({
required BuildContext context,
required String text,
required bool isActive,
required VoidCallback onTap,
required String iconPath,
required String activeIconPath,
}) {
final hasUnread = context.watch<HomeViewModel>().hasUnreadNotification;
return InkWell(
onTap: onTap,
child: SizedBox(
width: 115.0,
height: 64,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
clipBehavior: Clip.none,
children: [
SvgPicture.asset(isActive ? activeIconPath : iconPath),
if (text == TendersStrings.notifications && hasUnread)
Positioned(
right: -5,
top: -2,
child: Container(
width: 8,
height: 8,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
return InkWell(
onTap: onTap,
child: SizedBox(
width: 115.0,
height: 64,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
clipBehavior: Clip.none,
children: [
SvgPicture.asset(isActive ? activeIconPath : iconPath),
if (text == TendersStrings.notifications && hasUnread)
Positioned(
right: -5,
top: -2,
child: Container(
width: 8,
height: 8,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
),
),
],
),
const SizedBox(width: 8),
Text(
text,
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color: isActive ? AppColors.primaryColor : AppColors.grey60,
],
),
),
],
const SizedBox(width: 8),
Text(
text,
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color: isActive ? AppColors.primaryColor : AppColors.grey60,
),
),
],
),
),
),
);
}
);
}
}
@@ -12,6 +12,7 @@ import 'package:tm_app/views/profile/strings/profile_strings.dart';
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
import '../../core/routes/app_routes.dart';
import '../../view_models/notification_view_model.dart';
class TabletNavigationWidget extends StatelessWidget {
const TabletNavigationWidget({required this.currentIndex, super.key});
@@ -93,6 +94,7 @@ class TabletNavigationWidget extends StatelessWidget {
context,
() => const NotificationRouteData().go(context),
);
context.read<NotificationViewModel>().init();
}
},
iconPath: AssetsManager.notify,