challenge_detail_screen.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import 'package:flutter/material.dart';
  2. import 'package:intl/intl.dart';
  3. import 'package:japp_flutter/core/models/challenge_model.dart';
  4. import 'package:japp_flutter/features/challenge/view_models/challenge_detail_vm.dart';
  5. import 'package:flutter_riverpod/flutter_riverpod.dart';
  6. class ChallengeDetailScreen extends ConsumerWidget {
  7. final int challengeId;
  8. const ChallengeDetailScreen({super.key, required this.challengeId});
  9. @override
  10. Widget build(BuildContext context, WidgetRef ref) {
  11. final challengeAsync = ref.watch(challengeDetailProvider);
  12. return Scaffold(
  13. appBar: AppBar(
  14. title: const Text("挑战详情"),
  15. actions: [
  16. IconButton(
  17. icon: const Icon(Icons.edit),
  18. onPressed: () {
  19. final challenge = challengeAsync.value;
  20. if (challenge != null) {
  21. Navigator.pushNamed(context, '/edit/${challenge.id}');
  22. }
  23. },
  24. ),
  25. ],
  26. ),
  27. body: switch (challengeAsync) {
  28. AsyncError(:final error) => Center(child: Text('加载失败: $error')),
  29. AsyncData(value: final value) => _buildChallengeContent(value!),
  30. _ => const Center(child: CircularProgressIndicator()),
  31. },
  32. );
  33. }
  34. Widget _buildChallengeContent(ChallengeModel challenge) {
  35. return SingleChildScrollView(
  36. padding: const EdgeInsets.all(16),
  37. child: Column(
  38. crossAxisAlignment: CrossAxisAlignment.start,
  39. children: [
  40. Text(
  41. challenge.title,
  42. style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
  43. ),
  44. const SizedBox(height: 8),
  45. Chip(
  46. label: Text(
  47. challenge.difficulty,
  48. style: const TextStyle(color: Colors.white),
  49. ),
  50. backgroundColor: _getDifficultyColor(challenge.difficulty),
  51. ),
  52. const SizedBox(height: 16),
  53. Text(
  54. challenge.description,
  55. style: const TextStyle(fontSize: 16, height: 1.5),
  56. ),
  57. const SizedBox(height: 24),
  58. _buildDateInfo('开始时间', challenge.startDate),
  59. _buildDateInfo('结束时间', challenge.endDate),
  60. const SizedBox(height: 16),
  61. _buildParticipantInfo(challenge.participants),
  62. const SizedBox(height: 24),
  63. _buildProgressSection(challenge),
  64. ],
  65. ),
  66. );
  67. }
  68. Widget _buildDateInfo(String label, DateTime date) {
  69. return Padding(
  70. padding: const EdgeInsets.only(bottom: 8),
  71. child: Row(
  72. children: [
  73. Text('$label: ', style: const TextStyle(fontWeight: FontWeight.bold)),
  74. Text(DateFormat('yyyy年MM月dd日').format(date)),
  75. ],
  76. ),
  77. );
  78. }
  79. Widget _buildParticipantInfo(int count) {
  80. return Row(
  81. children: [
  82. const Icon(Icons.people, size: 20),
  83. const SizedBox(width: 8),
  84. Text('$count 人参与'),
  85. ],
  86. );
  87. }
  88. Widget _buildProgressSection(ChallengeModel challenge) {
  89. final totalDays = challenge.endDate.difference(challenge.startDate).inDays;
  90. final passedDays = totalDays - challenge.remainingDays!;
  91. final progress = passedDays / totalDays;
  92. return Column(
  93. crossAxisAlignment: CrossAxisAlignment.start,
  94. children: [
  95. Text(
  96. '进度 ${(progress * 100).toStringAsFixed(0)}%',
  97. style: const TextStyle(fontWeight: FontWeight.bold),
  98. ),
  99. const SizedBox(height: 8),
  100. LinearProgressIndicator(
  101. value: progress,
  102. minHeight: 10,
  103. borderRadius: BorderRadius.circular(5),
  104. color: Colors.blue,
  105. backgroundColor: Colors.blue.shade100,
  106. ),
  107. const SizedBox(height: 8),
  108. Row(
  109. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  110. children: [
  111. Text('已进行 $passedDays 天'),
  112. Text('剩余 ${challenge.remainingDays} 天'),
  113. ],
  114. ),
  115. ],
  116. );
  117. }
  118. Color _getDifficultyColor(String difficulty) {
  119. switch (difficulty) {
  120. case '简单':
  121. return Colors.green;
  122. case '中等':
  123. return Colors.orange;
  124. case '困难':
  125. return Colors.red;
  126. default:
  127. return Colors.grey;
  128. }
  129. }
  130. }