refactor(messages): use MessageActionSheet for all message types
This commit is contained in:
@@ -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<MessageInviteListScreen> {
|
||||
late final InboxApi _inboxApi;
|
||||
late final FriendsApi _friendsApi;
|
||||
late final CalendarApi _calendarApi;
|
||||
late final UsersApi _usersApi;
|
||||
|
||||
List<MessageWithFriend> _unreadMessages = [];
|
||||
List<MessageWithFriend> _readMessages = [];
|
||||
@@ -45,6 +46,7 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
|
||||
_inboxApi = sl<InboxApi>();
|
||||
_friendsApi = sl<FriendsApi>();
|
||||
_calendarApi = sl<CalendarApi>();
|
||||
_usersApi = sl<UsersApi>();
|
||||
_loadMessages();
|
||||
}
|
||||
|
||||
@@ -115,14 +117,15 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
|
||||
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<MessageInviteListScreen> {
|
||||
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<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 {
|
||||
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<void>(
|
||||
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<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>(
|
||||
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<void>(
|
||||
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),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user