feat:增加提醒事项

This commit is contained in:
2025-11-08 22:06:16 +08:00
parent 27f0638c01
commit d5ff4c9b02
30 changed files with 1490 additions and 199 deletions

View File

@@ -13,6 +13,9 @@ android {
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
// 启用核心库脱糖
isCoreLibraryDesugaringEnabled = true
} }
kotlinOptions { kotlinOptions {
@@ -39,6 +42,11 @@ android {
} }
} }
dependencies {
// 添加核心库脱糖依赖
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}
flutter { flutter {
source = "../.." source = "../.."
} }

View File

@@ -27,6 +27,17 @@
</activity> </activity>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
@@ -42,4 +53,15 @@
<data android:mimeType="text/plain"/> <data android:mimeType="text/plain"/>
</intent> </intent>
</queries> </queries>
<!-- 声明精确闹钟权限 -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<!-- 如果需要在后台使用闹钟,可能还需要后台权限(可选) -->
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<!-- 振动权限 -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- 开机自启动通知 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- 通知权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
</manifest> </manifest>

View File

@@ -3,5 +3,5 @@
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/> <!-- 用于网络通知 -->
</manifest> </manifest>

View File

@@ -6,28 +6,16 @@ import '../provider/app_provider.dart';
class AppDrawer extends StatelessWidget { class AppDrawer extends StatelessWidget {
const AppDrawer({super.key}); const AppDrawer({super.key});
@override DrawerHeader buildDrawerHeader() {
Widget build(BuildContext context) { return DrawerHeader(
return Drawer( decoration: BoxDecoration(color: Colors.blue.shade700),
child: ListView(
padding: EdgeInsets.zero,
children: [
// 抽屉头部
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue.shade700,
),
child: const Column( child: const Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CircleAvatar( CircleAvatar(
radius: 30, radius: 30,
backgroundColor: Colors.white, backgroundColor: Colors.white,
child: Icon( child: Icon(Icons.flash_on, color: Colors.blue, size: 40),
Icons.flash_on,
color: Colors.blue,
size: 40,
),
), ),
SizedBox(height: 10), SizedBox(height: 10),
Text( Text(
@@ -40,14 +28,21 @@ class AppDrawer extends StatelessWidget {
), ),
Text( Text(
'记录每一刻的灵感', '记录每一刻的灵感',
style: TextStyle( style: TextStyle(color: Colors.white70, fontSize: 14),
color: Colors.white70,
fontSize: 14,
),
), ),
], ],
), ),
), );
}
@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
// 抽屉头部
buildDrawerHeader(),
// 菜单项 // 菜单项
_buildDrawerItem( _buildDrawerItem(
@@ -58,20 +53,12 @@ class AppDrawer extends StatelessWidget {
Provider.of<AppProvider>(context, listen: false).changeTab(0); Provider.of<AppProvider>(context, listen: false).changeTab(0);
}, },
), ),
_buildDrawerItem(
icon: Icons.note,
title: '笔记',
onTap: () {
Navigator.pop(context);
Provider.of<AppProvider>(context, listen: false).changeTab(1);
},
),
_buildDrawerItem( _buildDrawerItem(
icon: Icons.checklist, icon: Icons.checklist,
title: '待办事项', title: '待办事项',
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
Provider.of<AppProvider>(context, listen: false).changeTab(2); Provider.of<AppProvider>(context, listen: false).changeTab(1);
}, },
), ),
_buildDrawerItem( _buildDrawerItem(
@@ -79,7 +66,7 @@ class AppDrawer extends StatelessWidget {
title: '提醒任务', title: '提醒任务',
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
Provider.of<AppProvider>(context, listen: false).changeTab(3); Provider.of<AppProvider>(context, listen: false).changeTab(2);
}, },
), ),

View File

