diff --git a/lib/features/assets/presentation/asset_add_page.dart b/lib/features/assets/presentation/asset_add_page.dart index cf7c7d9..60b4f90 100644 --- a/lib/features/assets/presentation/asset_add_page.dart +++ b/lib/features/assets/presentation/asset_add_page.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart' hide AssetImage; +import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path_provider/path_provider.dart'; @@ -109,19 +110,40 @@ class _AssetAddPageState extends ConsumerState { } Future pickDate(BuildContext context) async { + final today = DateTime.now(); + final parsed = _parseDate(_dateCtrl.text.trim()); + final initialDate = parsed == null + ? today + : parsed.isBefore(DateTime(2000)) + ? DateTime(2000) + : parsed.isAfter(today) + ? today + : parsed; final DateTime? picked = await showDatePicker( context: context, - initialDate: DateTime.now(), + initialDate: initialDate, firstDate: DateTime(2000), - lastDate: DateTime.now(), + lastDate: today, + initialEntryMode: DatePickerEntryMode.calendarOnly, locale: const Locale('zh'), ); if (picked != null) { - print(picked.toString()); + setState(() { + _dateCtrl.text = _formatDate(picked); + }); } } + String _formatDate(DateTime value) { + return '${value.year}-${value.month.toString().padLeft(2, '0')}-${value.day.toString().padLeft(2, '0')}'; + } + + DateTime? _parseDate(String value) { + if (value.isEmpty) return null; + return DateTime.tryParse(value); + } + Future _showImageSourceSheet() async { if (!mounted) return; showModalBottomSheet( @@ -702,6 +724,11 @@ class _AssetAddPageState extends ConsumerState { keyboardType: const TextInputType.numberWithOptions( decimal: true, ), + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[0-9.]'), + ), + ], decoration: const InputDecoration( border: InputBorder.none, isDense: true, @@ -715,9 +742,12 @@ class _AssetAddPageState extends ConsumerState { label: '购买日期', child: TextField( controller: _dateCtrl, + readOnly: true, + onTap: () => pickDate(context), decoration: const InputDecoration( border: InputBorder.none, isDense: true, + hintText: 'YYYY-MM-DD', ), textAlign: TextAlign.right, ), diff --git a/lib/features/assets/presentation/asset_edit_page.dart b/lib/features/assets/presentation/asset_edit_page.dart index dac4684..0cf00ae 100644 --- a/lib/features/assets/presentation/asset_edit_page.dart +++ b/lib/features/assets/presentation/asset_edit_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; @@ -50,6 +51,39 @@ class _AssetEditPageState extends ConsumerState { _channelCtrl = TextEditingController(text: _holding.channel ?? ''); } + Future pickDate(BuildContext context) async { + final today = DateTime.now(); + final parsed = _parseDate(_dateCtrl.text.trim()) ?? _holding.purchaseDate; + final initialDate = parsed == null + ? today + : parsed.isBefore(DateTime(2000)) + ? DateTime(2000) + : parsed.isAfter(today) + ? today + : parsed; + final picked = await showDatePicker( + context: context, + initialDate: initialDate, + firstDate: DateTime(2000), + lastDate: today, + initialEntryMode: DatePickerEntryMode.calendarOnly, + locale: const Locale('zh'), + ); + if (picked == null || !mounted) return; + setState(() { + _dateCtrl.text = _formatDate(picked); + }); + } + + String _formatDate(DateTime value) { + return '${value.year}-${value.month.toString().padLeft(2, '0')}-${value.day.toString().padLeft(2, '0')}'; + } + + DateTime? _parseDate(String value) { + if (value.isEmpty) return null; + return DateTime.tryParse(value); + } + @override void dispose() { _weightCtrl.dispose(); @@ -214,6 +248,9 @@ class _AssetEditPageState extends ConsumerState { keyboardType: const TextInputType.numberWithOptions( decimal: true, ), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), + ], textAlign: TextAlign.right, decoration: const InputDecoration( border: InputBorder.none, @@ -227,6 +264,8 @@ class _AssetEditPageState extends ConsumerState { label: '购买日期', child: TextField( controller: _dateCtrl, + readOnly: true, + onTap: () => pickDate(context), textAlign: TextAlign.right, decoration: const InputDecoration( border: InputBorder.none,