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/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,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 {
|
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: '拒绝',
|
try {
|
||||||
isOutlined: true,
|
await _calendarApi.rejectSubscription(itemId);
|
||||||
onPressed: () async {
|
await _inboxApi.markAsRead(message.id);
|
||||||
try {
|
if (mounted) {
|
||||||
await _calendarApi.rejectSubscription(itemId);
|
Toast.show(context, '已拒绝', type: ToastType.success);
|
||||||
await _inboxApi.markAsRead(message.id);
|
_loadMessages();
|
||||||
if (mounted) {
|
}
|
||||||
Navigator.pop(ctx);
|
} catch (e) {
|
||||||
Toast.show(context, '已拒绝', type: ToastType.success);
|
if (mounted) {
|
||||||
_loadMessages();
|
Toast.show(context, '操作失败', type: ToastType.error);
|
||||||
}
|
}
|
||||||
} 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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
await _processFriendRequest(item, accept: true);
|
onAccept: isReadOnly
|
||||||
},
|
? null
|
||||||
onDecline: () async {
|
: () async {
|
||||||
Navigator.pop(ctx);
|
await _processFriendRequest(item, accept: true);
|
||||||
await _processFriendRequest(item, accept: false);
|
},
|
||||||
},
|
onDecline: isReadOnly
|
||||||
);
|
? null
|
||||||
},
|
: () async {
|
||||||
|
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user