@@ -1,6 +1,5 @@
import 'package:flisp_app/layout/app_drawer.dart'; import 'package:flisp_app/layout/app_drawer.dart';
import 'package:flisp_app/pages/flash_page.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/reminders_page.dart';
import 'package:flisp_app/pages/todo_page.dart'; import 'package:flisp_app/pages/todo_page.dart';
import 'package:flisp_app/provider/app_provider.dart'; import 'package:flisp_app/provider/app_provider.dart';
@@ -16,10 +15,10 @@ class MainScreen extends StatefulWidget {
class _MainScreenState extends State<MainScreen> { class _MainScreenState extends State<MainScreen> {
final GlobalKey<TodoPageState> _todoPageKey = GlobalKey(); final GlobalKey<TodoPageState> _todoPageKey = GlobalKey();
final GlobalKey<ReminderPageState> _reminderPageKey = GlobalKey();
List<BottomNavigationBarItem> navItems = [ List<BottomNavigationBarItem> navItems = [
BottomNavigationBarItem(icon: Icon(Icons.flash_on), label: '闪灵'), BottomNavigationBarItem(icon: Icon(Icons.flash_on), label: '闪灵'),
BottomNavigationBarItem(icon: Icon(Icons.note), label: '笔记'),
BottomNavigationBarItem(icon: Icon(Icons.checklist), label: '待办'), BottomNavigationBarItem(icon: Icon(Icons.checklist), label: '待办'),
BottomNavigationBarItem(icon: Icon(Icons.notifications), label: '提醒'), BottomNavigationBarItem(icon: Icon(Icons.notifications), label: '提醒'),
]; ];
@@ -51,9 +50,14 @@ class _MainScreenState extends State<MainScreen> {
} }
void _onPressFloatingButton(int index) { void _onPressFloatingButton(int index) {
if (index == 2) { print(index);
if (index == 1) {
if (_todoPageKey.currentState != null) { 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<MainScreen> {
case 0: case 0:
return const FlashPage(); return const FlashPage();
case 1: case 1:
return const NotesPage(); return TodoPage(key: _todoPageKey);
case 2: case 2:
return TodoPage(key: _todoPageKey); // 传递 key return RemindersPage(key: _reminderPageKey);
case 3:
return const RemindersPage();
default: default:
return const FlashPage(); return const FlashPage();
} }
} }
String _getAppBarTitle(int index) { String _getAppBarTitle(int index) {
final titles = {0: '闪灵', 1: '笔记', 2: '待办', 3: '提醒'}; final titles = {0: '闪灵', 1: '待办', 2: '提醒'};
return titles[index] ?? '闪灵'; return titles[index] ?? '闪灵';
} }
} }

View File

@@ -1,8 +1,11 @@
import 'package:flisp_app/models/reminder.dart';
import 'package:flisp_app/provider/app_provider.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/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:hive_flutter/adapters.dart'; import 'package:hive_flutter/adapters.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'layout/main_screen.dart'; import 'layout/main_screen.dart';
@@ -11,16 +14,25 @@ import 'provider/todo_provider.dart';
void main() async{ void main() async{
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// 初始化提醒服务
final notifyService = NotifyService();
await notifyService.initialize();
// 初始化Hive // 初始化Hive
await Hive.initFlutter(); await Hive.initFlutter();
// 注册适配器 // 注册适配器
Hive.registerAdapter(TodoAdapter()); Hive.registerAdapter(TodoAdapter());
Hive.registerAdapter(ReminderAdapter());
// 打开Box // 打开Box
final todosBox = await Hive.openBox<Todo>('todos'); final todosBox = await Hive.openBox<Todo>('todos');
// todosBox.clear();
todosBox.clear(); final remindersBox = await Hive.openBox<Reminder>('reminders');
// remindersBox.clear();
// notifyService.cancelAllNotifications();
runApp(const MyApp()); runApp(const MyApp());
} }
@@ -33,7 +45,8 @@ class MyApp extends StatelessWidget {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider(create: (_) => AppProvider()), ChangeNotifierProvider(create: (_) => AppProvider()),
ChangeNotifierProvider(create: (_) => TodoProvider()), // 新增 ChangeNotifierProvider(create: (_) => TodoProvider()),
ChangeNotifierProvider(create: (_) => ReminderProvider()),
], ],
child: MaterialApp( child: MaterialApp(
title: '闪灵', title: '闪灵',
@@ -41,6 +54,7 @@ class MyApp extends StatelessWidget {
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
FlutterQuillLocalizations.delegate,
], ],
supportedLocales: [ supportedLocales: [
const Locale('zh'), const Locale('zh'),

58
lib/models/reminder.dart Normal file
View File

@@ -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)),
);
}
}

