import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:japp_flutter/core/models/challenge_model.dart'; import 'package:japp_flutter/features/challenge/view_models/challenge_view_model.dart'; import 'package:provider/provider.dart'; class ChallengeListScreen extends StatefulWidget { const ChallengeListScreen({super.key}); @override State createState() => _ChallengeListScreenState(); } class _ChallengeListScreenState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false).fetchChallenges(); }); } @override Widget build(BuildContext context) { final viewModel = Provider.of(context); return Scaffold( appBar: AppBar( title: const Text('挑战列表'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: viewModel.fetchChallenges, ), ], ), body: _buildBody(viewModel), ); } Widget _buildBody(ChallengeListViewModel viewModel) { if (viewModel.isLoading) { return const Center(child: CircularProgressIndicator()); } if (viewModel.error.isNotEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error, color: Colors.red, size: 48), const SizedBox(height: 16), Text(viewModel.error, style: const TextStyle(color: Colors.red)), const SizedBox(height: 16), ElevatedButton( onPressed: viewModel.fetchChallenges, child: const Text('重试'), ), ], ), ); } if (viewModel.challenges.isEmpty) { return const Center( child: Text('暂无挑战', style: TextStyle(fontSize: 18)), ); } return RefreshIndicator( onRefresh: viewModel.fetchChallenges, child: ListView.builder( padding: const EdgeInsets.all(16), itemCount: viewModel.challenges.length, itemBuilder: (context, index) { return ChallengeCard(challenge: viewModel.challenges[index]); }, ), ); } } class ChallengeCard extends StatelessWidget { final ChallengeModel challenge; const ChallengeCard({super.key, required this.challenge}); Color _getDifficultyColor() { switch (challenge.difficulty) { case '简单': return Colors.green; case '中等': return Colors.orange; case '困难': return Colors.red; default: return Colors.grey; } } @override Widget build(BuildContext context) { final theme = Theme.of(context); // 获取当前主题 return Card( elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), margin: const EdgeInsets.only(bottom: 16), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( challenge.title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ), Chip( label: Text( challenge.difficulty, style: const TextStyle(color: Colors.white), ), backgroundColor: _getDifficultyColor(), ), ], ), const SizedBox(height: 8), Text( challenge.description, style: TextStyle(color: Colors.grey[700], fontSize: 14), ), const SizedBox(height: 16), _buildProgressBar(context), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildInfoChip( Icons.people, '${challenge.participants}人参加', ), _buildInfoChip( Icons.calendar_today, '剩余${challenge.remainingDays}天', ), ], ), ], ), ), ); } Widget _buildProgressBar(BuildContext context) { final theme = Theme.of(context); final totalDays = challenge.endDate.difference(challenge.startDate).inDays; final passedDays = totalDays - challenge.remainingDays; final progress = passedDays / totalDays; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${(progress * 100).toStringAsFixed(0)}%', style: const TextStyle(fontSize: 12), ), const SizedBox(height: 4), LinearProgressIndicator( value: progress, backgroundColor: Colors.grey[200], borderRadius: BorderRadius.circular(10), minHeight: 8, color: theme.primaryColor, // 使用主题色 ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( DateFormat('MM/dd').format(challenge.startDate), style: const TextStyle(fontSize: 12), ), Text( DateFormat('MM/dd').format(challenge.endDate), style: const TextStyle(fontSize: 12), ), ], ), ], ); } Widget _buildInfoChip(IconData icon, String text) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(20), ), child: Row( children: [ Icon(icon, size: 16, color: Colors.grey[600]), const SizedBox(width: 4), Text(text, style: TextStyle(color: Colors.grey[700])), ], ), ); } }