init
This commit is contained in:
@@ -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}日';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user