View File

@@ -0,0 +1,56 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'reminder.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class ReminderAdapter extends TypeAdapter<Reminder> {
@override
final int typeId = 1;
@override
Reminder read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
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;
}

View File

@@ -30,6 +30,7 @@ class Todo extends HiveObject {
late DateTime updateTime; late DateTime updateTime;
TodoPriority get priority => TodoPriority.values[priorityIndex]; TodoPriority get priority => TodoPriority.values[priorityIndex];
set priority(TodoPriority value) => priorityIndex = value.index; set priority(TodoPriority value) => priorityIndex = value.index;
Todo({ Todo({
@@ -43,7 +44,7 @@ class Todo extends HiveObject {
DateTime? updateTime, DateTime? updateTime,
}) { }) {
// 简单时间戳ID // 简单时间戳ID
this.id = id ?? DateTime.now().millisecondsSinceEpoch; this.id = id ?? DateTime.now().millisecondsSinceEpoch ~/ 1000;
this.priorityIndex = priority.index; this.priorityIndex = priority.index;
this.createTime = createTime ?? DateTime.now(); this.createTime = createTime ?? DateTime.now();
this.updateTime = updateTime ?? DateTime.now(); this.updateTime = updateTime ?? DateTime.now();
@@ -70,8 +71,8 @@ class Todo extends HiveObject {
static Todo getEmpty() { static Todo getEmpty() {
return Todo( return Todo(
id: DateTime.now().millisecondsSinceEpoch, id: DateTime.now().millisecondsSinceEpoch ~/ 1000,
title: '', title: '日常待办',
content: '', content: '',
isCompleted: false, isCompleted: false,
dueDate: null, dueDate: null,

View File

@@ -17,7 +17,7 @@ class TodoAdapter extends TypeAdapter<Todo> {
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
}; };
return Todo( return Todo(
id: fields[0] as int, id: fields[0] as int?,
title: fields[1] as String, title: fields[1] as String,
content: fields[2] as String, content: fields[2] as String,
isCompleted: fields[3] as bool, isCompleted: fields[3] as bool,

View File

@@ -1,25 +1,42 @@
import 'package:flisp_app/widgets/common.dart'; import 'package:flisp_app/widgets/common.dart';
import 'package:flutter/material.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}); const FlashPage({super.key});
@override
_FlashPageState createState() => _FlashPageState();
}
class _FlashPageState extends State<FlashPage> {
late QuillController _controller;
@override
void initState() {
super.initState();
_controller = QuillController.basic();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return buildBody( return buildBody(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(Icons.flash_on, size: 80, color: Colors.blue), QuillSimpleToolbar(
SizedBox(height: 20), controller: _controller,
Text( config: const QuillSimpleToolbarConfig(),
'闪灵', ),
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), Expanded(
child: QuillEditor.basic(
controller: _controller,
config: const QuillEditorConfig(),
), ),
SizedBox(height: 10),
Text(
'快速记录你的灵感瞬间',
style: TextStyle(fontSize: 16, color: Colors.grey),
), ),
], ],
), ),

View File

@@ -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),
),
],
),
);
}
}

View File

@@ -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/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 { class RemindersPage extends StatefulWidget {
const RemindersPage({super.key}); final VoidCallback? onAddPressed;
const RemindersPage({super.key, this.onAddPressed});
@override
State<RemindersPage> createState() => ReminderPageState();
}
class ReminderPageState extends State<RemindersPage> {
final ReminderService reminderService = ReminderService();
final NotifyService notifyService = NotifyService();
List<Reminder> _reminders = [];
void showAddDialog() {
_showDialog(false, null);
}
@override
void initState() {
super.initState();
_loadReminders();
}
Future<void> _loadReminders() async {
final reminders = await updateReminders();
if (mounted) {
setState(() {
_reminders = reminders;
});
}
}
Future<List<Reminder>> 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return buildBody( return buildBody(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(Icons.notifications, size: 80, color: Colors.red), Expanded(
SizedBox(height: 20), child: buildReminderList(
Text( reminders: _reminders,
'提醒任务', onEditReminder: (reminder) {
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), _showDialog(true, reminder);
},
), ),
SizedBox(height: 10),
Text(
'设置重要提醒',
style: TextStyle(fontSize: 16, color: Colors.grey),
), ),
], ],
), ),
); );
} }
// 显示对话框
void _showDialog(bool isEditing, Reminder? reminder) {
final reminderProvider = Provider.of<ReminderProvider>(
context,
listen: false,
);
if (isEditing) {
reminderProvider.initForm(reminder!);
} else {
reminderProvider.resetForm();
}
final formKey = GlobalKey<FormBuilderState>();
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 ? '更新失败' : '添加失败');
}
}
} }

