import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../core/services/notification_service.dart'; import '../../core/models/notification.dart'; import '../../core/utils/snackbar_util.dart'; import '../../shared/widgets/skeleton_loader.dart'; import '../../shared/widgets/empty_state_widget.dart'; class NotificationCenterPage extends StatefulWidget { const NotificationCenterPage({super.key}); @override State createState() => _NotificationCenterPageState(); } class _NotificationCenterPageState extends State { final _scrollController = ScrollController(); @override void initState() { super.initState(); // Initialize service if not already if (!Get.isRegistered()) { Get.put(NotificationService()); } // Load notifications NotificationService.to.loadNotifications(refresh: true); // Setup infinite scroll _scrollController.addListener(_onScroll); } @override void dispose() { _scrollController.dispose(); super.dispose(); } void _onScroll() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent * 0.8) { NotificationService.to.loadMore(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Notifications'), actions: [ // Mark all as read Obx(() { final unreadCount = NotificationService.to.unreadCount.value; if (unreadCount > 0) { return IconButton( icon: const Icon(Icons.done_all_rounded), tooltip: 'Mark all as read', onPressed: () async { final success = await NotificationService.to.markAllAsRead(); if (success) { SnackbarUtil.showSuccess('All notifications marked as read'); } }, ); } return const SizedBox(); }), ], ), body: Obx(() { final service = NotificationService.to; // Loading state (first load) if (service.isLoading.value && service.notifications.isEmpty) { return _buildSkeleton(); } // Empty state if (service.notifications.isEmpty && !service.isLoading.value) { return EmptyStateWidget( type: EmptyStateType.noActivities, customTitle: 'No Notifications', customMessage: 'You\'re all caught up!\nNotifications will appear here.', onActionPressed: () => service.refresh(), actionLabel: 'Refresh', ); } // Notifications list return RefreshIndicator( onRefresh: () => service.refresh(), child: ListView.builder( controller: _scrollController, padding: EdgeInsets.symmetric(vertical: 8.h), itemCount: service.notifications.length + (service.hasMore.value ? 1 : 0), itemBuilder: (context, index) { // Loading indicator at bottom if (index == service.notifications.length) { return Padding( padding: EdgeInsets.all(16.w), child: const Center(child: CircularProgressIndicator()), ); } final notification = service.notifications[index]; return _buildNotificationCard(notification); }, ), ); }), ); } Widget _buildNotificationCard(NotificationModel notification) { return Dismissible( key: Key(notification.id), direction: DismissDirection.endToStart, background: Container( alignment: Alignment.centerRight, padding: EdgeInsets.only(right: 20.w), color: Colors.red.shade600, child: const Icon(Icons.delete, color: Colors.white), ), onDismissed: (direction) async { await NotificationService.to.deleteNotification(notification.id); SnackbarUtil.showInfo('Notification deleted'); }, child: Card( margin: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), color: notification.isUnread ? notification.getColor().withOpacity(0.05) : null, child: InkWell( onTap: () => _handleNotificationTap(notification), borderRadius: BorderRadius.circular(16.r), child: Padding( padding: EdgeInsets.all(16.w), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Icon Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: notification.getColor().withOpacity(0.1), borderRadius: BorderRadius.circular(12.r), ), child: Icon( notification.getIcon(), color: notification.getColor(), size: 24.w, ), ), SizedBox(width: 16.w), // Content Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( notification.title, style: TextStyle( fontSize: 16.sp, fontWeight: notification.isUnread ? FontWeight.bold : FontWeight.w600, color: Colors.grey.shade800, ), ), ), if (notification.isUnread) Container( width: 8.w, height: 8.h, decoration: BoxDecoration( color: notification.getColor(), shape: BoxShape.circle, ), ), ], ), SizedBox(height: 6.h), Text( notification.message, style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, height: 1.4, ), maxLines: 3, overflow: TextOverflow.ellipsis, ), SizedBox(height: 8.h), Row( children: [ if (notification.groupName != null) ...[ Icon( Icons.group, size: 14.w, color: Colors.grey.shade500, ), SizedBox(width: 4.w), Text( notification.groupName!, style: TextStyle( fontSize: 13.sp, color: Colors.grey.shade500, ), ), SizedBox(width: 12.w), ], Icon( Icons.access_time_rounded, size: 14.w, color: Colors.grey.shade500, ), SizedBox(width: 4.w), Text( notification.getTimeAgo(), style: TextStyle( fontSize: 13.sp, color: Colors.grey.shade500, ), ), ], ), ], ), ), ], ), ), ), ), ); } void _handleNotificationTap(NotificationModel notification) { // Mark as read if unread if (notification.isUnread) { NotificationService.to.markAsRead(notification.id); } // Show full notification details _showNotificationDetails(notification); } void _showNotificationDetails(NotificationModel notification) { showDialog( context: context, builder: (context) => AlertDialog( title: Row( children: [ Icon( notification.getIcon(), color: notification.getColor(), size: 24.w, ), SizedBox(width: 12.w), Expanded( child: Text( notification.title, style: TextStyle(fontSize: 18.sp), ), ), ], ), content: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( notification.message, style: TextStyle( fontSize: 15.sp, height: 1.5, ), ), SizedBox(height: 16.h), if (notification.groupName != null) _buildDetailRow( 'Group', notification.groupName!, Icons.group, ), _buildDetailRow( 'Date', notification.getTimeAgo(), Icons.access_time_rounded, ), _buildDetailRow( 'Channel', notification.channel.toUpperCase(), Icons.send_rounded, ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Close'), ), ], ), ); } Widget _buildDetailRow(String label, String value, IconData icon) { return Padding( padding: EdgeInsets.only(bottom: 8.h), child: Row( children: [ Icon(icon, size: 16.w, color: Colors.grey.shade600), SizedBox(width: 8.w), Text( '$label: ', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade700, ), ), Expanded( child: Text( value, style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, ), ), ), ], ), ); } Widget _buildSkeleton() { return ListView.builder( padding: EdgeInsets.symmetric(vertical: 8.h), itemCount: 10, itemBuilder: (context, index) => const SkeletonListItem(), ); } }