|
|
@@ -1,9 +1,9 @@
|
|
|
// 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';
|
|
|
+import 'package:japp_flutter/features/challenge/views/widgets/challenge_card.dart';
|
|
|
|
|
|
class ChallengeListScreen extends ConsumerWidget {
|
|
|
const ChallengeListScreen({super.key});
|
|
|
@@ -57,191 +57,16 @@ class ChallengeListScreen extends ConsumerWidget {
|
|
|
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!,
|
|
|
- ),
|
|
|
- ],
|
|
|
- ),
|
|
|
- ),
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
+ itemBuilder: (_, index) => ChallengeCard(challenge: challenges[index]),
|
|
|
+
|
|
|
+ // itemBuilder: (context, index) => ListTile(
|
|
|
+ // title: Text(challenges[index].title),
|
|
|
+ // // 其他列表项内容
|
|
|
+ // ),
|
|
|
|
|
|
-// 将复杂子组件拆分为独立组件
|
|
|
-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])),
|
|
|
- ],
|
|
|
- ),
|
|
|
);
|
|
|
}
|
|
|
}
|