feat(apps): 更新消息邀请详情和认证流程路由
This commit is contained in:
@@ -4,6 +4,7 @@ import 'package:formz/formz.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../../core/router/app_routes.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_button.dart';
|
||||
import '../../../../shared/widgets/banner/app_banner.dart';
|
||||
@@ -59,7 +60,7 @@ class _LoginViewState extends State<LoginView> {
|
||||
final response = await cubit.submit();
|
||||
if (response != null && mounted) {
|
||||
context.read<AuthBloc>().add(AuthLoggedIn(user: response.user));
|
||||
context.go('/home');
|
||||
context.go(AppRoutes.homeMain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:formz/formz.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../../core/router/app_routes.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_button.dart';
|
||||
import '../../../../shared/widgets/banner/app_banner.dart';
|
||||
@@ -93,7 +94,7 @@ class _RegisterVerificationViewState extends State<RegisterVerificationView> {
|
||||
final response = await cubit.submitStep2();
|
||||
if (response != null && mounted) {
|
||||
context.read<AuthBloc>().add(AuthLoggedIn(user: response.user));
|
||||
context.go('/home');
|
||||
context.go(AppRoutes.homeMain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import 'package:flutter/material.dart' hide BackButton;
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_loading_indicator.dart';
|
||||
import '../../../../shared/widgets/page_header.dart';
|
||||
import '../../../../shared/widgets/toast/toast.dart';
|
||||
import '../../../../shared/widgets/toast/toast_type.dart';
|
||||
import '../../../calendar/data/calendar_api.dart';
|
||||
import '../../../users/data/users_api.dart';
|
||||
import '../../data/inbox_api.dart';
|
||||
|
||||
class MessageInviteDetailScreen extends StatefulWidget {
|
||||
const MessageInviteDetailScreen({super.key});
|
||||
final String inviteId;
|
||||
|
||||
const MessageInviteDetailScreen({super.key, required this.inviteId});
|
||||
|
||||
@override
|
||||
State<MessageInviteDetailScreen> createState() =>
|
||||
@@ -12,16 +22,155 @@ class MessageInviteDetailScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
final _reasonController = TextEditingController();
|
||||
late final InboxApi _inboxApi;
|
||||
late final CalendarApi _calendarApi;
|
||||
late final UsersApi _usersApi;
|
||||
|
||||
InboxMessageResponse? _message;
|
||||
String? _calendarTitle;
|
||||
String? _senderName;
|
||||
bool _loading = true;
|
||||
bool _submitting = false;
|
||||
String? _error;
|
||||
|
||||
bool get _isPending => _message?.status == InboxMessageStatus.pending;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_reasonController.dispose();
|
||||
super.dispose();
|
||||
void initState() {
|
||||
super.initState();
|
||||
_inboxApi = sl<InboxApi>();
|
||||
_calendarApi = sl<CalendarApi>();
|
||||
_usersApi = sl<UsersApi>();
|
||||
_loadDetail();
|
||||
}
|
||||
|
||||
Future<void> _loadDetail() async {
|
||||
setState(() {
|
||||
_loading = true;
|
||||
_error = null;
|
||||
});
|
||||
|
||||
try {
|
||||
final results = await Future.wait([
|
||||
_inboxApi.getMessages(isRead: false),
|
||||
_inboxApi.getMessages(isRead: true),
|
||||
]);
|
||||
final messages = [...results[0], ...results[1]];
|
||||
InboxMessageResponse? message;
|
||||
for (final item in messages) {
|
||||
if (item.id == widget.inviteId) {
|
||||
message = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (message == null) {
|
||||
throw StateError('邀请不存在或已失效');
|
||||
}
|
||||
|
||||
String? calendarTitle;
|
||||
if (message.scheduleItemId != null) {
|
||||
try {
|
||||
final event = await _calendarApi.getById(message.scheduleItemId!);
|
||||
calendarTitle = event.title;
|
||||
} catch (_) {
|
||||
calendarTitle = null;
|
||||
}
|
||||
}
|
||||
|
||||
String? senderName;
|
||||
if (message.senderId != null) {
|
||||
try {
|
||||
final sender = await _usersApi.getById(message.senderId!);
|
||||
senderName = sender.username;
|
||||
} catch (_) {
|
||||
senderName = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_message = message;
|
||||
_calendarTitle = calendarTitle;
|
||||
_senderName = senderName;
|
||||
_loading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_error = e.toString().replaceFirst('Bad state: ', '');
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _acceptInvite() async {
|
||||
final message = _message;
|
||||
final itemId = message?.scheduleItemId;
|
||||
if (message == null || itemId == null || _submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _submitting = true);
|
||||
try {
|
||||
await _calendarApi.acceptSubscription(itemId);
|
||||
await _inboxApi.markAsRead(message.id);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
Toast.show(context, '已接受邀请', type: ToastType.success);
|
||||
await _loadDetail();
|
||||
} catch (_) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
Toast.show(context, '操作失败,请稍后重试', type: ToastType.error);
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _submitting = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _rejectInvite() async {
|
||||
final message = _message;
|
||||
final itemId = message?.scheduleItemId;
|
||||
if (message == null || itemId == null || _submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _submitting = true);
|
||||
try {
|
||||
await _calendarApi.rejectSubscription(itemId);
|
||||
await _inboxApi.markAsRead(message.id);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
Toast.show(context, '已拒绝邀请', type: ToastType.success);
|
||||
await _loadDetail();
|
||||
} catch (_) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
Toast.show(context, '操作失败,请稍后重试', type: ToastType.error);
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _submitting = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_loading) {
|
||||
return const Scaffold(
|
||||
body: SafeArea(child: Center(child: AppLoadingIndicator(size: 22))),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.messageBg,
|
||||
body: SafeArea(
|
||||
@@ -40,8 +189,16 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
_buildCalendarTip(),
|
||||
const SizedBox(height: 14),
|
||||
_buildActionRow(),
|
||||
if (_error != null) ...[
|
||||
const SizedBox(height: 14),
|
||||
_buildRejectReasonCard(),
|
||||
Text(
|
||||
_error!,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.feedbackErrorText,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -53,6 +210,21 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
}
|
||||
|
||||
Widget _buildSummaryCard() {
|
||||
final message = _message;
|
||||
final statusText = message == null
|
||||
? '未知'
|
||||
: switch (message.status) {
|
||||
InboxMessageStatus.pending => '待处理',
|
||||
InboxMessageStatus.accepted => '已接受',
|
||||
InboxMessageStatus.rejected => '已拒绝',
|
||||
InboxMessageStatus.dismissed => '已处理',
|
||||
};
|
||||
|
||||
final createdAt = message?.createdAt;
|
||||
final createdAtText = createdAt == null
|
||||
? '未知'
|
||||
: '${createdAt.year}-${createdAt.month.toString().padLeft(2, '0')}-${createdAt.day.toString().padLeft(2, '0')} ${createdAt.hour.toString().padLeft(2, '0')}:${createdAt.minute.toString().padLeft(2, '0')}';
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(14),
|
||||
@@ -63,8 +235,8 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Text(
|
||||
children: [
|
||||
const Text(
|
||||
'日历邀请详情',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
@@ -72,46 +244,46 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
color: AppColors.slate900,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'事件:产品评审会',
|
||||
style: TextStyle(
|
||||
'事件:${_calendarTitle ?? '未命名日程'}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.slate700,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'邀请人:李文浩(产品经理)',
|
||||
style: TextStyle(
|
||||
'邀请人:${_senderName ?? '未知用户'}',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.slate500,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'时间:2026-02-12 14:00 - 15:30',
|
||||
style: TextStyle(
|
||||
'消息时间:$createdAtText',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.slate500,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'地点:3F-A 会议室 / 腾讯会议 231-889-100',
|
||||
style: TextStyle(
|
||||
'状态:$statusText',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.slate500,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'备注:请提前准备本周版本风险与排期结论。',
|
||||
style: TextStyle(
|
||||
'邀请ID:${widget.inviteId}',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.slate500,
|
||||
@@ -131,13 +303,13 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.messageTipBorder),
|
||||
),
|
||||
child: Row(
|
||||
children: const [
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.info_outline, size: 14, color: AppColors.slate500),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'更多附件与相关链接,请在订阅后在日历中查看',
|
||||
'同意后将加入该日历事件,拒绝后该邀请会被标记为已处理',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
@@ -151,22 +323,43 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
}
|
||||
|
||||
Widget _buildActionRow() {
|
||||
if (!_isPending) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.messageCardBg,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.messageCardBorder),
|
||||
),
|
||||
child: const Text(
|
||||
'该邀请已处理,无需重复操作',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.slate600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
height: 46,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: _handleReject,
|
||||
onTap: _submitting ? null : _rejectInvite,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.messageCardBg,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.messageRejectBorder),
|
||||
),
|
||||
child: Row(
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
children: [
|
||||
Text(
|
||||
'×',
|
||||
style: TextStyle(
|
||||
@@ -192,16 +385,16 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: _handleAccept,
|
||||
onTap: _submitting ? null : _acceptInvite,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.messageTagBg,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.messageAcceptBorder),
|
||||
),
|
||||
child: Row(
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
children: [
|
||||
Text(
|
||||
'√',
|
||||
style: TextStyle(
|
||||
@@ -228,66 +421,4 @@ class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRejectReasonCard() {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.messageCardBg,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: AppColors.messageReasonBorder),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'拒绝补充信息(可选)',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.slate600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 92,
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.messageBtnWrap,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: AppColors.messageInputBorder),
|
||||
),
|
||||
child: TextField(
|
||||
controller: _reasonController,
|
||||
maxLines: null,
|
||||
expands: true,
|
||||
style: const TextStyle(fontSize: 12, color: AppColors.slate700),
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: '可填写拒绝原因,例如:该时间段已有客户会议,无法参加。',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.messagePlaceholder,
|
||||
),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleReject() {
|
||||
final reason = _reasonController.text;
|
||||
debugPrint('Reject with reason: $reason');
|
||||
context.pop();
|
||||
}
|
||||
|
||||
void _handleAccept() {
|
||||
debugPrint('Accept invitation');
|
||||
context.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,14 @@ import 'package:flutter/material.dart' hide BackButton;
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../../core/router/app_routes.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_loading_indicator.dart';
|
||||
import '../../../../shared/widgets/app_pull_refresh_feedback.dart';
|
||||
import '../../../../shared/widgets/page_header.dart';
|
||||
import '../../../../shared/widgets/toast/toast.dart';
|
||||
import '../../../../shared/widgets/toast/toast_type.dart';
|
||||
import '../../../calendar/data/calendar_api.dart';
|
||||
import '../../../calendar/data/models/schedule_item_model.dart';
|
||||
import '../../../friends/data/friends_api.dart';
|
||||
import '../../../users/data/models/user_response.dart';
|
||||
import '../../../users/data/users_api.dart';
|
||||
import '../../data/inbox_api.dart';
|
||||
import '../../ui/widgets/message_action_sheet.dart';
|
||||
|
||||
@@ -34,8 +31,6 @@ class MessageInviteListScreen extends StatefulWidget {
|
||||
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 = [];
|
||||
@@ -48,8 +43,6 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
|
||||
super.initState();
|
||||
_inboxApi = sl<InboxApi>();
|
||||
_friendsApi = sl<FriendsApi>();
|
||||
_calendarApi = sl<CalendarApi>();
|
||||
_usersApi = sl<UsersApi>();
|
||||
_loadMessages();
|
||||
}
|
||||
|
||||
@@ -144,14 +137,12 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
|
||||
|
||||
final type = content['type'] as String?;
|
||||
if (type == 'invite') {
|
||||
if (message.status.value == 'pending') {
|
||||
await _showCalendarInviteSheet(message);
|
||||
} else {
|
||||
await _showCalendarInviteReadOnlySheet(message);
|
||||
}
|
||||
context.push(AppRoutes.messageInviteDetail(message.id));
|
||||
} else if (type == 'update') {
|
||||
if (message.scheduleItemId != null) {
|
||||
context.push('/calendar/events/${message.scheduleItemId}');
|
||||
context.push(
|
||||
AppRoutes.calendarEventDetail(message.scheduleItemId!),
|
||||
);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -172,103 +163,6 @@ class _MessageInviteListScreenState extends State<MessageInviteListScreen> {
|
||||
return content;
|
||||
}
|
||||
|
||||
Future<(String calendarTitle, String senderName)?> _getCalendarInviteInfo(
|
||||
InboxMessageResponse message,
|
||||
) async {
|
||||
if (message.scheduleItemId == null || message.senderId == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final result = await Future.wait([
|
||||
_calendarApi.getById(message.scheduleItemId!),
|
||||
_usersApi.getById(message.senderId!),
|
||||
]);
|
||||
final calendar = result[0] as ScheduleItemModel;
|
||||
final sender = result[1] as UserResponse;
|
||||
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) => 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);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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) => MessageActionSheet(
|
||||
title: title,
|
||||
description: description,
|
||||
statusText: statusText,
|
||||
isReadOnly: true,
|
||||
icon: Icons.calendar_today,
|
||||
iconColor: AppColors.blue500,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showFriendRequestSheet(
|
||||
MessageWithFriend item, {
|
||||
bool isReadOnly = false,
|
||||
|
||||
Reference in New Issue
Block a user