import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../constants.dart'; import '../../providers/bill_provider.dart'; import '../../theme/colors.dart'; import '../../widgets/number_pad.dart'; import '../../widgets/category_grid.dart'; class AddBillScreen extends ConsumerStatefulWidget { const AddBillScreen({super.key}); @override ConsumerState createState() => _AddBillScreenState(); } class _AddBillScreenState extends ConsumerState { bool _isExpense = true; String _amount = '0'; String _category = '餐饮'; String _note = ''; DateTime _selectedDate = DateTime.now(); bool _addToFamily = false; void _onKeyTap(String key) { setState(() { if (key == 'delete') { if (_amount.length > 1) { _amount = _amount.substring(0, _amount.length - 1); } else { _amount = '0'; } } else if (key == '.') { if (!_amount.contains('.')) { _amount += '.'; } } else { if (_amount == '0') { _amount = key; } else { // Limit to 2 decimal places final parts = _amount.split('.'); if (parts.length == 2 && parts[1].length >= 2) { return; } // Limit total length if (_amount.length >= 10) { return; } _amount += key; } } }); } String get _displayAmount { final value = double.tryParse(_amount) ?? 0; if (value == value.roundToDouble() && !_amount.contains('.')) { return value.toInt().toString(); } return _amount; } Future _selectDate() async { final picked = await showDatePicker( context: context, initialDate: _selectedDate, firstDate: DateTime(2020), lastDate: DateTime.now().add(const Duration(days: 365)), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: const ColorScheme.light( primary: AppColors.brand, onPrimary: Colors.white, surface: Colors.white, onSurface: AppColors.textPrimary, ), ), child: child!, ); }, ); if (picked != null) { setState(() { _selectedDate = picked; }); } } Future _saveBill() async { final amountValue = double.tryParse(_amount); if (amountValue == null || amountValue <= 0) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请输入有效金额')), ); return; } final data = { 'type': _isExpense ? 'expense' : 'income', 'amount': amountValue, 'category': _category, 'note': _note, 'emoji': AppConstants.categoryEmoji(_category), 'date': '${_selectedDate.year}-${_selectedDate.month.toString().padLeft(2, '0')}-${_selectedDate.day.toString().padLeft(2, '0')}', 'time': '${DateTime.now().hour.toString().padLeft(2, '0')}:${DateTime.now().minute.toString().padLeft(2, '0')}', 'familyId': _addToFamily ? 'default' : null, }; final success = await ref.read(billProvider.notifier).addBill(data); if (mounted) { if (success) { Navigator.of(context).pop(true); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('保存失败')), ); } } } @override Widget build(BuildContext context) { final categories = _isExpense ? AppConstants.expenseCategories : AppConstants.incomeCategories; // Set default category based on type if (_isExpense && _category == '工资') { _category = '餐饮'; } else if (!_isExpense && _category == '餐饮') { _category = '工资'; } return Scaffold( backgroundColor: AppColors.pageBg, body: SafeArea( child: Column( children: [ // Header Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.close, size: 28), color: AppColors.textPrimary, ), const Text( '添加账单', style: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), TextButton( onPressed: _saveBill, child: const Text( '保存', style: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: AppColors.brand, ), ), ), ], ), ), // iOS Segment Control Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Container( height: 36, decoration: BoxDecoration( color: Colors.white.withOpacity(0.7), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() { _isExpense = true; _category = '餐饮'; }), child: Container( decoration: BoxDecoration( color: _isExpense ? AppColors.expense : Colors.transparent, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( '支出', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: _isExpense ? Colors.white : AppColors.textSecondary, ), ), ), ), ), ), Expanded( child: GestureDetector( onTap: () => setState(() { _isExpense = false; _category = '工资'; }), child: Container( decoration: BoxDecoration( color: !_isExpense ? AppColors.income : Colors.transparent, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( '收入', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: !_isExpense ? Colors.white : AppColors.textSecondary, ), ), ), ), ), ), ], ), ), ), // Amount Display Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ const Text( '¥', style: TextStyle( fontSize: 28, fontWeight: FontWeight.w500, color: AppColors.textPrimary, ), ), const SizedBox(width: 4), Text( _displayAmount, style: const TextStyle( fontSize: 48, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), ], ), ), // Category Grid Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: CategoryGrid( categories: categories, selected: _category, onSelect: (cat) => setState(() => _category = cat), ), ), const SizedBox(height: 16), // Note Input Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: Colors.white.withOpacity(0.65), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ const Icon(Icons.edit_note, color: AppColors.textSecondary, size: 20), const SizedBox(width: 8), Expanded( child: TextField( onChanged: (v) => _note = v, style: const TextStyle( fontSize: 15, color: AppColors.textPrimary, ), decoration: const InputDecoration( hintText: '添加备注', hintStyle: TextStyle( color: AppColors.textSecondary, fontSize: 15, ), border: InputBorder.none, isDense: true, contentPadding: EdgeInsets.zero, ), ), ), ], ), ), ), const SizedBox(height: 12), // Date Picker & Family Toggle Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ // Date Picker Expanded( child: GestureDetector( onTap: _selectDate, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: Colors.white.withOpacity(0.65), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ const Icon(Icons.calendar_today, color: AppColors.textSecondary, size: 18), const SizedBox(width: 8), Text( '${_selectedDate.year}-${_selectedDate.month.toString().padLeft(2, '0')}-${_selectedDate.day.toString().padLeft(2, '0')}', style: const TextStyle( fontSize: 15, color: AppColors.textPrimary, ), ), ], ), ), ), ), const SizedBox(width: 12), // Family Toggle GestureDetector( onTap: () => setState(() => _addToFamily = !_addToFamily), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: _addToFamily ? AppColors.brand.withOpacity(0.1) : Colors.white.withOpacity(0.65), borderRadius: BorderRadius.circular(12), border: Border.all( color: _addToFamily ? AppColors.brand : Colors.white.withOpacity(0.5), width: 1, ), ), child: Row( children: [ Icon( Icons.family_restroom, color: _addToFamily ? AppColors.brand : AppColors.textSecondary, size: 18, ), const SizedBox(width: 6), Text( '家庭账本', style: TextStyle( fontSize: 14, fontWeight: _addToFamily ? FontWeight.w600 : FontWeight.w500, color: _addToFamily ? AppColors.brand : AppColors.textSecondary, ), ), ], ), ), ), ], ), ), const Spacer(), // Number Pad NumberPad(onKeyTap: _onKeyTap), const SizedBox(height: 20), ], ), ), ); } }