| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- // features/challenge/add/add_challenge_screen.dart
- import 'package:flutter/material.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:intl/intl.dart';
- import 'package:japp_flutter/core/constants/options.dart';
- import 'package:japp_flutter/core/models/challenge_model.dart';
- import 'package:japp_flutter/features/challenge/view_models/challenge_add_vm.dart';
- class AddChallengeScreen extends ConsumerWidget {
- const AddChallengeScreen({super.key});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final challengeState = ref.watch(addChallengeProvider);
- final theme = Theme.of(context);
- return Scaffold(
- appBar: AppBar(
- title: const Text('创建新挑战'),
- actions: [
- IconButton(
- icon: const Icon(Icons.check),
- onPressed: () async {
- await ref.read(addChallengeProvider.notifier).submitChallenge();
- if (context.mounted) Navigator.pop(context);
- },
- tooltip: '提交',
- ),
- ],
- ),
- body: challengeState.when(
- loading: () => const Center(child: CircularProgressIndicator()),
- error: (error, _) => Center(child: Text('错误: $error')),
- data: (challenge) => _BuildForm(challenge: challenge),
- ),
- );
- }
- }
- class _BuildForm extends ConsumerWidget {
- final ChallengeModel challenge;
- const _BuildForm({required this.challenge});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- return SingleChildScrollView(
- padding: const EdgeInsets.all(16),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- _TitleField(initialValue: challenge.title),
- const SizedBox(height: 24),
- _DateRangeField(
- startDate: challenge.startDate!,
- endDate: challenge.endDate!,
- ),
- const SizedBox(height: 24),
- _DifficultySelector(currentDifficulty: challenge.difficulty),
- const SizedBox(height: 24),
- _DescriptionField(initialValue: challenge.description),
- ],
- ),
- );
- }
- }
- class _TitleField extends ConsumerWidget {
- final String initialValue;
- const _TitleField({required this.initialValue});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- return TextFormField(
- initialValue: initialValue,
- decoration: const InputDecoration(
- labelText: '挑战标题*',
- border: OutlineInputBorder(),
- ),
- onChanged: (value) => ref.read(addChallengeProvider.notifier).updateTitle(value),
- );
- }
- }
- class _DescriptionField extends ConsumerWidget {
- final String initialValue;
- const _DescriptionField({required this.initialValue});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- return TextFormField(
- initialValue: initialValue,
- decoration: const InputDecoration(
- labelText: '挑战描述',
- border: OutlineInputBorder(),
- alignLabelWithHint: true,
- ),
- maxLines: 5,
- onChanged: (value) => ref.read(addChallengeProvider.notifier).updateDescription(value),
- );
- }
- }
- class _DifficultySelector extends ConsumerWidget {
- final int currentDifficulty;
- // static const difficulties = ['简单', '中等', '困难', '地狱'];
- const _DifficultySelector({required this.currentDifficulty});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const Text('难度级别*', style: TextStyle(fontSize: 16)),
- const SizedBox(height: 8),
- Wrap(
- spacing: 8,
- children: difficultOptions.map((option) {
- return ChoiceChip(
- label: Text(option.label),
- selected: currentDifficulty == option.value,
- onSelected: (selected) {
- if (selected) {
- ref.read(addChallengeProvider.notifier).updateDifficulty(option.value);
- }
- },
- );
- }).toList(),
- ),
- ],
- );
- }
- }
- class _DateRangeField extends ConsumerWidget {
- final DateTime startDate;
- final DateTime endDate;
- const _DateRangeField({
- required this.startDate,
- required this.endDate,
- });
- Future<void> _selectDate(BuildContext context, bool isStartDate, WidgetRef ref) async {
- final initialDate = isStartDate ? startDate : endDate;
- final picked = await showDatePicker(
- context: context,
- initialDate: initialDate,
- firstDate: DateTime.now(),
- lastDate: DateTime(2100),
- );
- if (picked != null) {
- final newStart = isStartDate ? picked : startDate;
- final newEnd = isStartDate ? endDate : picked;
- ref.read(addChallengeProvider.notifier).updateDateRange(newStart, newEnd);
- }
- }
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const Text('挑战周期*', style: TextStyle(fontSize: 16)),
- const SizedBox(height: 8),
- Row(
- children: [
- Expanded(
- child: OutlinedButton(
- onPressed: () => _selectDate(context, true, ref),
- child: Text(DateFormat('yyyy/MM/dd').format(startDate)),
- ),
- ),
- const Padding(
- padding: EdgeInsets.symmetric(horizontal: 8),
- child: Text('至'),
- ),
- Expanded(
- child: OutlinedButton(
- onPressed: () => _selectDate(context, false, ref),
- child: Text(DateFormat('yyyy/MM/dd').format(endDate)),
- ),
- ),
- ],
- ),
- const SizedBox(height: 4),
- Text(
- '总天数: ${endDate.difference(startDate).inDays}天',
- style: const TextStyle(color: Colors.grey),
- ),
- ],
- );
- }
- }
|