add two views
This commit is contained in:
@@ -1,17 +1,95 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../helper/input_validators.dart';
|
||||
import '../models/anwendung_model.dart';
|
||||
import '../models/kauf_filament_model.dart';
|
||||
import '../services/get_storage_services.dart';
|
||||
import 'home_controller.dart';
|
||||
|
||||
class AnwendungController extends GetxController {
|
||||
final count = 0.obs;
|
||||
AnwendungController({required this.filamentId});
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
static const storageKey = 'filament_anwendungen';
|
||||
final String filamentId;
|
||||
final storage = Get.find<GetStorageService>();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final druckbettController = TextEditingController();
|
||||
final druckController = TextEditingController();
|
||||
final bauraumController = TextEditingController();
|
||||
final sonstigesController = TextEditingController();
|
||||
final bauraumGeschlossen = false.obs;
|
||||
final isSaving = false.obs;
|
||||
final message = RxnString();
|
||||
final hasError = false.obs;
|
||||
final filament = Rxn<KaufFilamentModel>();
|
||||
final anwendungen = <AnwendungModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final filamente = storage
|
||||
.getModelList(HomeController.storageKey)
|
||||
.map(KaufFilamentModel.fromJson)
|
||||
.toList();
|
||||
filament.value = filamente.firstWhereOrNull(
|
||||
(item) => item.filamentId == filamentId,
|
||||
);
|
||||
anwendungen.assignAll(
|
||||
storage
|
||||
.getModelList(storageKey)
|
||||
.map(AnwendungModel.fromJson)
|
||||
.where((item) => item.filamentId == filamentId),
|
||||
);
|
||||
anwendungen.sort((a, b) => b.erstelltAm.compareTo(a.erstelltAm));
|
||||
}
|
||||
|
||||
Future<void> saveAnwendung() async {
|
||||
if (isSaving.value || filament.value == null) return;
|
||||
if (!(formKey.currentState?.validate() ?? false)) return;
|
||||
isSaving.value = true;
|
||||
message.value = null;
|
||||
try {
|
||||
final entry = AnwendungModel(
|
||||
anwendungId: const Uuid().v4(),
|
||||
filamentId: filamentId,
|
||||
erstelltAm: DateTime.now(),
|
||||
druckbettTemperatur: InputValidators.number(druckbettController.text)!,
|
||||
druckTemperatur: InputValidators.number(druckController.text)!,
|
||||
bauraumGeschlossen: bauraumGeschlossen.value,
|
||||
bauraumTemperatur: InputValidators.number(bauraumController.text),
|
||||
sonstiges: sonstigesController.text.trim(),
|
||||
);
|
||||
final entries = storage.getModelList(storageKey);
|
||||
await storage.saveModelList(storageKey, [...entries, entry.toJson()]);
|
||||
anwendungen.insert(0, entry);
|
||||
resetForm();
|
||||
hasError.value = false;
|
||||
message.value = 'Verarbeitungsprofil gespeichert.';
|
||||
} catch (_) {
|
||||
hasError.value = true;
|
||||
message.value = 'Speichern fehlgeschlagen. Bitte erneut versuchen.';
|
||||
} finally {
|
||||
isSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {}
|
||||
|
||||
@override
|
||||
void onClose() {}
|
||||
void resetForm() {
|
||||
formKey.currentState?.reset();
|
||||
druckbettController.clear();
|
||||
druckController.clear();
|
||||
bauraumController.clear();
|
||||
sonstigesController.clear();
|
||||
bauraumGeschlossen.value = false;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
druckbettController.dispose();
|
||||
druckController.dispose();
|
||||
bauraumController.dispose();
|
||||
sonstigesController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../helper/display_formats.dart';
|
||||
import '../helper/filament_bestand.dart';
|
||||
import '../helper/input_validators.dart';
|
||||
import '../helper/storage_keys.dart';
|
||||
import '../models/anwendung_model.dart';
|
||||
import '../models/bauteil_model.dart';
|
||||
import '../models/kauf_filament_model.dart';
|
||||
import '../services/bauteil_photo_service.dart';
|
||||
import '../services/get_storage_services.dart';
|
||||
import 'home_controller.dart';
|
||||
|
||||
class BauteilController extends GetxController {
|
||||
BauteilController({BauteilPhotoService? photoService})
|
||||
: photoService = photoService ?? BauteilPhotoService();
|
||||
|
||||
static const storageKey = StorageKeys.bauteile;
|
||||
final storage = Get.find<GetStorageService>();
|
||||
final BauteilPhotoService photoService;
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final scrollController = ScrollController();
|
||||
final nameController = TextEditingController();
|
||||
final verwendungController = TextEditingController();
|
||||
final stundenController = TextEditingController(text: '0');
|
||||
final minutenController = TextEditingController(text: '0');
|
||||
final gewichtController = TextEditingController();
|
||||
final abfallController = TextEditingController(text: '0');
|
||||
final _verbrauchControllers = <String, TextEditingController>{};
|
||||
final filamente = <KaufFilamentModel>[].obs;
|
||||
final profile = <AnwendungModel>[].obs;
|
||||
final bauteile = <BauteilModel>[].obs;
|
||||
final selectedFilamente = <String, String?>{}.obs;
|
||||
final editingId = RxnString();
|
||||
final foto = Rxn<Uint8List>();
|
||||
final isPickingPhoto = false.obs;
|
||||
final isSaving = false.obs;
|
||||
final message = RxnString();
|
||||
final hasError = false.obs;
|
||||
bool _closed = false;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
filamente.assignAll(
|
||||
storage
|
||||
.getModelList(StorageKeys.filamente)
|
||||
.map(KaufFilamentModel.fromJson),
|
||||
);
|
||||
profile.assignAll(
|
||||
storage
|
||||
.getModelList(StorageKeys.anwendungen)
|
||||
.map(AnwendungModel.fromJson),
|
||||
);
|
||||
bauteile.assignAll(_loadBauteile());
|
||||
bauteile.sort((a, b) => b.erstelltAm.compareTo(a.erstelltAm));
|
||||
}
|
||||
|
||||
List<BauteilModel> _loadBauteile() =>
|
||||
storage.getModelList(storageKey).map(BauteilModel.fromJson).toList();
|
||||
|
||||
TextEditingController verbrauchController(String id) =>
|
||||
_verbrauchControllers.putIfAbsent(id, () => TextEditingController());
|
||||
|
||||
List<AnwendungModel> profilesFor(String filamentId) =>
|
||||
profile.where((item) => item.filamentId == filamentId).toList()
|
||||
..sort((a, b) => b.erstelltAm.compareTo(a.erstelltAm));
|
||||
|
||||
String filamentLabel(String id) {
|
||||
final item = filamente.firstWhereOrNull((item) => item.filamentId == id);
|
||||
if (item == null) return 'Gelöschtes Filament ($id)';
|
||||
return '${item.marke} · ${item.material} · ${item.farbe}';
|
||||
}
|
||||
|
||||
double? verfuegbarGramm(String id) {
|
||||
final start = filamente
|
||||
.firstWhereOrNull((item) => item.filamentId == id)
|
||||
?.gewichtGramm;
|
||||
if (start == null) return null;
|
||||
final used = FilamentBestand.verbrauch(
|
||||
bauteile,
|
||||
ohneBauteilId: editingId.value,
|
||||
);
|
||||
return start - (used[id] ?? 0);
|
||||
}
|
||||
|
||||
void toggleFilament(String id, bool selected) {
|
||||
if (selected) {
|
||||
verbrauchController(id);
|
||||
selectedFilamente[id] = null;
|
||||
} else {
|
||||
selectedFilamente.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
void selectProfile(String filamentId, String? anwendungId) {
|
||||
if (!selectedFilamente.containsKey(filamentId)) return;
|
||||
if (anwendungId != null &&
|
||||
!profilesFor(filamentId)
|
||||
.any((item) => item.anwendungId == anwendungId)) {
|
||||
return;
|
||||
}
|
||||
selectedFilamente[filamentId] = anwendungId;
|
||||
}
|
||||
|
||||
Future<void> pickPhoto() async {
|
||||
if (isPickingPhoto.value || isSaving.value) return;
|
||||
isPickingPhoto.value = true;
|
||||
try {
|
||||
final bytes = await photoService.pickPhoto();
|
||||
if (!_closed && bytes != null) foto.value = bytes;
|
||||
} on FormatException catch (error) {
|
||||
if (!_closed) _error(error.message);
|
||||
} catch (_) {
|
||||
if (!_closed) {
|
||||
_error(
|
||||
'Das Foto konnte nicht geladen werden. Bitte ein JPG-, PNG- oder WebP-Bild auswählen.',
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (!_closed) isPickingPhoto.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void removePhoto() => foto.value = null;
|
||||
|
||||
void _error(String text) {
|
||||
hasError.value = true;
|
||||
message.value = text;
|
||||
}
|
||||
|
||||
String? _validateConsumption(
|
||||
BauteilModel entry,
|
||||
List<BauteilModel> existing,
|
||||
) {
|
||||
if (entry.filamente.isEmpty) {
|
||||
return 'Bitte mindestens ein Filament auswählen.';
|
||||
}
|
||||
final sum = entry.filamente.fold<double>(
|
||||
0,
|
||||
(sum, item) => sum + item.verbrauchGramm,
|
||||
);
|
||||
if (entry.filamente.any(
|
||||
(item) => !item.verbrauchGramm.isFinite || item.verbrauchGramm <= 0,
|
||||
)) {
|
||||
return 'Bitte für jedes verwendete Filament einen Verbrauch größer 0 eingeben.';
|
||||
}
|
||||
if (!sum.isFinite || (sum - entry.gesamtverbrauchGramm).abs() > 0.01) {
|
||||
return 'Der Filamentverbrauch muss zusammen ${DisplayFormats.number(entry.gesamtverbrauchGramm)} g ergeben (Bauteilgewicht + Abfall).';
|
||||
}
|
||||
final used = FilamentBestand.verbrauch(
|
||||
existing,
|
||||
ohneBauteilId: entry.bauteilId,
|
||||
);
|
||||
final currentFilamente = storage
|
||||
.getModelList(StorageKeys.filamente)
|
||||
.map(KaufFilamentModel.fromJson)
|
||||
.toList();
|
||||
for (final item in entry.filamente) {
|
||||
final filament = currentFilamente.firstWhereOrNull(
|
||||
(filament) => filament.filamentId == item.filamentId,
|
||||
);
|
||||
final start = filament?.gewichtGramm;
|
||||
if (start == null) {
|
||||
return 'Filament fehlt oder sein Startgewicht ist ungültig. Bitte die Auswahl bzw. das Filament prüfen.';
|
||||
}
|
||||
final available = start - (used[item.filamentId] ?? 0);
|
||||
if (item.verbrauchGramm - available > 0.000001) {
|
||||
return '${filamentLabel(item.filamentId)}: nur ${DisplayFormats.number(available)} g verfügbar.';
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// One persisted ledger determines all remaining weights. Updating or deleting
|
||||
/// an entry therefore cannot leave a second stock table out of sync.
|
||||
Future<void> _commit(List<BauteilModel> entries) async {
|
||||
await storage.saveModelList(
|
||||
storageKey,
|
||||
entries.map((item) => item.toJson()).toList(),
|
||||
);
|
||||
entries.sort((a, b) => b.erstelltAm.compareTo(a.erstelltAm));
|
||||
bauteile.assignAll(entries);
|
||||
if (Get.isRegistered<HomeController>()) {
|
||||
Get.find<HomeController>().loadVerbrauch();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveBauteil() async {
|
||||
if (isSaving.value || isPickingPhoto.value) return;
|
||||
message.value = null;
|
||||
if (!(formKey.currentState?.validate() ?? false)) return;
|
||||
if (selectedFilamente.isEmpty) {
|
||||
_error('Bitte mindestens ein Filament auswählen.');
|
||||
return;
|
||||
}
|
||||
final duration =
|
||||
int.parse(stundenController.text.trim()) * 60 +
|
||||
int.parse(minutenController.text.trim());
|
||||
if (duration <= 0) {
|
||||
_error('Die Druckdauer muss mindestens eine Minute betragen.');
|
||||
return;
|
||||
}
|
||||
isSaving.value = true;
|
||||
try {
|
||||
final existing = _loadBauteile();
|
||||
final previous = existing.firstWhereOrNull(
|
||||
(item) => item.bauteilId == editingId.value,
|
||||
);
|
||||
if (editingId.value != null && previous == null) {
|
||||
_error('Das bearbeitete Bauteil wurde nicht gefunden.');
|
||||
return;
|
||||
}
|
||||
final entry = BauteilModel(
|
||||
bauteilId: editingId.value ?? const Uuid().v4(),
|
||||
erstelltAm: previous?.erstelltAm ?? DateTime.now(),
|
||||
name: nameController.text.trim(),
|
||||
verwendung: verwendungController.text.trim(),
|
||||
druckdauerMinuten: duration,
|
||||
gewichtGramm: InputValidators.number(gewichtController.text)!,
|
||||
abfallGramm: InputValidators.number(abfallController.text)!,
|
||||
fotoBase64: foto.value == null ? null : base64Encode(foto.value!),
|
||||
filamente: selectedFilamente.entries
|
||||
.map(
|
||||
(item) => BauteilFilamentModel(
|
||||
filamentId: item.key,
|
||||
anwendungId: item.value,
|
||||
verbrauchGramm:
|
||||
InputValidators.number(
|
||||
verbrauchController(item.key).text,
|
||||
) ??
|
||||
double.nan,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
final error = _validateConsumption(entry, existing);
|
||||
if (error != null) {
|
||||
_error(error);
|
||||
return;
|
||||
}
|
||||
await _commit([
|
||||
...existing.where((item) => item.bauteilId != entry.bauteilId),
|
||||
entry,
|
||||
]);
|
||||
resetForm();
|
||||
hasError.value = false;
|
||||
message.value = 'Bauteil und Filamentverbrauch gespeichert.';
|
||||
} catch (_) {
|
||||
_error('Speichern fehlgeschlagen. Bitte erneut versuchen.');
|
||||
} finally {
|
||||
isSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> editBauteil(BauteilModel entry) async {
|
||||
if (isSaving.value || isPickingPhoto.value) return;
|
||||
resetForm();
|
||||
message.value = null;
|
||||
nameController.text = entry.name;
|
||||
verwendungController.text = entry.verwendung;
|
||||
stundenController.text = '${entry.druckdauerMinuten ~/ 60}';
|
||||
minutenController.text = '${entry.druckdauerMinuten % 60}';
|
||||
gewichtController.text = DisplayFormats.number(entry.gewichtGramm);
|
||||
abfallController.text = DisplayFormats.number(entry.abfallGramm);
|
||||
foto.value = entry.fotoBytes;
|
||||
for (final item in entry.filamente) {
|
||||
verbrauchController(item.filamentId).text = item.verbrauchGramm > 0
|
||||
? DisplayFormats.number(item.verbrauchGramm)
|
||||
: '';
|
||||
selectedFilamente[item.filamentId] = item.anwendungId;
|
||||
}
|
||||
editingId.value = entry.bauteilId;
|
||||
await scrollToForm();
|
||||
}
|
||||
|
||||
Future<void> duplicateBauteil(BauteilModel entry) async {
|
||||
if (isSaving.value || isPickingPhoto.value) return;
|
||||
isSaving.value = true;
|
||||
try {
|
||||
final existing = _loadBauteile();
|
||||
final copy = entry.copyWith(
|
||||
bauteilId: const Uuid().v4(),
|
||||
erstelltAm: DateTime.now(),
|
||||
);
|
||||
final error = _validateConsumption(copy, existing);
|
||||
if (error != null) {
|
||||
_error(error);
|
||||
await scrollToForm();
|
||||
return;
|
||||
}
|
||||
await _commit([...existing, copy]);
|
||||
hasError.value = false;
|
||||
message.value = 'Bauteil dupliziert und Verbrauch erneut gebucht.';
|
||||
} catch (_) {
|
||||
_error('Duplizieren fehlgeschlagen. Bitte erneut versuchen.');
|
||||
await scrollToForm();
|
||||
} finally {
|
||||
isSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteBauteil(String id) async {
|
||||
if (isSaving.value || isPickingPhoto.value) return;
|
||||
isSaving.value = true;
|
||||
try {
|
||||
await _commit(
|
||||
_loadBauteile().where((item) => item.bauteilId != id).toList(),
|
||||
);
|
||||
if (editingId.value == id) resetForm();
|
||||
hasError.value = false;
|
||||
message.value = 'Bauteil gelöscht und Verbrauch zurückgebucht.';
|
||||
} catch (_) {
|
||||
_error('Löschen fehlgeschlagen. Bitte erneut versuchen.');
|
||||
await scrollToForm();
|
||||
} finally {
|
||||
isSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> scrollToForm() async {
|
||||
if (scrollController.hasClients) {
|
||||
await scrollController.animateTo(
|
||||
0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOutCubic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void resetForm() {
|
||||
formKey.currentState?.reset();
|
||||
editingId.value = null;
|
||||
nameController.clear();
|
||||
verwendungController.clear();
|
||||
stundenController.text = '0';
|
||||
minutenController.text = '0';
|
||||
gewichtController.clear();
|
||||
abfallController.text = '0';
|
||||
selectedFilamente.clear();
|
||||
for (final controller in _verbrauchControllers.values) {
|
||||
controller.clear();
|
||||
}
|
||||
foto.value = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_closed = true;
|
||||
scrollController.dispose();
|
||||
nameController.dispose();
|
||||
verwendungController.dispose();
|
||||
stundenController.dispose();
|
||||
minutenController.dispose();
|
||||
gewichtController.dispose();
|
||||
abfallController.dispose();
|
||||
for (final controller in _verbrauchControllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,40 @@ import 'package:get/get.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../models/kauf_filament_model.dart';
|
||||
import '../models/bauteil_model.dart';
|
||||
import '../helper/storage_keys.dart';
|
||||
import '../helper/filament_bestand.dart';
|
||||
import '../helper/display_formats.dart';
|
||||
import '../helper/input_validators.dart';
|
||||
import '../services/get_storage_services.dart';
|
||||
|
||||
class HomeController extends GetxController {
|
||||
static const storageKey = 'kauf_filamente';
|
||||
static const storageKey = StorageKeys.filamente;
|
||||
|
||||
final storage = Get.find<GetStorageService>();
|
||||
final uuid = const Uuid();
|
||||
|
||||
final filamente = <KaufFilamentModel>[].obs;
|
||||
final verbrauch = <String, double>{}.obs;
|
||||
|
||||
void loadVerbrauch() {
|
||||
verbrauch.assignAll(
|
||||
FilamentBestand.verbrauch(
|
||||
storage.getModelList(StorageKeys.bauteile).map(BauteilModel.fromJson),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double? restgewicht(KaufFilamentModel filament) {
|
||||
final gewicht = filament.gewichtGramm;
|
||||
return gewicht == null
|
||||
? null
|
||||
: gewicht - (verbrauch[filament.filamentId] ?? 0);
|
||||
}
|
||||
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final pageScrollController = ScrollController();
|
||||
final formScrollController = ScrollController();
|
||||
|
||||
final haendlerController = TextEditingController();
|
||||
final farbeController = TextEditingController();
|
||||
@@ -46,19 +69,16 @@ class HomeController extends GetxController {
|
||||
}
|
||||
|
||||
void loadFilamente() {
|
||||
loadVerbrauch();
|
||||
final data = storage.getModelList(storageKey);
|
||||
|
||||
filamente.assignAll(
|
||||
data.map(KaufFilamentModel.fromJson),
|
||||
);
|
||||
filamente.assignAll(data.map(KaufFilamentModel.fromJson));
|
||||
|
||||
sortFilamente();
|
||||
}
|
||||
|
||||
void sortFilamente() {
|
||||
filamente.sort(
|
||||
(a, b) => b.kaufdatum.compareTo(a.kaufdatum),
|
||||
);
|
||||
filamente.sort((a, b) => b.kaufdatum.compareTo(a.kaufdatum));
|
||||
}
|
||||
|
||||
Future<void> persist() async {
|
||||
@@ -80,6 +100,22 @@ class HomeController extends GetxController {
|
||||
return;
|
||||
}
|
||||
|
||||
loadVerbrauch();
|
||||
final gewicht = InputValidators.number(gewichtController.text);
|
||||
final bereitsVerbraucht = editingId.value == null
|
||||
? 0
|
||||
: (verbrauch[editingId.value!] ?? 0);
|
||||
if (gewicht == null ||
|
||||
!gewicht.isFinite ||
|
||||
gewicht <= 0 ||
|
||||
gewicht < bereitsVerbraucht) {
|
||||
Get.snackbar(
|
||||
'Ungültiges Gewicht',
|
||||
'Das Startgewicht muss positiv sein und mindestens dem bereits gebuchten Verbrauch entsprechen.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final filament = KaufFilamentModel(
|
||||
filamentId: editingId.value ?? uuid.v4(),
|
||||
marke: markeController.text.trim(),
|
||||
@@ -88,9 +124,7 @@ class HomeController extends GetxController {
|
||||
material: material.value,
|
||||
preis: preis,
|
||||
farbe: farbeController.text.trim(),
|
||||
gewicht: gewichtController.text.trim().isEmpty
|
||||
? '1kg'
|
||||
: gewichtController.text.trim(),
|
||||
gewicht: gewicht.toString(),
|
||||
);
|
||||
|
||||
if (editingId.value == null) {
|
||||
@@ -113,7 +147,7 @@ class HomeController extends GetxController {
|
||||
resetForm();
|
||||
}
|
||||
|
||||
void editFilament(KaufFilamentModel filament) {
|
||||
Future<void> editFilament(KaufFilamentModel filament) async {
|
||||
editingId.value = filament.filamentId;
|
||||
kaufdatum.value = filament.kaufdatum;
|
||||
markeController.text = filament.marke;
|
||||
@@ -121,15 +155,24 @@ class HomeController extends GetxController {
|
||||
material.value = filament.material;
|
||||
preisController.text = filament.preis.toStringAsFixed(2);
|
||||
farbeController.text = filament.farbe;
|
||||
gewichtController.text = filament.gewicht;
|
||||
gewichtController.text = filament.gewichtGramm == null
|
||||
? filament.gewicht
|
||||
: DisplayFormats.number(filament.gewichtGramm!);
|
||||
|
||||
final scroll = formScrollController.hasClients
|
||||
? formScrollController
|
||||
: pageScrollController;
|
||||
if (scroll.hasClients) {
|
||||
await scroll.animateTo(
|
||||
0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOutCubic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> duplicateFilament(
|
||||
KaufFilamentModel filament,
|
||||
) async {
|
||||
filamente.add(
|
||||
filament.copyWith(filamentId: uuid.v4()),
|
||||
);
|
||||
Future<void> duplicateFilament(KaufFilamentModel filament) async {
|
||||
filamente.add(filament.copyWith(filamentId: uuid.v4()));
|
||||
|
||||
sortFilamente();
|
||||
await persist();
|
||||
@@ -151,11 +194,12 @@ class HomeController extends GetxController {
|
||||
material.value = 'PLA';
|
||||
gewichtController.clear();
|
||||
formKey.currentState?.reset();
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
pageScrollController.dispose();
|
||||
formScrollController.dispose();
|
||||
haendlerController.dispose();
|
||||
markeController.dispose();
|
||||
farbeController.dispose();
|
||||
@@ -163,4 +207,4 @@ class HomeController extends GetxController {
|
||||
gewichtController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user