View File

@@ -28,8 +28,8 @@ class TodoPageState extends State<TodoPage> {
// 获取过滤后的待办事项 // 获取过滤后的待办事项
List<Todo> get _activeTodos => getActiveTodos(_currentTab, _todos); List<Todo> get _activeTodos => getActiveTodos(_currentTab, _todos);
void showAddTodoDialog() { void showAddDialog() {
_showTodoDialog(false, null); _showDialog(false, null);
} }
@override @override
@@ -72,7 +72,7 @@ class TodoPageState extends State<TodoPage> {
}); });
}, },
onEditTodo: (todo) { onEditTodo: (todo) {
_showTodoDialog(true, todo); _showDialog(true, todo);
}, },
); );
} }
@@ -85,7 +85,7 @@ class TodoPageState extends State<TodoPage> {
} }
// 显示对话框 // 显示对话框
void _showTodoDialog(bool isEditing, Todo? todo) { void _showDialog(bool isEditing, Todo? todo) {
final todoProvider = Provider.of<TodoProvider>(context, listen: false); final todoProvider = Provider.of<TodoProvider>(context, listen: false);
if (isEditing) { if (isEditing) {

View File

@@ -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();
}
}

View File

@@ -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<Reminder> get box => Hive.box<Reminder>(boxName);
Future<bool> addReminder(Reminder reminder) async {
try {
await box.add(reminder);
return true;
} catch (e) {
return false;
}
}
List<Reminder> getAllReminders() {
return box.values.toList();
}
Future<bool> updateReminder(Reminder reminder) async {
try {
await reminder.save();
return true;
} catch (e) {
return false;
}
}
Future<bool> deleteReminder(Reminder reminder) async {
try {
await reminder.delete();
return true;
} catch (e) {
return false;
}
}
}

View File

@@ -1,3 +1,7 @@
String formatDate(DateTime date) { // String formatDate(DateTime date) {
return '${date.month}${date.day}'; // return '${date.month}月${date.day}日';
} // }
//
// String formatTime(DateTime datetime) {
// return '${datetime.year}-${datetime.month}-${datetime.day} ${datetime.hour}:${datetime.minute}:${datetime.second}';
// }

146
lib/utils/notify_utils.dart Normal file
View File

@@ -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<void> 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<void> showInstantNotification({
required String title,
required String body,
int id = 0,
}) async {
await _notifications.show(id, title, body, _details);
}
// 安排定时通知
Future<void> 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<void> cancelNotification(int id) async {
print("cancelNotification: $id");
await _notifications.cancel(id);
}
// 取消所有通知
Future<void> cancelAllNotifications() async {
await _notifications.cancelAll();
}
// 检查通知权限
Future<bool> checkPermission() async {
final bool? result =
await _notifications
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.areNotificationsEnabled();
return result ?? false;
}
// 请求权限
Future<void> requestPermission() async {
await _notifications
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin
>()
?.requestPermissions(alert: true, badge: true, sound: true);
}
// 获取所有待处理的通知
Future<List<PendingNotificationRequest>> getPendingNotifications() async {
return await _notifications.pendingNotificationRequests();
}
}

