Files
MookNote/lib/pages/movie_form_page.dart
DelLevin-Home adad6372a3 基础功能
2026-03-05 10:06:32 +08:00

291 lines
9.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/app_provider.dart';
import '../models/data_models.dart';
/// 添加/编辑影视记录页面
class MovieFormPage extends StatefulWidget {
final Movie? movie; // 如果为 null则是添加模式否则是编辑模式
const MovieFormPage({super.key, this.movie});
@override
State<MovieFormPage> createState() => _MovieFormPageState();
}
class _MovieFormPageState extends State<MovieFormPage> {
final _formKey = GlobalKey<FormState>();
late TextEditingController _titleController;
late TextEditingController _yearController;
late TextEditingController _ratingController;
late TextEditingController _noteController;
late String _status;
DateTime? _watchDate;
@override
void initState() {
super.initState();
_titleController = TextEditingController(text: widget.movie?.title ?? '');
_yearController = TextEditingController(text: widget.movie?.year?.toString() ?? '');
_ratingController = TextEditingController(text: widget.movie?.rating?.toString() ?? '');
_noteController = TextEditingController(text: widget.movie?.note ?? '');
_status = widget.movie?.status ?? 'want_to_watch';
_watchDate = widget.movie?.watchDate;
}
@override
void dispose() {
_titleController.dispose();
_yearController.dispose();
_ratingController.dispose();
_noteController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isEdit = widget.movie != null;
return Scaffold(
appBar: AppBar(
title: Text(isEdit ? '编辑影片' : '添加影片'),
actions: [
IconButton(
icon: const Icon(Icons.save),
onPressed: _saveMovie,
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题
TextFormField(
controller: _titleController,
decoration: const InputDecoration(
labelText: '影片名称 *',
hintText: '请输入影片名称',
prefixIcon: Icon(Icons.movie),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return '请输入影片名称';
}
return null;
},
),
const SizedBox(height: 16),
// 年份和评分
Row(
children: [
Expanded(
child: TextFormField(
controller: _yearController,
decoration: const InputDecoration(
labelText: '年份',
hintText: '例如2024',
prefixIcon: Icon(Icons.calendar_today),
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
),
),
const SizedBox(width: 16),
Expanded(
child: TextFormField(
controller: _ratingController,
decoration: const InputDecoration(
labelText: '评分',
hintText: '0-10',
prefixIcon: Icon(Icons.star),
border: OutlineInputBorder(),
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value != null && value.isNotEmpty) {
final rating = double.tryParse(value);
if (rating == null || rating < 0 || rating > 10) {
return '评分必须在 0-10 之间';
}
}
return null;
},
),
),
],
),
const SizedBox(height: 16),
// 状态选择
DropdownButtonFormField<String>(
value: _status,
decoration: const InputDecoration(
labelText: '状态',
prefixIcon: Icon(Icons.check_circle_outline),
border: OutlineInputBorder(),
),
items: const [
DropdownMenuItem(value: 'watched', child: Text('已看')),
DropdownMenuItem(value: 'want_to_watch', child: Text('想看')),
DropdownMenuItem(value: 'watching', child: Text('在看')),
],
onChanged: (value) {
setState(() {
_status = value!;
});
},
),
const SizedBox(height: 16),
// 观看日期选择
InkWell(
onTap: _selectWatchDate,
child: InputDecorator(
decoration: const InputDecoration(
labelText: '观看日期',
prefixIcon: Icon(Icons.event),
border: OutlineInputBorder(),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_watchDate != null
? '${_watchDate!.year}-${_watchDate!.month.toString().padLeft(2, '0')}-${_watchDate!.day.toString().padLeft(2, '0')}'
: '选择日期',
style: TextStyle(
color: _watchDate != null
? Theme.of(context).colorScheme.onSurface
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
if (_watchDate != null)
IconButton(
icon: const Icon(Icons.clear, size: 20),
onPressed: () {
setState(() {
_watchDate = null;
});
},
),
],
),
),
),
const SizedBox(height: 16),
// 笔记
TextFormField(
controller: _noteController,
decoration: const InputDecoration(
labelText: '笔记',
hintText: '写下你的观后感...',
prefixIcon: Icon(Icons.edit_note),
border: OutlineInputBorder(),
alignLabelWithHint: true,
),
maxLines: 5,
),
const SizedBox(height: 32),
// 保存按钮
SizedBox(
width: double.infinity,
height: 48,
child: ElevatedButton.icon(
onPressed: _saveMovie,
icon: const Icon(Icons.save),
label: Text(isEdit ? '保存修改' : '添加记录'),
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
],
),
),
),
);
}
/// 选择观看日期
Future<void> _selectWatchDate() async {
final picked = await showDatePicker(
context: context,
initialDate: _watchDate ?? DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
);
if (picked != null) {
setState(() {
_watchDate = picked;
});
}
}
/// 保存影视记录
Future<void> _saveMovie() async {
if (!_formKey.currentState!.validate()) {
return;
}
final year = _yearController.text.isNotEmpty ? int.tryParse(_yearController.text) : null;
final rating = _ratingController.text.isNotEmpty ? double.tryParse(_ratingController.text) : null;
if (widget.movie == null) {
// 添加新模式
final newMovie = Movie(
id: DateTime.now().millisecondsSinceEpoch.toString(),
title: _titleController.text.trim(),
year: year,
rating: rating,
status: _status,
watchDate: _watchDate,
note: _noteController.text.trim(),
);
await context.read<AppProvider>().addMovie(newMovie);
} else {
// 编辑现有模式
final updatedMovie = Movie(
id: widget.movie!.id,
title: _titleController.text.trim(),
year: year,
rating: rating,
status: _status,
watchDate: _watchDate,
note: _noteController.text.trim(),
);
await context.read<AppProvider>().updateMovie(updatedMovie);
}
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(widget.movie == null ? '添加成功' : '更新成功'),
behavior: SnackBarBehavior.floating,
),
);
Navigator.pop(context);
}
}