// challenge_list_screen.dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import 'package:japp_flutter/core/models/challenge_model.dart'; import 'package:japp_flutter/features/challenge/view_models/challenge_list_vm.dart'; class ChallengeListScreen extends ConsumerWidget { const ChallengeListScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final challengesState = ref.watch(challengeListProvider); return Scaffold( appBar: AppBar( title: const Text('挑战列表'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: () => ref.read(challengeListProvider.notifier).refresh(), ), ], ), body: _buildBody(challengesState, ref), floatingActionButton: FloatingActionButton( onPressed: () => Navigator.pushNamed(context, '/challenge/add'), child: const Icon(Icons.add), ), ); } Widget _buildBody(AsyncValue> state, WidgetRef ref) { return state.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) => Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error, color: Colors.red, size: 48), const SizedBox(height: 16), Text('加载失败: $error', style: const TextStyle(color: Colors.red)), const SizedBox(height: 16), ElevatedButton( onPressed: () => ref.read(challengeListProvider.notifier).refresh(), child: const Text('重试'), ), ], ), ), data: (challenges) => challenges.isEmpty ? const Center(child: Text('暂无挑战', style: TextStyle(fontSize: 18))) : RefreshIndicator( onRefresh: () => ref.read(challengeListProvider.notifier).refresh(), child: ListView.builder( padding: const EdgeInsets.all(16), itemCount: challenges.length, // itemBuilder: (_, index) => ChallengeCard(challenge: challenges[index]), itemBuilder: (context, index) => ListTile( title: Text(challenges[index].title), // 其他列表项内容 ), ), ), ); } } class ChallengeCard extends StatelessWidget { final ChallengeModel challenge; const ChallengeCard({super.key, required this.challenge}); @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, ), ), ), _DifficultyChip(difficulty: challenge.difficulty), ], ), const SizedBox(height: 8), Text( challenge.description, style: TextStyle(color: Colors.grey[700], fontSize: 14), ), const SizedBox(height: 16), _ProgressBar( startDate: challenge.startDate, endDate: challenge.endDate, remainingDays: challenge.remainingDays!, ), const SizedBox(height: 12), _CardFooter( participants: challenge.participants, remainingDays: challenge.remainingDays!, ), ], ), ), ); } } // 将复杂子组件拆分为独立组件 class _DifficultyChip extends StatelessWidget { final String difficulty; const _DifficultyChip({required this.difficulty}); Color _getColor() { switch (difficulty) { case '简单': return Colors.green; case '中等': return Colors.orange; case '困难': return Colors.red; default: return Colors.grey; } } @override Widget build(BuildContext context) { return Chip( label: Text(difficulty, style: const TextStyle(color: Colors.white)), backgroundColor: _getColor(), ); } } class _ProgressBar extends StatelessWidget { final DateTime startDate; final DateTime endDate; final int remainingDays; const _ProgressBar({ required this.startDate, required this.endDate, required this.remainingDays, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); final totalDays = endDate.difference(startDate).inDays; final passedDays = totalDays - 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(startDate), style: const TextStyle(fontSize: 12), ), Text( DateFormat('MM/dd').format(endDate), style: const TextStyle(fontSize: 12), ), ], ), ], ); } } class _CardFooter extends StatelessWidget { final int participants; final int remainingDays; const _CardFooter({required this.participants, required this.remainingDays}); @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _InfoChip(icon: Icons.people, text: '$participants人参加'), _InfoChip(icon: Icons.calendar_today, text: '剩余${remainingDays}天'), ], ); } } class _InfoChip extends StatelessWidget { final IconData icon; final String text; const _InfoChip({required this.icon, required this.text}); @override Widget build(BuildContext context) { 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])), ], ), ); } }