import 'package:flutter/material.dart' hide BackButton; import '../../../../core/di/injection.dart'; import '../../../../core/theme/design_tokens.dart'; import '../../../../shared/widgets/app_button.dart'; import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; import '../../data/calendar_api.dart'; class CalendarShareDialog extends StatefulWidget { final String eventId; final String eventTitle; final bool canInvite; final bool canEdit; const CalendarShareDialog({ super.key, required this.eventId, required this.eventTitle, this.canInvite = false, this.canEdit = false, }); static Future show( BuildContext context, String eventId, String eventTitle, { bool canInvite = false, bool canEdit = false, }) { return showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => CalendarShareDialog( eventId: eventId, eventTitle: eventTitle, canInvite: canInvite, canEdit: canEdit, ), ); } @override State createState() => _CalendarShareDialogState(); } class _CalendarShareDialogState extends State { final _emailController = TextEditingController(); bool _permissionView = true; bool _permissionEdit = false; bool _permissionInvite = false; bool _isLoading = false; @override void dispose() { _emailController.dispose(); super.dispose(); } Future _handleShare() async { final email = _emailController.text.trim(); if (email.isEmpty) { Toast.show(context, '请输入邮箱地址', type: ToastType.error); return; } setState(() => _isLoading = true); try { final api = sl(); await api.share( widget.eventId, email: email, view: _permissionView, edit: _permissionEdit, invite: _permissionInvite, ); if (mounted) { Toast.show(context, '邀请已发送', type: ToastType.success); Navigator.of(context).pop(); } } catch (e) { if (mounted) { Toast.show(context, '发送邀请失败', type: ToastType.error); } } finally { if (mounted) { setState(() => _isLoading = false); } } } @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), decoration: BoxDecoration( color: AppColors.background, borderRadius: const BorderRadius.vertical( top: Radius.circular(AppRadius.lg), ), ), child: SafeArea( child: Padding( padding: const EdgeInsets.all(AppSpacing.lg), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( '分享日历', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), ), IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.close), ), ], ), const SizedBox(height: AppSpacing.md), Text(widget.eventTitle, style: const TextStyle(fontSize: 16)), const SizedBox(height: AppSpacing.lg), TextField( controller: _emailController, decoration: InputDecoration( labelText: '邮箱地址', hintText: '输入对方的邮箱', border: OutlineInputBorder( borderRadius: BorderRadius.circular(AppRadius.md), ), ), keyboardType: TextInputType.emailAddress, ), const SizedBox(height: AppSpacing.lg), const Text('权限设置', style: TextStyle(fontWeight: FontWeight.w600)), const SizedBox(height: AppSpacing.sm), _buildPermissionSwitch('查看', '可以查看此日历事件(必选)', true, null), _buildPermissionSwitch( '编辑', '可以编辑此日历事件', _permissionEdit, widget.canEdit ? (v) => setState(() => _permissionEdit = v) : null, ), _buildPermissionSwitch( '邀请', '可以邀请其他人', _permissionInvite, widget.canInvite ? (v) => setState(() => _permissionInvite = v) : null, ), const SizedBox(height: AppSpacing.lg), AppButton( text: '发送邀请', onPressed: _isLoading ? null : _handleShare, isLoading: _isLoading, ), ], ), ), ), ); } Widget _buildPermissionSwitch( String title, String description, bool value, ValueChanged? onChanged, ) { final enabled = onChanged != null; return Padding( padding: const EdgeInsets.symmetric(vertical: AppSpacing.xs), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle(color: enabled ? null : Colors.grey), ), Text( description, style: TextStyle( fontSize: 12, color: enabled ? Colors.grey : Colors.grey.shade400, ), ), ], ), ), Switch(value: value, onChanged: enabled ? onChanged : null), ], ), ); } }