refactor(messages): use MessageActionSheet for all message types

This commit is contained in:
qzl
2026-03-11 21:04:51 +08:00
parent e99725400f
commit 98f22a2127
@@ -8,11 +8,11 @@ import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/page_header.dart'; import '../../../../shared/widgets/page_header.dart';
import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast.dart';
import '../../../../shared/widgets/toast/toast_type.dart'; import '../../../../shared/widgets/toast/toast_type.dart';
import '../../../../shared/widgets/app_button.dart';
import '../../../calendar/data/calendar_api.dart'; import '../../../calendar/data/calendar_api.dart';
import '../../../friends/data/friends_api.dart'; import '../../../friends/data/friends_api.dart';
import '../../../users/data/users_api.dart';
import '../../data/inbox_api.dart'; import '../../data/inbox_api.dart';
import '../../ui/widgets/calendar_message_card.dart'; import '../../ui/widgets/message_action_sheet.dart';
class MessageWithFriend { class MessageWithFriend {
final InboxMessageResponse message; final InboxMessageResponse message;
@@ -33,6 +33,7 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
late final InboxApi _inboxApi; late final InboxApi _inboxApi;
late final FriendsApi _friendsApi; late final FriendsApi _friendsApi;
late final CalendarApi _calendarApi; late final CalendarApi _calendarApi;
late final UsersApi _usersApi;
List<MessageWithFriend> _unreadMessages = []; List<MessageWithFriend> _unreadMessages = [];
List<MessageWithFriend> _readMessages = []; List<MessageWithFriend> _readMessages = [];
@@ -45,6 +46,7 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
_inboxApi = sl<InboxApi>(); _inboxApi = sl<InboxApi>();
_friendsApi = sl<FriendsApi>(); _friendsApi = sl<FriendsApi>();
_calendarApi = sl<CalendarApi>(); _calendarApi = sl<CalendarApi>();
_usersApi = sl<UsersApi>();
_loadMessages(); _loadMessages();
} }
@@ -115,14 +117,15 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
if (type == 'invite') { if (type == 'invite') {
if (message.status.value == 'pending') { if (message.status.value == 'pending') {
await _showCalendarInviteSheet(message); await _showCalendarInviteSheet(message);
} else if (message.status.value == 'accepted') { } else {
if (message.scheduleItemId != null) { await _showCalendarInviteReadOnlySheet(message);
context.push('/calendar/${message.scheduleItemId}'); if (message.scheduleItemId != null && context.mounted) {
context.push('/calendar/events/${message.scheduleItemId}');
} }
} }
} else if (type == 'update') { } else if (type == 'update') {
if (message.scheduleItemId != null) { if (message.scheduleItemId != null) {
context.push('/calendar/${message.scheduleItemId}'); context.push('/calendar/events/${message.scheduleItemId}');
} }
} }
return; return;
@@ -131,11 +134,7 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
Toast.show(context, '发送者信息加载失败,请下拉重试', type: ToastType.error); Toast.show(context, '发送者信息加载失败,请下拉重试', type: ToastType.error);
return; return;
} }
if (message.isRead) { _showFriendRequestSheet(item, isReadOnly: message.isRead);
_showFriendRequestReadOnlySheet(item);
} else {
_showFriendRequestActionSheet(item);
}
return; return;
case InboxMessageType.system: case InboxMessageType.system:
case InboxMessageType.group: case InboxMessageType.group:
@@ -152,41 +151,58 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
} }
} }
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<void> _showCalendarInviteSheet(InboxMessageResponse message) async { Future<void> _showCalendarInviteSheet(InboxMessageResponse message) async {
final itemId = message.scheduleItemId; final itemId = message.scheduleItemId;
if (itemId == null) return; if (itemId == null) return;
final info = await _getCalendarInviteInfo(message);
final title = info != null ? '${info.$2} 邀请你加入日历' : '日历邀请';
final description = info?.$1;
if (!mounted) return;
showModalBottomSheet<void>( showModalBottomSheet<void>(
context: context, context: context,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
builder: (ctx) => Container( builder: (ctx) => MessageActionSheet(
padding: const EdgeInsets.all(AppSpacing.lg), title: title,
decoration: const BoxDecoration( description: description,
color: AppColors.background, icon: Icons.calendar_today,
borderRadius: BorderRadius.vertical( iconColor: AppColors.blue500,
top: Radius.circular(AppRadius.lg), onAccept: () async {
), try {
), await _calendarApi.acceptSubscription(itemId);
child: Column( await _inboxApi.markAsRead(message.id);
mainAxisSize: MainAxisSize.min, if (mounted) {
children: [ Toast.show(context, '已接受', type: ToastType.success);
const Text( _loadMessages();
'日历邀请', }
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), } catch (e) {
), if (mounted) {
const SizedBox(height: AppSpacing.lg), Toast.show(context, '操作失败', type: ToastType.error);
Row( }
children: [ }
Expanded( },
child: AppButton( onDecline: () async {
text: '拒绝',
isOutlined: true,
onPressed: () async {
try { try {
await _calendarApi.rejectSubscription(itemId); await _calendarApi.rejectSubscription(itemId);
await _inboxApi.markAsRead(message.id); await _inboxApi.markAsRead(message.id);
if (mounted) { if (mounted) {
Navigator.pop(ctx);
Toast.show(context, '已拒绝', type: ToastType.success); Toast.show(context, '已拒绝', type: ToastType.success);
_loadMessages(); _loadMessages();
} }
@@ -197,71 +213,77 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
} }
}, },
), ),
),
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),
],
),
),
); );
} }
void _showFriendRequestReadOnlySheet(MessageWithFriend item) { Future<void> _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<void>( showModalBottomSheet<void>(
context: context, context: context,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
builder: (ctx) { builder: (ctx) => MessageActionSheet(
return _FriendRequestSheet( title: title,
message: item.message, description: description,
friendRequest: item.friendRequest!, statusText: statusText,
isReadOnly: true, 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<void>( showModalBottomSheet<void>(
context: context, context: context,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
isScrollControlled: true, isScrollControlled: true,
builder: (ctx) { builder: (ctx) => MessageActionSheet(
return _FriendRequestSheet( title: title,
message: item.message, description: description,
friendRequest: item.friendRequest!, statusText: statusText,
isReadOnly: false, isReadOnly: isReadOnly,
onAccept: () async { icon: Icons.person_add_outlined,
Navigator.pop(ctx); iconColor: AppColors.emerald500,
onAccept: isReadOnly
? null
: () async {
await _processFriendRequest(item, accept: true); await _processFriendRequest(item, accept: true);
}, },
onDecline: () async { onDecline: isReadOnly
Navigator.pop(ctx); ? null
: () async {
await _processFriendRequest(item, accept: false); await _processFriendRequest(item, accept: false);
}, },
); ),
},
); );
} }
@@ -601,149 +623,3 @@ class _MessageCard extends StatelessWidget {
return message.content ?? '点击查看详情'; 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),
],
),
);
}
}