From bd8eee3bdc35b298b4f5d6ef1c3b4e4f5d316fd1 Mon Sep 17 00:00:00 2001 From: ddshi <8811906+ddshi@user.noreply.gitee.com> Date: Thu, 26 Dec 2024 19:18:34 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91bug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=20=E8=AE=B0=E5=BD=95=E5=88=86=E7=B1=BBico?= =?UTF-8?q?n=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/categories.dart | 248 +++++++++--- lib/data/icons.dart | 49 +++ lib/data/mock_data.dart | 19 +- lib/models/record.dart | 30 +- lib/pages/record_page.dart | 15 +- lib/pages/record_page_base.dart | 533 -------------------------- lib/widgets/record_detail_dialog.dart | 6 +- lib/widgets/record_list.dart | 6 +- 8 files changed, 302 insertions(+), 604 deletions(-) create mode 100644 lib/data/icons.dart delete mode 100644 lib/pages/record_page_base.dart diff --git a/lib/data/categories.dart b/lib/data/categories.dart index 282b903..187b001 100644 --- a/lib/data/categories.dart +++ b/lib/data/categories.dart @@ -1,54 +1,200 @@ -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, - ), - // 可以继续添加更多分类... -]; +/// 分类配置 +class CategoryConfig { + static const Map> expenseCategories = { + 'food': { + 'name': '餐饮', + 'iconKey': 'food', + 'sortOrder': 0, + }, + 'shopping': { + 'name': '购物', + 'iconKey': 'shopping', + 'sortOrder': 1, + }, + 'transport': { + 'name': '交通', + 'iconKey': 'transport', + 'sortOrder': 2, + }, + 'entertainment': { + 'name': '娱乐', + 'iconKey': 'entertainment', + 'sortOrder': 3, + }, + 'housing': { + 'name': '住房', + 'iconKey': 'housing', + 'sortOrder': 4, + }, + 'utilities': { + 'name': '水电', + 'iconKey': 'utilities', + 'sortOrder': 5, + }, + 'medical': { + 'name': '医疗', + 'iconKey': 'medical', + 'sortOrder': 6, + }, + 'education': { + 'name': '教育', + 'iconKey': 'education', + 'sortOrder': 7, + }, + 'clothing': { + 'name': '服饰', + 'iconKey': 'clothing', + 'sortOrder': 8, + }, + 'travel': { + 'name': '旅行', + 'iconKey': 'travel', + 'sortOrder': 9, + }, + 'sports': { + 'name': '运动', + 'iconKey': 'sports', + 'sortOrder': 10, + }, + 'beauty': { + 'name': '美容', + 'iconKey': 'beauty', + 'sortOrder': 11, + }, + 'digital': { + 'name': '数码', + 'iconKey': 'digital', + 'sortOrder': 12, + }, + 'pets': { + 'name': '宠物', + 'iconKey': 'pets', + 'sortOrder': 13, + }, + 'gifts': { + 'name': '礼物', + 'iconKey': 'gifts', + 'sortOrder': 14, + }, + 'books': { + 'name': '书籍', + 'iconKey': 'books', + 'sortOrder': 15, + }, + 'insurance': { + 'name': '保险', + 'iconKey': 'insurance', + 'sortOrder': 16, + }, + 'children': { + 'name': '育儿', + 'iconKey': 'children', + 'sortOrder': 17, + }, + 'social': { + 'name': '社交', + 'iconKey': 'social', + 'sortOrder': 18, + }, + 'car': { + 'name': '汽车', + 'iconKey': 'car', + 'sortOrder': 19, + }, + }; -/// 预设收入分类 -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 + static const Map> incomeCategories = { + 'salary': { + 'name': '工资', + 'iconKey': 'salary', + 'sortOrder': 0, + }, + 'bonus': { + 'name': '奖金', + 'iconKey': 'bonus', + 'sortOrder': 1, + }, + 'investment': { + 'name': '投资', + 'iconKey': 'investment', + 'sortOrder': 2, + }, + 'partTime': { + 'name': '兼职', + 'iconKey': 'partTime', + 'sortOrder': 3, + }, + 'dividend': { + 'name': '分红', + 'iconKey': 'dividend', + 'sortOrder': 4, + }, + 'rental': { + 'name': '租金', + 'iconKey': 'rental', + 'sortOrder': 5, + }, + 'refund': { + 'name': '报销', + 'iconKey': 'refund', + 'sortOrder': 6, + }, + 'lottery': { + 'name': '中奖', + 'iconKey': 'lottery', + 'sortOrder': 7, + }, + 'gifts_received': { + 'name': '礼金', + 'iconKey': 'gifts_received', + 'sortOrder': 8, + }, + 'pension': { + 'name': '养老金', + 'iconKey': 'pension', + 'sortOrder': 9, + }, + 'interest': { + 'name': '利息', + 'iconKey': 'interest', + 'sortOrder': 10, + }, + 'business': { + 'name': '经营', + 'iconKey': 'business', + 'sortOrder': 11, + }, + 'royalties': { + 'name': '版权', + 'iconKey': 'royalties', + 'sortOrder': 12, + }, + }; + + /// 获取分类配置 + static List getCategoriesByType(RecordType type) { + final map = type == RecordType.expense ? expenseCategories : incomeCategories; + return map.entries.map((entry) => Category( + id: entry.key, + name: entry.value['name'], + iconKey: entry.value['iconKey'], + type: type, + sortOrder: entry.value['sortOrder'], + )).toList() + ..sort((a, b) => a.sortOrder.compareTo(b.sortOrder)); + } + + /// 转换为JSON格式,方便存储和同步 + static Map toJson() => { + 'expense': expenseCategories, + 'income': incomeCategories, + }; + + /// 从JSON格式转换回对象 + static CategoryConfig fromJson(Map json) { + // TODO: 实现从JSON恢复配置的逻辑 + return CategoryConfig(); + } +} \ No newline at end of file diff --git a/lib/data/icons.dart b/lib/data/icons.dart new file mode 100644 index 0000000..d290171 --- /dev/null +++ b/lib/data/icons.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +/// 预设图标映射表 +class IconMapping { + static const Map icons = { + // 支出类图标 + 'food': Icons.restaurant, + 'shopping': Icons.shopping_cart, + 'transport': Icons.directions_bus, + 'entertainment': Icons.sports_esports, + 'medical': Icons.local_hospital, + 'education': Icons.school, + 'housing': Icons.home, + 'utilities': Icons.power, + 'clothing': Icons.checkroom, + 'travel': Icons.flight, + 'sports': Icons.sports_basketball, + 'beauty': Icons.face, + 'digital': Icons.devices, + 'pets': Icons.pets, + 'gifts': Icons.card_giftcard, + 'books': Icons.book, + 'insurance': Icons.security, + 'children': Icons.child_care, + 'social': Icons.people, + 'car': Icons.directions_car, + + // 收入类图标 + 'salary': Icons.account_balance_wallet, + 'bonus': Icons.monetization_on, + 'investment': Icons.trending_up, + 'partTime': Icons.work, + 'refund': Icons.replay, + 'dividend': Icons.account_balance, + 'rental': Icons.house, + 'lottery': Icons.casino, + 'gifts_received': Icons.redeem, + 'pension': Icons.elderly, + 'interest': Icons.savings, + 'business': Icons.store, + 'royalties': Icons.copyright, + 'other': Icons.more_horiz, + }; + + /// 获取图标 + static IconData getIcon(String iconKey) { + return icons[iconKey] ?? Icons.help_outline; + } +} \ No newline at end of file diff --git a/lib/data/mock_data.dart b/lib/data/mock_data.dart index ca22181..7f4fa4c 100644 --- a/lib/data/mock_data.dart +++ b/lib/data/mock_data.dart @@ -1,6 +1,8 @@ import '../models/record.dart'; +import 'categories.dart'; -final List mockRecords = [ +/// 模拟数据 +final mockRecords = [ Record( id: '1', type: RecordType.expense, @@ -14,8 +16,17 @@ final List mockRecords = [ type: RecordType.income, categoryId: 'salary', note: '工资', - amount: 5000.0, + amount: 8000.0, createTime: DateTime.now().subtract(const Duration(days: 1)), ), - // 可以添加更多模拟数据... -]; \ No newline at end of file + // ... 其他模拟数据 +]; + +/// 获取分类名称 +String getCategoryName(String categoryId, RecordType type) { + final categories = type == RecordType.expense + ? CategoryConfig.expenseCategories + : CategoryConfig.incomeCategories; + + return categories[categoryId]?['name'] ?? '未知分类'; +} \ No newline at end of file diff --git a/lib/models/record.dart b/lib/models/record.dart index 82ee288..bf3cde3 100644 --- a/lib/models/record.dart +++ b/lib/models/record.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../data/icons.dart'; /// 记账类型枚举 enum RecordType { @@ -10,17 +11,38 @@ enum RecordType { class Category { final String id; final String name; - final IconData icon; + final String iconKey; // 改为使用图标key final RecordType type; - final String? parentId; // 为未来二级分类预留 + final int sortOrder; // 添加排序字段 const Category({ required this.id, required this.name, - required this.icon, + required this.iconKey, required this.type, - this.parentId, + required this.sortOrder, }); + + // 获取图标 + IconData get icon => IconMapping.getIcon(iconKey); + + // 转换为JSON格式 + Map toJson() => { + 'id': id, + 'name': name, + 'iconKey': iconKey, + 'type': type.index, + 'sortOrder': sortOrder, + }; + + // 从JSON格式转换回对象 + factory Category.fromJson(Map json) => Category( + id: json['id'], + name: json['name'], + iconKey: json['iconKey'], + type: RecordType.values[json['type']], + sortOrder: json['sortOrder'], + ); } /// 记账记录模型 diff --git a/lib/pages/record_page.dart b/lib/pages/record_page.dart index c08e916..86a0a31 100644 --- a/lib/pages/record_page.dart +++ b/lib/pages/record_page.dart @@ -53,7 +53,7 @@ class _RecordPageState extends State _amount = widget.record!.amount; _selectedDate = widget.record!.createTime; // 设置输入缓冲区为当前金额的格式化字符串 - _inputBuffer = _formatNumberForDisplay(widget.record!.amount); + _inputValue = _formatNumberForDisplay(widget.record!.amount); } else { // 新建模式:默认选中第一个分类 _selectedCategoryId = _currentCategories.first.id; @@ -73,8 +73,7 @@ class _RecordPageState extends State _tabController.index == 0 ? RecordType.expense : RecordType.income; /// 获取当前分类列表 - List get _currentCategories => - _currentType == RecordType.expense ? expenseCategories : incomeCategories; + List get _currentCategories => CategoryConfig.getCategoriesByType(_currentType); /// 保存记录 void _saveRecord() { @@ -154,6 +153,8 @@ class _RecordPageState extends State } } else if (_pendingOperation != null) { _pendingOperation = null; + _inputValue = _pendingValue; + _pendingValue = null; } else if (_pendingValue != null) { if (_pendingValue!.length > 1) { _pendingValue = @@ -174,6 +175,8 @@ class _RecordPageState extends State // 先保存当前运算符,因为计算可能会重置状态 final newOperator = operator; _calculateResult(); + _pendingValue = _inputValue; + _inputValue = null; // 计算完成后,设置新的运算符 setState(() { @@ -184,7 +187,7 @@ class _RecordPageState extends State _pendingOperation = newOperator; } }); - } else if (_inputValue != null) { + } else if (_inputValue != null ) { // 正常设置运算符 setState(() { _pendingOperation = operator; @@ -231,10 +234,10 @@ class _RecordPageState extends State setState(() { // 格式化结果,去掉不必要的小数位 - _pendingValue = _formatNumberForDisplay(result); + _pendingValue = null; _amount = result; _pendingOperation = null; - _inputValue = null; + _inputValue = _formatNumberForDisplay(result); }); } diff --git a/lib/pages/record_page_base.dart b/lib/pages/record_page_base.dart deleted file mode 100644 index 73580c4..0000000 --- a/lib/pages/record_page_base.dart +++ /dev/null @@ -1,533 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '../models/record.dart'; -import '../data/categories.dart'; -import 'package:uuid/uuid.dart'; - -class RecordPage extends StatefulWidget { - 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 with SingleTickerProviderStateMixin { - late TabController _tabController; - String? _selectedCategoryId; - String _note = ''; - double _amount = 0.0; - DateTime _selectedDate = DateTime.now(); - final _uuid = const Uuid(); - String _inputBuffer = '0.0'; // 用于显示的字符串 - String? _pendingOperation; // 等待执行的运算符 - double? _pendingValue; // 等待计算的第一个值 - bool _isNewInput = true; // 是否开始新的输入 - - @override - void initState() { - super.initState(); - // 先初始化 TabController - _tabController = TabController( - length: 2, - vsync: this, - initialIndex: widget.record?.type == RecordType.income ? 1 : 0, - ); - _tabController.addListener(_onTabChanged); - - // 初始化数据 - if (widget.record != null) { - // 编辑模式:初始化现有记录的数据 - _selectedCategoryId = widget.record!.categoryId; - _note = widget.record!.note ?? ''; - _amount = widget.record!.amount; - _selectedDate = widget.record!.createTime; - // 设置输入缓冲区为当前金额的格式化字符串 - _inputBuffer = _formatNumberForDisplay(widget.record!.amount); - _isNewInput = false; - } else { - // 新建模式:默认选中第一个分类 - _selectedCategoryId = _currentCategories.first.id; - } - } - - /// 标签切换监听 - void _onTabChanged() { - setState(() { - // 切换类型时选中新类型的第一个分类 - _selectedCategoryId = _currentCategories.first.id; - }); - } - - /// 获取当前记录类型 - 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(); - } - - /// 格式化显示金额 - String get _displayAmount { - if (_pendingOperation != null && _pendingValue != null) { - return '$_pendingValue $_pendingOperation ${_isNewInput ? "" : _inputBuffer}'; - } - return _inputBuffer; - } - - /// 处理数字输入 - void _handleNumber(String digit) { - setState(() { - if (_isNewInput) { - // 新输入时直接替换 - _inputBuffer = digit; - _isNewInput = false; - } else if (_inputBuffer == '0' && !_inputBuffer.contains('.')) { - // 当前是0且没有小数点时,直接替换0 - _inputBuffer = digit; - } else if (_inputBuffer == '0.0') { - // 如果是默认状态,直接替换为新数字 - _inputBuffer = digit; - _isNewInput = false; - } else { - // 其他情况追加数字 - _inputBuffer = _inputBuffer + digit; - } - _amount = double.parse(_inputBuffer); - }); - } - - /// 处理小数点 - void _handleDecimal() { - setState(() { - if (!_inputBuffer.contains('.')) { - // 如果是默认状态(0.0)或只有0,直接显示0. - if (_inputBuffer == '0.0' || _inputBuffer == '0') { - _inputBuffer = '0.'; - _isNewInput = false; - } else { - // 其他数字直接加小数点 - _inputBuffer = '$_inputBuffer.'; - } - } else { - // 已有小数点时震动反馈 - HapticFeedback.heavyImpact(); - } - }); - } - - /// 处理删除 - void _handleDelete() { - setState(() { - if (_pendingOperation != null && !_isNewInput) { - // 删除第二个数字 - if (_inputBuffer.length > 1) { - _inputBuffer = _inputBuffer.substring(0, _inputBuffer.length - 1); - if (_inputBuffer.isEmpty || _inputBuffer == '0') { - _inputBuffer = '0.0'; - _isNewInput = true; - } - } else { - _inputBuffer = '0.0'; - _isNewInput = true; - } - } else if (_pendingOperation != null) { - // 删除运算符 - _inputBuffer = _pendingValue.toString(); - _pendingOperation = null; - _pendingValue = null; - _isNewInput = false; - } else { - // 删除普通数字 - if (_inputBuffer.length > 1) { - _inputBuffer = _inputBuffer.substring(0, _inputBuffer.length - 1); - if (_inputBuffer.isEmpty || _inputBuffer == '0') { - _inputBuffer = '0.0'; - } - } else { - _inputBuffer = '0.0'; - } - } - _amount = double.parse(_inputBuffer); - }); - } - - /// 处理运算符 - void _handleOperator(String operator) { - // 如果有待处理的运算,先计算结果 - if (_pendingOperation != null && !_isNewInput) { - // 先保存当前运算符,因为计算可能会重置状态 - final newOperator = operator; - _calculateResult(); - - // 如果计算导致重置(结果为0),不添加新的运算符 - if (_inputBuffer == '0.0') { - return; - } - - // 计算完成后,设置新的运算符 - setState(() { - _pendingOperation = newOperator; - _pendingValue = double.parse(_inputBuffer); - _isNewInput = true; - }); - } else { - // 正常设置运算符 - setState(() { - _pendingOperation = operator; - _pendingValue = double.parse(_inputBuffer); - _isNewInput = true; - }); - } - } - - /// 计算结果 - void _calculateResult() { - if (_pendingOperation != null && _pendingValue != null && !_isNewInput) { - final currentValue = double.parse(_inputBuffer); - double result; - - switch (_pendingOperation) { - case '+': - result = _pendingValue! + currentValue; - if (result == 0) { - _resetToDefault(); - return; - } - break; - case '-': - result = _pendingValue! - currentValue; - if (result <= 0) { - _resetToDefault(); - return; - } - break; - default: - return; - } - - setState(() { - // 格式化结果,去掉不必要的小数位 - _inputBuffer = _formatNumberForDisplay(result); - _amount = result; - _pendingOperation = null; - _pendingValue = null; - _isNewInput = true; - }); - } - } - - /// 重置到默认状态 - void _resetToDefault() { - setState(() { - _inputBuffer = '0.0'; - _amount = 0; - _pendingOperation = null; - _pendingValue = null; - _isNewInput = true; - }); - } - - /// 格式化数字用于显示 - String _formatNumberForDisplay(double number) { - // 如果是整数,直接返回整数部分 - if (number % 1 == 0) { - return number.toInt().toString(); - } - // 如果是小数,去掉末尾的0 - String numStr = number.toString(); - while (numStr.endsWith('0')) { - numStr = numStr.substring(0, numStr.length - 1); - } - if (numStr.endsWith('.')) { - numStr = numStr.substring(0, numStr.length - 1); - } - return numStr; - } - - /// 修改键盘按钮处理逻辑 - void _onKeyboardButtonPressed(String value) { - switch (value) { - case '删除': - _handleDelete(); - break; - case '保存': - _calculateResult(); - _saveRecord(); - break; - case 'again': - // TODO: 实现again功能 - break; - case '+': - case '-': - _handleOperator(value); - break; - case '.': - _handleDecimal(); - break; - default: - _handleNumber(value); - } - } - - /// 格式化日期显示 - String _formatDate(DateTime date) { - final now = DateTime.now(); - final today = DateTime(now.year, now.month, now.day); - final dateToCheck = DateTime(date.year, date.month, date.day); - final difference = today.difference(dateToCheck).inDays; - - // 检查是否是今天、昨天、前天 - switch (difference) { - case 0: - return '今天'; - case 1: - return '昨天'; - case 2: - return '前天'; - default: - // 如果是当年 - if (date.year == now.year) { - return '${date.month}/${date.day}'; - } - // 不是当年 - return '${date.year}/${date.month}/${date.day}'; - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: TabBar( - controller: _tabController, - tabs: const [ - Tab(text: '支出'), - Tab(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: [ - // 备注和金额 - _buildNoteAndAmount(), - // 配置按钮 - 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(_formatDate(_selectedDate)), - ), - 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, - ), - ), - ); - } - - /// 构建底部编辑区域中的备注和金额行 - Widget _buildNoteAndAmount() { - return Row( - children: [ - Expanded( - child: TextField( - controller: TextEditingController(text: _note), // 使用控制器设置初始值 - decoration: const InputDecoration( - hintText: '添加备注', - border: InputBorder.none, - ), - onChanged: (value) => setState(() => _note = value), - ), - ), - Text( - _displayAmount, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - ], - ); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/widgets/record_detail_dialog.dart b/lib/widgets/record_detail_dialog.dart index a42034b..ebc0a26 100644 --- a/lib/widgets/record_detail_dialog.dart +++ b/lib/widgets/record_detail_dialog.dart @@ -15,14 +15,14 @@ class RecordDetailDialog extends StatelessWidget { }) : super(key: key); /// 获取分类信息 - Category _getCategory(String categoryId) { - return [...expenseCategories, ...incomeCategories] + Category _getCategory(String categoryId, RecordType type) { + return CategoryConfig.getCategoriesByType(type) .firstWhere((c) => c.id == categoryId); } @override Widget build(BuildContext context) { - final category = _getCategory(record.categoryId); + final category = _getCategory(record.categoryId, record.type); return AlertDialog( title: Row( diff --git a/lib/widgets/record_list.dart b/lib/widgets/record_list.dart index 485ce02..b75bf2c 100644 --- a/lib/widgets/record_list.dart +++ b/lib/widgets/record_list.dart @@ -17,8 +17,8 @@ class RecordList extends StatelessWidget { }) : super(key: key); /// 获取分类信息 - Category _getCategory(String categoryId) { - return [...expenseCategories, ...incomeCategories] + Category _getCategory(String categoryId, RecordType type) { + return CategoryConfig.getCategoriesByType(type) .firstWhere((c) => c.id == categoryId); } @@ -96,7 +96,7 @@ class RecordList extends StatelessWidget { ), // 记录列表 ...dayRecords.map((record) { - final category = _getCategory(record.categoryId); + final category = _getCategory(record.categoryId, record.type); return ListTile( leading: Icon(category.icon), title: Text(category.name),