Merge remote-tracking branch 'daodaoshi/main'

This commit is contained in:
daodaoshi 2024-12-18 21:05:42 +08:00
commit 9b2ee71519
10 changed files with 890 additions and 50 deletions

54
lib/data/categories.dart Normal file
View File

@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import '../models/record.dart';
/// 预设支出分类
final List<Category> 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<Category> 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,
),
// 可以继续添加更多分类...
];

21
lib/data/mock_data.dart Normal file
View File

@ -0,0 +1,21 @@
import '../models/record.dart';
final List<Record> 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)),
),
// 可以添加更多模拟数据...
];

73
lib/models/record.dart Normal file
View File

@ -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<String>? 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<String, dynamic> toJson() => {
'id': id,
'type': type.index,
'categoryId': categoryId,
'note': note,
'amount': amount,
'createTime': createTime.toIso8601String(),
'accountId': accountId,
'imageUrls': imageUrls,
};
// 从JSON格式转换回对象
factory Record.fromJson(Map<String, dynamic> 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<String>.from(json['imageUrls'])
: null,
);
}

View File

@ -2,7 +2,11 @@ import 'package:flutter/material.dart';
import 'package:sensors_plus/sensors_plus.dart'; import 'package:sensors_plus/sensors_plus.dart';
import 'package:vibration/vibration.dart'; import 'package:vibration/vibration.dart';
import 'dart:async'; import 'dart:async';
import '../models/record.dart';
import './record_page.dart'; import './record_page.dart';
import '../widgets/record_list.dart';
import '../data/mock_data.dart'; // 暂时使用模拟数据
import '../services/database_service.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key); const HomePage({Key? key}) : super(key: key);
@ -16,11 +20,23 @@ class _HomePageState extends State<HomePage> {
DateTime? _lastShakeTime; DateTime? _lastShakeTime;
int _shakeCount = 0; int _shakeCount = 0;
bool _isNavigating = false; bool _isNavigating = false;
final _dbService = DatabaseService();
List<Record> records = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initShakeDetection(); _initShakeDetection();
_loadRecords();
}
/// 加载记录
Future<void> _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<HomePage> {
}); });
} }
/// 通过摇晃触发的导航(带震动) /// 带震动的记账页面导航
void _navigateToRecordPageWithVibration() async { void _navigateToRecordPageWithVibration() async {
if (_isNavigating) return; if (_isNavigating) return;
@ -61,10 +77,25 @@ class _HomePageState extends State<HomePage> {
Vibration.vibrate(duration: 200); Vibration.vibrate(duration: 200);
} }
_navigateToRecordPage();
}
/// 导航到记账页面
void _navigateToRecordPage([Record? record]) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( 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, maintainState: false,
), ),
).then((_) { ).then((_) {
@ -72,26 +103,10 @@ class _HomePageState extends State<HomePage> {
}); });
} }
/// 通过按钮触发的导航(无震动) /// 删除记录
void _navigateToRecordPage() { void _deleteRecord(String recordId) async {
if (_isNavigating) return; await _dbService.deleteRecord(recordId);
await _loadRecords();
_isNavigating = true;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const RecordPage(),
maintainState: false,
),
).then((_) {
_isNavigating = false;
});
}
@override
void dispose() {
_accelerometerSubscription?.cancel();
super.dispose();
} }
@override @override
@ -100,17 +115,21 @@ class _HomePageState extends State<HomePage> {
appBar: AppBar( appBar: AppBar(
title: const Text('记账本'), title: const Text('记账本'),
), ),
body: Center( body: RecordList(
child: Column( records: records,
mainAxisAlignment: MainAxisAlignment.center, onRecordTap: _navigateToRecordPage,
children: [ onRecordDelete: _deleteRecord,
ElevatedButton( ),
onPressed: _navigateToRecordPage, floatingActionButton: FloatingActionButton(
child: const Text('记账'), onPressed: () => _navigateToRecordPage(),
), child: const Icon(Icons.add),
],
),
), ),
); );
} }
@override
void dispose() {
_accelerometerSubscription?.cancel();
super.dispose();
}
} }

View File

@ -1,32 +1,322 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../models/record.dart';
import '../data/categories.dart';
import 'package:uuid/uuid.dart';
class RecordPage extends StatefulWidget { 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 @override
State<RecordPage> createState() => _RecordPageState(); State<RecordPage> createState() => _RecordPageState();
} }
class _RecordPageState extends State<RecordPage> { class _RecordPageState extends State<RecordPage> 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<Category> 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( return Scaffold(
onWillPop: () async { appBar: AppBar(
Navigator.of(context).pop(); title: TabBar(
return false; controller: _tabController,
}, tabs: const [
child: Scaffold( Tab(text: '支出'),
appBar: AppBar( Tab(text: '收入'),
title: const Text('记账'), ],
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
), ),
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();
}
} }

View File

@ -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<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
/// 初始化数据库
Future<Database> _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<void> insertRecord(Record record) async {
final db = await database;
await db.insert(
'records',
record.toJson()..addAll({
'imageUrls': record.imageUrls?.join(','),
}),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
/// 更新记录
Future<void> 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<void> deleteRecord(String id) async {
final db = await database;
await db.delete(
'records',
where: 'id = ?',
whereArgs: [id],
);
}
/// 获取所有记录
Future<List<Record>> getAllRecords() async {
final db = await database;
final List<Map<String, dynamic>> 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(','),
);
});
}
}

View File

@ -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: 跳转到账户页
},
),
],
),
);
}
}

View File

@ -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<Record> 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<String, List<Record>> _groupByDate() {
final groups = <String, List<Record>>{};
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<Record> 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 = <String>[];
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(),
],
);
},
);
}
}

View File

@ -41,6 +41,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "1.18.0" version: "1.18.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -89,6 +97,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -153,7 +169,7 @@ packages:
source: hosted source: hosted
version: "1.10.0" version: "1.10.0"
path: path:
dependency: transitive dependency: "direct main"
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
@ -205,6 +221,30 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "1.10.0" 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: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -229,6 +269,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "1.2.0" 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: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -245,6 +293,22 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "0.6.1" 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: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -295,4 +359,4 @@ packages:
version: "1.1.2" version: "1.1.2"
sdks: sdks:
dart: ">=3.2.5 <4.0.0" dart: ">=3.2.5 <4.0.0"
flutter: ">=3.3.0" flutter: ">=3.7.0"

View File

@ -32,6 +32,9 @@ dependencies:
sdk: flutter sdk: flutter
sensors_plus: ^1.4.1 # 用于检测手机摇晃 sensors_plus: ^1.4.1 # 用于检测手机摇晃
vibration: ^1.8.4 # 添加震动支持 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. # The following adds the Cupertino Icons font to your application.