Fixed notification pagination for all and unread

This commit is contained in:
llsajjad
2025-09-27 08:54:11 +03:30
parent e432853478
commit 811a1c1385
9 changed files with 371 additions and 189 deletions
+185 -91
View File
@@ -5,6 +5,7 @@ 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/data/services/model/notification__response/notification_response_model.dart';
import 'package:tm_app/views/notification/strings/notification_strings.dart'; import 'package:tm_app/views/notification/strings/notification_strings.dart';
class NotificationViewModel with ChangeNotifier { class NotificationViewModel with ChangeNotifier {
final NotificationsRepository _repository; final NotificationsRepository _repository;
@@ -13,72 +14,71 @@ class NotificationViewModel with ChangeNotifier {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
getNotifications(); getNotifications();
getUnreadNotifications(); getUnreadNotifications();
getImportantNotifications();
}); });
} }
bool _isLoading = false;
String? _errorMessage;
NotificationResponseModel? _notificationResponseModel;
int currentPage = 1;
static const int _pageSize = 10; static const int _pageSize = 10;
int _totalPages = 0;
bool _hasMoreData = true;
bool get isLoading => _isLoading; String? _errorMessage;
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
NotificationResponseModel? get notificationResponse =>
_notificationResponseModel;
bool get hasMoreData => _hasMoreData;
int get totalPages => _totalPages;
NotificationResponseModel? _unreadNotificationResponse; // All
bool _isUnreadLoading = false; NotificationResponseModel? allNotificationResponse;
bool isLoadingAll = false;
bool isMoreLoadingAll = false;
bool hasMoreAll = true;
int currentPageAll = 1;
int totalPagesAll = 0;
NotificationResponseModel? get unreadNotificationResponse => // Unread
_unreadNotificationResponse; NotificationResponseModel? unreadNotificationResponse;
bool get isUnreadLoading => _isUnreadLoading; bool isLoadingUnread = false;
bool isMoreLoadingUnread = false;
bool hasMoreUnread = true;
int currentPageUnread = 1;
int totalPagesUnread = 0;
bool _isMoreLoading = false; // Important
bool get isMoreLoading => _isMoreLoading; NotificationResponseModel? importantNotificationResponse;
bool isLoadingImportant = false;
bool isMoreLoadingImportant = false;
bool hasMoreImportant = true;
int currentPageImportant = 1;
int totalPagesImportant = 0;
/// Fetch notifications
Future<void> getNotifications({int page = 1, bool isMobile = false}) async { Future<void> getNotifications({int page = 1, bool isPagination = false}) async {
if (isMobile && page > 1) { if (isPagination) {
_isMoreLoading = true; isMoreLoadingAll = true;
} else { } else {
_isLoading = true; isLoadingAll = true;
} }
notifyListeners(); notifyListeners();
final int offset = _pageSize * page; 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) { switch (result) {
case Ok<NotificationResponseModel>(): case Ok<NotificationResponseModel>():
if (isMobile && page > 1) { final data = result.value;
final oldNotifications = if (isPagination && allNotificationResponse != null) {
_notificationResponseModel?.data?.notifications ?? []; final old = allNotificationResponse?.data?.notifications ?? [];
final fresh = data.data?.notifications ?? [];
final newNotifications = result.value.data?.notifications ?? []; allNotificationResponse = data.copyWith(
data: data.data?.copyWith(
_notificationResponseModel = result.value.copyWith( notifications: [...old, ...fresh],
data: result.value.data?.copyWith(
notifications: [...oldNotifications, ...newNotifications],
), ),
); );
} else { } else {
_notificationResponseModel = result.value; allNotificationResponse = data;
} }
currentPage = page; _updateImportantFromAll();
_hasMoreData =
(result.value.data?.notifications?.length ?? 0) >= _pageSize; currentPageAll = page;
_totalPages = result.value.data?.meta?.pages ?? 1; totalPagesAll = data.data?.meta?.pages ?? 1;
hasMoreAll = (data.data?.notifications?.length ?? 0) >= _pageSize;
break; break;
case Error<NotificationResponseModel>(): case Error<NotificationResponseModel>():
@@ -86,22 +86,136 @@ class NotificationViewModel with ChangeNotifier {
break; break;
} }
_isLoading = false; isLoadingAll = false;
_isMoreLoading = false; isMoreLoadingAll = false;
notifyListeners(); notifyListeners();
} }
/// Jump to page Future<void> getUnreadNotifications({int page = 1, bool isPagination = false}) async {
Future<void> jumpToPage(int page) async { if (isPagination) {
if (_totalPages == 0 || page < 1 || page > _totalPages) { 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?.notifications ?? [];
final fresh = data.data?.notifications ?? [];
unreadNotificationResponse = data.copyWith(
data: data.data?.copyWith(
notifications: [...old, ...fresh],
),
);
} else {
unreadNotificationResponse = data;
}
currentPageUnread = page;
totalPagesUnread = data.data?.meta?.pages ?? 1;
hasMoreUnread = (data.data?.notifications?.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?.notifications ?? [];
final fresh = data.data?.notifications ?? [];
importantNotificationResponse = data.copyWith(
data: data.data?.copyWith(
notifications: [...old, ...fresh],
),
);
} else {
importantNotificationResponse = data;
}
currentPageImportant = page;
totalPagesImportant = data.data?.meta?.pages ?? 1;
hasMoreImportant = (data.data?.notifications?.length ?? 0) >= _pageSize;
break;
case Error<NotificationResponseModel>():
_errorMessage = result.error.toString();
_updateImportantFromAll();
break;
}
isLoadingImportant = false;
isMoreLoadingImportant = false;
notifyListeners();
}
void _updateImportantFromAll() {
final all = allNotificationResponse?.data?.notifications ?? [];
final filtered = (all.where((n) {
final p = n.priority ?? '';
return p.toLowerCase() == 'important';
}).toList());
if (allNotificationResponse != null) {
importantNotificationResponse = allNotificationResponse!.copyWith(
data: allNotificationResponse!.data!.copyWith(notifications: filtered),
);
} else {
importantNotificationResponse = null;
}
}
Future<void> jumpToPageAll(int page) async {
if (totalPagesAll == 0 || page < 1 || page > totalPagesAll) {
return; return;
} }
await getNotifications(page: page); await getNotifications(page: page);
} }
/// Mark all as read 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 { Future<void> markAllAsRead(BuildContext context) async {
_isLoading = true; isLoadingAll = true;
_errorMessage = null; _errorMessage = null;
notifyListeners(); notifyListeners();
@@ -115,35 +229,39 @@ class NotificationViewModel with ChangeNotifier {
case Ok<Map<String, dynamic>>(): case Ok<Map<String, dynamic>>():
final response = result.value; final response = result.value;
final success = response['success'] as bool? ?? false; final success = response['success'] as bool? ?? false;
final message = final message = response['message'] as String? ?? NotificationStrings.unknownResponse;
response['message'] as String? ??
NotificationStrings.unknownResponse;
if (success) { if (success) {
if (_notificationResponseModel?.data?.notifications != null) { if (allNotificationResponse?.data?.notifications != null) {
final updatedNotifications = final updatedNotifications = allNotificationResponse!.data!.notifications!
_notificationResponseModel!.data!.notifications!
.map((n) => n.copyWith(seen: true)) .map((n) => n.copyWith(seen: true))
.toList(); .toList();
_notificationResponseModel = _notificationResponseModel!.copyWith( allNotificationResponse = allNotificationResponse!.copyWith(
data: _notificationResponseModel!.data!.copyWith( data: allNotificationResponse!.data!.copyWith(
notifications: updatedNotifications, notifications: updatedNotifications,
), ),
); );
_unreadNotificationResponse = _unreadNotificationResponse?.copyWith( unreadNotificationResponse = unreadNotificationResponse?.copyWith(
data: _unreadNotificationResponse?.data?.copyWith( data: unreadNotificationResponse?.data?.copyWith(notifications: []),
notifications: [], );
if (importantNotificationResponse?.data?.notifications != null) {
final updatedImportant = importantNotificationResponse!.data!.notifications!
.map((n) => n.copyWith(seen: true))
.toList();
importantNotificationResponse = importantNotificationResponse!.copyWith(
data: importantNotificationResponse!.data!.copyWith(
notifications: updatedImportant,
), ),
); );
} }
}
if (context.mounted) { if (context.mounted) {
AppToast.success( AppToast.success(context, NotificationStrings.allNotificationMarkedAsRead);
context,
NotificationStrings.allNotificationMarkedAsRead,
);
} }
} else { } else {
_errorMessage = message; _errorMessage = message;
@@ -161,7 +279,7 @@ class NotificationViewModel with ChangeNotifier {
break; break;
} }
_isLoading = false; isLoadingAll = false;
notifyListeners(); notifyListeners();
} }
@@ -182,28 +300,4 @@ class NotificationViewModel with ChangeNotifier {
return '${difference.inDays} ${NotificationStrings.daysAgo}'; return '${difference.inDays} ${NotificationStrings.daysAgo}';
} }
} }
Future<void> getUnreadNotifications({int page = 1}) async {
_isUnreadLoading = true;
notifyListeners();
final int offset = _pageSize * page;
final result = await _repository.getUnreadNotifications(
limit: _pageSize,
offset: offset,
);
switch (result) {
case Ok<NotificationResponseModel>():
_unreadNotificationResponse = result.value;
break;
case Error<NotificationResponseModel>():
_errorMessage = result.error.toString();
break;
}
_isUnreadLoading = false;
notifyListeners();
}
} }
@@ -40,6 +40,26 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
Widget build(BuildContext context) { Widget build(BuildContext context) {
final viewModel = context.watch<NotificationViewModel>(); final viewModel = context.watch<NotificationViewModel>();
final activeIndex = controller.index;
int currentPage = 1;
int totalPages = 1;
bool isLoading = false;
if (activeIndex == 0) {
currentPage = viewModel.currentPageAll;
totalPages = viewModel.totalPagesAll;
isLoading = viewModel.isLoadingAll;
} else if (activeIndex == 1) {
currentPage = viewModel.currentPageUnread;
totalPages = viewModel.totalPagesUnread;
isLoading = viewModel.isLoadingUnread;
} else {
currentPage = viewModel.currentPageImportant;
totalPages = viewModel.totalPagesImportant;
isLoading = viewModel.isLoadingImportant;
}
return SafeArea( return SafeArea(
child: Scaffold( child: Scaffold(
backgroundColor: AppColors.backgroundColor, backgroundColor: AppColors.backgroundColor,
@@ -60,6 +80,7 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
NotificationStrings.unread, NotificationStrings.unread,
NotificationStrings.important, NotificationStrings.important,
], ],
onTap: (_) => setState(() {}),
), ),
SizedBox(height: 12.0.h()), SizedBox(height: 12.0.h()),
Padding( Padding(
@@ -93,9 +114,16 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
), ),
), ),
SizedBox(height: 12.0.h()), SizedBox(height: 12.0.h()),
viewModel.isLoading if (isLoading)
? Container() const Expanded(
: Expanded( child: Center(
child: CircularProgressIndicator(
color: AppColors.secondary50,
),
),
)
else
Expanded(
child: TabBarView( child: TabBarView(
controller: controller, controller: controller,
children: const [ children: const [
@@ -105,15 +133,6 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
], ],
), ),
), ),
if (viewModel.isLoading) ...[
const Spacer(),
const Center(
child: CircularProgressIndicator(
color: AppColors.secondary50,
),
),
const Spacer(),
],
SizedBox(height: 10.0.h()), SizedBox(height: 10.0.h()),
Row( Row(
children: [ children: [
@@ -131,14 +150,19 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
onTap: () async { onTap: () async {
final selectedPage = await showDialog<int>( final selectedPage = await showDialog<int>(
context: context, context: context,
builder: builder: (context) => PageSelectionDialog(
(context) => PageSelectionDialog( totalPages: totalPages,
totalPages: viewModel.totalPages,
), ),
); );
if (selectedPage != null) { if (selectedPage != null) {
viewModel.jumpToPage(selectedPage); if (activeIndex == 0) {
viewModel.jumpToPageAll(selectedPage);
} else if (activeIndex == 1) {
viewModel.jumpToPageUnread(selectedPage);
} else {
viewModel.jumpToPageImportant(selectedPage);
}
} }
}, },
child: Container( child: Container(
@@ -153,7 +177,7 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
children: [ children: [
SizedBox(width: 5.0.w()), SizedBox(width: 5.0.w()),
Text( Text(
viewModel.currentPage.toString(), currentPage.toString(),
style: TextStyle( style: TextStyle(
fontSize: 14.0.sp(), fontSize: 14.0.sp(),
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@@ -181,7 +205,7 @@ class _DesktopNotificationPageState extends State<DesktopNotificationPage>
), ),
SizedBox(width: 5.0.w()), SizedBox(width: 5.0.w()),
Text( Text(
viewModel.totalPages.toString(), totalPages.toString(),
style: TextStyle( style: TextStyle(
fontSize: 13.0.sp(), fontSize: 13.0.sp(),
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@@ -21,22 +21,37 @@ class MobileNotificationPage extends StatefulWidget {
class _MobileNotificationPageState extends State<MobileNotificationPage> class _MobileNotificationPageState extends State<MobileNotificationPage>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late TabController controller; late TabController controller;
final ScrollController _scrollController = ScrollController();
final ScrollController _scrollAll = ScrollController();
final ScrollController _scrollUnread = ScrollController();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
controller = TabController(length: 3, vsync: this); controller = TabController(length: 3, vsync: this);
_scrollController.addListener(() {
final viewModel = context.read<NotificationViewModel>(); final viewModel = context.read<NotificationViewModel>();
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent - 100 && _scrollAll.addListener(() {
!viewModel.isLoading && if (_scrollAll.position.pixels >=
viewModel.hasMoreData) { _scrollAll.position.maxScrollExtent - 100 &&
!viewModel.isLoadingAll &&
viewModel.hasMoreAll) {
viewModel.getNotifications( viewModel.getNotifications(
page: viewModel.currentPage + 1, page: viewModel.currentPageAll + 1,
isMobile: true, isPagination: true,
);
}
});
_scrollUnread.addListener(() {
if (_scrollUnread.position.pixels >=
_scrollUnread.position.maxScrollExtent - 100 &&
!viewModel.isLoadingUnread &&
viewModel.hasMoreUnread) {
viewModel.getUnreadNotifications(
page: viewModel.currentPageUnread + 1,
isPagination: true,
); );
} }
}); });
@@ -45,7 +60,8 @@ class _MobileNotificationPageState extends State<MobileNotificationPage>
@override @override
void dispose() { void dispose() {
controller.dispose(); controller.dispose();
_scrollController.dispose(); _scrollAll.dispose();
_scrollUnread.dispose();
super.dispose(); super.dispose();
} }
@@ -98,37 +114,43 @@ class _MobileNotificationPageState extends State<MobileNotificationPage>
), ),
), ),
SizedBox(height: 12.0.h()), SizedBox(height: 12.0.h()),
viewModel.isLoading
? Container() Expanded(
: Expanded(
child: TabBarView( child: TabBarView(
controller: controller, controller: controller,
children: [ children: [
NotificationAllTab(scrollController: _scrollController), NotificationAllTab(scrollController: _scrollAll),
NotificationUnreadTab(scrollController: _scrollController), NotificationUnreadTab(scrollController: _scrollUnread),
NotificationImportantTab( const NotificationImportantTab(),
scrollController: _scrollController,
),
], ],
), ),
), ),
if (viewModel.isMoreLoading) ...[
if (viewModel.isMoreLoadingAll)
const Padding( const Padding(
padding: EdgeInsets.symmetric(vertical: 16), padding: EdgeInsets.symmetric(vertical: 16),
child: Center( child: Center(
child: CircularProgressIndicator(color: AppColors.secondary50), child: CircularProgressIndicator(color: AppColors.secondary50),
), ),
), ),
],
if (viewModel.isLoading && if (viewModel.isMoreLoadingUnread)
(viewModel.notificationResponse?.data?.notifications?.isEmpty ?? const Padding(
true)) ...[ padding: EdgeInsets.symmetric(vertical: 16),
const Spacer(), child: Center(
const Center(
child: CircularProgressIndicator(color: AppColors.secondary50), child: CircularProgressIndicator(color: AppColors.secondary50),
), ),
const Spacer(), ),
],
if ((viewModel.isLoadingAll &&
(viewModel.allNotificationResponse?.data?.notifications?.isEmpty ?? true)) ||
(viewModel.isLoadingUnread &&
(viewModel.unreadNotificationResponse?.data?.notifications?.isEmpty ?? true)))
const Expanded(
child: Center(
child: CircularProgressIndicator(color: AppColors.secondary50),
),
),
], ],
), ),
); );
@@ -25,6 +25,7 @@ class TabletNotificationPage extends StatefulWidget {
class _TabletNotificationPageState extends State<TabletNotificationPage> class _TabletNotificationPageState extends State<TabletNotificationPage>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late TabController controller; late TabController controller;
final GlobalKey<ScaffoldState> key = GlobalKey();
@override @override
void initState() { void initState() {
@@ -41,7 +42,25 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final viewModel = context.watch<NotificationViewModel>(); final viewModel = context.watch<NotificationViewModel>();
final GlobalKey<ScaffoldState> key = GlobalKey(); final activeIndex = controller.index;
int currentPage = 1;
int totalPages = 1;
bool isLoading = false;
if (activeIndex == 0) {
currentPage = viewModel.currentPageAll;
totalPages = viewModel.totalPagesAll;
isLoading = viewModel.isLoadingAll;
} else if (activeIndex == 1) {
currentPage = viewModel.currentPageUnread;
totalPages = viewModel.totalPagesUnread;
isLoading = viewModel.isLoadingUnread;
} else {
currentPage = viewModel.currentPageImportant;
totalPages = viewModel.totalPagesImportant;
isLoading = viewModel.isLoadingImportant;
}
return Scaffold( return Scaffold(
key: key, key: key,
@@ -63,6 +82,7 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
NotificationStrings.unread, NotificationStrings.unread,
NotificationStrings.important, NotificationStrings.important,
], ],
onTap: (_) => setState(() {}),
), ),
SizedBox(height: 12.0.h()), SizedBox(height: 12.0.h()),
Padding( Padding(
@@ -96,9 +116,16 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
), ),
), ),
SizedBox(height: 12.0.h()), SizedBox(height: 12.0.h()),
viewModel.isLoading if (isLoading)
? Container() const Expanded(
: Expanded( child: Center(
child: CircularProgressIndicator(
color: AppColors.secondary50,
),
),
)
else
Expanded(
child: TabBarView( child: TabBarView(
controller: controller, controller: controller,
children: const [ children: const [
@@ -108,15 +135,6 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
], ],
), ),
), ),
if (viewModel.isLoading) ...[
const Spacer(),
const Center(
child: CircularProgressIndicator(
color: AppColors.secondary50,
),
),
const Spacer(),
],
SizedBox(height: 10.0.h()), SizedBox(height: 10.0.h()),
Row( Row(
children: [ children: [
@@ -134,14 +152,19 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
onTap: () async { onTap: () async {
final selectedPage = await showDialog<int>( final selectedPage = await showDialog<int>(
context: context, context: context,
builder: builder: (context) => PageSelectionDialog(
(context) => PageSelectionDialog( totalPages: totalPages,
totalPages: viewModel.totalPages,
), ),
); );
if (selectedPage != null) { if (selectedPage != null) {
viewModel.jumpToPage(selectedPage); if (activeIndex == 0) {
viewModel.jumpToPageAll(selectedPage);
} else if (activeIndex == 1) {
viewModel.jumpToPageUnread(selectedPage);
} else {
viewModel.jumpToPageImportant(selectedPage);
}
} }
}, },
child: Container( child: Container(
@@ -153,7 +176,7 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
children: [ children: [
SizedBox(width: 5.0.w()), SizedBox(width: 5.0.w()),
Text( Text(
viewModel.currentPage.toString(), currentPage.toString(),
style: TextStyle( style: TextStyle(
fontSize: 14.0.sp(), fontSize: 14.0.sp(),
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@@ -184,7 +207,7 @@ class _TabletNotificationPageState extends State<TabletNotificationPage>
), ),
SizedBox(width: 5.0.w()), SizedBox(width: 5.0.w()),
Text( Text(
viewModel.totalPages.toString(), totalPages.toString(),
style: TextStyle( style: TextStyle(
fontSize: 13.0.sp(), fontSize: 13.0.sp(),
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@@ -22,4 +22,5 @@ class NotificationStrings {
static const String reject = 'reject'; static const String reject = 'reject';
static const String info = 'info'; static const String info = 'info';
static const String noUnreadNotifications = 'No unread notifications'; static const String noUnreadNotifications = 'No unread notifications';
static const String noImportantNotifications = 'No important notifications';
} }
@@ -13,7 +13,7 @@ class NotificationAllTab extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final viewModel = context.watch<NotificationViewModel>(); final viewModel = context.watch<NotificationViewModel>();
final notifications = final notifications =
viewModel.notificationResponse?.data?.notifications ?? []; viewModel.allNotificationResponse?.data?.notifications ?? [];
return ListView.builder( return ListView.builder(
controller: scrollController, controller: scrollController,
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tm_app/view_models/notification_view_model.dart'; import 'package:tm_app/view_models/notification_view_model.dart';
import 'package:tm_app/views/notification/strings/notification_strings.dart';
import 'notification_card.dart'; import 'notification_card.dart';
class NotificationImportantTab extends StatelessWidget { class NotificationImportantTab extends StatelessWidget {
@@ -12,13 +12,25 @@ class NotificationImportantTab extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final viewModel = context.watch<NotificationViewModel>(); final viewModel = context.watch<NotificationViewModel>();
final allNotifications =
viewModel.notificationResponse?.data?.notifications ?? [];
final importantNotifications = allNotifications if (viewModel.isLoadingImportant) {
.where((n) => n.priority?.toLowerCase() == 'important') return const Center(child: CircularProgressIndicator());
}
final importantFromApi = viewModel.importantNotificationResponse?.data?.notifications ?? [];
final allNotifications = viewModel.allNotificationResponse?.data?.notifications ?? [];
final source = importantFromApi.isNotEmpty ? importantFromApi : allNotifications;
final importantNotifications = source
.where((n) => (n.priority ?? '').toLowerCase() == 'important')
.toList(); .toList();
if (importantNotifications.isEmpty) {
return const Center(child: Text(NotificationStrings.noImportantNotifications));
}
return ListView.builder( return ListView.builder(
controller: scrollController, controller: scrollController,
itemCount: importantNotifications.length, itemCount: importantNotifications.length,
@@ -14,7 +14,7 @@ class NotificationUnreadTab extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final viewModel = context.watch<NotificationViewModel>(); final viewModel = context.watch<NotificationViewModel>();
if (viewModel.isUnreadLoading) { if (viewModel.isLoadingUnread){
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
+9 -3
View File
@@ -1,13 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../core/theme/colors.dart'; import '../../core/theme/colors.dart';
import '../../core/utils/size_config.dart'; import '../../core/utils/size_config.dart';
class MainTabBar extends StatefulWidget { class MainTabBar extends StatefulWidget {
const MainTabBar({required this.controller, required this.titles, super.key}); const MainTabBar({
required this.controller,
required this.titles,
this.onTap,
super.key,
});
final TabController controller; final TabController controller;
final List<String> titles; final List<String> titles;
final ValueChanged<int>? onTap;
@override @override
State<MainTabBar> createState() => _MainTabBarState(); State<MainTabBar> createState() => _MainTabBarState();
@@ -27,6 +32,8 @@ class _MainTabBarState extends State<MainTabBar> {
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: TabBar( child: TabBar(
controller: widget.controller,
onTap: widget.onTap,
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.tab,
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
indicator: BoxDecoration( indicator: BoxDecoration(
@@ -40,7 +47,6 @@ class _MainTabBarState extends State<MainTabBar> {
), ),
], ],
), ),
controller: widget.controller,
labelColor: AppColors.mainBlue, labelColor: AppColors.mainBlue,
unselectedLabelColor: AppColors.grey60, unselectedLabelColor: AppColors.grey60,
labelStyle: TextStyle(fontSize: 16.0.sp(), fontWeight: FontWeight.w600), labelStyle: TextStyle(fontSize: 16.0.sp(), fontWeight: FontWeight.w600),