From d5ff4c9b02f8572c5772688c13c6a8b78575670f Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Sat, 8 Nov 2025 22:06:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=8F=90=E9=86=92?= =?UTF-8?q?=E4=BA=8B=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle.kts | 8 + android/app/src/main/AndroidManifest.xml | 22 + android/app/src/profile/AndroidManifest.xml | 2 +- lib/layout/app_drawer.dart | 79 ++- lib/layout/main_screen.dart | 20 +- lib/main.dart | 20 +- lib/models/reminder.dart | 58 ++ lib/models/reminder.g.dart | 56 ++ lib/models/todo.dart | 7 +- lib/models/todo.g.dart | 2 +- lib/pages/flash_page.dart | 39 +- lib/pages/notes_page.dart | 28 - lib/pages/reminders_page.dart | 173 +++++- lib/pages/todo_page.dart | 28 +- lib/provider/reminder_provider.dart | 18 + lib/service/reminder_service.dart | 39 ++ lib/utils/date_utils.dart | 10 +- lib/utils/notify_utils.dart | 146 ++++++ lib/widgets/reminder_form.dart | 208 ++++++++ lib/widgets/reminder_widget.dart | 96 ++++ lib/widgets/todo_form.dart | 43 +- lib/widgets/todo_widget.dart | 43 +- linux/flutter/generated_plugin_registrant.cc | 8 + linux/flutter/generated_plugins.cmake | 2 + macos/Flutter/GeneratedPluginRegistrant.swift | 10 + pubspec.lock | 496 +++++++++++++++++- pubspec.yaml | 2 +- test/widget_test.dart | 18 - .../flutter/generated_plugin_registrant.cc | 6 + windows/flutter/generated_plugins.cmake | 2 + 30 files changed, 1490 insertions(+), 199 deletions(-) create mode 100644 lib/models/reminder.dart create mode 100644 lib/models/reminder.g.dart delete mode 100644 lib/pages/notes_page.dart create mode 100644 lib/provider/reminder_provider.dart create mode 100644 lib/service/reminder_service.dart create mode 100644 lib/utils/notify_utils.dart create mode 100644 lib/widgets/reminder_form.dart create mode 100644 lib/widgets/reminder_widget.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index aa2d6c9..7737df2 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -13,6 +13,9 @@ android { compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 + + // 启用核心库脱糖 + isCoreLibraryDesugaringEnabled = true } kotlinOptions { @@ -39,6 +42,11 @@ android { } } +dependencies { + // 添加核心库脱糖依赖 + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") +} + flutter { source = "../.." } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b5a3ee0..b5eeeb8 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -27,6 +27,17 @@ + + + + + + + + + + + @@ -42,4 +53,15 @@ + + + + + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 399f698..95cdb6c 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -3,5 +3,5 @@ the Flutter tool needs it to communicate with the running application to allow setting breakpoints, to provide hot reload, etc. --> - + diff --git a/lib/layout/app_drawer.dart b/lib/layout/app_drawer.dart index 67ef4df..b2fb453 100644 --- a/lib/layout/app_drawer.dart +++ b/lib/layout/app_drawer.dart @@ -6,6 +6,35 @@ import '../provider/app_provider.dart'; class AppDrawer extends StatelessWidget { const AppDrawer({super.key}); + DrawerHeader buildDrawerHeader() { + return DrawerHeader( + decoration: BoxDecoration(color: Colors.blue.shade700), + child: const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 30, + backgroundColor: Colors.white, + child: Icon(Icons.flash_on, color: Colors.blue, size: 40), + ), + SizedBox(height: 10), + Text( + '闪灵', + style: TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + Text( + '记录每一刻的灵感', + style: TextStyle(color: Colors.white70, fontSize: 14), + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { return Drawer( @@ -13,41 +42,7 @@ class AppDrawer extends StatelessWidget { padding: EdgeInsets.zero, children: [ // 抽屉头部 - DrawerHeader( - decoration: BoxDecoration( - color: Colors.blue.shade700, - ), - child: const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - CircleAvatar( - radius: 30, - backgroundColor: Colors.white, - child: Icon( - Icons.flash_on, - color: Colors.blue, - size: 40, - ), - ), - SizedBox(height: 10), - Text( - '闪灵', - style: TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - Text( - '记录每一刻的灵感', - style: TextStyle( - color: Colors.white70, - fontSize: 14, - ), - ), - ], - ), - ), + buildDrawerHeader(), // 菜单项 _buildDrawerItem( @@ -58,20 +53,12 @@ class AppDrawer extends StatelessWidget { Provider.of(context, listen: false).changeTab(0); }, ), - _buildDrawerItem( - icon: Icons.note, - title: '笔记', - onTap: () { - Navigator.pop(context); - Provider.of(context, listen: false).changeTab(1); - }, - ), _buildDrawerItem( icon: Icons.checklist, title: '待办事项', onTap: () { Navigator.pop(context); - Provider.of(context, listen: false).changeTab(2); + Provider.of(context, listen: false).changeTab(1); }, ), _buildDrawerItem( @@ -79,7 +66,7 @@ class AppDrawer extends StatelessWidget { title: '提醒任务', onTap: () { Navigator.pop(context); - Provider.of(context, listen: false).changeTab(3); + Provider.of(context, listen: false).changeTab(2); }, ), @@ -137,4 +124,4 @@ class AppDrawer extends StatelessWidget { onTap: onTap, ); } -} \ No newline at end of file +} diff --git a/lib/layout/main_screen.dart b/lib/layout/main_screen.dart index 45596e5..cd14454 100644 --- a/lib/layout/main_screen.dart +++ b/lib/layout/main_screen.dart @@ -1,6 +1,5 @@ import 'package:flisp_app/layout/app_drawer.dart'; import 'package:flisp_app/pages/flash_page.dart'; -import 'package:flisp_app/pages/notes_Page.dart'; import 'package:flisp_app/pages/reminders_page.dart'; import 'package:flisp_app/pages/todo_page.dart'; import 'package:flisp_app/provider/app_provider.dart'; @@ -16,10 +15,10 @@ class MainScreen extends StatefulWidget { class _MainScreenState extends State { final GlobalKey _todoPageKey = GlobalKey(); + final GlobalKey _reminderPageKey = GlobalKey(); List navItems = [ BottomNavigationBarItem(icon: Icon(Icons.flash_on), label: '闪灵'), - BottomNavigationBarItem(icon: Icon(Icons.note), label: '笔记'), BottomNavigationBarItem(icon: Icon(Icons.checklist), label: '待办'), BottomNavigationBarItem(icon: Icon(Icons.notifications), label: '提醒'), ]; @@ -51,9 +50,14 @@ class _MainScreenState extends State { } void _onPressFloatingButton(int index) { - if (index == 2) { + print(index); + if (index == 1) { if (_todoPageKey.currentState != null) { - _todoPageKey.currentState!.showAddTodoDialog(); + _todoPageKey.currentState!.showAddDialog(); + } + } else if (index == 2) { + if (_reminderPageKey.currentState != null) { + _reminderPageKey.currentState!.showAddDialog(); } } } @@ -92,18 +96,16 @@ class _MainScreenState extends State { case 0: return const FlashPage(); case 1: - return const NotesPage(); + return TodoPage(key: _todoPageKey); case 2: - return TodoPage(key: _todoPageKey); // 传递 key - case 3: - return const RemindersPage(); + return RemindersPage(key: _reminderPageKey); default: return const FlashPage(); } } String _getAppBarTitle(int index) { - final titles = {0: '闪灵', 1: '笔记', 2: '待办', 3: '提醒'}; + final titles = {0: '闪灵', 1: '待办', 2: '提醒'}; return titles[index] ?? '闪灵'; } } diff --git a/lib/main.dart b/lib/main.dart index c358e6a..2be61ab 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,11 @@ +import 'package:flisp_app/models/reminder.dart'; import 'package:flisp_app/provider/app_provider.dart'; +import 'package:flisp_app/provider/reminder_provider.dart'; +import 'package:flisp_app/utils/notify_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_quill/flutter_quill.dart'; import 'package:hive_flutter/adapters.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'layout/main_screen.dart'; @@ -11,16 +14,25 @@ import 'provider/todo_provider.dart'; void main() async{ WidgetsFlutterBinding.ensureInitialized(); + // 初始化提醒服务 + final notifyService = NotifyService(); + await notifyService.initialize(); + // 初始化Hive await Hive.initFlutter(); // 注册适配器 Hive.registerAdapter(TodoAdapter()); + Hive.registerAdapter(ReminderAdapter()); // 打开Box final todosBox = await Hive.openBox('todos'); + // todosBox.clear(); - todosBox.clear(); + final remindersBox = await Hive.openBox('reminders'); + // remindersBox.clear(); + + // notifyService.cancelAllNotifications(); runApp(const MyApp()); } @@ -33,7 +45,8 @@ class MyApp extends StatelessWidget { return MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => AppProvider()), - ChangeNotifierProvider(create: (_) => TodoProvider()), // 新增 + ChangeNotifierProvider(create: (_) => TodoProvider()), + ChangeNotifierProvider(create: (_) => ReminderProvider()), ], child: MaterialApp( title: '闪灵', @@ -41,6 +54,7 @@ class MyApp extends StatelessWidget { GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + FlutterQuillLocalizations.delegate, ], supportedLocales: [ const Locale('zh'), diff --git a/lib/models/reminder.dart b/lib/models/reminder.dart new file mode 100644 index 0000000..5add4fd --- /dev/null +++ b/lib/models/reminder.dart @@ -0,0 +1,58 @@ +import 'package:hive/hive.dart'; +// flutter packages pub run build_runner build +part 'reminder.g.dart'; + +@HiveType(typeId: 1) +class Reminder extends HiveObject { + @HiveField(0) + late int id; + + @HiveField(1) + late String title; + + @HiveField(2) + late String content; + + @HiveField(3) + late DateTime scheduledTime; + + @HiveField(4) + late DateTime createTime; + + @HiveField(5) + late DateTime updateTime; + + Reminder({ + int? id, + required this.title, + required this.content, + required this.scheduledTime, + DateTime? createTime, + DateTime? updateTime, + }) { + // 简单时间戳ID + this.id = id ?? DateTime.now().millisecondsSinceEpoch ~/ 1000; + this.createTime = createTime ?? DateTime.now(); + this.updateTime = updateTime ?? DateTime.now(); + } + + Reminder copyWith({String? title, String? content, DateTime? scheduledTime}) { + return Reminder( + id: id, + title: title ?? this.title, + content: content ?? this.content, + scheduledTime: scheduledTime ?? this.scheduledTime, + createTime: createTime, + updateTime: DateTime.now(), + ); + } + + static Reminder getEmpty() { + return Reminder( + id: DateTime.now().millisecondsSinceEpoch ~/ 1000, + title: '日常提醒', + content: '', + scheduledTime: DateTime.now().add(Duration(minutes: 5)), + ); + } +} diff --git a/lib/models/reminder.g.dart b/lib/models/reminder.g.dart new file mode 100644 index 0000000..89ab40f --- /dev/null +++ b/lib/models/reminder.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'reminder.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ReminderAdapter extends TypeAdapter { + @override + final int typeId = 1; + + @override + Reminder read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return Reminder( + id: fields[0] as int?, + title: fields[1] as String, + content: fields[2] as String, + scheduledTime: fields[3] as DateTime, + createTime: fields[4] as DateTime?, + updateTime: fields[5] as DateTime?, + ); + } + + @override + void write(BinaryWriter writer, Reminder obj) { + writer + ..writeByte(6) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.title) + ..writeByte(2) + ..write(obj.content) + ..writeByte(3) + ..write(obj.scheduledTime) + ..writeByte(4) + ..write(obj.createTime) + ..writeByte(5) + ..write(obj.updateTime); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ReminderAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/models/todo.dart b/lib/models/todo.dart index 2929301..84d0c36 100644 --- a/lib/models/todo.dart +++ b/lib/models/todo.dart @@ -30,6 +30,7 @@ class Todo extends HiveObject { late DateTime updateTime; TodoPriority get priority => TodoPriority.values[priorityIndex]; + set priority(TodoPriority value) => priorityIndex = value.index; Todo({ @@ -43,7 +44,7 @@ class Todo extends HiveObject { DateTime? updateTime, }) { // 简单时间戳ID - this.id = id ?? DateTime.now().millisecondsSinceEpoch; + this.id = id ?? DateTime.now().millisecondsSinceEpoch ~/ 1000; this.priorityIndex = priority.index; this.createTime = createTime ?? DateTime.now(); this.updateTime = updateTime ?? DateTime.now(); @@ -70,8 +71,8 @@ class Todo extends HiveObject { static Todo getEmpty() { return Todo( - id: DateTime.now().millisecondsSinceEpoch, - title: '', + id: DateTime.now().millisecondsSinceEpoch ~/ 1000, + title: '日常待办', content: '', isCompleted: false, dueDate: null, diff --git a/lib/models/todo.g.dart b/lib/models/todo.g.dart index 4d29ff3..426a7cd 100644 --- a/lib/models/todo.g.dart +++ b/lib/models/todo.g.dart @@ -17,7 +17,7 @@ class TodoAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return Todo( - id: fields[0] as int, + id: fields[0] as int?, title: fields[1] as String, content: fields[2] as String, isCompleted: fields[3] as bool, diff --git a/lib/pages/flash_page.dart b/lib/pages/flash_page.dart index 6446222..092ccd5 100644 --- a/lib/pages/flash_page.dart +++ b/lib/pages/flash_page.dart @@ -1,25 +1,42 @@ import 'package:flisp_app/widgets/common.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_quill/flutter_quill.dart'; -class FlashPage extends StatelessWidget { +class FlashPage extends StatefulWidget { const FlashPage({super.key}); + @override + _FlashPageState createState() => _FlashPageState(); +} + +class _FlashPageState extends State { + late QuillController _controller; + + @override + void initState() { + super.initState(); + _controller = QuillController.basic(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { return buildBody( child: Column( - mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.flash_on, size: 80, color: Colors.blue), - SizedBox(height: 20), - Text( - '闪灵', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + QuillSimpleToolbar( + controller: _controller, + config: const QuillSimpleToolbarConfig(), ), - SizedBox(height: 10), - Text( - '快速记录你的灵感瞬间', - style: TextStyle(fontSize: 16, color: Colors.grey), + Expanded( + child: QuillEditor.basic( + controller: _controller, + config: const QuillEditorConfig(), + ), ), ], ), diff --git a/lib/pages/notes_page.dart b/lib/pages/notes_page.dart deleted file mode 100644 index 0b6b148..0000000 --- a/lib/pages/notes_page.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flisp_app/widgets/common.dart'; -import 'package:flutter/material.dart'; - -class NotesPage extends StatelessWidget { - const NotesPage({super.key}); - - @override - Widget build(BuildContext context) { - return buildBody( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.note, size: 80, color: Colors.green), - SizedBox(height: 20), - Text( - '笔记', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - SizedBox(height: 10), - Text( - '管理你的所有笔记', - style: TextStyle(fontSize: 16, color: Colors.grey), - ), - ], - ), - ); - } -} \ No newline at end of file diff --git a/lib/pages/reminders_page.dart b/lib/pages/reminders_page.dart index cb88931..47f46ea 100644 --- a/lib/pages/reminders_page.dart +++ b/lib/pages/reminders_page.dart @@ -1,28 +1,171 @@ -import 'package:flisp_app/widgets/common.dart'; +import 'package:flisp_app/models/reminder.dart'; +import 'package:flisp_app/provider/reminder_provider.dart'; +import 'package:flisp_app/service/reminder_service.dart'; +import 'package:flisp_app/utils/notify_utils.dart'; +import 'package:flisp_app/widgets/awesome_dialog.dart'; +import 'package:flisp_app/widgets/reminder_form.dart'; +import 'package:flisp_app/widgets/reminder_widget.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:provider/provider.dart'; +import 'package:flisp_app/widgets/common.dart'; -class RemindersPage extends StatelessWidget { - const RemindersPage({super.key}); +class RemindersPage extends StatefulWidget { + final VoidCallback? onAddPressed; + + const RemindersPage({super.key, this.onAddPressed}); + + @override + State createState() => ReminderPageState(); +} + +class ReminderPageState extends State { + final ReminderService reminderService = ReminderService(); + final NotifyService notifyService = NotifyService(); + + List _reminders = []; + + void showAddDialog() { + _showDialog(false, null); + } + + @override + void initState() { + super.initState(); + _loadReminders(); + } + + Future _loadReminders() async { + final reminders = await updateReminders(); + if (mounted) { + setState(() { + _reminders = reminders; + }); + } + } + + Future> updateReminders() async { + // 获取flutter_local_notifications中所有的通知ID + final pendingNotifications = await notifyService.getPendingNotifications(); + print("notifyService: ${pendingNotifications.length}"); + final notificationIds = pendingNotifications.map((n) => n.id).toSet(); + + // 获取Hive中所有的提醒 + final hiveReminders = reminderService.getAllReminders(); + print("hiveReminders: ${hiveReminders.length}"); + final hiveReminderIds = hiveReminders.map((r) => r.id).toSet(); + + // 情况1:删除Hive中存在但通知中不存在的提醒(已触发或已取消) + final remindersToDeleteFromHive = + hiveReminders.where((reminder) { + return !notificationIds.contains(reminder.id); + }).toList(); + + for (final reminder in remindersToDeleteFromHive) { + await reminderService.deleteReminder(reminder); + } + + // 情况2:对于通知中存在但Hive中不存在的提醒,重新创建(保留时间等完整信息) + final remindersToRecreate = + pendingNotifications.where((notification) { + return !hiveReminderIds.contains(notification.id); + }).toList(); + + for (final notification in remindersToRecreate) { + final newReminder = Reminder( + id: notification.id, + title: notification.title ?? '新提醒', + content: notification.body ?? '', + scheduledTime: DateTime.now().add(const Duration(days: 1)), + ); + await reminderService.addReminder(newReminder); + } + + // 更新本地列表 + _reminders = reminderService.getAllReminders(); + + return _reminders; + } @override Widget build(BuildContext context) { return buildBody( child: Column( - mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.notifications, size: 80, color: Colors.red), - SizedBox(height: 20), - Text( - '提醒任务', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - SizedBox(height: 10), - Text( - '设置重要提醒', - style: TextStyle(fontSize: 16, color: Colors.grey), + Expanded( + child: buildReminderList( + reminders: _reminders, + onEditReminder: (reminder) { + _showDialog(true, reminder); + }, + ), ), ], ), ); } -} \ No newline at end of file + + // 显示对话框 + void _showDialog(bool isEditing, Reminder? reminder) { + final reminderProvider = Provider.of( + context, + listen: false, + ); + + if (isEditing) { + reminderProvider.initForm(reminder!); + } else { + reminderProvider.resetForm(); + } + + final formKey = GlobalKey(); + + showAwesomeDialog( + context: context, + body: ReminderForm( + formKey: formKey, + isEditing: isEditing, + initialReminder: reminder, + ), + onOk: () { + if (formKey.currentState!.saveAndValidate()) { + Navigator.of(context).pop(); + _saveOrUpdateReminder(isEditing, reminderProvider.formItem); + } + }, + onCancel: () { + reminderProvider.resetForm(); + }, + ); + } + + // 保存提醒事项 + void _saveOrUpdateReminder(bool isEditing, Reminder reminder) async { + late bool isSuccess; + + if (isEditing) { + // 先删除 + await notifyService.cancelNotification(reminder.id); + await reminderService.deleteReminder(reminder); + // 在重新新建 + reminder.id = DateTime.now().millisecondsSinceEpoch ~/ 1000; + } + + isSuccess = await reminderService.addReminder(reminder); + + await notifyService.scheduleNotification( + id: reminder.id, + title: reminder.title, + body: reminder.content, + scheduledTime: reminder.scheduledTime, + ); + + await _loadReminders(); + + if (isSuccess) { + showSuccessDialog(context, isEditing ? '更新成功' : '添加成功'); + } else { + showErrorDialog(context, isEditing ? '更新失败' : '添加失败'); + } + } +} diff --git a/lib/pages/todo_page.dart b/lib/pages/todo_page.dart index 0315afe..d3e559e 100644 --- a/lib/pages/todo_page.dart +++ b/lib/pages/todo_page.dart @@ -28,8 +28,8 @@ class TodoPageState extends State { // 获取过滤后的待办事项 List get _activeTodos => getActiveTodos(_currentTab, _todos); - void showAddTodoDialog() { - _showTodoDialog(false, null); + void showAddDialog() { + _showDialog(false, null); } @override @@ -65,16 +65,16 @@ class TodoPageState extends State { return _activeTodos.isEmpty ? buildEmptyState(_currentTab) : buildTodoList( - todos: _activeTodos, - onToggleTodo: (todo) { - setState(() { - _toggleTodo(todo); - }); - }, - onEditTodo: (todo) { - _showTodoDialog(true, todo); - }, - ); + todos: _activeTodos, + onToggleTodo: (todo) { + setState(() { + _toggleTodo(todo); + }); + }, + onEditTodo: (todo) { + _showDialog(true, todo); + }, + ); } // 切换待办事项完成状态 @@ -85,7 +85,7 @@ class TodoPageState extends State { } // 显示对话框 - void _showTodoDialog(bool isEditing, Todo? todo) { + void _showDialog(bool isEditing, Todo? todo) { final todoProvider = Provider.of(context, listen: false); if (isEditing) { @@ -113,7 +113,7 @@ class TodoPageState extends State { // 保存待办事项 void _saveTodo(bool isEditing, Todo todo) async { - late bool isSuccess ; + late bool isSuccess; if (isEditing) { isSuccess = await todoService.updateTodo(todo); } else { diff --git a/lib/provider/reminder_provider.dart b/lib/provider/reminder_provider.dart new file mode 100644 index 0000000..5af5722 --- /dev/null +++ b/lib/provider/reminder_provider.dart @@ -0,0 +1,18 @@ +import 'package:flisp_app/models/reminder.dart'; +import 'package:flutter/material.dart'; + +class ReminderProvider with ChangeNotifier { + late Reminder _formItem; + + Reminder get formItem => _formItem; + + void resetForm() { + _formItem = Reminder.getEmpty(); + notifyListeners(); + } + + void initForm(Reminder reminder) { + _formItem = reminder; + notifyListeners(); + } +} diff --git a/lib/service/reminder_service.dart b/lib/service/reminder_service.dart new file mode 100644 index 0000000..d48b3d1 --- /dev/null +++ b/lib/service/reminder_service.dart @@ -0,0 +1,39 @@ +import 'package:flisp_app/models/reminder.dart'; +import 'package:hive_flutter/hive_flutter.dart'; + +class ReminderService { + static const String boxName = 'reminders'; + + Box get box => Hive.box(boxName); + + Future addReminder(Reminder reminder) async { + try { + await box.add(reminder); + return true; + } catch (e) { + return false; + } + } + + List getAllReminders() { + return box.values.toList(); + } + + Future updateReminder(Reminder reminder) async { + try { + await reminder.save(); + return true; + } catch (e) { + return false; + } + } + + Future deleteReminder(Reminder reminder) async { + try { + await reminder.delete(); + return true; + } catch (e) { + return false; + } + } +} diff --git a/lib/utils/date_utils.dart b/lib/utils/date_utils.dart index d92aa43..378e608 100644 --- a/lib/utils/date_utils.dart +++ b/lib/utils/date_utils.dart @@ -1,3 +1,7 @@ -String formatDate(DateTime date) { - return '${date.month}月${date.day}日'; -} \ No newline at end of file +// String formatDate(DateTime date) { +// return '${date.month}月${date.day}日'; +// } +// +// String formatTime(DateTime datetime) { +// return '${datetime.year}-${datetime.month}-${datetime.day} ${datetime.hour}:${datetime.minute}:${datetime.second}'; +// } diff --git a/lib/utils/notify_utils.dart b/lib/utils/notify_utils.dart new file mode 100644 index 0000000..0afb9a6 --- /dev/null +++ b/lib/utils/notify_utils.dart @@ -0,0 +1,146 @@ +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:timezone/data/latest_all.dart' as tz; +import 'package:timezone/timezone.dart' as tz; + +class NotifyService { + static final NotifyService _instance = NotifyService._internal(); + + factory NotifyService() => _instance; + + NotifyService._internal(); + + late FlutterLocalNotificationsPlugin _notifications; + + // 使用绝对时间(而不是相对时间),避免时区转换问题。 + final dateInterpretation = UILocalNotificationDateInterpretation.absoluteTime; + + // Android特殊模式,即使设备处于省电模式也能准时触发。 + final scheduleMode = AndroidScheduleMode.exactAllowWhileIdle; + + // 初始化通知服务 + Future initialize() async { + _notifications = FlutterLocalNotificationsPlugin(); + + // 初始化时区 + tz.initializeTimeZones(); + // String timeZoneName = await FlutterNativeTimezone.getLocalTimezone(); + tz.setLocalLocation(tz.getLocation("Asia/Shanghai")); + + // 设置Android平台的初始化配置 使用应用图标作为通知图标 + const AndroidInitializationSettings androidSettings = + AndroidInitializationSettings('@mipmap/ic_launcher'); + + // 设置iOS平台的初始化配置 + const DarwinInitializationSettings iosSettings = + DarwinInitializationSettings( + requestAlertPermission: true, + requestBadgePermission: true, + requestSoundPermission: true, + ); + + // 初始化设置 + const InitializationSettings settings = InitializationSettings( + android: androidSettings, + iOS: iosSettings, + ); + + await _notifications.initialize(settings); + } + + // 创建Android通知详情 + AndroidNotificationDetails _androidNotificationDetails() { + const channelId = 'com.cxx.flisp_app'; + const channelName = '闪灵'; + const channelDescription = '闪灵通知'; + return const AndroidNotificationDetails( + channelId, + channelName, + channelDescription: channelDescription, + importance: Importance.high, + priority: Priority.high, + playSound: true, + enableVibration: true, + ); + } + + // 创建iOS通知详情 + DarwinNotificationDetails _iosNotificationDetails() { + return const DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + } + + NotificationDetails get _details { + return NotificationDetails( + android: _androidNotificationDetails(), + iOS: _iosNotificationDetails(), + ); + } + + // 立即显示通知 + Future showInstantNotification({ + required String title, + required String body, + int id = 0, + }) async { + await _notifications.show(id, title, body, _details); + } + + // 安排定时通知 + Future scheduleNotification({ + required int id, + required String title, + required String body, + required DateTime scheduledTime, + }) async { + print("scheduleNotification: $id"); + await _notifications.zonedSchedule( + id, + title, + body, + tz.TZDateTime.from(scheduledTime, tz.local), + _details, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, + ); + } + + // 取消特定通知 + Future cancelNotification(int id) async { + print("cancelNotification: $id"); + await _notifications.cancel(id); + } + + // 取消所有通知 + Future cancelAllNotifications() async { + await _notifications.cancelAll(); + } + + // 检查通知权限 + Future checkPermission() async { + final bool? result = + await _notifications + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin + >() + ?.areNotificationsEnabled(); + return result ?? false; + } + + // 请求权限 + Future requestPermission() async { + await _notifications + .resolvePlatformSpecificImplementation< + IOSFlutterLocalNotificationsPlugin + >() + ?.requestPermissions(alert: true, badge: true, sound: true); + } + + // 获取所有待处理的通知 + Future> getPendingNotifications() async { + return await _notifications.pendingNotificationRequests(); + } +} diff --git a/lib/widgets/reminder_form.dart b/lib/widgets/reminder_form.dart new file mode 100644 index 0000000..4163f36 --- /dev/null +++ b/lib/widgets/reminder_form.dart @@ -0,0 +1,208 @@ +import 'package:flisp_app/models/reminder.dart'; +import 'package:flisp_app/provider/reminder_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:flisp_app/utils/date_utils.dart'; + +class ReminderForm extends StatefulWidget { + final GlobalKey formKey; + final bool isEditing; + final Reminder? initialReminder; + + const ReminderForm({ + super.key, + required this.formKey, + required this.isEditing, + this.initialReminder, + }); + + @override + State createState() => _ReminderFormState(); +} + +class _ReminderFormState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + final int maxTitleCount = 10; + final int maxContentCount = 20; + final provider = Provider.of(context); + + Widget buildTitle() { + return Row( + children: [ + Icon( + widget.isEditing ? Icons.edit_note : Icons.add_task, + color: Colors.orange, + size: 24, + ), + SizedBox(width: 8), + Text( + widget.isEditing ? '编辑提醒事项' : '添加提醒事项', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.orange, + ), + ), + ], + ); + } + + FormBuilderTextField buildTitleField() { + return FormBuilderTextField( + name: 'title', + initialValue: provider.formItem.title, + onChanged: (value) { + setState(() { + provider.formItem.title = value ?? ''; + }); + }, + decoration: InputDecoration( + labelText: '标题', + hintText: '请输入提醒事项标题...', + counterText: '', + suffixText: '${provider.formItem.title.length}/$maxTitleCount', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.orange), + ), + filled: true, + fillColor: Colors.white, + prefixIcon: Icon(Icons.title, color: Colors.blue), + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), + ), + maxLength: maxTitleCount, + validator: (value) { + if (value == null || value.isEmpty) { + return '请输入标题'; + } + if (value.length > maxTitleCount) { + return '标题不能超过$maxTitleCount个字符'; + } + return null; + }, + ); + } + + FormBuilderTextField buildContentField() { + return FormBuilderTextField( + name: 'content', + initialValue: provider.formItem.content, + onChanged: (value) { + setState(() { + provider.formItem.content = value ?? ''; + }); + }, + decoration: InputDecoration( + labelText: '内容', + hintText: '请输入提醒事项内容...', + counterText: '', + suffixText: '${provider.formItem.content.length}/$maxContentCount', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.orange), + ), + filled: true, + fillColor: Colors.white, + prefixIcon: Icon(Icons.description, color: Colors.green), + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), + ), + maxLines: 2, + maxLength: maxContentCount, + validator: (value) { + if (value != null && value.length > maxContentCount) { + return '内容不能超过$maxContentCount个字符'; + } + return null; + }, + ); + } + + FormBuilderDateTimePicker buildDateField() { + return FormBuilderDateTimePicker( + name: 'dueDate', + format: DateFormat('yyyy-MM-dd HH:mm:ss'), + initialValue: provider.formItem.scheduledTime, + inputType: InputType.both, + onChanged: (value) { + setState(() { + provider.formItem.scheduledTime = value!; + }); + }, + decoration: InputDecoration( + labelText: '提醒时间', + labelStyle: TextStyle(color: Colors.black87), + prefixIcon: Icon(Icons.calendar_today, color: Colors.purple), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: Colors.orange), + ), + filled: true, + fillColor: Colors.white, + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), + ), + validator: (value) { + if (value != null && value.isBefore(DateTime.now())) { + return '不能选择过去的时间'; + } + return null; + }, + ); + } + + FormBuilder buildForm() { + return FormBuilder( + key: widget.formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + buildTitleField(), + SizedBox(height: 12), + buildContentField(), + SizedBox(height: 12), + buildDateField(), + ], + ), + ); + } + + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [buildTitle(), SizedBox(height: 20), buildForm()], + ), + ); + } +} diff --git a/lib/widgets/reminder_widget.dart b/lib/widgets/reminder_widget.dart new file mode 100644 index 0000000..ed7c61e --- /dev/null +++ b/lib/widgets/reminder_widget.dart @@ -0,0 +1,96 @@ +import 'package:flisp_app/models/reminder.dart'; +import 'package:flisp_app/widgets/common.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +Widget buildReminderList({ + required List reminders, + required ValueChanged onEditReminder, +}) { + return ListView.separated( + itemCount: reminders.length, + separatorBuilder: (context, index) => SizedBox(height: 8), + itemBuilder: (context, index) { + final reminder = reminders[index]; + return _buildReminderItem(reminder: reminder, onEdit: onEditReminder); + }, + ); +} + +Widget _buildReminderItem({ + required Reminder reminder, + required ValueChanged onEdit, +}) { + return buildCard( + child: ListTile( + contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 0), + leading: Icon(Icons.notifications, color: Colors.blue), + title: _buildReminderTitle(reminder), + subtitle: _buildReminderSubtitle(reminder), + onTap: () => onEdit(reminder), + ), + ); +} + +Widget _buildReminderTitle(Reminder reminder) { + return Text( + reminder.title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ); +} + +Widget _buildReminderSubtitle(Reminder reminder) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 4), + Text( + reminder.content, + style: TextStyle( + fontSize: 14, + color: Colors.grey[700], + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 8), + Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.blue[50], + borderRadius: BorderRadius.circular(4), + ), + child: Text( + DateFormat('MM月dd日 HH:mm').format(reminder.scheduledTime), + style: TextStyle( + fontSize: 12, + color: Colors.blue[700], + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ); +} + +// 空状态 +Widget buildEmptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.task_alt, size: 80, color: Colors.orange.shade600), + Text( + '📋 还没有任何待办事项\n点击下方+号开始规划你的任务吧!', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.orange.shade600), + ), + ], + ), + ); +} diff --git a/lib/widgets/todo_form.dart b/lib/widgets/todo_form.dart index 24a096d..7e2e96a 100644 --- a/lib/widgets/todo_form.dart +++ b/lib/widgets/todo_form.dart @@ -1,9 +1,9 @@ import 'package:flisp_app/provider/todo_provider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:flisp_app/models/todo.dart'; -import 'package:flisp_app/utils/date_utils.dart'; class TodoForm extends StatefulWidget { final GlobalKey formKey; @@ -31,7 +31,7 @@ class _TodoFormState extends State { Widget build(BuildContext context) { final int maxTitleCount = 10; final int maxContentCount = 20; - final store = Provider.of(context); + final provider = Provider.of(context); Widget buildTitle() { return Row( @@ -57,17 +57,17 @@ class _TodoFormState extends State { FormBuilderTextField buildTitleField() { return FormBuilderTextField( name: 'title', - initialValue: store.formItem.title, + initialValue: provider.formItem.title, onChanged: (value) { setState(() { - store.formItem.title = value ?? ''; + provider.formItem.title = value ?? ''; }); }, decoration: InputDecoration( labelText: '标题', hintText: '请输入待办事项标题...', counterText: '', - suffixText: '${store.formItem.title.length}/$maxTitleCount', + suffixText: '${provider.formItem.title.length}/$maxTitleCount', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), @@ -98,20 +98,20 @@ class _TodoFormState extends State { ); } - FormBuilderTextField buildDescriptionField() { + FormBuilderTextField buildContentField() { return FormBuilderTextField( - name: 'description', - initialValue: store.formItem.content, + name: 'content', + initialValue: provider.formItem.content, onChanged: (value) { setState(() { - store.formItem.content = value ?? ''; + provider.formItem.content = value ?? ''; }); }, decoration: InputDecoration( labelText: '内容', hintText: '请输入待办事项内容...', counterText: '', - suffixText: '${store.formItem.content.length}/$maxContentCount', + suffixText: '${provider.formItem.content.length}/$maxContentCount', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), @@ -145,7 +145,7 @@ class _TodoFormState extends State { icon: Icon(Icons.clear, size: 18), onPressed: () { setState(() { - store.formItem.dueDate = null; + provider.formItem.dueDate = null; }); widget.formKey.currentState?.fields['dueDate']?.didChange(null); }, @@ -155,21 +155,24 @@ class _TodoFormState extends State { FormBuilderDateTimePicker buildDateField() { return FormBuilderDateTimePicker( name: 'dueDate', - initialValue: store.formItem.dueDate, + format: DateFormat('yyyy-MM-dd'), + initialValue: provider.formItem.dueDate, inputType: InputType.date, onChanged: (value) { setState(() { - store.formItem.dueDate = value; + provider.formItem.dueDate = value; }); }, decoration: InputDecoration( labelText: - store.formItem.dueDate == null + provider.formItem.dueDate == null ? '选择截止日期' - : '截止: ${formatDate(store.formItem.dueDate!)}', + : '截止: ${DateFormat('yyyy-MM-dd').format(provider.formItem.dueDate!)}', labelStyle: TextStyle( color: - store.formItem.dueDate == null ? Colors.grey : Colors.black87, + provider.formItem.dueDate == null + ? Colors.grey + : Colors.black87, ), prefixIcon: Icon(Icons.calendar_today, color: Colors.purple), border: OutlineInputBorder( @@ -188,7 +191,7 @@ class _TodoFormState extends State { fillColor: Colors.white, contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), suffixIcon: - store.formItem.dueDate != null + provider.formItem.dueDate != null ? buildClearDateSuffixIcon() : null, ), @@ -205,7 +208,7 @@ class _TodoFormState extends State { FormBuilderRadioGroup builderRadioGroup() { return FormBuilderRadioGroup( name: 'priority', - initialValue: store.formItem.priority, + initialValue: provider.formItem.priority, decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.zero, @@ -225,7 +228,7 @@ class _TodoFormState extends State { onChanged: (value) { if (value != null) { setState(() { - store.formItem.priority = value; + provider.formItem.priority = value; }); } }, @@ -264,7 +267,7 @@ class _TodoFormState extends State { children: [ buildTitleField(), SizedBox(height: 12), - buildDescriptionField(), + buildContentField(), SizedBox(height: 12), buildDateField(), SizedBox(height: 12), diff --git a/lib/widgets/todo_widget.dart b/lib/widgets/todo_widget.dart index 2bc6867..b761588 100644 --- a/lib/widgets/todo_widget.dart +++ b/lib/widgets/todo_widget.dart @@ -1,7 +1,7 @@ import 'package:flisp_app/models/todo.dart'; -import 'package:flisp_app/utils/date_utils.dart'; import 'package:flisp_app/widgets/common.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:toggle_switch/toggle_switch.dart'; // 统计卡片 @@ -119,6 +119,7 @@ Widget _buildTodoTitle(Todo todo) { style: TextStyle( decoration: todo.isCompleted ? TextDecoration.lineThrough : null, color: todo.isCompleted ? Colors.grey : null, + fontSize: 16, fontWeight: FontWeight.w500, ), ); @@ -128,31 +129,45 @@ Widget _buildTodoTitle(Todo todo) { Widget? _buildTodoSubtitle(Todo todo) { final isOverdue = todo.dueDate != null && - todo.dueDate!.isBefore(DateTime.now()) && - !todo.isCompleted; + todo.dueDate!.isBefore(DateTime.now()) && + !todo.isCompleted; final hasContent = todo.content.isNotEmpty == true || todo.dueDate != null; if (!hasContent) return null; - return Wrap( - direction: Axis.vertical, - spacing: 5, + return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox(height: 4), if (todo.content.isNotEmpty == true) Text( todo.content, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 12, color: Colors.grey.shade600), - ), - if (todo.dueDate != null) - Text( - '截止: ${formatDate(todo.dueDate!)}', style: TextStyle( - fontSize: 11, - color: isOverdue ? Colors.red : Colors.grey, - fontWeight: isOverdue ? FontWeight.bold : FontWeight.normal, + fontSize: 14, + color: Colors.grey[700], + ), + ), + SizedBox(height: 8), + if (todo.dueDate != null) + Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration( + color: isOverdue ? Colors.red[50] : Colors.grey[50], + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: isOverdue ? Colors.red[100]! : Colors.grey[300]!, + ), + ), + child: Text( + '截止: ${DateFormat("yyyy-MM-dd").format(todo.dueDate!)}', + style: TextStyle( + fontSize: 11, + color: isOverdue ? Colors.red[600] : Colors.grey[600], + fontWeight: isOverdue ? FontWeight.w600 : FontWeight.normal, + ), ), ), ], diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 92ce211..41d3d2c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,18 @@ #include "generated_plugin_registrant.h" +#include #include +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) rive_native_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin"); rive_native_plugin_register_with_registrar(rive_native_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b7557d4..e2b0ef4 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,7 +3,9 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux rive_native + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 37b91af..8ef3b11 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,22 @@ import FlutterMacOS import Foundation +import file_selector_macos +import flutter_local_notifications import path_provider_foundation +import quill_native_bridge_macos import rive_native import shared_preferences_foundation +import url_launcher_macos +import video_player_avfoundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin")) RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 00c75f5..bfae732 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -58,10 +58,10 @@ packages: dependency: transitive description: name: build - sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.4" + version: "2.4.2" build_config: dependency: transitive description: @@ -82,26 +82,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.4" + version: "2.4.4" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" + sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.4" + version: "2.4.14" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" url: "https://pub.flutter-io.cn" source: hosted - version: "9.1.2" + version: "8.0.0" built_collection: dependency: transitive description: @@ -126,6 +126,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -166,6 +174,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.5" crypto: dependency: transitive description: @@ -174,6 +190,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" cupertino_icons: dependency: "direct main" description: @@ -182,6 +206,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.8" + dart_quill_delta: + dependency: transitive + description: + name: dart_quill_delta + sha256: bddb0b2948bd5b5a328f1651764486d162c59a8ccffd4c63e8b2c5e44be1dac4 + url: "https://pub.flutter-io.cn" + source: hosted + version: "10.8.3" dart_style: dependency: transitive description: @@ -190,6 +222,22 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.3.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.11" + diff_match_patch: + dependency: transitive + description: + name: diff_match_patch + sha256: "2efc9e6e8f449d0abe15be240e2c2a3bcd977c8d126cfd70598aee60af35c0a4" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.1" fake_async: dependency: transitive description: @@ -214,6 +262,38 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.4+4" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.3+4" fixnum: dependency: transitive description: @@ -227,6 +307,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_colorpicker: + dependency: transitive + description: + name: flutter_colorpicker + sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" flutter_form_builder: dependency: "direct main" description: @@ -235,6 +323,46 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "10.0.1" + flutter_keyboard_visibility_linux: + dependency: transitive + description: + name: flutter_keyboard_visibility_linux + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_macos: + dependency: transitive + description: + name: flutter_keyboard_visibility_macos + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_temp_fork: + dependency: transitive + description: + name: flutter_keyboard_visibility_temp_fork + sha256: e3d02900640fbc1129245540db16944a0898b8be81694f4bf04b6c985bed9048 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.5" + flutter_keyboard_visibility_windows: + dependency: transitive + description: + name: flutter_keyboard_visibility_windows + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" flutter_lints: dependency: "direct dev" description: @@ -243,11 +371,67 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "5.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: ef41ae901e7529e52934feba19ed82827b11baa67336829564aeab3129460610 + url: "https://pub.flutter-io.cn" + source: hosted + version: "18.0.1" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52" + url: "https://pub.flutter-io.cn" + source: hosted + version: "8.0.0" flutter_localizations: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: c2fe1001710127dfa7da89977a08d591398370d099aacdaa6d44da7eb14b8476 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.31" + flutter_quill: + dependency: "direct main" + description: + name: flutter_quill + sha256: b96bb8525afdeaaea52f5d02f525e05cc34acd176467ab6d6f35d434cf14fde2 + url: "https://pub.flutter-io.cn" + source: hosted + version: "11.5.0" + flutter_quill_delta_from_html: + dependency: transitive + description: + name: flutter_quill_delta_from_html + sha256: "0eb801ea8dd498cadc057507af5da794d4c9599ce58b2569cb3d4bb53ba8bed2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.5.3" + flutter_quill_extensions: + dependency: "direct main" + description: + name: flutter_quill_extensions + sha256: "099dbaa962d14ac562eb028fd24d37670338352863044b7751fe642a2d2de938" + url: "https://pub.flutter-io.cn" + source: hosted + version: "11.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -322,6 +506,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.15.6" http: dependency: transitive description: @@ -346,6 +538,70 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.1.2" + image_picker: + dependency: transitive + description: + name: image_picker + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.13+1" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.13" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.11.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.2" intl: dependency: "direct main" description: @@ -366,10 +622,10 @@ packages: dependency: transitive description: name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.2" + version: "0.6.7" json_annotation: dependency: transitive description: @@ -426,6 +682,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.1.3-main.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "7.3.0" matcher: dependency: transitive description: @@ -530,6 +794,22 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.0" + photo_view: + dependency: transitive + description: + name: photo_view + sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.15.0" platform: dependency: transitive description: @@ -578,6 +858,70 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.5.0" + quill_native_bridge: + dependency: transitive + description: + name: quill_native_bridge + sha256: "76a16512e398e84216f3f659f7cb18a89ec1e141ea908e954652b4ce6cf15b18" + url: "https://pub.flutter-io.cn" + source: hosted + version: "11.1.0" + quill_native_bridge_android: + dependency: transitive + description: + name: quill_native_bridge_android + sha256: b75c7e6ede362a7007f545118e756b1f19053994144ec9eda932ce5e54a57569 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+2" + quill_native_bridge_ios: + dependency: transitive + description: + name: quill_native_bridge_ios + sha256: d23de3cd7724d482fe2b514617f8eedc8f296e120fb297368917ac3b59d8099f + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1" + quill_native_bridge_macos: + dependency: transitive + description: + name: quill_native_bridge_macos + sha256: "1c0631bd1e2eee765a8b06017c5286a4e829778f4585736e048eb67c97af8a77" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1" + quill_native_bridge_platform_interface: + dependency: transitive + description: + name: quill_native_bridge_platform_interface + sha256: "8264a2bdb8a294c31377a27b46c0f8717fa9f968cf113f7dc52d332ed9c84526" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2+1" + quill_native_bridge_web: + dependency: transitive + description: + name: quill_native_bridge_web + sha256: "7c723f6824b0250d7f33e8b6c23f2f8eb0103fe48ee7ebf47ab6786b64d5c05d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2" + quill_native_bridge_windows: + dependency: transitive + description: + name: quill_native_bridge_windows + sha256: "3f96ced19e3206ddf4f6f7dde3eb16bdd05e10294964009ea3a806d995aa7caa" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.2.2" rive: dependency: transitive description: @@ -662,10 +1006,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -743,6 +1087,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.7.4" + timezone: + dependency: "direct main" + description: + name: timezone + sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.10.1" timing: dependency: transitive description: @@ -767,6 +1119,70 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" + url_launcher: + dependency: transitive + description: + name: url_launcher + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.3.2" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "81777b08c498a292d93ff2feead633174c386291e35612f8da438d6e92c4447e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.3.20" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7 + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.3.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.2.3" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.4" vector_math: dependency: transitive description: @@ -775,6 +1191,46 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" + video_player: + dependency: transitive + description: + name: video_player + sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.10.0" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: a8dc4324f67705de057678372bedb66cd08572fe7c495605ac68c5f503324a39 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.8.15" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: f9a780aac57802b2892f93787e5ea53b5f43cc57dc107bee9436458365be71cd + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.8.4" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "57c5d73173f76d801129d0531c2774052c5a7c11ccb962f1830630decd9f24ec" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.6.0" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" vm_service: dependency: transitive description: @@ -815,6 +1271,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.0.3" + win32: + dependency: transitive + description: + name: win32 + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.13.0" xdg_directories: dependency: transitive description: @@ -823,6 +1287,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.5.0" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c5fc025..022eec9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1 +1 @@ -name: flisp_app description: "闪灵" # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 provider: ^6.1.1 # 状态管理 shared_preferences: ^2.2.2 # 本地存储 awesome_dialog: ^3.3.0 toggle_switch: ^2.3.0 fluttertoast: ^8.2.2 flutter_form_builder: ^10.0.0 form_builder_validators: ^10.0.0 intl: ^0.19.0 hive: ^2.2.3 hive_flutter: ^1.1.0 path_provider: ^2.1.1 dev_dependencies: flutter_test: sdk: flutter hive_generator: ^2.0.1 build_runner: ^2.4.6 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package \ No newline at end of file +name: flisp_app description: "闪灵" # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 provider: ^6.1.1 # 状态管理 shared_preferences: ^2.2.2 # 本地存储 awesome_dialog: ^3.3.0 toggle_switch: ^2.3.0 fluttertoast: ^8.2.2 flutter_form_builder: ^10.0.0 form_builder_validators: ^10.0.0 intl: ^0.19.0 hive: ^2.2.3 hive_flutter: ^1.1.0 path_provider: ^2.1.1 flutter_quill: ^11.0.0 flutter_quill_extensions: ^11.0.0 flutter_local_notifications: ^18.0.0 timezone: ^0.10.1 dev_dependencies: flutter_test: sdk: flutter hive_generator: ^2.0.1 build_runner: ^2.4.6 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package \ No newline at end of file diff --git a/test/widget_test.dart b/test/widget_test.dart index 149f1a6..c1c251c 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -8,23 +8,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:flisp_app/main.dart'; - void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); } diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 1a3db62..51957d7 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,15 @@ #include "generated_plugin_registrant.h" +#include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); RiveNativePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("RiveNativePlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 22806d1..6fdbe43 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,9 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows rive_native + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST