This commit is contained in:
sjk
2025-11-17 14:09:17 +08:00
commit 31e46c5bf6
479 changed files with 109324 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../shared/providers/notification_provider.dart';
import '../../../core/theme/app_colors.dart';
import '../../../shared/widgets/custom_card.dart';
/// 通知列表页面
class NotificationListScreen extends ConsumerStatefulWidget {
const NotificationListScreen({super.key});
@override
ConsumerState<NotificationListScreen> createState() => _NotificationListScreenState();
}
class _NotificationListScreenState extends ConsumerState<NotificationListScreen> {
@override
void initState() {
super.initState();
// 加载通知列表
Future.microtask(() {
ref.read(notificationProvider.notifier).loadNotifications();
});
}
@override
Widget build(BuildContext context) {
final notificationState = ref.watch(notificationProvider);
final notifications = notificationState.notifications;
return Scaffold(
appBar: AppBar(
title: const Text('消息通知'),
actions: [
// 标记全部已读
if (notifications.any((n) => !n.isRead))
TextButton(
onPressed: () {
ref.read(notificationProvider.notifier).markAllAsRead();
},
child: const Text(
'全部已读',
style: TextStyle(color: Colors.white),
),
),
],
),
body: notificationState.isLoading
? const Center(child: CircularProgressIndicator())
: notifications.isEmpty
? _buildEmptyState()
: RefreshIndicator(
onRefresh: () async {
await ref.read(notificationProvider.notifier).loadNotifications();
},
child: ListView.separated(
padding: const EdgeInsets.all(16),
itemCount: notifications.length,
separatorBuilder: (context, index) => const SizedBox(height: 12),
itemBuilder: (context, index) {
final notification = notifications[index];
return _buildNotificationItem(notification);
},
),
),
);
}
/// 构建空状态
Widget _buildEmptyState() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.notifications_none,
size: 100,
color: AppColors.onSurfaceVariant.withOpacity(0.3),
),
const SizedBox(height: 16),
Text(
'暂无消息',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: AppColors.onSurfaceVariant,
),
),
const SizedBox(height: 8),
Text(
'您目前没有任何通知消息',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: AppColors.onSurfaceVariant.withOpacity(0.7),
),
),
],
),
);
}
/// 构建通知项
Widget _buildNotificationItem(notification) {
final isUnread = !notification.isRead;
return CustomCard(
child: InkWell(
onTap: () {
// 标记为已读
if (isUnread) {
ref.read(notificationProvider.notifier).markAsRead(notification.id);
}
// TODO: 根据通知类型跳转到对应页面
},
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 图标
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: _getNotificationColor(notification.type).withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
_getNotificationIcon(notification.type),
color: _getNotificationColor(notification.type),
size: 24,
),
),
const SizedBox(width: 12),
// 内容
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
notification.title,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: isUnread ? FontWeight.bold : FontWeight.normal,
),
),
),
if (isUnread)
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: AppColors.error,
shape: BoxShape.circle,
),
),
],
),
const SizedBox(height: 4),
Text(
notification.content,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: AppColors.onSurfaceVariant,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
Text(
_formatTime(notification.createdAt),
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: AppColors.onSurfaceVariant.withOpacity(0.6),
),
),
],
),
),
],
),
),
),
);
}
/// 获取通知图标
IconData _getNotificationIcon(String type) {
switch (type) {
case 'system':
return Icons.info_outline;
case 'learning':
return Icons.school_outlined;
case 'achievement':
return Icons.emoji_events_outlined;
case 'reminder':
return Icons.notifications_active_outlined;
default:
return Icons.notifications_outlined;
}
}
/// 获取通知颜色
Color _getNotificationColor(String type) {
switch (type) {
case 'system':
return AppColors.primary;
case 'learning':
return AppColors.success;
case 'achievement':
return AppColors.warning;
case 'reminder':
return AppColors.info;
default:
return AppColors.primary;
}
}
/// 格式化时间
String _formatTime(DateTime dateTime) {
final now = DateTime.now();
final difference = now.difference(dateTime);
if (difference.inMinutes < 1) {
return '刚刚';
} else if (difference.inHours < 1) {
return '${difference.inMinutes}分钟前';
} else if (difference.inDays < 1) {
return '${difference.inHours}小时前';
} else if (difference.inDays < 7) {
return '${difference.inDays}天前';
} else {
return '${dateTime.month}${dateTime.day}';
}
}
}