diff --git a/lib/data/categories.dart b/lib/data/categories.dart new file mode 100644 index 0000000..282b903 --- /dev/null +++ b/lib/data/categories.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import '../models/record.dart'; + +/// 预设支出分类 +final List expenseCategories = [ + Category( + id: 'food', + name: '餐饮', + icon: Icons.restaurant, + type: RecordType.expense, + ), + Category( + id: 'shopping', + name: '购物', + icon: Icons.shopping_bag, + type: RecordType.expense, + ), + Category( + id: 'transport', + name: '交通', + icon: Icons.directions_bus, + type: RecordType.expense, + ), + Category( + id: 'entertainment', + name: '娱乐', + icon: Icons.sports_esports, + type: RecordType.expense, + ), + // 可以继续添加更多分类... +]; + +/// 预设收入分类 +final List incomeCategories = [ + Category( + id: 'salary', + name: '工资', + icon: Icons.account_balance_wallet, + type: RecordType.income, + ), + Category( + id: 'bonus', + name: '奖金', + icon: Icons.card_giftcard, + type: RecordType.income, + ), + Category( + id: 'investment', + name: '投资', + icon: Icons.trending_up, + type: RecordType.income, + ), + // 可以继续添加更多分类... +]; \ No newline at end of file diff --git a/lib/data/mock_data.dart b/lib/data/mock_data.dart new file mode 100644 index 0000000..ca22181 --- /dev/null +++ b/lib/data/mock_data.dart @@ -0,0 +1,21 @@ +import '../models/record.dart'; + +final List mockRecords = [ + Record( + id: '1', + type: RecordType.expense, + categoryId: 'food', + note: '午餐', + amount: 25.0, + createTime: DateTime.now().subtract(const Duration(hours: 2)), + ), + Record( + id: '2', + type: RecordType.income, + categoryId: 'salary', + note: '工资', + amount: 5000.0, + createTime: DateTime.now().subtract(const Duration(days: 1)), + ), + // 可以添加更多模拟数据... +]; \ No newline at end of file diff --git a/lib/models/record.dart b/lib/models/record.dart new file mode 100644 index 0000000..82ee288 --- /dev/null +++ b/lib/models/record.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; + +/// 记账类型枚举 +enum RecordType { + expense, // 支出 + income, // 收入 +} + +/// 记账分类模型 +class Category { + final String id; + final String name; + final IconData icon; + final RecordType type; + final String? parentId; // 为未来二级分类预留 + + const Category({ + required this.id, + required this.name, + required this.icon, + required this.type, + this.parentId, + }); +} + +/// 记账记录模型 +class Record { + final String id; + final RecordType type; + final String categoryId; + final String? note; + final double amount; + final DateTime createTime; + final String? accountId; // 为未来账户功能预留 + final List? imageUrls; // 为未来配图功能预留 + + Record({ + required this.id, + required this.type, + required this.categoryId, + this.note, + required this.amount, + required this.createTime, + this.accountId, + this.imageUrls, + }); + + // 转换为JSON格式,方便存储 + Map toJson() => { + 'id': id, + 'type': type.index, + 'categoryId': categoryId, + 'note': note, + 'amount': amount, + 'createTime': createTime.toIso8601String(), + 'accountId': accountId, + 'imageUrls': imageUrls, + }; + + // 从JSON格式转换回对象 + factory Record.fromJson(Map json) => Record( + id: json['id'], + type: RecordType.values[json['type']], + categoryId: json['categoryId'], + note: json['note'], + amount: json['amount'], + createTime: DateTime.parse(json['createTime']), + accountId: json['accountId'], + imageUrls: json['imageUrls'] != null + ? List.from(json['imageUrls']) + : null, + ); +} \ No newline at end of file diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 5bcd5bf..e8017a3 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -2,7 +2,11 @@ import 'package:flutter/material.dart'; import 'package:sensors_plus/sensors_plus.dart'; import 'package:vibration/vibration.dart'; import 'dart:async'; +import '../models/record.dart'; import './record_page.dart'; +import '../widgets/record_list.dart'; +import '../data/mock_data.dart'; // 暂时使用模拟数据 +import '../services/database_service.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @@ -16,11 +20,23 @@ class _HomePageState extends State { DateTime? _lastShakeTime; int _shakeCount = 0; bool _isNavigating = false; + final _dbService = DatabaseService(); + List records = []; @override void initState() { super.initState(); _initShakeDetection(); + _loadRecords(); + } + + /// 加载记录 + Future _loadRecords() async { + final loadedRecords = await _dbService.getAllRecords(); + setState(() { + records = loadedRecords; + records.sort((a, b) => b.createTime.compareTo(a.createTime)); + }); } /// 初始化摇晃检测 @@ -51,7 +67,7 @@ class _HomePageState extends State { }); } - /// 通过摇晃触发的导航(带震动) + /// 带震动的记账页面导航 void _navigateToRecordPageWithVibration() async { if (_isNavigating) return; @@ -61,10 +77,25 @@ class _HomePageState extends State { Vibration.vibrate(duration: 200); } + _navigateToRecordPage(); + } + + /// 导航到记账页面 + void _navigateToRecordPage([Record? record]) { Navigator.push( context, MaterialPageRoute( - builder: (context) => const RecordPage(), + builder: (context) => RecordPage( + record: record, + onSave: (newRecord) async { + if (record != null) { + await _dbService.updateRecord(newRecord); + } else { + await _dbService.insertRecord(newRecord); + } + await _loadRecords(); + }, + ), maintainState: false, ), ).then((_) { @@ -72,26 +103,10 @@ class _HomePageState extends State { }); } - /// 通过按钮触发的导航(无震动) - void _navigateToRecordPage() { - if (_isNavigating) return; - - _isNavigating = true; - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const RecordPage(), - maintainState: false, - ), - ).then((_) { - _isNavigating = false; - }); - } - - @override - void dispose() { - _accelerometerSubscription?.cancel(); - super.dispose(); + /// 删除记录 + void _deleteRecord(String recordId) async { + await _dbService.deleteRecord(recordId); + await _loadRecords(); } @override @@ -100,17 +115,21 @@ class _HomePageState extends State { appBar: AppBar( title: const Text('记账本'), ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - onPressed: _navigateToRecordPage, - child: const Text('记账'), - ), - ], - ), + body: RecordList( + records: records, + onRecordTap: _navigateToRecordPage, + onRecordDelete: _deleteRecord, + ), + floatingActionButton: FloatingActionButton( + onPressed: () => _navigateToRecordPage(), + child: const Icon(Icons.add), ), ); } + + @override + void dispose() { + _accelerometerSubscription?.cancel(); + super.dispose(); + } } \ No newline at end of file diff --git a/lib/pages/record_page.dart b/lib/pages/record_page.dart index 1679626..53b06ab 100644 --- a/lib/pages/record_page.dart +++ b/lib/pages/record_page.dart @@ -1,32 +1,322 @@ import 'package:flutter/material.dart'; +import '../models/record.dart'; +import '../data/categories.dart'; +import 'package:uuid/uuid.dart'; class RecordPage extends StatefulWidget { - const RecordPage({Key? key}) : super(key: key); + final Record? record; + final Function(Record) onSave; // 添加保存回调 + + const RecordPage({ + Key? key, + this.record, + required this.onSave, + }) : super(key: key); @override State createState() => _RecordPageState(); } -class _RecordPageState extends State { +class _RecordPageState extends State with SingleTickerProviderStateMixin { + late TabController _tabController; + String? _selectedCategoryId; + String _note = ''; + double _amount = 0.0; + DateTime _selectedDate = DateTime.now(); + final _uuid = const Uuid(); + + @override + void initState() { + super.initState(); + // 如果是编辑模式,初始化现有记录的数据 + if (widget.record != null) { + _selectedCategoryId = widget.record!.categoryId; + _note = widget.record!.note ?? ''; + _amount = widget.record!.amount; + _selectedDate = widget.record!.createTime; + } + + _tabController = TabController( + length: 2, + vsync: this, + initialIndex: widget.record?.type == RecordType.income ? 1 : 0, + ); + _tabController.addListener(_onTabChanged); + } + + /// 标签切换监听 + void _onTabChanged() { + setState(() { + _selectedCategoryId = null; // 切换类型时重置选中的分类 + }); + } + + /// 获取当前记录类型 + RecordType get _currentType => + _tabController.index == 0 ? RecordType.expense : RecordType.income; + + /// 获取当前分类列表 + List get _currentCategories => + _currentType == RecordType.expense ? expenseCategories : incomeCategories; + + /// 保存记录 + void _saveRecord() { + if (_selectedCategoryId == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('请选择分类')), + ); + return; + } + if (_amount <= 0) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('请输入金额')), + ); + return; + } + + final record = Record( + id: widget.record?.id ?? _uuid.v4(), + type: _currentType, + categoryId: _selectedCategoryId!, + note: _note.isEmpty ? null : _note, + amount: _amount, + createTime: _selectedDate, + ); + + widget.onSave(record); + Navigator.of(context).pop(); + } + @override Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - Navigator.of(context).pop(); - return false; - }, - child: Scaffold( - appBar: AppBar( - title: const Text('记账'), - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.of(context).pop(), - ), + return Scaffold( + appBar: AppBar( + title: TabBar( + controller: _tabController, + tabs: const [ + Tab(text: '支出'), + Tab(text: '收入'), + ], ), - body: const Center( - child: Text('记账页面'), + ), + body: Column( + children: [ + // 分类网格 + Expanded( + child: GridView.builder( + padding: const EdgeInsets.all(16), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + mainAxisSpacing: 16, + crossAxisSpacing: 16, + ), + itemCount: _currentCategories.length, + itemBuilder: (context, index) { + final category = _currentCategories[index]; + final isSelected = category.id == _selectedCategoryId; + return _buildCategoryItem(category, isSelected); + }, + ), + ), + // 底部编辑区域 + _buildBottomEditor(), + ], + ), + ); + } + + /// 构建分类项 + Widget _buildCategoryItem(Category category, bool isSelected) { + return InkWell( + onTap: () => setState(() => _selectedCategoryId = category.id), + child: Container( + decoration: BoxDecoration( + color: isSelected ? Theme.of(context).primaryColor.withOpacity(0.1) : null, + border: Border.all( + color: isSelected ? Theme.of(context).primaryColor : Colors.grey, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + category.icon, + color: isSelected ? Theme.of(context).primaryColor : Colors.grey, + ), + const SizedBox(height: 4), + Text( + category.name, + style: TextStyle( + color: isSelected ? Theme.of(context).primaryColor : Colors.grey, + ), + ), + ], ), ), ); } + + /// 构建底部编辑区域 + Widget _buildBottomEditor() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, -2), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 备注和金额 + Row( + children: [ + Expanded( + child: TextField( + decoration: const InputDecoration( + hintText: '添加备注', + border: InputBorder.none, + ), + onChanged: (value) => setState(() => _note = value), + ), + ), + Text( + '¥${_amount.toStringAsFixed(2)}', + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + // 配置按钮 + Row( + children: [ + TextButton.icon( + onPressed: () { + // TODO: 实现账户选择 + }, + icon: const Icon(Icons.account_balance_wallet), + label: const Text('默认账户'), + ), + TextButton.icon( + onPressed: () async { + final date = await showDatePicker( + context: context, + initialDate: _selectedDate, + firstDate: DateTime(2000), + lastDate: DateTime.now(), + ); + if (date != null) { + setState(() => _selectedDate = date); + } + }, + icon: const Icon(Icons.calendar_today), + label: Text(_selectedDate == DateTime.now() + ? '今天' + : '${_selectedDate.month}月${_selectedDate.day}日'), + ), + TextButton.icon( + onPressed: () { + // TODO: 实现图片选择 + }, + icon: const Icon(Icons.photo), + label: const Text('图片'), + ), + ], + ), + // 数字键盘 + _buildNumberKeyboard(), + ], + ), + ); + } + + /// 构建数字键盘 + Widget _buildNumberKeyboard() { + return GridView.count( + shrinkWrap: true, + crossAxisCount: 4, + childAspectRatio: 2, + children: [ + _buildKeyboardButton('7'), + _buildKeyboardButton('8'), + _buildKeyboardButton('9'), + _buildKeyboardButton('删除', isFunction: true), + _buildKeyboardButton('4'), + _buildKeyboardButton('5'), + _buildKeyboardButton('6'), + _buildKeyboardButton('+'), + _buildKeyboardButton('1'), + _buildKeyboardButton('2'), + _buildKeyboardButton('3'), + _buildKeyboardButton('-'), + _buildKeyboardButton('again'), + _buildKeyboardButton('0'), + _buildKeyboardButton('.'), + _buildKeyboardButton('保存', isFunction: true), + ], + ); + } + + /// 构建键盘按钮 + Widget _buildKeyboardButton(String text, {bool isFunction = false}) { + return TextButton( + onPressed: () => _onKeyboardButtonPressed(text), + child: Text( + text, + style: TextStyle( + fontSize: 20, + color: isFunction ? Theme.of(context).primaryColor : Colors.black, + ), + ), + ); + } + + /// 处理键盘按钮点击 + void _onKeyboardButtonPressed(String value) { + switch (value) { + case '删除': + setState(() { + final amountStr = _amount.toStringAsFixed(2); + if (amountStr.length > 1) { + _amount = double.parse(amountStr.substring(0, amountStr.length - 1)); + } else { + _amount = 0; + } + }); + break; + case '保存': + _saveRecord(); + break; + case 'again': + // TODO: 实现again功能 + break; + case '+': + case '-': + // TODO: 实现加减功能 + break; + case '.': + // TODO: 实现小数点功能 + break; + default: + if (_amount == 0) { + setState(() => _amount = double.parse(value)); + } else { + setState(() => _amount = double.parse('$_amount$value')); + } + } + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } } \ No newline at end of file diff --git a/lib/services/database_service.dart b/lib/services/database_service.dart new file mode 100644 index 0000000..3673b73 --- /dev/null +++ b/lib/services/database_service.dart @@ -0,0 +1,94 @@ +import 'package:sqflite/sqflite.dart' show Database, openDatabase, getDatabasesPath, ConflictAlgorithm; +import 'package:path/path.dart' as path_helper; +import '../models/record.dart'; + +class DatabaseService { + static Database? _database; + + /// 获取数据库实例 + Future get database async { + if (_database != null) return _database!; + _database = await _initDatabase(); + return _database!; + } + + /// 初始化数据库 + Future _initDatabase() async { + final path = await getDatabasesPath(); + final dbPath = path_helper.join(path, 'records.db'); + + return await openDatabase( + dbPath, + version: 1, + onCreate: (db, version) async { + await db.execute(''' + CREATE TABLE records( + id TEXT PRIMARY KEY, + type INTEGER NOT NULL, + categoryId TEXT NOT NULL, + note TEXT, + amount REAL NOT NULL, + createTime TEXT NOT NULL, + accountId TEXT, + imageUrls TEXT + ) + '''); + }, + ); + } + + /// 插入记录 + Future insertRecord(Record record) async { + final db = await database; + await db.insert( + 'records', + record.toJson()..addAll({ + 'imageUrls': record.imageUrls?.join(','), + }), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + + /// 更新记录 + Future updateRecord(Record record) async { + final db = await database; + await db.update( + 'records', + record.toJson()..addAll({ + 'imageUrls': record.imageUrls?.join(','), + }), + where: 'id = ?', + whereArgs: [record.id], + ); + } + + /// 删除记录 + Future deleteRecord(String id) async { + final db = await database; + await db.delete( + 'records', + where: 'id = ?', + whereArgs: [id], + ); + } + + /// 获取所有记录 + Future> getAllRecords() async { + final db = await database; + final List> maps = await db.query('records'); + + return List.generate(maps.length, (i) { + final map = maps[i]; + return Record( + id: map['id'], + type: RecordType.values[map['type']], + categoryId: map['categoryId'], + note: map['note'], + amount: map['amount'], + createTime: DateTime.parse(map['createTime']), + accountId: map['accountId'], + imageUrls: map['imageUrls']?.split(','), + ); + }); + } +} \ No newline at end of file diff --git a/lib/widgets/record_detail_dialog.dart b/lib/widgets/record_detail_dialog.dart new file mode 100644 index 0000000..a42034b --- /dev/null +++ b/lib/widgets/record_detail_dialog.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import '../models/record.dart'; +import '../data/categories.dart'; + +class RecordDetailDialog extends StatelessWidget { + final Record record; + final VoidCallback onEdit; + final VoidCallback onDelete; + + const RecordDetailDialog({ + Key? key, + required this.record, + required this.onEdit, + required this.onDelete, + }) : super(key: key); + + /// 获取分类信息 + Category _getCategory(String categoryId) { + return [...expenseCategories, ...incomeCategories] + .firstWhere((c) => c.id == categoryId); + } + + @override + Widget build(BuildContext context) { + final category = _getCategory(record.categoryId); + + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('记录详情'), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + Navigator.of(context).pop(); + onEdit(); + }, + ), + IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + Navigator.of(context).pop(); + onDelete(); + }, + ), + ], + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: const Text('分类'), + subtitle: Text(category.name), + leading: Icon(category.icon), + onTap: () { + // TODO: 跳转到分类详情页 + }, + ), + if (record.note != null) + ListTile( + title: const Text('备注'), + subtitle: Text(record.note!), + ), + ListTile( + title: const Text('金额'), + subtitle: Text( + '${record.type == RecordType.expense ? "-" : "+"}¥${record.amount.toStringAsFixed(2)}', + style: TextStyle( + color: record.type == RecordType.expense + ? Colors.red + : Colors.green, + fontWeight: FontWeight.bold, + ), + ), + ), + ListTile( + title: const Text('时间'), + subtitle: Text( + '${record.createTime.year}-${record.createTime.month}-${record.createTime.day} ' + '${record.createTime.hour}:${record.createTime.minute}', + ), + ), + ListTile( + title: const Text('账户'), + subtitle: const Text('默认账户'), + onTap: () { + // TODO: 跳转到账户页 + }, + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/record_list.dart b/lib/widgets/record_list.dart new file mode 100644 index 0000000..97f3984 --- /dev/null +++ b/lib/widgets/record_list.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import '../models/record.dart'; +import '../data/categories.dart'; +import './record_detail_dialog.dart'; + +class RecordList extends StatelessWidget { + final List records; + final Function(Record) onRecordTap; + final Function(String) onRecordDelete; + + const RecordList({ + Key? key, + required this.records, + required this.onRecordTap, + required this.onRecordDelete, + }) : super(key: key); + + /// 获取分类信息 + Category _getCategory(String categoryId) { + return [...expenseCategories, ...incomeCategories] + .firstWhere((c) => c.id == categoryId); + } + + /// 按日期分组记录 + Map> _groupByDate() { + final groups = >{}; + for (final record in records) { + final date = _formatDate(record.createTime); + if (!groups.containsKey(date)) { + groups[date] = []; + } + groups[date]!.add(record); + } + return groups; + } + + /// 格式化日期 + String _formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } + + /// 计算日汇总 + String _getDailySummary(List dayRecords) { + double expense = 0; + double income = 0; + for (final record in dayRecords) { + if (record.type == RecordType.expense) { + expense += record.amount; + } else { + income += record.amount; + } + } + + final parts = []; + if (expense > 0) parts.add('支:¥${expense.toStringAsFixed(2)}'); + if (income > 0) parts.add('收:¥${income.toStringAsFixed(2)}'); + return parts.join(' '); + } + + @override + Widget build(BuildContext context) { + final groups = _groupByDate(); + final dates = groups.keys.toList()..sort((a, b) => b.compareTo(a)); + + return ListView.builder( + itemCount: dates.length, + itemBuilder: (context, index) { + final date = dates[index]; + final dayRecords = groups[date]!; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 日期头部 + Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + date, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + Text(_getDailySummary(dayRecords)), + ], + ), + ), + // 记录列表 + ...dayRecords.map((record) { + final category = _getCategory(record.categoryId); + return ListTile( + leading: Icon(category.icon), + title: Text(category.name), + subtitle: record.note != null ? Text(record.note!) : null, + trailing: Text( + '${record.type == RecordType.expense ? "-" : "+"}¥${record.amount.toStringAsFixed(2)}', + style: TextStyle( + color: record.type == RecordType.expense + ? Colors.red + : Colors.green, + fontWeight: FontWeight.bold, + ), + ), + onTap: () => showDialog( + context: context, + builder: (context) => RecordDetailDialog( + record: record, + onEdit: () => onRecordTap(record), + onDelete: () => onRecordDelete(record.id), + ), + ), + ); + }).toList(), + const Divider(), + ], + ); + }, + ); + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index dfeac06..0091f89 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -89,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -153,7 +169,7 @@ packages: source: hosted version: "1.10.0" path: - dependency: transitive + dependency: "direct main" description: name: path sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" @@ -205,6 +221,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: "direct main" + description: + name: sqflite + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" stack_trace: dependency: transitive description: @@ -229,6 +269,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -245,6 +293,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" vector_math: dependency: transitive description: @@ -295,4 +359,4 @@ packages: version: "1.1.2" sdks: dart: ">=3.2.5 <4.0.0" - flutter: ">=3.3.0" + flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index bdc2383..b4588a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,9 @@ dependencies: sdk: flutter sensors_plus: ^1.4.1 # 用于检测手机摇晃 vibration: ^1.8.4 # 添加震动支持 + uuid: ^4.3.3 # 添加uuid包用于生成唯一ID + sqflite: ^2.3.2 # 添加 SQLite 支持 + path: ^1.8.3 # 用于处理文件路径 # The following adds the Cupertino Icons font to your application.