153 lines
5.1 KiB
Dart
153 lines
5.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import '../models/vehicle.dart';
|
|
import '../services/app_state.dart';
|
|
|
|
/// Add/edit form for a vehicle. Pass an existing [vehicle] to edit it, or
|
|
/// omit it to create a new one.
|
|
class AddEditVehicleScreen extends StatefulWidget {
|
|
final Vehicle? vehicle;
|
|
|
|
const AddEditVehicleScreen({super.key, this.vehicle});
|
|
|
|
@override
|
|
State<AddEditVehicleScreen> createState() => _AddEditVehicleScreenState();
|
|
}
|
|
|
|
class _AddEditVehicleScreenState extends State<AddEditVehicleScreen> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
late final TextEditingController _makeController;
|
|
late final TextEditingController _modelController;
|
|
late final TextEditingController _colorController;
|
|
late final TextEditingController _plateController;
|
|
|
|
bool get _isEditing => widget.vehicle != null;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_makeController = TextEditingController(text: widget.vehicle?.make ?? '');
|
|
_modelController = TextEditingController(text: widget.vehicle?.model ?? '');
|
|
_colorController = TextEditingController(text: widget.vehicle?.color ?? '');
|
|
_plateController = TextEditingController(text: widget.vehicle?.licensePlate ?? '');
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_makeController.dispose();
|
|
_modelController.dispose();
|
|
_colorController.dispose();
|
|
_plateController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _save() async {
|
|
if (!_formKey.currentState!.validate()) return;
|
|
|
|
final appState = context.read<AppState>();
|
|
if (_isEditing) {
|
|
await appState.updateVehicle(widget.vehicle!.copyWith(
|
|
make: _makeController.text.trim(),
|
|
model: _modelController.text.trim(),
|
|
color: _colorController.text.trim(),
|
|
licensePlate: _plateController.text.trim(),
|
|
));
|
|
} else {
|
|
await appState.addVehicle(
|
|
make: _makeController.text.trim(),
|
|
model: _modelController.text.trim(),
|
|
color: _colorController.text.trim(),
|
|
licensePlate: _plateController.text.trim(),
|
|
);
|
|
}
|
|
|
|
if (mounted) Navigator.of(context).pop();
|
|
}
|
|
|
|
Future<void> _confirmDelete() async {
|
|
final confirmed = await showDialog<bool>(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('Delete vehicle?'),
|
|
content: Text(
|
|
'This will also delete all fuel entries and receipt photos logged for '
|
|
'${widget.vehicle!.displayName}. This cannot be undone.',
|
|
),
|
|
actions: [
|
|
TextButton(onPressed: () => Navigator.of(context).pop(false), child: const Text('Cancel')),
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(true),
|
|
child: const Text('Delete', style: TextStyle(color: Colors.red)),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
if (confirmed == true && mounted) {
|
|
await context.read<AppState>().deleteVehicle(widget.vehicle!.id);
|
|
if (mounted) {
|
|
Navigator.of(context)
|
|
..pop()
|
|
..pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(_isEditing ? 'Edit Vehicle' : 'Add Vehicle'),
|
|
actions: [
|
|
if (_isEditing)
|
|
IconButton(
|
|
icon: const Icon(Icons.delete_outline),
|
|
tooltip: 'Delete vehicle',
|
|
onPressed: _confirmDelete,
|
|
),
|
|
],
|
|
),
|
|
body: Form(
|
|
key: _formKey,
|
|
child: ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
TextFormField(
|
|
controller: _makeController,
|
|
decoration: const InputDecoration(labelText: 'Make', hintText: 'e.g. Ford'),
|
|
textCapitalization: TextCapitalization.words,
|
|
validator: (v) => (v == null || v.trim().isEmpty) ? 'Required' : null,
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextFormField(
|
|
controller: _modelController,
|
|
decoration: const InputDecoration(labelText: 'Model', hintText: 'e.g. F-150'),
|
|
textCapitalization: TextCapitalization.words,
|
|
validator: (v) => (v == null || v.trim().isEmpty) ? 'Required' : null,
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextFormField(
|
|
controller: _colorController,
|
|
decoration: const InputDecoration(labelText: 'Color', hintText: 'e.g. Red'),
|
|
textCapitalization: TextCapitalization.words,
|
|
validator: (v) => (v == null || v.trim().isEmpty) ? 'Required' : null,
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextFormField(
|
|
controller: _plateController,
|
|
decoration: const InputDecoration(labelText: 'License Plate'),
|
|
textCapitalization: TextCapitalization.characters,
|
|
validator: (v) => (v == null || v.trim().isEmpty) ? 'Required' : null,
|
|
),
|
|
const SizedBox(height: 24),
|
|
FilledButton(
|
|
onPressed: _save,
|
|
child: Text(_isEditing ? 'Save Changes' : 'Add Vehicle'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|