Files
ertl_filament_verwaltung/lib/pages/home_view.dart
T

325 lines
12 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:get/get.dart';
import 'package:intl/intl.dart';
import '../controller/home_controller.dart';
import '../models/kauf_filament_model.dart';
import 'anwendung_view.dart';
class HomeView extends GetView<HomeController> {
static const routeName = '/home-view';
const HomeView({super.key});
@override
Widget build(BuildContext context) {
final dateFormat = DateFormat('dd.MM.yyyy');
return Scaffold(
appBar: AppBar(
title: const Text('Filament Einkaufsverwaltung'),
centerTitle: true,
backgroundColor: Colors.blue.shade300,
),
body: Column(
children: [
// EINGABEBEREICH
Padding(
padding: const EdgeInsets.all(12),
child: Form(
key: controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Obx(() => ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
side: const BorderSide(
color: Colors.grey,
width: 1,
),
),
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
title: const Text('Kaufdatum'),
subtitle: Text(
dateFormat.format(controller.kaufdatum.value),
),
trailing: const Icon(Icons.calendar_month),
onTap: () async {
final date = await showDatePicker(
context: context,
initialDate: controller.kaufdatum.value,
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
if (date != null) {
controller.kaufdatum.value = date;
}
},
)),
const SizedBox(height: 8),
TextFormField(
controller: controller.haendlerController,
decoration: const InputDecoration(
labelText: 'Wo gekauft / Händler',
border: OutlineInputBorder(),
),
validator: (value) =>
value == null || value.trim().isEmpty
? 'Händler eingeben'
: null,
),
const SizedBox(height: 8),
TextFormField(
controller: controller.markeController,
decoration: const InputDecoration(
labelText: 'Marke',
border: OutlineInputBorder(),
),
validator: (value) =>
value == null || value.trim().isEmpty
? 'Marke eingeben'
: null,
),
const SizedBox(height: 8),
Obx(() => DropdownButtonFormField<String>(
key: ValueKey(
'${controller.editingId.value ?? "new"}'
'_${controller.material.value}',
),
initialValue: controller.material.value,
decoration: const InputDecoration(
labelText: 'Material',
border: OutlineInputBorder(),
),
items: controller.materialien.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item),
);
}).toList(),
onChanged: (value) {
if (value != null) {
controller.material.value = value;
}
},
)),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: TextFormField(
controller: controller.farbeController,
decoration: const InputDecoration(
labelText: 'Farbe',
border: OutlineInputBorder(),
),
validator: (value) =>
value == null || value.trim().isEmpty
? 'Farbe eingeben'
: null,
),
),
const SizedBox(width: 8),
Expanded(
child: TextFormField(
controller: controller.preisController,
keyboardType:
const TextInputType.numberWithOptions(
decimal: true,
),
decoration: const InputDecoration(
labelText: 'Preis (€)',
border: OutlineInputBorder(),
),
validator: (value) {
final price = double.tryParse(
(value ?? '').replaceAll(',', '.'),
);
if (price == null ||
!price.isFinite ||
price < 0) {
return 'Preis ungültig';
}
return null;
},
),
),
],
),
const SizedBox(height: 8),
TextFormField(
controller: controller.gewichtController,
decoration: const InputDecoration(
labelText: 'Gewicht in Gramm (g)',
border: OutlineInputBorder(),
),
validator: (value) =>
value == null || value.trim().isEmpty
? 'Gewicht eingeben g'
: null,
),
const SizedBox(height: 12),
Obx(() => Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: controller.saveFilament,
icon: Icon(
controller.editingId.value == null
? Icons.add
: Icons.save,
),
label: Text(
controller.editingId.value == null
? 'Filament speichern'
: 'Änderungen speichern',
),
),
),
if (controller.editingId.value != null)
IconButton(
tooltip: 'Bearbeitung abbrechen',
onPressed: controller.resetForm,
icon: const Icon(Icons.close),
),
],
)),
],
),
),
),
const Divider(),
// LISTENBEREICH
Expanded(
child: Obx(() {
final filamente = controller.filamente;
if (filamente.isEmpty) {
return const Center(
child: Text('Noch keine Filamente gespeichert'),
);
}
return ListView.builder(
itemCount: filamente.length,
itemBuilder: (context, index) {
final filament = filamente[index];
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
child: ListTile(
leading: const CircleAvatar(
child: Icon(Icons.inventory_2_outlined),
),
title: Text(
'${filament.material} – ${filament.farbe}',
),
subtitle: Text(
'${filament.haendler}\n'
'${dateFormat.format(filament.kaufdatum)}'
' | ${filament.preis.toStringAsFixed(2)} €',
),
isThreeLine: true,
onTap: () => Get.to(
() => AnwendungView(
filamentId: filament.filamentId,
),
),
trailing: PopupMenuButton<String>(
onSelected: (action) =>
_handleAction(context, action, filament),
itemBuilder: (context) => const [
PopupMenuItem(
value: 'edit',
child: ListTile(
leading: Icon(Icons.edit),
title: Text('Bearbeiten'),
),
),
PopupMenuItem(
value: 'duplicate',
child: ListTile(
leading: Icon(Icons.copy),
title: Text('Duplizieren'),
),
),
PopupMenuItem(
value: 'delete',
child: ListTile(
leading: Icon(Icons.delete_outline),
title: Text('Löschen'),
),
),
],
),
),
);
},
);
}),
),
],
),
);
}
Future<void> _handleAction(
BuildContext context,
String action,
KaufFilamentModel filament,
) async {
switch (action) {
case 'edit':
controller.editFilament(filament);
break;
case 'duplicate':
await controller.duplicateFilament(filament);
break;
case 'delete':
final confirmed = await showDialog<bool>(
context: context,
builder: (dialogContext) => AlertDialog(
title: const Text('Filament löschen?'),
content: Text(
'${filament.material} – ${filament.farbe} löschen?',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext, false),
child: const Text('Abbrechen'),
),
FilledButton(
onPressed: () => Navigator.pop(dialogContext, true),
child: const Text('Löschen'),
),
],
),
);
if (confirmed == true) {
await controller.deleteFilament(filament.filamentId);
}
break;
}
}
}