add_calendar 0.0.1
add_calendar: ^0.0.1 copied to clipboard
A Flutter plugin that invokes the native calendar app's "Add Event" page with prefilled fields, across Android, iOS, and HarmonyOS.
import 'package:add_calendar/add_calendar.dart';
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _addCalendarPlugin = AddCalendarPlugin();
final TextEditingController _titleController = TextEditingController(
text: 'Flutter 插件示例日程',
);
final TextEditingController _notesController = TextEditingController(
text: '这是一条由 plugindev 添加的测试日程',
);
final TextEditingController _reminderController = TextEditingController(
text: '5,15,30',
);
bool _allDay = false;
DateTime _startTime = DateTime.now().add(const Duration(hours: 1));
DateTime _endTime = DateTime.now().add(const Duration(hours: 2));
String _statusText = '';
@override
void dispose() {
_titleController.dispose();
_notesController.dispose();
_reminderController.dispose();
super.dispose();
}
Future<void> _pickStartTime() async {
final picked = await _showDateTimePicker(_startTime);
if (picked != null) {
setState(() {
_startTime = picked;
if (!_endTime.isAfter(_startTime)) {
_endTime = _startTime.add(const Duration(hours: 1));
}
});
}
}
Future<void> _pickEndTime() async {
final picked = await _showDateTimePicker(_endTime);
if (picked != null) {
setState(() {
_endTime = picked;
});
}
}
Future<DateTime?> _showDateTimePicker(DateTime initial) async {
final date = await showDatePicker(
context: context,
initialDate: initial,
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
if (date == null || !mounted) return null;
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(initial),
);
if (time == null) return null;
return DateTime(date.year, date.month, date.day, time.hour, time.minute);
}
Future<void> _requestPermission() async {
final granted = await _addCalendarPlugin.requestPermission();
setState(() {
_statusText = granted ? '权限已授予' : '权限被拒绝';
});
}
Future<void> _addEvent() async {
if (_titleController.text.trim().isEmpty) {
setState(() => _statusText = '标题不能为空');
return;
}
final reminders = _reminderController.text
.split(RegExp(r'[,,\s]+'))
.where((s) => s.isNotEmpty)
.map(int.tryParse)
.whereType<int>()
.where((n) => n > 0)
.toList();
final event = AddCalendarEvent(
title: _titleController.text.trim(),
startTimeMs: _startTime.millisecondsSinceEpoch,
endTimeMs: _endTime.millisecondsSinceEpoch,
allDay: _allDay,
notes: _notesController.text.trim().isEmpty
? null
: _notesController.text.trim(),
minutesBeforeList: reminders.isEmpty ? null : reminders,
);
final saved = await _addCalendarPlugin.addEvent(event);
setState(() => _statusText = saved ? '日程已添加' : '已取消或未保存');
}
String _formatDateTime(DateTime dt) {
String two(int n) => n.toString().padLeft(2, '0');
return '${dt.year}-${two(dt.month)}-${two(dt.day)} ${two(dt.hour)}:${two(dt.minute)}';
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('添加系统日历日程'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: _requestPermission,
child: const Text(
'申请日历权限',
style: TextStyle(color: Colors.black, fontSize: 16),
),
),
const SizedBox(height: 24),
const Text('标题', style: TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
TextField(
controller: _titleController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: '请输入日程标题',
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'开始时间',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: _pickStartTime,
child: Text(_formatDateTime(_startTime)),
),
],
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'结束时间',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: _pickEndTime,
child: Text(_formatDateTime(_endTime)),
),
],
),
),
],
),
const SizedBox(height: 16),
SwitchListTile(
contentPadding: EdgeInsets.zero,
title: const Text('全天事件'),
value: _allDay,
onChanged: (v) => setState(() => _allDay = v),
),
const SizedBox(height: 8),
const Text(
'提醒(提前分钟数,逗号分隔)',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
TextField(
controller: _reminderController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: '例:5,15,30',
),
),
const SizedBox(height: 16),
const Text('备注', style: TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
TextField(
controller: _notesController,
maxLines: 3,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: '请输入备注',
),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: _addEvent,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
),
child: const Text(
'添加日程到系统日历',
style: TextStyle(color: Colors.black, fontSize: 16),
),
),
const SizedBox(height: 24),
if (_statusText.isNotEmpty)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Text(_statusText),
),
const SizedBox(height: 40),
],
),
),
),
);
}
}