add some props an features

This commit is contained in:
atseirjo
2026-10-28 14:07:40 +01:00
parent 77fbe16867
commit c876405a8f
7 changed files with 231 additions and 96 deletions
+12
View File
@@ -17,6 +17,8 @@ class AnwendungController extends GetxController {
final formKey = GlobalKey<FormState>();
final druckbettController = TextEditingController();
final druckController = TextEditingController();
final empfohleneDrucktemperaturController = TextEditingController();
final empfohlenerHeizbettbereichController = TextEditingController();
final bauraumController = TextEditingController();
final sonstigesController = TextEditingController();
final bauraumGeschlossen = false.obs;
@@ -48,6 +50,10 @@ class AnwendungController extends GetxController {
anwendungen.assignAll([profile]);
druckbettController.text = profile.druckbettTemperatur.toString();
druckController.text = profile.druckTemperatur.toString();
empfohleneDrucktemperaturController.text =
profile.empfohleneDrucktemperatur;
empfohlenerHeizbettbereichController.text =
profile.empfohlenerHeizbettbereich;
bauraumController.text = profile.bauraumTemperatur?.toString() ?? '';
sonstigesController.text = profile.sonstiges;
bauraumGeschlossen.value = profile.bauraumGeschlossen;
@@ -67,6 +73,10 @@ class AnwendungController extends GetxController {
erstelltAm: existing?.erstelltAm ?? DateTime.now(),
druckbettTemperatur: InputValidators.number(druckbettController.text)!,
druckTemperatur: InputValidators.number(druckController.text)!,
empfohleneDrucktemperatur: empfohleneDrucktemperaturController.text
.trim(),
empfohlenerHeizbettbereich: empfohlenerHeizbettbereichController.text
.trim(),
bauraumGeschlossen: bauraumGeschlossen.value,
bauraumTemperatur: InputValidators.number(bauraumController.text),
sonstiges: sonstigesController.text.trim(),
@@ -94,6 +104,8 @@ class AnwendungController extends GetxController {
void onClose() {
druckbettController.dispose();
druckController.dispose();
empfohleneDrucktemperaturController.dispose();
empfohlenerHeizbettbereichController.dispose();
bauraumController.dispose();
sonstigesController.dispose();
super.onClose();
+10
View File
@@ -4,6 +4,8 @@ class AnwendungModel {
final DateTime erstelltAm;
final double druckbettTemperatur;
final double druckTemperatur;
final String empfohleneDrucktemperatur;
final String empfohlenerHeizbettbereich;
final bool bauraumGeschlossen;
final double? bauraumTemperatur;
final String sonstiges;
@@ -15,6 +17,8 @@ class AnwendungModel {
required this.druckbettTemperatur,
required this.druckTemperatur,
required this.bauraumGeschlossen,
this.empfohleneDrucktemperatur = '',
this.empfohlenerHeizbettbereich = '',
this.bauraumTemperatur,
this.sonstiges = '',
});
@@ -25,6 +29,8 @@ class AnwendungModel {
'erstelltAm': erstelltAm.toIso8601String(),
'druckbettTemperatur': druckbettTemperatur,
'druckTemperatur': druckTemperatur,
'empfohleneDrucktemperatur': empfohleneDrucktemperatur,
'empfohlenerHeizbettbereich': empfohlenerHeizbettbereich,
'bauraumGeschlossen': bauraumGeschlossen,
'bauraumTemperatur': bauraumTemperatur,
'sonstiges': sonstiges,
@@ -36,6 +42,10 @@ class AnwendungModel {
erstelltAm: DateTime.parse(json['erstelltAm'] as String),
druckbettTemperatur: (json['druckbettTemperatur'] as num).toDouble(),
druckTemperatur: (json['druckTemperatur'] as num).toDouble(),
empfohleneDrucktemperatur:
json['empfohleneDrucktemperatur'] as String? ?? '',
empfohlenerHeizbettbereich:
json['empfohlenerHeizbettbereich'] as String? ?? '',
bauraumGeschlossen: json['bauraumGeschlossen'] as bool,
bauraumTemperatur: (json['bauraumTemperatur'] as num?)?.toDouble(),
sonstiges: json['sonstiges'] as String? ?? '',
+20 -1
View File
@@ -22,11 +22,30 @@ class AnwendungForm extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
EntryFieldGrid(
children: [
TextFormField(
controller: controller.empfohleneDrucktemperaturController,
decoration: const InputDecoration(
labelText: 'Empfohlene Drucktemperatur von–bis',
hintText: 'z. B. 220–260 °C',
),
),
TextFormField(
controller: controller.empfohlenerHeizbettbereichController,
decoration: const InputDecoration(
labelText: 'Empfohlener Heizbettbereich von–bis',
hintText: 'z. B. 0–60 °C',
),
),
],
),
const SizedBox(height: 16),
EntryFieldGrid(
children: [
EntryNumberField(
controller: controller.druckController,
label: 'Drucktemperatur',
label: 'Nozzletemperatur',
unit: '°C',
validator: InputValidators.positive,
),
+134 -94
View File
@@ -13,115 +13,155 @@ class BauteilFilamentAuswahl extends StatelessWidget {
@override
Widget build(BuildContext context) => Obx(() {
final ids = {
...controller.filamente.map((item) => item.filamentId),
...controller.selectedFilamente.keys,
};
if (ids.isEmpty) {
final ids = controller.selectedFilamente.keys.toList();
final availableFilamente = controller.filamente
.where(
(item) => !controller.selectedFilamente.containsKey(item.filamentId),
)
.toList();
if (controller.filamente.isEmpty && ids.isEmpty) {
return const Text(
'Erfasse zuerst ein Filament in der Einkaufsverwaltung.',
);
}
return Column(
children: ids.map((id) {
final selected = controller.selectedFilamente.containsKey(id);
final profiles = controller.profilesFor(id);
final available = controller.verfuegbarGramm(id);
final checkbox = CheckboxListTile(
key: ValueKey('filament-$id'),
title: Text(controller.filamentLabel(id)),
subtitle: Text(
available == null
? 'Startgewicht unbekannt'
: '${DisplayFormats.number(available)} g verfügbar',
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (availableFilamente.isNotEmpty) ...[
DropdownButtonFormField<String>(
key: ValueKey(
availableFilamente
.map((item) => item.filamentId)
.toList()
.toString(),
),
isExpanded: true,
decoration: const InputDecoration(labelText: 'Filament hinzufügen'),
hint: const Text('Filament auswählen'),
items: availableFilamente
.map(
(item) => DropdownMenuItem(
value: item.filamentId,
child: Text(
controller.filamentLabel(item.filamentId),
overflow: TextOverflow.ellipsis,
),
),
)
.toList(),
onChanged: (id) {
if (id != null) controller.toggleFilament(id, true);
},
),
value: selected,
controlAffinity: ListTileControlAffinity.leading,
onChanged: (value) => controller.toggleFilament(id, value ?? false),
);
final consumption = selected
? Padding(
padding: const EdgeInsets.all(16),
child: EntryNumberField(
controller: controller.verbrauchController(id),
label: 'Verbrauch',
unit: 'g',
validator: InputValidators.positive,
),
)
: const SizedBox.shrink();
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Material(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
clipBehavior: Clip.antiAlias,
child: Column(
children: [
LayoutBuilder(
builder: (context, constraints) =>
constraints.maxWidth >= 500 && selected
? Row(
children: [
Expanded(child: checkbox),
SizedBox(width: 190, child: consumption),
],
)
: Column(children: [checkbox, if (selected) consumption]),
),
if (selected && profiles.isNotEmpty)
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: DropdownButtonFormField<String>(
key: ValueKey(
'profile-$id-${controller.selectedFilamente[id]}',
),
initialValue:
profiles.any(
(item) =>
item.anwendungId ==
controller.selectedFilamente[id],
const SizedBox(height: 12),
] else if (controller.filamente.isNotEmpty) ...[
const Text('Alle Filamente wurden hinzugefügt.'),
const SizedBox(height: 12),
],
if (ids.isEmpty)
const Text(
'Noch keine Filamente hinzugefügt.',
style: TextStyle(color: AppTheme.muted),
),
...ids.map((id) {
final profiles = controller.profilesFor(id);
final available = controller.verfuegbarGramm(id);
final filament = ListTile(
key: ValueKey('filament-$id'),
title: Text(controller.filamentLabel(id)),
subtitle: Text(
available == null
? 'Startgewicht unbekannt'
: '${DisplayFormats.number(available)} g verfügbar',
),
trailing: IconButton(
tooltip: 'Filament entfernen',
icon: const Icon(Icons.close),
onPressed: () => controller.toggleFilament(id, false),
),
);
final consumption = Padding(
padding: const EdgeInsets.all(16),
child: EntryNumberField(
controller: controller.verbrauchController(id),
label: 'Verbrauch',
unit: 'g',
validator: InputValidators.positive,
),
);
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Material(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
clipBehavior: Clip.antiAlias,
child: Column(
children: [
LayoutBuilder(
builder: (context, constraints) =>
constraints.maxWidth >= 500
? Row(
children: [
Expanded(child: filament),
SizedBox(width: 190, child: consumption),
],
)
? controller.selectedFilamente[id]
: '',
isExpanded: true,
decoration: const InputDecoration(
labelText: 'Verarbeitungsprofil',
),
items: [
const DropdownMenuItem(
value: '',
child: Text('Ohne Profil'),
: Column(children: [filament, consumption]),
),
if (profiles.isNotEmpty)
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: DropdownButtonFormField<String>(
key: ValueKey(
'profile-$id-${controller.selectedFilamente[id]}',
),
...profiles.map(
(profile) => DropdownMenuItem(
value: profile.anwendungId,
child: Text(
'${DisplayFormats.number(profile.druckTemperatur)} °C · Bett ${DisplayFormats.number(profile.druckbettTemperatur)} °C · ${DisplayFormats.date(profile.erstelltAm)}',
overflow: TextOverflow.ellipsis,
initialValue:
profiles.any(
(item) =>
item.anwendungId ==
controller.selectedFilamente[id],
)
? controller.selectedFilamente[id]
: '',
isExpanded: true,
decoration: const InputDecoration(
labelText: 'Verarbeitungsprofil',
),
items: [
const DropdownMenuItem(
value: '',
child: Text('Ohne Profil'),
),
...profiles.map(
(profile) => DropdownMenuItem(
value: profile.anwendungId,
child: Text(
'${DisplayFormats.number(profile.druckTemperatur)} °C · Bett ${DisplayFormats.number(profile.druckbettTemperatur)} °C · ${DisplayFormats.date(profile.erstelltAm)}',
overflow: TextOverflow.ellipsis,
),
),
),
],
onChanged: (value) => controller.selectProfile(
id,
value == '' ? null : value,
),
],
onChanged: (value) => controller.selectProfile(
id,
value == '' ? null : value,
),
),
),
if (selected && profiles.isEmpty)
const Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Text(
'Noch kein Profil. Einstellungen kannst du über das Filament in der Einkaufsübersicht erfassen.',
style: TextStyle(color: AppTheme.muted),
if (profiles.isEmpty)
const Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Text(
'Noch kein Profil. Einstellungen kannst du über das Filament in der Einkaufsübersicht erfassen.',
style: TextStyle(color: AppTheme.muted),
),
),
),
],
],
),
),
),
);
}).toList(),
);
}),
],
);
});
}