feat(apps/calendar): 新增日历事件创建/编辑/分享功能

This commit is contained in:
zl-q
2026-03-19 00:51:51 +08:00
parent adccecd691
commit 14ccf2cb28
8 changed files with 959 additions and 654 deletions
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../../../core/router/app_routes.dart';
import '../../../home/ui/navigation/home_return_policy.dart';
import '../../../../core/di/injection.dart';
import '../../../../core/theme/design_tokens.dart';
@@ -14,7 +16,6 @@ import '../dayweek/day_event_layout_engine.dart';
import '../dayweek/day_timeline_metrics.dart';
import '../dayweek/day_view_scale.dart';
import '../widgets/bottom_dock.dart';
import '../widgets/create_event_sheet.dart';
class CalendarDayWeekScreen extends StatefulWidget {
final DateTime? initialDate;
@@ -118,7 +119,7 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (!didPop) {
context.go('/home');
returnToHomePreserveState(context);
}
},
child: SafeArea(
@@ -313,10 +314,8 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
if (isNotToday) const SizedBox(width: 8),
AppPressable(
borderRadius: BorderRadius.circular(AppRadius.full),
onTap: () => CreateEventSheet.show(
context,
initialDate: _selectedDate,
onSaved: _loadEvents,
onTap: () => context.push(
'${AppRoutes.calendarEventCreate}?date=${formatYmd(_selectedDate)}',
),
child: Container(
width: 36,
@@ -636,7 +635,8 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
height: tapHeight,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => context.push('/calendar/events/${layout.event.id}'),
onTap: () =>
context.push(AppRoutes.calendarEventDetail(layout.event.id)),
child: Stack(
children: [
Positioned(
@@ -696,13 +696,13 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
activeTab: DockTab.calendar,
onTodoTap: () {
_calendarManager.setViewType(CalendarViewType.day);
context.go('/todo');
context.push(AppRoutes.todoList);
},
onCalendarTap: () {
_calendarManager.setViewType(CalendarViewType.day);
context.go('/calendar/month');
context.push(AppRoutes.calendarMonth);
},
onHomeTap: () => context.go('/home'),
onHomeTap: () => returnToHomePreserveState(context),
);
}
}
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import '../../../../core/theme/design_tokens.dart';
import '../widgets/create_event_sheet.dart';
class CalendarEventCreateScreen extends StatelessWidget {
final DateTime? initialDate;
const CalendarEventCreateScreen({super.key, this.initialDate});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.background,
body: SafeArea(
child: CreateEventSheet(initialDate: initialDate, pageMode: true),
),
);
}
}
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/di/injection.dart';
import '../../../../core/router/app_routes.dart';
import '../../../../core/notifications/local_notification_service.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/app_loading_indicator.dart';
@@ -11,8 +12,6 @@ import '../../../../shared/widgets/destructive_action_sheet.dart';
import '../../data/services/calendar_service.dart';
import '../../data/models/schedule_item_model.dart';
import '../utils/event_color_resolver.dart';
import '../widgets/create_event_sheet.dart';
import '../widgets/calendar_share_dialog.dart';
enum _CalendarHeaderAction { edit, delete, share }
@@ -58,34 +57,50 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
}
if (_event == null) {
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC),
backgroundColor: AppColors.background,
body: SafeArea(
child: Center(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [AppColors.homeBackgroundTop, AppColors.background],
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Event not found',
style: TextStyle(color: AppColors.slate600),
),
const SizedBox(height: 16),
SizedBox(
height: AppSpacing.xxl * 2,
child: TextButton(
onPressed: () => context.pop(),
style: TextButton.styleFrom(
const BackTitlePageHeader(title: '日程详情'),
Expanded(
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
horizontal: AppSpacing.xl,
),
backgroundColor: AppColors.blue600,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.full),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'未找到该日程',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.slate700,
),
),
const SizedBox(height: AppSpacing.sm),
const Text(
'可能已被删除,或你没有访问权限。',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13,
color: AppColors.slate500,
),
),
],
),
),
child: const Text(
'返回',
style: TextStyle(color: AppColors.white),
),
),
),
],
@@ -97,15 +112,41 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
final event = _event!;
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC),
backgroundColor: AppColors.background,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildHeader(event),
Expanded(child: _buildDetailOverlay(event)),
_buildInputContainer(),
],
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [AppColors.homeBackgroundTop, AppColors.background],
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildHeader(event),
Expanded(
child: ListView(
padding: const EdgeInsets.fromLTRB(
AppSpacing.lg,
AppSpacing.sm,
AppSpacing.lg,
AppSpacing.xl,
),
children: [
_buildHeroSurface(event),
const SizedBox(height: AppSpacing.md),
_buildMetaSurface(event),
if (_hasExtraInfo(event)) ...[
const SizedBox(height: AppSpacing.md),
_buildExtraSurface(event),
],
],
),
),
],
),
),
),
);
@@ -123,7 +164,7 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
final items = <DetailHeaderActionItem<_CalendarHeaderAction>>[];
if (event.canEdit) {
items.add(
const DetailHeaderActionItem<_CalendarHeaderAction>(
DetailHeaderActionItem<_CalendarHeaderAction>(
value: _CalendarHeaderAction.edit,
label: '编辑',
icon: LucideIcons.pencil,
@@ -132,7 +173,7 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
}
if (event.canDelete) {
items.add(
const DetailHeaderActionItem<_CalendarHeaderAction>(
DetailHeaderActionItem<_CalendarHeaderAction>(
value: _CalendarHeaderAction.delete,
label: '删除',
icon: LucideIcons.trash2,
@@ -142,7 +183,7 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
}
if (event.canInvite) {
items.add(
const DetailHeaderActionItem<_CalendarHeaderAction>(
DetailHeaderActionItem<_CalendarHeaderAction>(
value: _CalendarHeaderAction.share,
label: '分享',
icon: LucideIcons.share2,
@@ -162,85 +203,220 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
) {
switch (action) {
case _CalendarHeaderAction.edit:
CreateEventSheet.edit(
context,
event,
onSaved: () {
setState(() {
_loadEvent();
});
},
);
context.push(AppRoutes.calendarEventEdit(event.id)).then((_) {
_loadEvent();
});
return;
case _CalendarHeaderAction.delete:
_showDeleteConfirmation();
return;
case _CalendarHeaderAction.share:
CalendarShareDialog.show(
context,
event.id,
event.title,
canInvite: event.canInvite,
canEdit: event.canEdit,
);
context.push(AppRoutes.calendarEventShare(event.id));
return;
}
}
Widget _buildDetailOverlay(ScheduleItemModel event) {
final startAt = event.startAt;
final endAt = event.endAt;
final dateStr =
'${startAt.year}${startAt.month}${startAt.day}${_getWeekday(startAt.weekday)}';
final timeStr = endAt != null
? '${_formatTime(startAt)} - ${_formatTime(endAt)}'
: _formatTime(startAt);
Widget _buildHeroSurface(ScheduleItemModel event) {
final color = resolveEventColor(
status: event.status,
colorHex: event.metadata?.color,
);
final timeRange = _formatRangeLabel(event.startAt, event.endAt);
return Padding(
padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 12),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
border: Border.all(color: const Color(0xFFD8E3F5)),
),
child: SingleChildScrollView(
child: SizedBox(
return Container(
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.circular(AppRadius.xl),
border: Border.all(color: AppColors.borderTertiary),
boxShadow: [
BoxShadow(
color: AppColors.slate200.withValues(alpha: 0.38),
blurRadius: AppRadius.lg,
offset: const Offset(0, AppSpacing.xs),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: AppSpacing.sm,
height: AppSpacing.xxl,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(AppRadius.full),
),
),
const SizedBox(width: AppSpacing.md),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
event.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: AppColors.slate900,
),
),
const SizedBox(height: AppSpacing.xs),
_buildStatusBadge(event.status),
],
),
),
],
),
const SizedBox(height: AppSpacing.md),
Container(
width: double.infinity,
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: AppColors.surfaceInfoLight,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(color: AppColors.borderQuaternary),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTitleRow(event),
const SizedBox(height: 14),
Container(height: 1, color: const Color(0xFFE5E7EB)),
const SizedBox(height: 14),
_buildDetailField('日期', dateStr),
const SizedBox(height: 14),
_buildDetailField('时间范围', timeStr),
const SizedBox(height: 14),
_buildDetailField(
'提醒时间',
_formatReminderText(event.metadata?.reminderMinutes),
const Text(
'时间安排',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.slate500,
),
),
const SizedBox(height: AppSpacing.xs),
Text(
timeRange,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
color: AppColors.slate800,
),
),
const SizedBox(height: 14),
_buildColorField(event),
const SizedBox(height: 14),
if (event.metadata?.location != null) ...[
_buildDetailField('地点', event.metadata!.location!),
const SizedBox(height: 14),
],
if (event.description != null) ...[
_buildDetailField('描述', event.description!),
const SizedBox(height: 14),
],
if (event.metadata?.notes != null) ...[
_buildNotesField(event.metadata!.notes!),
],
],
),
),
),
],
),
);
}
Widget _buildMetaSurface(ScheduleItemModel event) {
final startAt = event.startAt;
final dateStr =
'${startAt.year}${startAt.month}${startAt.day}${_getWeekday(startAt.weekday)}';
final color = resolveEventColor(
status: event.status,
colorHex: event.metadata?.color,
);
return Container(
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.circular(AppRadius.xl),
border: Border.all(color: AppColors.borderSecondary),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'基础信息',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.slate500,
),
),
const SizedBox(height: AppSpacing.md),
_buildDetailRow('日期', dateStr),
const SizedBox(height: AppSpacing.md),
_buildDetailRow(
'提醒',
_formatReminderText(event.metadata?.reminderMinutes),
),
const SizedBox(height: AppSpacing.md),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(
width: AppSpacing.xxl * 3,
child: Text(
'颜色',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.slate500,
),
),
),
Container(
width: AppSpacing.xl,
height: AppSpacing.xl,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
border: Border.all(color: AppColors.borderSecondary),
),
),
],
),
],
),
);
}
bool _hasExtraInfo(ScheduleItemModel event) {
return (event.metadata?.location?.trim().isNotEmpty ?? false) ||
(event.description?.trim().isNotEmpty ?? false) ||
(event.metadata?.notes?.trim().isNotEmpty ?? false);
}
Widget _buildExtraSurface(ScheduleItemModel event) {
return Container(
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: BoxDecoration(
color: AppColors.surfaceSecondary,
borderRadius: BorderRadius.circular(AppRadius.xl),
border: Border.all(color: AppColors.borderSecondary),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'补充信息',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.slate500,
),
),
if (event.metadata?.location?.trim().isNotEmpty ?? false) ...[
const SizedBox(height: AppSpacing.md),
_buildDetailRow('地点', event.metadata!.location!.trim()),
],
if (event.description?.trim().isNotEmpty ?? false) ...[
const SizedBox(height: AppSpacing.md),
_buildDetailRow('描述', event.description!.trim()),
],
if (event.metadata?.notes?.trim().isNotEmpty ?? false) ...[
const SizedBox(height: AppSpacing.md),
_buildDetailRow(
'备注',
event.metadata!.notes!.trim(),
multiline: true,
),
],
],
),
);
}
@@ -264,44 +440,6 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
return '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}';
}
Widget _buildTitleRow(ScheduleItemModel event) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 4,
height: 20,
decoration: BoxDecoration(
color: resolveEventColor(
status: event.status,
colorHex: event.metadata?.color,
),
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 10),
Flexible(
child: Text(
event.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: AppColors.slate900,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
),
],
);
}
Future<void> _showDeleteConfirmation() async {
final confirmed = await showDestructiveActionSheet(
context,
@@ -322,140 +460,76 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
context.pop();
}
Widget _buildDetailField(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.slate400,
),
),
const SizedBox(height: 4),
Text(
value,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: AppColors.slate900,
),
),
],
);
String _formatRangeLabel(DateTime startAt, DateTime? endAt) {
final dateLabel =
'${startAt.month}${startAt.day}${_getWeekday(startAt.weekday)}';
if (endAt == null) {
return '$dateLabel ${_formatTime(startAt)}';
}
return '$dateLabel ${_formatTime(startAt)} - ${_formatTime(endAt)}';
}
Widget _buildColorField(ScheduleItemModel event) {
final color = resolveEventColor(
status: event.status,
colorHex: event.metadata?.color,
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'日程颜色',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.slate400,
),
),
const SizedBox(height: 6),
Row(
children: [
Container(
width: 28,
height: 28,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
],
),
],
);
}
Widget _buildNotesField(String notes) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'备注',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.slate400,
),
),
const SizedBox(height: 6),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFFDFEFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFDCE5F4)),
),
child: Text(
notes,
style: const TextStyle(fontSize: 14, color: AppColors.slate700),
),
),
],
);
}
Widget _buildInputContainer() {
Widget _buildStatusBadge(ScheduleStatus status) {
final isArchived = status == ScheduleStatus.archived;
return Container(
height: 80,
padding: const EdgeInsets.all(16),
color: const Color(0xFFF8FAFC),
child: Row(
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(18),
border: Border.all(color: const Color(0xFFDCE5F4)),
),
child: const Icon(
LucideIcons.plus,
size: 20,
color: AppColors.slate500,
),
),
const SizedBox(width: 8),
Expanded(
child: Container(
height: 48,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
),
child: Row(
children: [
const Expanded(
child: Text(
'输入消息...',
style: TextStyle(fontSize: 14, color: AppColors.slate400),
),
),
const Icon(
LucideIcons.mic,
size: 20,
color: AppColors.slate500,
),
],
),
),
),
],
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.sm,
vertical: AppSpacing.xs,
),
decoration: BoxDecoration(
color: isArchived
? AppColors.feedbackWarningSurface
: AppColors.feedbackSuccessSurface,
borderRadius: BorderRadius.circular(AppRadius.full),
border: Border.all(
color: isArchived
? AppColors.feedbackWarningBorder
: AppColors.feedbackSuccessBorder,
),
),
child: Text(
isArchived ? '已过期' : '启用',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
color: isArchived
? AppColors.feedbackWarningText
: AppColors.feedbackSuccessText,
),
),
);
}
Widget _buildDetailRow(String label, String value, {bool multiline = false}) {
return Row(
crossAxisAlignment: multiline
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [
SizedBox(
width: AppSpacing.xxl * 3,
child: Text(
label,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.slate500,
),
),
),
const SizedBox(width: AppSpacing.sm),
Expanded(
child: Text(
value,
style: TextStyle(
fontSize: 14,
height: multiline ? 1.4 : 1.0,
fontWeight: FontWeight.w600,
color: AppColors.slate800,
),
),
),
],
);
}
}
@@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import '../../../../core/di/injection.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/app_loading_indicator.dart';
import '../widgets/create_event_sheet.dart';
import '../../data/models/schedule_item_model.dart';
import '../../data/services/calendar_service.dart';
class CalendarEventEditScreen extends StatefulWidget {
final String eventId;
const CalendarEventEditScreen({super.key, required this.eventId});
@override
State<CalendarEventEditScreen> createState() =>
_CalendarEventEditScreenState();
}
class _CalendarEventEditScreenState extends State<CalendarEventEditScreen> {
ScheduleItemModel? _event;
bool _loading = true;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
try {
_event = await sl<CalendarService>().getEventById(widget.eventId);
} catch (_) {
_event = null;
}
if (!mounted) {
return;
}
setState(() {
_loading = false;
});
}
@override
Widget build(BuildContext context) {
if (_loading) {
return const Scaffold(
body: SafeArea(child: Center(child: AppLoadingIndicator(size: 22))),
);
}
if (_event == null) {
return const Scaffold(
body: SafeArea(child: Center(child: Text('日程不存在或无权限'))),
);
}
return Scaffold(
backgroundColor: AppColors.background,
body: SafeArea(
child: CreateEventSheet(editingEvent: _event, pageMode: true),
),
);
}
}
@@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import '../../../../core/di/injection.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/app_loading_indicator.dart';
import '../../../../shared/widgets/back_title_page_header.dart';
import '../../data/models/schedule_item_model.dart';
import '../../data/services/calendar_service.dart';
import '../widgets/calendar_share_dialog.dart';
class CalendarEventShareScreen extends StatefulWidget {
final String eventId;
const CalendarEventShareScreen({super.key, required this.eventId});
@override
State<CalendarEventShareScreen> createState() =>
_CalendarEventShareScreenState();
}
class _CalendarEventShareScreenState extends State<CalendarEventShareScreen> {
ScheduleItemModel? _event;
bool _loading = true;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
try {
_event = await sl<CalendarService>().getEventById(widget.eventId);
} catch (_) {
_event = null;
}
if (!mounted) {
return;
}
setState(() {
_loading = false;
});
}
@override
Widget build(BuildContext context) {
if (_loading) {
return const Scaffold(
body: SafeArea(child: Center(child: AppLoadingIndicator(size: 22))),
);
}
final event = _event;
if (event == null) {
return const Scaffold(
body: SafeArea(child: Center(child: Text('日程不存在或无权限'))),
);
}
return Scaffold(
backgroundColor: AppColors.background,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const BackTitlePageHeader(title: '分享日程'),
Expanded(
child: CalendarShareDialog(
eventId: event.id,
eventTitle: event.title,
canInvite: event.canInvite,
canEdit: event.canEdit,
),
),
],
),
),
);
}
}
@@ -3,13 +3,14 @@ import 'package:flutter/cupertino.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../../../core/di/injection.dart';
import '../../../../core/router/app_routes.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/app_pressable.dart';
import '../../../home/ui/navigation/home_return_policy.dart';
import '../calendar_state_manager.dart';
import '../calendar_time_utils.dart';
import '../utils/event_color_resolver.dart';
import '../widgets/bottom_dock.dart';
import '../widgets/create_event_sheet.dart';
import '../../data/models/schedule_item_model.dart';
import '../../data/services/calendar_service.dart';
@@ -104,7 +105,7 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (!didPop) {
context.go('/home');
returnToHomePreserveState(context);
}
},
child: SafeArea(
@@ -171,10 +172,7 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
const Spacer(),
AppPressable(
borderRadius: BorderRadius.circular(AppRadius.full),
onTap: () => CreateEventSheet.show(
context,
onSaved: _loadMonthEvents,
),
onTap: () => context.push(AppRoutes.calendarEventCreate),
child: Container(
width: 36,
height: 36,
@@ -293,7 +291,9 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
});
_calendarManager.setSelectedDate(date);
_calendarManager.setViewType(CalendarViewType.month);
context.push('/calendar/dayweek?date=${formatYmd(date)}');
context.push(
'${AppRoutes.calendarDayWeek}?date=${formatYmd(date)}',
);
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 140),
@@ -400,7 +400,9 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
onTap: () {
_calendarManager.setSelectedDate(date);
_calendarManager.setViewType(CalendarViewType.day);
context.push('/calendar/dayweek?date=${formatYmd(date)}');
context.push(
'${AppRoutes.calendarDayWeek}?date=${formatYmd(date)}',
);
},
child: Text(
'+$remainingCount',
@@ -517,10 +519,10 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
activeTab: DockTab.calendar,
onTodoTap: () {
_calendarManager.setViewType(CalendarViewType.month);
context.go('/todo');
context.push(AppRoutes.todoList);
},
onCalendarTap: () {},
onHomeTap: () => context.go('/home'),
onHomeTap: () => returnToHomePreserveState(context),
);
}
}