feat: 实现日历提醒 in-app fallback 机制及通知服务重构
This commit is contained in:
@@ -4,6 +4,7 @@ import '../../../../core/di/injection.dart';
|
||||
import '../../../../core/notifications/local_notification_service.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_loading_indicator.dart';
|
||||
import '../../../../shared/widgets/app_selection_sheet.dart';
|
||||
import '../../../../shared/widgets/app_sheet_input_field.dart';
|
||||
import '../../../../shared/widgets/back_title_page_header.dart';
|
||||
import '../../../../shared/widgets/toast/toast.dart';
|
||||
@@ -107,12 +108,21 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
||||
event.metadata?.reminderMinutes,
|
||||
);
|
||||
} else {
|
||||
final now =
|
||||
widget.initialDate ?? _roundToNearestMinute(DateTime.now(), 5);
|
||||
_startDate = now;
|
||||
_startTime = now;
|
||||
_endDate = now;
|
||||
_endTime = now.add(const Duration(hours: 1));
|
||||
final now = DateTime.now();
|
||||
final initial = widget.initialDate;
|
||||
final rounded = _roundToNearestMinute(now, 5);
|
||||
_startDate = initial != null
|
||||
? DateTime(
|
||||
initial.year,
|
||||
initial.month,
|
||||
initial.day,
|
||||
rounded.hour,
|
||||
rounded.minute,
|
||||
)
|
||||
: rounded;
|
||||
_startTime = _startDate;
|
||||
_endDate = _startDate;
|
||||
_endTime = _startDate.add(const Duration(hours: 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,15 +149,19 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.pageMode) {
|
||||
return Container(
|
||||
color: AppColors.background,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_buildPageHeader(),
|
||||
_buildTabBar(),
|
||||
Expanded(child: _buildTabContent()),
|
||||
],
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: Container(
|
||||
color: AppColors.background,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_buildPageHeader(),
|
||||
_buildTabBar(),
|
||||
Expanded(child: _buildTabContent()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -331,12 +345,7 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTextField(
|
||||
'标题',
|
||||
_titleController,
|
||||
'请输入日程标题',
|
||||
autofocus: !_isEditing,
|
||||
),
|
||||
_buildTextField('标题', _titleController, '请输入日程标题'),
|
||||
const SizedBox(height: 20),
|
||||
_buildDateTimePicker('开始', _startDate, _startTime, (date, time) {
|
||||
setState(() {
|
||||
@@ -580,7 +589,6 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
||||
}
|
||||
|
||||
Widget _buildReminderPicker() {
|
||||
final options = _buildReminderOptions();
|
||||
String labelOf(int? value) {
|
||||
if (value == null) {
|
||||
return '无提醒';
|
||||
@@ -603,37 +611,51 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(color: AppColors.border),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<int?>(
|
||||
value: _reminderMinutes,
|
||||
isExpanded: true,
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final options = _buildReminderOptions();
|
||||
final selected = await showAppSelectionSheet<int?>(
|
||||
context,
|
||||
title: '选择提醒时间',
|
||||
items: options
|
||||
.map(
|
||||
(value) => DropdownMenuItem<int?>(
|
||||
value: value,
|
||||
child: Text(
|
||||
labelOf(value),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppColors.slate700,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.map((v) => AppSelectionItem(value: v, label: labelOf(v)))
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_reminderMinutes = value;
|
||||
});
|
||||
},
|
||||
selectedValue: _reminderMinutes,
|
||||
);
|
||||
if (selected != null) {
|
||||
setState(() {
|
||||
_reminderMinutes = selected;
|
||||
});
|
||||
}
|
||||
},
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(AppSpacing.md),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.slate50,
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
border: Border.all(color: AppColors.borderSecondary),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
labelOf(_reminderMinutes),
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.slate900,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: AppColors.slate400,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -54,7 +54,7 @@ class _DateTimePickerSheetState extends State<DateTimePickerSheet> {
|
||||
if (_selectedYear == minDate.year &&
|
||||
_selectedMonth == minDate.month &&
|
||||
_selectedDay == minDate.day) {
|
||||
return _allHours.where((h) => h > minDate.hour).toList();
|
||||
return _allHours.where((h) => h >= minDate.hour).toList();
|
||||
}
|
||||
return _allHours;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ class _DateTimePickerSheetState extends State<DateTimePickerSheet> {
|
||||
_selectedMonth == minDate.month &&
|
||||
_selectedDay == minDate.day &&
|
||||
_selectedHour == minDate.hour) {
|
||||
return _allMinutes.where((m) => m > minDate.minute).toList();
|
||||
return _allMinutes.where((m) => m >= minDate.minute).toList();
|
||||
}
|
||||
return _allMinutes;
|
||||
}
|
||||
@@ -100,6 +100,12 @@ class _DateTimePickerSheetState extends State<DateTimePickerSheet> {
|
||||
_hourController = FixedExtentScrollController(
|
||||
initialItem: _filteredHours.indexOf(_selectedHour),
|
||||
);
|
||||
|
||||
if (_filteredMinutes.isEmpty) {
|
||||
_selectedMinute = 0;
|
||||
} else if (!_filteredMinutes.contains(_selectedMinute)) {
|
||||
_selectedMinute = _filteredMinutes.first;
|
||||
}
|
||||
_minuteController = FixedExtentScrollController(
|
||||
initialItem: _filteredMinutes.indexOf(_selectedMinute),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user