diff --git a/apps/lib/features/messages/ui/screens/message_invite_list_screen.dart b/apps/lib/features/messages/ui/screens/message_invite_list_screen.dart index 98d3551..6f7bc99 100644 --- a/apps/lib/features/messages/ui/screens/message_invite_list_screen.dart +++ b/apps/lib/features/messages/ui/screens/message_invite_list_screen.dart @@ -8,11 +8,11 @@ import '../../../../core/theme/design_tokens.dart'; import '../../../../shared/widgets/page_header.dart'; import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; -import '../../../../shared/widgets/app_button.dart'; import '../../../calendar/data/calendar_api.dart'; import '../../../friends/data/friends_api.dart'; +import '../../../users/data/users_api.dart'; import '../../data/inbox_api.dart'; -import '../../ui/widgets/calendar_message_card.dart'; +import '../../ui/widgets/message_action_sheet.dart'; class MessageWithFriend { final InboxMessageResponse message; @@ -33,6 +33,7 @@ class _MessageInviteListScreenState extends State { late final InboxApi _inboxApi; late final FriendsApi _friendsApi; late final CalendarApi _calendarApi; + late final UsersApi _usersApi; List _unreadMessages = []; List _readMessages = []; @@ -45,6 +46,7 @@ class _MessageInviteListScreenState extends State { _inboxApi = sl(); _friendsApi = sl(); _calendarApi = sl(); + _usersApi = sl(); _loadMessages(); } @@ -115,14 +117,15 @@ class _MessageInviteListScreenState extends State { if (type == 'invite') { if (message.status.value == 'pending') { await _showCalendarInviteSheet(message); - } else if (message.status.value == 'accepted') { - if (message.scheduleItemId != null) { - context.push('/calendar/${message.scheduleItemId}'); + } else { + await _showCalendarInviteReadOnlySheet(message); + if (message.scheduleItemId != null && context.mounted) { + context.push('/calendar/events/${message.scheduleItemId}'); } } } else if (type == 'update') { if (message.scheduleItemId != null) { - context.push('/calendar/${message.scheduleItemId}'); + context.push('/calendar/events/${message.scheduleItemId}'); } } return; @@ -131,11 +134,7 @@ class _MessageInviteListScreenState extends State { Toast.show(context, '发送者信息加载失败,请下拉重试', type: ToastType.error); return; } - if (message.isRead) { - _showFriendRequestReadOnlySheet(item); - } else { - _showFriendRequestActionSheet(item); - } + _showFriendRequestSheet(item, isReadOnly: message.isRead); return; case InboxMessageType.system: case InboxMessageType.group: @@ -152,116 +151,139 @@ class _MessageInviteListScreenState extends State { } } + Future<(String calendarTitle, String senderName)?> _getCalendarInviteInfo( + InboxMessageResponse message, + ) async { + if (message.scheduleItemId == null || message.senderId == null) { + return null; + } + try { + final calendar = await _calendarApi.getById(message.scheduleItemId!); + final sender = await _usersApi.getById(message.senderId!); + return (calendar.title, sender.username); + } catch (e) { + return null; + } + } + Future _showCalendarInviteSheet(InboxMessageResponse message) async { final itemId = message.scheduleItemId; if (itemId == null) return; + final info = await _getCalendarInviteInfo(message); + final title = info != null ? '${info.$2} 邀请你加入日历' : '日历邀请'; + final description = info?.$1; + + if (!mounted) return; + showModalBottomSheet( context: context, backgroundColor: Colors.transparent, - builder: (ctx) => Container( - padding: const EdgeInsets.all(AppSpacing.lg), - decoration: const BoxDecoration( - color: AppColors.background, - borderRadius: BorderRadius.vertical( - top: Radius.circular(AppRadius.lg), - ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - '日历邀请', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - const SizedBox(height: AppSpacing.lg), - Row( - children: [ - Expanded( - child: AppButton( - text: '拒绝', - isOutlined: true, - onPressed: () async { - try { - await _calendarApi.rejectSubscription(itemId); - await _inboxApi.markAsRead(message.id); - if (mounted) { - Navigator.pop(ctx); - Toast.show(context, '已拒绝', type: ToastType.success); - _loadMessages(); - } - } catch (e) { - if (mounted) { - Toast.show(context, '操作失败', type: ToastType.error); - } - } - }, - ), - ), - const SizedBox(width: AppSpacing.md), - Expanded( - child: AppButton( - text: '接受', - onPressed: () async { - try { - await _calendarApi.acceptSubscription(itemId); - await _inboxApi.markAsRead(message.id); - if (mounted) { - Navigator.pop(ctx); - Toast.show(context, '已接受', type: ToastType.success); - _loadMessages(); - } - } catch (e) { - if (mounted) { - Toast.show(context, '操作失败', type: ToastType.error); - } - } - }, - ), - ), - ], - ), - const SizedBox(height: AppSpacing.md), - ], - ), + builder: (ctx) => MessageActionSheet( + title: title, + description: description, + icon: Icons.calendar_today, + iconColor: AppColors.blue500, + onAccept: () async { + try { + await _calendarApi.acceptSubscription(itemId); + await _inboxApi.markAsRead(message.id); + if (mounted) { + Toast.show(context, '已接受', type: ToastType.success); + _loadMessages(); + } + } catch (e) { + if (mounted) { + Toast.show(context, '操作失败', type: ToastType.error); + } + } + }, + onDecline: () async { + try { + await _calendarApi.rejectSubscription(itemId); + await _inboxApi.markAsRead(message.id); + if (mounted) { + Toast.show(context, '已拒绝', type: ToastType.success); + _loadMessages(); + } + } catch (e) { + if (mounted) { + Toast.show(context, '操作失败', type: ToastType.error); + } + } + }, ), ); } - void _showFriendRequestReadOnlySheet(MessageWithFriend item) { + Future _showCalendarInviteReadOnlySheet( + InboxMessageResponse message, + ) async { + final itemId = message.scheduleItemId; + if (itemId == null) return; + + final info = await _getCalendarInviteInfo(message); + final title = info != null ? '${info.$2} 邀请你加入日历' : '日历邀请'; + final description = info?.$1; + + final statusText = message.status.value == 'accepted' ? '已接受' : '已拒绝'; + + if (!mounted) return; + showModalBottomSheet( context: context, backgroundColor: Colors.transparent, - builder: (ctx) { - return _FriendRequestSheet( - message: item.message, - friendRequest: item.friendRequest!, - isReadOnly: true, - ); - }, + builder: (ctx) => MessageActionSheet( + title: title, + description: description, + statusText: statusText, + isReadOnly: true, + icon: Icons.calendar_today, + iconColor: AppColors.blue500, + ), ); } - void _showFriendRequestActionSheet(MessageWithFriend item) { + void _showFriendRequestSheet( + MessageWithFriend item, { + bool isReadOnly = false, + }) { + final message = item.message; + final friendRequest = item.friendRequest; + if (friendRequest == null) return; + + final title = '${friendRequest.sender.username} 请求添加您为好友'; + final description = message.content; + final statusText = isReadOnly + ? (friendRequest.status == 'accepted' + ? '已接受' + : friendRequest.status == 'rejected' + ? '已拒绝' + : '已处理') + : null; + showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, - builder: (ctx) { - return _FriendRequestSheet( - message: item.message, - friendRequest: item.friendRequest!, - isReadOnly: false, - onAccept: () async { - Navigator.pop(ctx); - await _processFriendRequest(item, accept: true); - }, - onDecline: () async { - Navigator.pop(ctx); - await _processFriendRequest(item, accept: false); - }, - ); - }, + builder: (ctx) => MessageActionSheet( + title: title, + description: description, + statusText: statusText, + isReadOnly: isReadOnly, + icon: Icons.person_add_outlined, + iconColor: AppColors.emerald500, + onAccept: isReadOnly + ? null + : () async { + await _processFriendRequest(item, accept: true); + }, + onDecline: isReadOnly + ? null + : () async { + await _processFriendRequest(item, accept: false); + }, + ), ); } @@ -601,149 +623,3 @@ class _MessageCard extends StatelessWidget { return message.content ?? '点击查看详情'; } } - -class _FriendRequestSheet extends StatelessWidget { - final InboxMessageResponse message; - final FriendRequestResponse friendRequest; - final bool isReadOnly; - final VoidCallback? onAccept; - final VoidCallback? onDecline; - - const _FriendRequestSheet({ - required this.message, - required this.friendRequest, - required this.isReadOnly, - this.onAccept, - this.onDecline, - }); - - @override - Widget build(BuildContext context) { - final status = friendRequest.status; - final statusText = status == 'accepted' - ? '已接受' - : status == 'rejected' - ? '已拒绝' - : '已处理'; - - return Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(24, 20, 24, 0), - decoration: const BoxDecoration( - color: AppColors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 40, - height: 4, - decoration: BoxDecoration( - color: AppColors.slate300, - borderRadius: BorderRadius.circular(2), - ), - ), - const SizedBox(height: 20), - Container( - width: 72, - height: 72, - decoration: BoxDecoration( - color: AppColors.emerald500.withValues(alpha: 0.1), - shape: BoxShape.circle, - ), - child: const Icon( - Icons.person_add_outlined, - size: 32, - color: AppColors.emerald500, - ), - ), - const SizedBox(height: 16), - Text( - '${friendRequest.sender.username} 请求添加您为好友', - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - color: AppColors.slate900, - ), - textAlign: TextAlign.center, - ), - if ((message.content ?? '').isNotEmpty) ...[ - const SizedBox(height: 8), - Text( - '备注: ${message.content}', - style: const TextStyle(fontSize: 14, color: AppColors.slate500), - ), - ], - if (isReadOnly) ...[ - const SizedBox(height: 16), - Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), - decoration: BoxDecoration( - color: AppColors.slate100, - borderRadius: BorderRadius.circular(20), - ), - child: Text( - statusText, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.slate600, - ), - ), - ), - ] else ...[ - const SizedBox(height: 28), - Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: onDecline, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), - side: const BorderSide(color: AppColors.slate300), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - '拒绝', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.slate600, - ), - ), - ), - ), - const SizedBox(width: 16), - Expanded( - child: ElevatedButton( - onPressed: onAccept, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.blue500, - elevation: 0, - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - '接受', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.white, - ), - ), - ), - ), - ], - ), - ], - SizedBox(height: MediaQuery.of(context).padding.bottom + 12), - ], - ), - ); - } -}