新增静态演示界面
This commit is contained in:
@@ -0,0 +1,723 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patbond_flutter/core/theme/app_theme.dart';
|
||||
import 'package:patbond_flutter/data/demo_data.dart';
|
||||
import 'package:patbond_flutter/models/models.dart';
|
||||
import 'package:patbond_flutter/state/app_state.dart';
|
||||
import 'package:patbond_flutter/widgets/common.dart';
|
||||
|
||||
class PetsPage extends StatelessWidget {
|
||||
const PetsPage({required this.appState, super.key});
|
||||
|
||||
final AppState appState;
|
||||
|
||||
String ageLabel(String value) {
|
||||
final birthday = DateTime.tryParse(value);
|
||||
if (birthday == null) return '年龄未知';
|
||||
final today = DateTime.now();
|
||||
var age = today.year - birthday.year;
|
||||
if (today.month < birthday.month ||
|
||||
(today.month == birthday.month && today.day < birthday.day)) {
|
||||
age--;
|
||||
}
|
||||
return '${age < 0 ? 0 : age} 岁';
|
||||
}
|
||||
|
||||
Future<void> editPet(BuildContext context) async {
|
||||
final value = await showModalBottomSheet<PetProfile>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
builder: (context) => EditPetSheet(pet: appState.pet),
|
||||
);
|
||||
if (value != null) await appState.updatePet(value);
|
||||
}
|
||||
|
||||
Future<void> editVaccines(BuildContext context) async {
|
||||
final value = await showModalBottomSheet<VaccineRecord>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
builder: (context) => VaccineSheet(record: appState.vaccines),
|
||||
);
|
||||
if (value != null) await appState.updateVaccines(value);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pet = appState.pet;
|
||||
final vaccines = appState.vaccines;
|
||||
final progress = vaccines.totalDoses == 0
|
||||
? 0.0
|
||||
: vaccines.completedDoses / vaccines.totalDoses;
|
||||
|
||||
return ListView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 30),
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => editPet(context),
|
||||
borderRadius: BorderRadius.circular(54),
|
||||
child: RemoteImage(
|
||||
url: pet.avatarUrl,
|
||||
width: 104,
|
||||
height: 104,
|
||||
borderRadius: BorderRadius.circular(52),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor: AppColors.primary,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
tooltip: '编辑资料',
|
||||
onPressed: () => editPet(context),
|
||||
icon: const Icon(
|
||||
Icons.edit,
|
||||
color: Colors.white,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(pet.name, style: Theme.of(context).textTheme.headlineSmall),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${pet.breed} · ${pet.gender == PetGender.male ? '男孩' : '女孩'} · ${ageLabel(pet.birthday)} · 活泼',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () => editPet(context),
|
||||
icon: const Icon(Icons.settings_outlined, size: 17),
|
||||
label: const Text('编辑资料'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
children: [
|
||||
Text('宠物数据', style: Theme.of(context).textTheme.titleLarge),
|
||||
const Spacer(),
|
||||
TextButton.icon(
|
||||
onPressed: () => editPet(context),
|
||||
icon: const Icon(Icons.edit_outlined, size: 16),
|
||||
label: const Text('编辑'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _StatCard(
|
||||
icon: Icons.monitor_weight_outlined,
|
||||
color: AppColors.primary,
|
||||
value: '${pet.weight.toStringAsFixed(1)}kg',
|
||||
label: '体重',
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: _StatCard(
|
||||
icon: Icons.vaccines_outlined,
|
||||
color: AppColors.success,
|
||||
value: '${vaccines.completedDoses}/${vaccines.totalDoses}',
|
||||
label: '疫苗进度',
|
||||
onTap: () => editVaccines(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const Expanded(
|
||||
child: _StatCard(
|
||||
icon: Icons.payments_outlined,
|
||||
color: AppColors.warning,
|
||||
value: '¥328',
|
||||
label: '本月花费',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SectionCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text('健康概览', style: Theme.of(context).textTheme.titleMedium),
|
||||
const Spacer(),
|
||||
Text('更新于今日', style: Theme.of(context).textTheme.bodySmall),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox.square(
|
||||
dimension: 62,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: progress,
|
||||
strokeWidth: 7,
|
||||
backgroundColor: const Color(0xFFE2E8F0),
|
||||
color: AppColors.success,
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
'${(progress * 100).round()}%',
|
||||
style: const TextStyle(
|
||||
color: AppColors.success,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
progress >= 1 ? '疫苗接种完成' : '疫苗接种进行中',
|
||||
style: const TextStyle(fontWeight: FontWeight.w800),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
'下一针:${vaccines.reminderVaccine}\n预计 ${vaccines.reminderDate}',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: '管理疫苗',
|
||||
onPressed: () => editVaccines(context),
|
||||
icon: const Icon(Icons.edit_outlined),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(18),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFECFDF5),
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
border: Border.all(color: const Color(0xFFA7F3D0)),
|
||||
),
|
||||
child: const Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Icons.auto_awesome, color: AppColors.success),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'健康提醒:已经半年没有进行体内外驱虫,建议本周安排一次。',
|
||||
style: TextStyle(color: Color(0xFF047857), height: 1.5),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 22),
|
||||
Text('成长足迹', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 10),
|
||||
const _TimelineTile(
|
||||
icon: Icons.medical_services_outlined,
|
||||
title: '医疗 · 狂犬疫苗接种',
|
||||
subtitle: '2025-06-12 · 瑞派宠物医院',
|
||||
status: '已完成',
|
||||
),
|
||||
const _TimelineTile(
|
||||
icon: Icons.restaurant_outlined,
|
||||
title: '喂养 · 更换幼犬粮',
|
||||
subtitle: '2025-05-20 · 体重增长稳定',
|
||||
status: '已记录',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _StatCard extends StatelessWidget {
|
||||
const _StatCard({
|
||||
required this.icon,
|
||||
required this.color,
|
||||
required this.value,
|
||||
required this.label,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
final String value;
|
||||
final String label;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(icon, color: color),
|
||||
const SizedBox(height: 6),
|
||||
Text(value, style: const TextStyle(fontWeight: FontWeight.w800)),
|
||||
const SizedBox(height: 2),
|
||||
Text(label, style: Theme.of(context).textTheme.bodySmall),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TimelineTile extends StatelessWidget {
|
||||
const _TimelineTile({
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final String status;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: SectionCard(
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(child: Icon(icon, color: AppColors.primary, size: 20)),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(fontWeight: FontWeight.w800),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
|
||||
],
|
||||
),
|
||||
),
|
||||
TagPill(status, color: AppColors.success),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EditPetSheet extends StatefulWidget {
|
||||
const EditPetSheet({required this.pet, super.key});
|
||||
|
||||
final PetProfile pet;
|
||||
|
||||
@override
|
||||
State<EditPetSheet> createState() => _EditPetSheetState();
|
||||
}
|
||||
|
||||
class _EditPetSheetState extends State<EditPetSheet> {
|
||||
late final TextEditingController nameController;
|
||||
late final TextEditingController weightController;
|
||||
late String breed;
|
||||
late PetGender gender;
|
||||
late DateTime birthday;
|
||||
late String avatar;
|
||||
|
||||
static const breeds = ['柴犬', '金毛寻回犬', '柯基', '哈士奇', '英国短毛猫', '其他'];
|
||||
static const avatars = [
|
||||
petAvatar,
|
||||
'https://images.unsplash.com/photo-1517849845537-4d257902454a?auto=format&fit=crop&w=600&q=85',
|
||||
'https://images.unsplash.com/photo-1543466835-00a7907e9de1?auto=format&fit=crop&w=600&q=85',
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
nameController = TextEditingController(text: widget.pet.name);
|
||||
weightController = TextEditingController(text: '${widget.pet.weight}');
|
||||
breed = breeds.contains(widget.pet.breed) ? widget.pet.breed : '其他';
|
||||
gender = widget.pet.gender;
|
||||
birthday = DateTime.tryParse(widget.pet.birthday) ?? DateTime(2024, 5, 15);
|
||||
avatar = widget.pet.avatarUrl;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
weightController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
String dateText(DateTime value) {
|
||||
return '${value.year}-${value.month.toString().padLeft(2, '0')}-${value.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
20,
|
||||
10,
|
||||
20,
|
||||
MediaQuery.viewInsetsOf(context).bottom + 20,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const _SheetHandle(),
|
||||
Row(
|
||||
children: [
|
||||
Text('编辑宠物资料', style: Theme.of(context).textTheme.titleLarge),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
Center(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
final index = avatars.indexOf(avatar);
|
||||
setState(
|
||||
() => avatar = avatars[(index + 1) % avatars.length],
|
||||
);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
child: Stack(
|
||||
children: [
|
||||
RemoteImage(
|
||||
url: avatar,
|
||||
width: 96,
|
||||
height: 96,
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
),
|
||||
const Positioned(
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: CircleAvatar(
|
||||
radius: 15,
|
||||
child: Icon(Icons.edit, size: 15),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
TextField(
|
||||
controller: nameController,
|
||||
decoration: const InputDecoration(labelText: '宠物昵称'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: breed,
|
||||
decoration: const InputDecoration(labelText: '品种'),
|
||||
items: breeds
|
||||
.map(
|
||||
(value) =>
|
||||
DropdownMenuItem(value: value, child: Text(value)),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) setState(() => breed = value);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SegmentedButton<PetGender>(
|
||||
segments: const [
|
||||
ButtonSegment(
|
||||
value: PetGender.male,
|
||||
icon: Icon(Icons.male),
|
||||
label: Text('男孩'),
|
||||
),
|
||||
ButtonSegment(
|
||||
value: PetGender.female,
|
||||
icon: Icon(Icons.female),
|
||||
label: Text('女孩'),
|
||||
),
|
||||
],
|
||||
selected: {gender},
|
||||
onSelectionChanged: (value) =>
|
||||
setState(() => gender = value.first),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: const BorderSide(color: AppColors.border),
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
),
|
||||
leading: const Icon(Icons.cake_outlined),
|
||||
title: const Text('生日'),
|
||||
subtitle: Text(dateText(birthday)),
|
||||
trailing: const Icon(Icons.calendar_month_outlined),
|
||||
onTap: () async {
|
||||
final value = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: birthday,
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime.now(),
|
||||
);
|
||||
if (value != null) setState(() => birthday = value);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: weightController,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true,
|
||||
),
|
||||
decoration: const InputDecoration(labelText: '体重(kg)'),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.icon(
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(50),
|
||||
),
|
||||
onPressed: () {
|
||||
final name = nameController.text.trim();
|
||||
final weight = double.tryParse(weightController.text);
|
||||
if (name.isEmpty || weight == null || weight <= 0) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('请填写有效的昵称和体重')));
|
||||
return;
|
||||
}
|
||||
Navigator.pop(
|
||||
context,
|
||||
widget.pet.copyWith(
|
||||
name: name,
|
||||
breed: breed,
|
||||
gender: gender,
|
||||
birthday: dateText(birthday),
|
||||
weight: weight,
|
||||
avatarUrl: avatar,
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.save_outlined),
|
||||
label: const Text('保存修改'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VaccineSheet extends StatefulWidget {
|
||||
const VaccineSheet({required this.record, super.key});
|
||||
|
||||
final VaccineRecord record;
|
||||
|
||||
@override
|
||||
State<VaccineSheet> createState() => _VaccineSheetState();
|
||||
}
|
||||
|
||||
class _VaccineSheetState extends State<VaccineSheet> {
|
||||
late List<VaccineItem> items;
|
||||
late int totalDoses;
|
||||
late final TextEditingController reminderController;
|
||||
late final TextEditingController dateController;
|
||||
|
||||
int get completed =>
|
||||
items.where((item) => item.status == VaccineStatus.completed).length;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
items = List<VaccineItem>.from(widget.record.items);
|
||||
totalDoses = widget.record.totalDoses;
|
||||
reminderController = TextEditingController(
|
||||
text: widget.record.reminderVaccine,
|
||||
);
|
||||
dateController = TextEditingController(text: widget.record.reminderDate);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
reminderController.dispose();
|
||||
dateController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void changeTotal(int delta) {
|
||||
final minimum = completed > items.length ? completed : items.length;
|
||||
setState(() => totalDoses = (totalDoses + delta).clamp(minimum, 20));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final progress = totalDoses == 0 ? 0.0 : completed / totalDoses;
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
20,
|
||||
10,
|
||||
20,
|
||||
MediaQuery.viewInsetsOf(context).bottom + 20,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const _SheetHandle(),
|
||||
Row(
|
||||
children: [
|
||||
const CircleAvatar(child: Icon(Icons.vaccines_outlined)),
|
||||
const SizedBox(width: 10),
|
||||
Text('疫苗接种管理', style: Theme.of(context).textTheme.titleLarge),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SectionCard(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('已接种 / 总规划'),
|
||||
const Spacer(),
|
||||
IconButton.filledTonal(
|
||||
onPressed: () => changeTotal(-1),
|
||||
icon: const Icon(Icons.remove),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Text(
|
||||
'$completed / $totalDoses',
|
||||
style: const TextStyle(fontWeight: FontWeight.w800),
|
||||
),
|
||||
),
|
||||
IconButton.filled(
|
||||
onPressed: () => changeTotal(1),
|
||||
icon: const Icon(Icons.add),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
LinearProgressIndicator(value: progress, minHeight: 9),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text('接种详情', style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 8),
|
||||
...items.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final item = entry.value;
|
||||
final done = item.status == VaccineStatus.completed;
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
child: CheckboxListTile(
|
||||
value: done,
|
||||
title: Text(item.name),
|
||||
subtitle: Text(
|
||||
done ? '接种时间:${item.date}' : '计划接种:${item.date}',
|
||||
),
|
||||
secondary: Icon(
|
||||
done ? Icons.check_circle : Icons.radio_button_unchecked,
|
||||
color: done ? AppColors.success : AppColors.muted,
|
||||
),
|
||||
onChanged: (_) {
|
||||
final today = DateTime.now();
|
||||
final date =
|
||||
'${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')}';
|
||||
setState(() {
|
||||
items[index] = item.copyWith(
|
||||
status: done
|
||||
? VaccineStatus.pending
|
||||
: VaccineStatus.completed,
|
||||
date: done ? '待定' : date,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 10),
|
||||
TextField(
|
||||
controller: reminderController,
|
||||
decoration: const InputDecoration(labelText: '下一针提醒'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: dateController,
|
||||
decoration: const InputDecoration(labelText: '预计日期(YYYY-MM-DD)'),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.icon(
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(50),
|
||||
),
|
||||
onPressed: () => Navigator.pop(
|
||||
context,
|
||||
VaccineRecord(
|
||||
completedDoses: completed,
|
||||
totalDoses: totalDoses,
|
||||
items: items,
|
||||
reminderVaccine: reminderController.text.trim(),
|
||||
reminderDate: dateController.text.trim(),
|
||||
),
|
||||
),
|
||||
icon: const Icon(Icons.save_outlined),
|
||||
label: const Text('保存疫苗记录'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SheetHandle extends StatelessWidget {
|
||||
const _SheetHandle();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: 44,
|
||||
height: 5,
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.border,
|
||||
borderRadius: BorderRadius.circular(99),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user