|
|
|
@ -17,145 +17,114 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:intl/intl.dart';
|
|
|
|
import 'package:intl/intl.dart';
|
|
|
|
|
|
|
|
|
|
|
|
class NotificationsListPage extends StatelessWidget {
|
|
|
|
class NotificationsListPage extends StatefulWidget {
|
|
|
|
const NotificationsListPage({super.key});
|
|
|
|
const NotificationsListPage({super.key});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
|
|
State<NotificationsListPage> createState() => _NotificationsListPageState();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _NotificationsListPageState extends State<NotificationsListPage> {
|
|
|
|
|
|
|
|
final GlobalKey _bottomKey = GlobalKey();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void _scrollToBottom() {
|
|
|
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
|
|
|
|
final ctx = _bottomKey.currentContext;
|
|
|
|
|
|
|
|
if (ctx != null) {
|
|
|
|
|
|
|
|
Scrollable.ensureVisible(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
duration: const Duration(milliseconds: 400),
|
|
|
|
|
|
|
|
curve: Curves.easeOut,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return CollapsingListView(
|
|
|
|
return CollapsingListView(
|
|
|
|
title: LocaleKeys.notification.tr(context: context),
|
|
|
|
title: LocaleKeys.notification.tr(context: context),
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
child: Consumer<NotificationsViewModel>(builder: (context, notificationsVM, child) {
|
|
|
|
child: Consumer<NotificationsViewModel>(builder: (context, notificationsVM, child) {
|
|
|
|
return Column(
|
|
|
|
return Container(
|
|
|
|
children: [
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 24.h),
|
|
|
|
Container(
|
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 24.h),
|
|
|
|
color: AppColors.whiteColor,
|
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
|
|
|
borderRadius: 24.h,
|
|
|
|
color: AppColors.whiteColor,
|
|
|
|
hasShadow: false,
|
|
|
|
borderRadius: 24.h,
|
|
|
|
),
|
|
|
|
hasShadow: false,
|
|
|
|
child: ListView.builder(
|
|
|
|
),
|
|
|
|
itemCount: notificationsVM.isNotificationsLoading ? 4 : notificationsVM.notificationsList.length,
|
|
|
|
child: ListView.builder(
|
|
|
|
physics: NeverScrollableScrollPhysics(),
|
|
|
|
itemCount: notificationsVM.isNotificationsLoading
|
|
|
|
shrinkWrap: true,
|
|
|
|
? 4
|
|
|
|
padding: EdgeInsetsGeometry.zero,
|
|
|
|
: notificationsVM.notificationsList.length + (notificationsVM.hasMoreNotifications ? 1 : 0),
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
physics: NeverScrollableScrollPhysics(),
|
|
|
|
return notificationsVM.isNotificationsLoading
|
|
|
|
shrinkWrap: true,
|
|
|
|
? LabResultItemView(
|
|
|
|
padding: EdgeInsetsGeometry.zero,
|
|
|
|
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
|
|
|
|
if (notificationsVM.isNotificationsLoading) {
|
|
|
|
|
|
|
|
return LabResultItemView(
|
|
|
|
onTap: () {},
|
|
|
|
onTap: () {},
|
|
|
|
labOrder: null,
|
|
|
|
labOrder: null,
|
|
|
|
index: index,
|
|
|
|
index: index,
|
|
|
|
isLoading: true,
|
|
|
|
isLoading: true,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
: AnimationConfiguration.staggeredList(
|
|
|
|
}
|
|
|
|
position: index,
|
|
|
|
return AnimationConfiguration.staggeredList(
|
|
|
|
duration: const Duration(milliseconds: 500),
|
|
|
|
position: index,
|
|
|
|
child: SlideAnimation(
|
|
|
|
duration: const Duration(milliseconds: 500),
|
|
|
|
verticalOffset: 100.0,
|
|
|
|
child: SlideAnimation(
|
|
|
|
child: FadeInAnimation(
|
|
|
|
verticalOffset: 100.0,
|
|
|
|
child: GestureDetector(
|
|
|
|
child: FadeInAnimation(
|
|
|
|
onTap: () {
|
|
|
|
child: GestureDetector(
|
|
|
|
notificationsVM.markAsRead(notificationID: notificationsVM.notificationsList[index].id ?? 0);
|
|
|
|
onTap: () {
|
|
|
|
Navigator.push(
|
|
|
|
notificationsVM.markAsRead(notificationID: notificationsVM.notificationsList[index].id ?? 0);
|
|
|
|
context,
|
|
|
|
Navigator.push(
|
|
|
|
MaterialPageRoute(
|
|
|
|
context,
|
|
|
|
builder: (context) => NotificationDetailsPage(
|
|
|
|
MaterialPageRoute(
|
|
|
|
notification: notificationsVM.notificationsList[index],
|
|
|
|
builder: (context) => NotificationDetailsPage(
|
|
|
|
),
|
|
|
|
notification: notificationsVM.notificationsList[index],
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
child: AnimatedContainer(
|
|
|
|
|
|
|
|
duration: Duration(milliseconds: 300),
|
|
|
|
|
|
|
|
curve: Curves.easeInOut,
|
|
|
|
|
|
|
|
child: Column(
|
|
|
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
SizedBox(height: 16.h),
|
|
|
|
|
|
|
|
// Message row with red dot for unread
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Expanded(
|
|
|
|
|
|
|
|
child: notificationsVM.notificationsList[index].message!.toText16(
|
|
|
|
|
|
|
|
isBold: (notificationsVM.notificationsList[index].isRead == false),
|
|
|
|
|
|
|
|
weight: (notificationsVM.notificationsList[index].isRead == false)
|
|
|
|
|
|
|
|
? FontWeight.w600
|
|
|
|
|
|
|
|
: FontWeight.w400,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(width: 8.w),
|
|
|
|
),
|
|
|
|
// Red dot for unread notifications ONLY
|
|
|
|
);
|
|
|
|
if (notificationsVM.notificationsList[index].isRead == false)
|
|
|
|
},
|
|
|
|
Container(
|
|
|
|
child: AnimatedContainer(
|
|
|
|
width: 8.w,
|
|
|
|
duration: Duration(milliseconds: 300),
|
|
|
|
height: 8.w,
|
|
|
|
curve: Curves.easeInOut,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
child: Column(
|
|
|
|
color: Colors.red,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
SizedBox(height: 12.h),
|
|
|
|
|
|
|
|
// First row: Time and Date chips with arrow
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
// Time chip with clock icon
|
|
|
|
SizedBox(height: 16.h),
|
|
|
|
Container(
|
|
|
|
// Message row with red dot for unread
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
|
|
|
Row(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
color: AppColors.greyColor,
|
|
|
|
children: [
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
Expanded(
|
|
|
|
),
|
|
|
|
child: notificationsVM.notificationsList[index].message!.toText16(
|
|
|
|
child: Row(
|
|
|
|
isBold: (notificationsVM.notificationsList[index].isRead == false),
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
weight: (notificationsVM.notificationsList[index].isRead == false)
|
|
|
|
children: [
|
|
|
|
? FontWeight.w600
|
|
|
|
Icon(Icons.access_time, size: 12.w, color: AppColors.textColor),
|
|
|
|
: FontWeight.w400,
|
|
|
|
SizedBox(width: 4.w),
|
|
|
|
|
|
|
|
_formatTime(notificationsVM.notificationsList[index].isSentOn).toText10(
|
|
|
|
|
|
|
|
weight: FontWeight.w500,
|
|
|
|
|
|
|
|
color: AppColors.textColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(width: 8.w),
|
|
|
|
),
|
|
|
|
// Red dot for unread notifications ONLY
|
|
|
|
SizedBox(width: 8.w),
|
|
|
|
if (notificationsVM.notificationsList[index].isRead == false)
|
|
|
|
// Date chip with calendar icon
|
|
|
|
Container(
|
|
|
|
Container(
|
|
|
|
width: 8.w,
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
|
|
|
height: 8.w,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
color: AppColors.greyColor,
|
|
|
|
color: Colors.red,
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
child: Row(
|
|
|
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Icon(Icons.calendar_today, size: 12.w, color: AppColors.textColor),
|
|
|
|
|
|
|
|
SizedBox(width: 4.w),
|
|
|
|
|
|
|
|
_formatDate(notificationsVM.notificationsList[index].isSentOn).toText10(
|
|
|
|
|
|
|
|
weight: FontWeight.w500,
|
|
|
|
|
|
|
|
color: AppColors.textColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Spacer(),
|
|
|
|
|
|
|
|
// Arrow icon
|
|
|
|
|
|
|
|
Utils.buildSvgWithAssets(
|
|
|
|
|
|
|
|
icon: AppAssets.arrow_forward,
|
|
|
|
|
|
|
|
width: 16.w,
|
|
|
|
|
|
|
|
height: 16.h,
|
|
|
|
|
|
|
|
iconColor: AppColors.greyTextColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
SizedBox(height: 12.h),
|
|
|
|
),
|
|
|
|
// First row: Time and Date chips with arrow
|
|
|
|
// Second row: Contains Image chip (if MessageType is "image")
|
|
|
|
Row(
|
|
|
|
if (notificationsVM.notificationsList[index].messageType != null &&
|
|
|
|
|
|
|
|
notificationsVM.notificationsList[index].messageType!.toLowerCase() == "image")
|
|
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
|
|
padding: EdgeInsets.only(top: 8.h),
|
|
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
|
|
|
|
// Time chip with clock icon
|
|
|
|
Container(
|
|
|
|
Container(
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
@ -165,31 +134,100 @@ class NotificationsListPage extends StatelessWidget {
|
|
|
|
child: Row(
|
|
|
|
child: Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Icon(Icons.image_outlined, size: 12.w, color: AppColors.textColor),
|
|
|
|
Icon(Icons.access_time, size: 12.w, color: AppColors.textColor),
|
|
|
|
SizedBox(width: 4.w),
|
|
|
|
SizedBox(width: 4.w),
|
|
|
|
'Contains Image'.toText10(
|
|
|
|
_formatTime(notificationsVM.notificationsList[index].isSentOn).toText10(
|
|
|
|
weight: FontWeight.w500,
|
|
|
|
weight: FontWeight.w500,
|
|
|
|
color: AppColors.textColor,
|
|
|
|
color: AppColors.textColor,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
SizedBox(width: 8.w),
|
|
|
|
|
|
|
|
// Date chip with calendar icon
|
|
|
|
|
|
|
|
Container(
|
|
|
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
|
|
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
|
|
|
color: AppColors.greyColor,
|
|
|
|
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Icon(Icons.calendar_today, size: 12.w, color: AppColors.textColor),
|
|
|
|
|
|
|
|
SizedBox(width: 4.w),
|
|
|
|
|
|
|
|
_formatDate(notificationsVM.notificationsList[index].isSentOn).toText10(
|
|
|
|
|
|
|
|
weight: FontWeight.w500,
|
|
|
|
|
|
|
|
color: AppColors.textColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Spacer(),
|
|
|
|
|
|
|
|
// Arrow icon
|
|
|
|
|
|
|
|
Utils.buildSvgWithAssets(
|
|
|
|
|
|
|
|
icon: AppAssets.arrow_forward,
|
|
|
|
|
|
|
|
width: 16.w,
|
|
|
|
|
|
|
|
height: 16.h,
|
|
|
|
|
|
|
|
iconColor: AppColors.greyTextColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
// Second row: Contains Image chip (if MessageType is "image")
|
|
|
|
SizedBox(height: 16.h),
|
|
|
|
if (notificationsVM.notificationsList[index].messageType != null &&
|
|
|
|
1.divider,
|
|
|
|
notificationsVM.notificationsList[index].messageType!.toLowerCase() == "image")
|
|
|
|
],
|
|
|
|
Padding(
|
|
|
|
|
|
|
|
padding: EdgeInsets.only(top: 8.h),
|
|
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Container(
|
|
|
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
|
|
|
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
|
|
|
color: AppColors.greyColor,
|
|
|
|
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Icon(Icons.image_outlined, size: 12.w, color: AppColors.textColor),
|
|
|
|
|
|
|
|
SizedBox(width: 4.w),
|
|
|
|
|
|
|
|
'Contains Image'.toText10(
|
|
|
|
|
|
|
|
weight: FontWeight.w500,
|
|
|
|
|
|
|
|
color: AppColors.textColor,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
SizedBox(height: 16.h),
|
|
|
|
|
|
|
|
1.divider,
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
),
|
|
|
|
}).paddingSymmetrical(16.w, 0.h),
|
|
|
|
);
|
|
|
|
).paddingSymmetrical(24.w, 0.h),
|
|
|
|
}).paddingSymmetrical(16.w, 0.h),
|
|
|
|
SizedBox(height: 16.h),
|
|
|
|
).paddingSymmetrical(24.w, 0.h);
|
|
|
|
SizedBox(
|
|
|
|
|
|
|
|
key: _bottomKey,
|
|
|
|
|
|
|
|
child: "Show more notifications".toText16(
|
|
|
|
|
|
|
|
color: AppColors.primaryRedColor,
|
|
|
|
|
|
|
|
isBold: true,
|
|
|
|
|
|
|
|
isUnderLine: true
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
).onPress(() async {
|
|
|
|
|
|
|
|
await notificationsVM.loadMoreNotifications();
|
|
|
|
|
|
|
|
_scrollToBottom();
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
SizedBox(height: 24.h),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|