|
|
@@ -5,6 +5,8 @@ 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';
|
|
|
+import 'package:japp_flutter/features/widgets/app_dropdown.dart';
|
|
|
+import 'package:japp_flutter/features/widgets/date_picker.dart';
|
|
|
|
|
|
class AddChallengeScreen extends ConsumerWidget {
|
|
|
const AddChallengeScreen({super.key});
|
|
|
@@ -49,88 +51,116 @@ class _BuildForm extends ConsumerWidget {
|
|
|
child: Column(
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
children: [
|
|
|
- _TitleField(initialValue: challenge.title),
|
|
|
- const SizedBox(height: 24),
|
|
|
+ TextFormField(
|
|
|
+ initialValue: challenge.title,
|
|
|
+ decoration: const InputDecoration(
|
|
|
+ labelText: '目标',
|
|
|
+ hintText: '请输入目标名称',
|
|
|
+ border: OutlineInputBorder(),
|
|
|
+ ),
|
|
|
+ onChanged: (value) =>
|
|
|
+ ref.read(addChallengeProvider.notifier).updateTitle(value),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ TextFormField(
|
|
|
+ initialValue: challenge.description,
|
|
|
+ decoration: const InputDecoration(
|
|
|
+ labelText: '简介',
|
|
|
+ hintText: '请输入目标的简介',
|
|
|
+ border: OutlineInputBorder(),
|
|
|
+ alignLabelWithHint: true,
|
|
|
+ ),
|
|
|
+ maxLines: 3,
|
|
|
+ onChanged: (value) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updateDescription(value),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ AppDropdown(
|
|
|
+ label: '目标类型',
|
|
|
+ value: challenge.actionType,
|
|
|
+ items: challengeActionTypeOpts,
|
|
|
+ onChanged: (value) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updateActionType(value ?? 0),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ AppDropdown(
|
|
|
+ label: '挑战状态',
|
|
|
+ value: challenge.status,
|
|
|
+ items: challengeStatusOpts,
|
|
|
+ onChanged: (value) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updateStatus(value ?? 0),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ AppDropdown(
|
|
|
+ label: '挑战难度',
|
|
|
+ value: challenge.difficulty,
|
|
|
+ items: challengeDifficultyOpts,
|
|
|
+ onChanged: (value) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updateDifficulty(value ?? 0),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 16),
|
|
|
_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),
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ TextFormField(
|
|
|
+ keyboardType: TextInputType.number,
|
|
|
+ initialValue: challenge.sort.toString(),
|
|
|
+ decoration: const InputDecoration(
|
|
|
+ labelText: '排序',
|
|
|
+ border: OutlineInputBorder(),
|
|
|
+ alignLabelWithHint: true,
|
|
|
+ ),
|
|
|
+ onChanged: (value) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updateSort(int.parse(value)),
|
|
|
+ ),
|
|
|
|
|
|
-class _DescriptionField extends ConsumerWidget {
|
|
|
- final String initialValue;
|
|
|
|
|
|
- const _DescriptionField({required this.initialValue});
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ DatePickerField(
|
|
|
+ labelText: '计划完成日期',
|
|
|
+ onDateSelected: (date) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updatePlanFinishDate(date!),
|
|
|
+ ),
|
|
|
|
|
|
- @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),
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ DatePickerField(
|
|
|
+ labelText: '完成日期',
|
|
|
+ onDateSelected: (date) => ref
|
|
|
+ .read(addChallengeProvider.notifier)
|
|
|
+ .updateFinishDate(date!),
|
|
|
+ ),
|
|
|
|
|
|
-class _DifficultySelector extends ConsumerWidget {
|
|
|
- final int currentDifficulty;
|
|
|
- // static const difficulties = ['简单', '中等', '困难', '地狱'];
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ TextFormField(
|
|
|
+ initialValue: challenge.remark,
|
|
|
+ decoration: const InputDecoration(
|
|
|
+ labelText: '备注',
|
|
|
+ border: OutlineInputBorder(),
|
|
|
+ alignLabelWithHint: true,
|
|
|
+ ),
|
|
|
+ maxLines: 3,
|
|
|
+ onChanged: (value) =>
|
|
|
+ ref.read(addChallengeProvider.notifier).updateRemark(value),
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 16),
|
|
|
|
|
|
- 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(),
|
|
|
- ),
|
|
|
- ],
|
|
|
+ ],
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
@@ -139,12 +169,13 @@ class _DateRangeField extends ConsumerWidget {
|
|
|
final DateTime startDate;
|
|
|
final DateTime endDate;
|
|
|
|
|
|
- const _DateRangeField({
|
|
|
- required this.startDate,
|
|
|
- required this.endDate,
|
|
|
- });
|
|
|
+ const _DateRangeField({required this.startDate, required this.endDate});
|
|
|
|
|
|
- Future<void> _selectDate(BuildContext context, bool isStartDate, WidgetRef ref) async {
|
|
|
+ Future<void> _selectDate(
|
|
|
+ BuildContext context,
|
|
|
+ bool isStartDate,
|
|
|
+ WidgetRef ref,
|
|
|
+ ) async {
|
|
|
final initialDate = isStartDate ? startDate : endDate;
|
|
|
final picked = await showDatePicker(
|
|
|
context: context,
|
|
|
@@ -195,4 +226,4 @@ class _DateRangeField extends ConsumerWidget {
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
-}
|
|
|
+}
|