import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../theme/app_theme.dart'; import '../models/time_goal.dart'; import '../database/time_goal_dao.dart'; class GoalSettingScreen extends ConsumerStatefulWidget { const GoalSettingScreen({super.key}); @override ConsumerState createState() => _GoalSettingScreenState(); } class _GoalSettingScreenState extends ConsumerState { final TimeGoalDao _goalDao = TimeGoalDao(); TimeGoal? _dailyTotalGoal; final Map _categoryGoals = {}; @override void initState() { super.initState(); _loadGoals(); } Future _loadGoals() async { // 获取所有目标(包括非激活的),以便正确显示开关状态 final allGoals = await _goalDao.getAllGoals(); setState(() { // 查找每日总时长目标 final dailyTotal = allGoals.firstWhere( (g) => g.goalType == 'daily_total', orElse: () => TimeGoal( goalType: 'daily_total', targetTime: 28800, // 默认 8 小时 isActive: _dailyTotalGoal?.isActive ?? true, // 保持当前状态 createdAt: _dailyTotalGoal?.createdAt ?? DateTime.now(), updatedAt: DateTime.now(), ), ); // 如果找到的目标有 ID,使用它;否则保持当前 ID(如果有) _dailyTotalGoal = TimeGoal( id: dailyTotal.id ?? _dailyTotalGoal?.id, goalType: dailyTotal.goalType, targetTime: dailyTotal.targetTime, isActive: dailyTotal.isActive, createdAt: dailyTotal.createdAt, updatedAt: dailyTotal.updatedAt, ); final categories = ['work', 'study', 'entertainment', 'social', 'tool']; for (final category in categories) { _categoryGoals[category] = allGoals.firstWhere( (g) => g.goalType == 'daily_category' && g.category == category, orElse: () => TimeGoal( goalType: 'daily_category', category: category, targetTime: 0, isActive: false, createdAt: DateTime.now(), updatedAt: DateTime.now(), ), ); } }); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( appBar: AppBar( title: const Text('时间目标'), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 每日总时长目标 _buildDailyTotalGoalCard(theme), const SizedBox(height: 16), // 分类时间限制 _buildCategoryGoalsCard(theme), ], ), ), ); } Widget _buildDailyTotalGoalCard(ThemeData theme) { return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.timer, color: AppTheme.primaryColor), const SizedBox(width: 8), Text( '每日总时长目标', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), ], ), const SizedBox(height: 16), if (_dailyTotalGoal != null) ...[ Row( children: [ Expanded( child: Text( _dailyTotalGoal!.formattedTargetTime, style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, color: AppTheme.primaryColor, ), ), ), Switch( value: _dailyTotalGoal!.isActive, onChanged: (value) async { // 先更新本地状态,立即显示变化 setState(() { _dailyTotalGoal = TimeGoal( id: _dailyTotalGoal!.id, goalType: _dailyTotalGoal!.goalType, targetTime: _dailyTotalGoal!.targetTime, isActive: value, createdAt: _dailyTotalGoal!.createdAt, updatedAt: DateTime.now(), ); }); // 然后保存到数据库 await _goalDao.upsertTimeGoal(_dailyTotalGoal!); // 重新加载以确保数据同步 await _loadGoals(); }, ), ], ), const SizedBox(height: 16), _buildTimePicker( theme, '设置目标时长', _dailyTotalGoal!.targetTime, (hours, minutes) async { final targetTime = hours * 3600 + minutes * 60; final updatedGoal = TimeGoal( id: _dailyTotalGoal!.id, goalType: 'daily_total', targetTime: targetTime, isActive: _dailyTotalGoal!.isActive, createdAt: _dailyTotalGoal!.createdAt, updatedAt: DateTime.now(), ); await _goalDao.upsertTimeGoal(updatedGoal); await _loadGoals(); }, ), ], ], ), ), ); } Widget _buildCategoryGoalsCard(ThemeData theme) { return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.category, color: AppTheme.primaryColor), const SizedBox(width: 8), Text( '分类时间限制', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), ], ), const SizedBox(height: 16), ...['work', 'study', 'entertainment', 'social', 'tool'].map((category) { final goal = _categoryGoals[category]; return _buildCategoryGoalItem(theme, category, goal); }), ], ), ), ); } Widget _buildCategoryGoalItem( ThemeData theme, String category, TimeGoal? goal, ) { final isActive = goal?.isActive ?? false; final targetTime = goal?.targetTime ?? 0; return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( children: [ Container( width: 12, height: 12, decoration: BoxDecoration( color: AppTheme.getCategoryColor(category), shape: BoxShape.circle, ), ), const SizedBox(width: 12), Expanded( child: Text( AppTheme.getCategoryName(category), style: theme.textTheme.bodyLarge, ), ), Text( targetTime > 0 ? _formatTime(targetTime) : '未设置', style: theme.textTheme.bodyMedium?.copyWith( color: isActive ? AppTheme.primaryColor : theme.colorScheme.onSurface.withOpacity(0.5), fontWeight: isActive ? FontWeight.w600 : FontWeight.normal, ), ), const SizedBox(width: 12), Switch( value: isActive, onChanged: (value) async { if (value && targetTime == 0) { // 如果启用但未设置时间,先设置默认值 final defaultGoal = TimeGoal( id: goal?.id, goalType: 'daily_category', category: category, targetTime: 7200, // 默认 2 小时 isActive: true, createdAt: goal?.createdAt ?? DateTime.now(), updatedAt: DateTime.now(), ); await _goalDao.upsertTimeGoal(defaultGoal); } else { final updatedGoal = TimeGoal( id: goal?.id, goalType: 'daily_category', category: category, targetTime: targetTime, isActive: value, createdAt: goal?.createdAt ?? DateTime.now(), updatedAt: DateTime.now(), ); await _goalDao.upsertTimeGoal(updatedGoal); } await _loadGoals(); }, ), IconButton( icon: const Icon(Icons.edit), onPressed: () { _showCategoryGoalDialog(theme, category, goal); }, ), ], ), ); } void _showCategoryGoalDialog(ThemeData theme, String category, TimeGoal? goal) { final currentTime = goal?.targetTime ?? 0; final hours = currentTime ~/ 3600; final minutes = (currentTime % 3600) ~/ 60; showDialog( context: context, builder: (context) => _TimePickerDialog( title: '设置 ${AppTheme.getCategoryName(category)} 时间限制', initialHours: hours, initialMinutes: minutes, onSave: (hours, minutes) async { final targetTime = hours * 3600 + minutes * 60; final updatedGoal = TimeGoal( id: goal?.id, goalType: 'daily_category', category: category, targetTime: targetTime, isActive: true, createdAt: goal?.createdAt ?? DateTime.now(), updatedAt: DateTime.now(), ); await _goalDao.upsertTimeGoal(updatedGoal); await _loadGoals(); }, ), ); } Widget _buildTimePicker( ThemeData theme, String title, int currentTime, Future Function(int hours, int minutes) onSave, ) { final hours = currentTime ~/ 3600; final minutes = (currentTime % 3600) ~/ 60; return ElevatedButton.icon( onPressed: () { showDialog( context: context, builder: (context) => _TimePickerDialog( title: title, initialHours: hours, initialMinutes: minutes, onSave: onSave, ), ); }, icon: const Icon(Icons.access_time), label: Text('${hours}小时 ${minutes}分钟'), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ); } String _formatTime(int seconds) { final hours = seconds ~/ 3600; final minutes = (seconds % 3600) ~/ 60; if (hours > 0) { return '${hours}h ${minutes}m'; } return '${minutes}m'; } } class _TimePickerDialog extends StatefulWidget { final String title; final int initialHours; final int initialMinutes; final Future Function(int hours, int minutes) onSave; const _TimePickerDialog({ required this.title, required this.initialHours, required this.initialMinutes, required this.onSave, }); @override State<_TimePickerDialog> createState() => _TimePickerDialogState(); } class _TimePickerDialogState extends State<_TimePickerDialog> { late int _hours; late int _minutes; @override void initState() { super.initState(); _hours = widget.initialHours; _minutes = widget.initialMinutes; } @override Widget build(BuildContext context) { final theme = Theme.of(context); return AlertDialog( title: Text(widget.title), content: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // 小时选择 Column( children: [ Text('小时', style: theme.textTheme.bodySmall), const SizedBox(height: 8), Row( children: [ IconButton( icon: const Icon(Icons.remove_circle_outline), onPressed: () { setState(() { if (_hours > 0) _hours--; }); }, ), SizedBox( width: 60, child: Text( '$_hours', textAlign: TextAlign.center, style: theme.textTheme.headlineMedium, ), ), IconButton( icon: const Icon(Icons.add_circle_outline), onPressed: () { setState(() { if (_hours < 24) _hours++; }); }, ), ], ), ], ), const SizedBox(width: 24), // 分钟选择 Column( children: [ Text('分钟', style: theme.textTheme.bodySmall), const SizedBox(height: 8), Row( children: [ IconButton( icon: const Icon(Icons.remove_circle_outline), onPressed: () { setState(() { if (_minutes > 0) { _minutes -= 15; if (_minutes < 0) _minutes = 0; } }); }, ), SizedBox( width: 60, child: Text( '$_minutes', textAlign: TextAlign.center, style: theme.textTheme.headlineMedium, ), ), IconButton( icon: const Icon(Icons.add_circle_outline), onPressed: () { setState(() { _minutes += 15; if (_minutes >= 60) { _hours++; _minutes = 0; } if (_hours >= 24) { _hours = 23; _minutes = 59; } }); }, ), ], ), ], ), ], ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('取消'), ), ElevatedButton( onPressed: () async { await widget.onSave(_hours, _minutes); if (mounted) { Navigator.of(context).pop(); } }, child: const Text('保存'), ), ], ); } }