View File

@@ -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<FormBuilderState> formKey;
final bool isEditing;
final Reminder? initialReminder;
const ReminderForm({
super.key,
required this.formKey,
required this.isEditing,
this.initialReminder,
});
@override
State<ReminderForm> createState() => _ReminderFormState();
}
class _ReminderFormState extends State<ReminderForm> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final int maxTitleCount = 10;
final int maxContentCount = 20;
final provider = Provider.of<ReminderProvider>(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()],
),
);
}
}

View File

@@ -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<Reminder> reminders,
required ValueChanged<Reminder> 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<Reminder> 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),
),
],
),
);
}

View File

@@ -1,9 +1,9 @@
import 'package:flisp_app/provider/todo_provider.dart'; import 'package:flisp_app/provider/todo_provider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flisp_app/models/todo.dart'; import 'package:flisp_app/models/todo.dart';
import 'package:flisp_app/utils/date_utils.dart';
class TodoForm extends StatefulWidget { class TodoForm extends StatefulWidget {
final GlobalKey<FormBuilderState> formKey; final GlobalKey<FormBuilderState> formKey;
@@ -31,7 +31,7 @@ class _TodoFormState extends State<TodoForm> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final int maxTitleCount = 10; final int maxTitleCount = 10;
final int maxContentCount = 20; final int maxContentCount = 20;
final store = Provider.of<TodoProvider>(context); final provider = Provider.of<TodoProvider>(context);
Widget buildTitle() { Widget buildTitle() {
return Row( return Row(
@@ -57,17 +57,17 @@ class _TodoFormState extends State<TodoForm> {
FormBuilderTextField buildTitleField() { FormBuilderTextField buildTitleField() {
return FormBuilderTextField( return FormBuilderTextField(
name: 'title', name: 'title',
initialValue: store.formItem.title, initialValue: provider.formItem.title,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
store.formItem.title = value ?? ''; provider.formItem.title = value ?? '';
}); });
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: '标题', labelText: '标题',
hintText: '请输入待办事项标题...', hintText: '请输入待办事项标题...',
counterText: '', counterText: '',
suffixText: '${store.formItem.title.length}/$maxTitleCount', suffixText: '${provider.formItem.title.length}/$maxTitleCount',
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey.shade200), borderSide: BorderSide(color: Colors.grey.shade200),
@@ -98,20 +98,20 @@ class _TodoFormState extends State<TodoForm> {
); );
} }
FormBuilderTextField buildDescriptionField() { FormBuilderTextField buildContentField() {
return FormBuilderTextField( return FormBuilderTextField(
name: 'description', name: 'content',
initialValue: store.formItem.content, initialValue: provider.formItem.content,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
store.formItem.content = value ?? ''; provider.formItem.content = value ?? '';
}); });
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: '内容', labelText: '内容',
hintText: '请输入待办事项内容...', hintText: '请输入待办事项内容...',
counterText: '', counterText: '',
suffixText: '${store.formItem.content.length}/$maxContentCount', suffixText: '${provider.formItem.content.length}/$maxContentCount',
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey.shade200), borderSide: BorderSide(color: Colors.grey.shade200),
@@ -145,7 +145,7 @@ class _TodoFormState extends State<TodoForm> {
icon: Icon(Icons.clear, size: 18), icon: Icon(Icons.clear, size: 18),
onPressed: () { onPressed: () {
setState(() { setState(() {
store.formItem.dueDate = null; provider.formItem.dueDate = null;
}); });
widget.formKey.currentState?.fields['dueDate']?.didChange(null); widget.formKey.currentState?.fields['dueDate']?.didChange(null);
}, },
@@ -155,21 +155,24 @@ class _TodoFormState extends State<TodoForm> {
FormBuilderDateTimePicker buildDateField() { FormBuilderDateTimePicker buildDateField() {
return FormBuilderDateTimePicker( return FormBuilderDateTimePicker(
name: 'dueDate', name: 'dueDate',
initialValue: store.formItem.dueDate, format: DateFormat('yyyy-MM-dd'),
initialValue: provider.formItem.dueDate,
inputType: InputType.date, inputType: InputType.date,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
store.formItem.dueDate = value; provider.formItem.dueDate = value;
}); });
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: labelText:
store.formItem.dueDate == null provider.formItem.dueDate == null
? '选择截止日期' ? '选择截止日期'
: '截止: ${formatDate(store.formItem.dueDate!)}', : '截止: ${DateFormat('yyyy-MM-dd').format(provider.formItem.dueDate!)}',
labelStyle: TextStyle( labelStyle: TextStyle(
color: 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), prefixIcon: Icon(Icons.calendar_today, color: Colors.purple),
border: OutlineInputBorder( border: OutlineInputBorder(
@@ -188,7 +191,7 @@ class _TodoFormState extends State<TodoForm> {
fillColor: Colors.white, fillColor: Colors.white,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
suffixIcon: suffixIcon:
store.formItem.dueDate != null provider.formItem.dueDate != null
? buildClearDateSuffixIcon() ? buildClearDateSuffixIcon()
: null, : null,
), ),
@@ -205,7 +208,7 @@ class _TodoFormState extends State<TodoForm> {
FormBuilderRadioGroup builderRadioGroup() { FormBuilderRadioGroup builderRadioGroup() {
return FormBuilderRadioGroup<TodoPriority>( return FormBuilderRadioGroup<TodoPriority>(
name: 'priority', name: 'priority',
initialValue: store.formItem.priority, initialValue: provider.formItem.priority,
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
@@ -225,7 +228,7 @@ class _TodoFormState extends State<TodoForm> {
onChanged: (value) { onChanged: (value) {
if (value != null) { if (value != null) {
setState(() { setState(() {
store.formItem.priority = value; provider.formItem.priority = value;
}); });
} }
}, },
@@ -264,7 +267,7 @@ class _TodoFormState extends State<TodoForm> {
children: [ children: [
buildTitleField(), buildTitleField(),
SizedBox(height: 12), SizedBox(height: 12),
buildDescriptionField(), buildContentField(),
SizedBox(height: 12), SizedBox(height: 12),
buildDateField(), buildDateField(),
SizedBox(height: 12), SizedBox(height: 12),

View File

@@ -1,7 +1,7 @@
import 'package:flisp_app/models/todo.dart'; import 'package:flisp_app/models/todo.dart';
import 'package:flisp_app/utils/date_utils.dart';
import 'package:flisp_app/widgets/common.dart'; import 'package:flisp_app/widgets/common.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:toggle_switch/toggle_switch.dart'; import 'package:toggle_switch/toggle_switch.dart';
// 统计卡片 // 统计卡片
@@ -119,6 +119,7 @@ Widget _buildTodoTitle(Todo todo) {
style: TextStyle( style: TextStyle(
decoration: todo.isCompleted ? TextDecoration.lineThrough : null, decoration: todo.isCompleted ? TextDecoration.lineThrough : null,
color: todo.isCompleted ? Colors.grey : null, color: todo.isCompleted ? Colors.grey : null,
fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
); );
@@ -135,24 +136,38 @@ Widget? _buildTodoSubtitle(Todo todo) {
if (!hasContent) return null; if (!hasContent) return null;
return Wrap( return Column(
direction: Axis.vertical, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 5,
children: [ children: [
SizedBox(height: 4),
if (todo.content.isNotEmpty == true) if (todo.content.isNotEmpty == true)
Text( Text(
todo.content, todo.content,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: Colors.grey.shade600), style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
), ),
),
SizedBox(height: 8),
if (todo.dueDate != null) if (todo.dueDate != null)
Text( Container(
'截止: ${formatDate(todo.dueDate!)}', 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( style: TextStyle(
fontSize: 11, fontSize: 11,
color: isOverdue ? Colors.red : Colors.grey, color: isOverdue ? Colors.red[600] : Colors.grey[600],
fontWeight: isOverdue ? FontWeight.bold : FontWeight.normal, fontWeight: isOverdue ? FontWeight.w600 : FontWeight.normal,
),
), ),
), ),
], ],

View File

@@ -6,10 +6,18 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <rive_native/rive_native_plugin.h> #include <rive_native/rive_native_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { 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 = g_autoptr(FlPluginRegistrar) rive_native_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin");
rive_native_plugin_register_with_registrar(rive_native_registrar); 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);
} }

View File

@@ -3,7 +3,9 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
rive_native rive_native
url_launcher_linux
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@@ -5,12 +5,22 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import file_selector_macos
import flutter_local_notifications
import path_provider_foundation import path_provider_foundation
import quill_native_bridge_macos
import rive_native import rive_native
import shared_preferences_foundation import shared_preferences_foundation
import url_launcher_macos
import video_player_avfoundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 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")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin"))
RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin")) RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
} }

View File

@@ -58,10 +58,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build name: build
sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.4" version: "2.4.2"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
@@ -82,26 +82,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_resolvers name: build_resolvers
sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.4" version: "2.4.4"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.4" version: "2.4.14"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "9.1.2" version: "8.0.0"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@@ -126,6 +126,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.4.0" 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: checked_yaml:
dependency: transitive dependency: transitive
description: description:
@@ -166,6 +174,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.2" 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: crypto:
dependency: transitive dependency: transitive
description: description:
@@ -174,6 +190,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.7" 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: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -182,6 +206,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.8" 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: dart_style:
dependency: transitive dependency: transitive
description: description:
@@ -190,6 +222,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.3.8" 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: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -214,6 +262,38 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "7.0.1" 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: fixnum:
dependency: transitive dependency: transitive
description: description:
@@ -227,6 +307,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: flutter_form_builder:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -235,6 +323,46 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "10.0.1" 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: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -243,11 +371,67 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.0.0" 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: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@@ -322,6 +506,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.1" 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: http:
dependency: transitive dependency: transitive
description: description:
@@ -346,6 +538,70 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "4.1.2" 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: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -366,10 +622,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.7.2" version: "0.6.7"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@@ -426,6 +682,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.3-main.0" 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: matcher:
dependency: transitive dependency: transitive
description: description:
@@ -530,6 +794,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.3.0" 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: platform:
dependency: transitive dependency: transitive
description: description:
@@ -578,6 +858,70 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.5.0" 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: rive:
dependency: transitive dependency: transitive
description: description:
@@ -662,10 +1006,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.0" version: "2.0.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -743,6 +1087,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.7.4" 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: timing:
dependency: transitive dependency: transitive
description: description:
@@ -767,6 +1119,70 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.4.0" 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: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -775,6 +1191,46 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.4" 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: vm_service:
dependency: transitive dependency: transitive
description: description:
@@ -815,6 +1271,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.3" 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: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@@ -823,6 +1287,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0" 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: yaml:
dependency: transitive dependency: transitive
description: description:

View File

@@ -1 +1 @@
name: flisp_app name: flisp_app

View File

@@ -8,23 +8,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flisp_app/main.dart';
void main() { 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);
});
} }

View File

@@ -6,9 +6,15 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <rive_native/rive_native_plugin.h> #include <rive_native/rive_native_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
RiveNativePluginRegisterWithRegistrar( RiveNativePluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("RiveNativePlugin")); registry->GetRegistrarForPlugin("RiveNativePlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
} }

View File

@@ -3,7 +3,9 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
rive_native rive_native
url_launcher_windows
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST