update edit and list and detail view

This commit is contained in:
2026-01-16 14:57:14 +01:00
parent 6df0da2776
commit 3a2dcfd7fc
7 changed files with 136 additions and 85 deletions

View File

@@ -5,13 +5,13 @@ import '../helpers/filament_repository.dart';
class EditController extends GetxController { class EditController extends GetxController {
Rx<FilamentModel?> originalFilament = Rx<FilamentModel?>(null); Rx<FilamentModel?> originalFilament = Rx<FilamentModel?>(null);
// Form Controllers // Form Controllers
final nameController = TextEditingController(); final nameController = TextEditingController();
final typeController = TextEditingController(); final typeController = TextEditingController();
final colorController = TextEditingController();
final weightController = TextEditingController(); final weightController = TextEditingController();
final weightUsedController = TextEditingController(); final weightUsedController = TextEditingController();
final currentUsageController = TextEditingController();
final priceController = TextEditingController(); final priceController = TextEditingController();
final manufacturerController = TextEditingController(); final manufacturerController = TextEditingController();
final purchaseDateController = TextEditingController(); final purchaseDateController = TextEditingController();
@@ -20,6 +20,9 @@ class EditController extends GetxController {
final printingTempController = TextEditingController(); final printingTempController = TextEditingController();
final bedTempController = TextEditingController(); final bedTempController = TextEditingController();
// Reactive color for UI updates
final selectedColor = 'White'.obs;
// Validation // Validation
final formKey = GlobalKey<FormState>(); final formKey = GlobalKey<FormState>();
final isSaving = false.obs; final isSaving = false.obs;
@@ -27,6 +30,7 @@ class EditController extends GetxController {
// Available options // Available options
final List<String> filamentTypes = [ final List<String> filamentTypes = [
'PLA', 'PLA',
'PLA+',
'ABS', 'ABS',
'PETG', 'PETG',
'TPU', 'TPU',
@@ -64,7 +68,8 @@ class EditController extends GetxController {
if (filament != null) { if (filament != null) {
nameController.text = filament.name; nameController.text = filament.name;
typeController.text = filament.type; typeController.text = filament.type;
colorController.text = filament.color; selectedColor.value = filament.color;
selectedColor.value = filament.color;
weightController.text = filament.weight.toString(); weightController.text = filament.weight.toString();
weightUsedController.text = filament.weightUsed.toString(); weightUsedController.text = filament.weightUsed.toString();
priceController.text = filament.price.toString(); priceController.text = filament.price.toString();
@@ -83,26 +88,33 @@ class EditController extends GetxController {
isSaving.value = true; isSaving.value = true;
try { try {
// Berechne den neuen Gesamtverbrauch
final currentWeightUsed = double.tryParse(weightUsedController.text) ?? 0;
final additionalUsage = double.tryParse(currentUsageController.text) ?? 0;
final totalWeightUsed = currentWeightUsed + additionalUsage;
final updatedFilament = FilamentModel( final updatedFilament = FilamentModel(
id: originalFilament.value?.id ?? DateTime.now().millisecondsSinceEpoch.toString(), id:
originalFilament.value?.id ??
DateTime.now().millisecondsSinceEpoch.toString(),
name: nameController.text.trim(), name: nameController.text.trim(),
type: typeController.text.trim(), type: typeController.text.trim(),
color: colorController.text.trim(), color: selectedColor.value.trim(),
weight: double.tryParse(weightController.text) ?? 0, weight: double.tryParse(weightController.text) ?? 0,
weightUsed: double.tryParse(weightUsedController.text) ?? 0, weightUsed: totalWeightUsed,
price: double.tryParse(priceController.text) ?? 0, price: double.tryParse(priceController.text) ?? 0,
manufacturer: manufacturerController.text.trim().isEmpty manufacturer: manufacturerController.text.trim().isEmpty
? null ? null
: manufacturerController.text.trim(), : manufacturerController.text.trim(),
purchaseDate: purchaseDateController.text.trim().isEmpty purchaseDate: purchaseDateController.text.trim().isEmpty
? null ? null
: purchaseDateController.text.trim(), : purchaseDateController.text.trim(),
notes: notesController.text.trim().isEmpty notes: notesController.text.trim().isEmpty
? null ? null
: notesController.text.trim(), : notesController.text.trim(),
pices: int.tryParse(piecesController.text), pices: int.tryParse(piecesController.text) ?? 0,
printingTemp: int.tryParse(printingTempController.text), printingTemp: int.tryParse(printingTempController.text) ?? 0,
bedTemp: int.tryParse(bedTempController.text), bedTemp: int.tryParse(bedTempController.text) ?? 0,
); );
bool success; bool success;
@@ -116,7 +128,7 @@ class EditController extends GetxController {
Get.back(result: updatedFilament); Get.back(result: updatedFilament);
Get.snackbar( Get.snackbar(
'Erfolg', 'Erfolg',
originalFilament.value != null originalFilament.value != null
? 'Filament wurde aktualisiert' ? 'Filament wurde aktualisiert'
: 'Filament wurde erstellt', : 'Filament wurde erstellt',
snackPosition: SnackPosition.BOTTOM, snackPosition: SnackPosition.BOTTOM,
@@ -149,9 +161,9 @@ class EditController extends GetxController {
void onClose() { void onClose() {
nameController.dispose(); nameController.dispose();
typeController.dispose(); typeController.dispose();
colorController.dispose();
weightController.dispose(); weightController.dispose();
weightUsedController.dispose(); weightUsedController.dispose();
currentUsageController.dispose();
priceController.dispose(); priceController.dispose();
manufacturerController.dispose(); manufacturerController.dispose();
purchaseDateController.dispose(); purchaseDateController.dispose();

View File

@@ -10,7 +10,7 @@ class ListController extends GetxController {
@override @override
void onInit() { void onInit() {
_loadListFillament(); loadListFillament();
super.onInit(); super.onInit();
} }
@@ -20,7 +20,7 @@ class ListController extends GetxController {
@override @override
void onClose() {} void onClose() {}
Future<void> _loadListFillament() async { Future<void> loadListFillament() async {
isLoadingFilament(true); isLoadingFilament(true);
if (filamentList.isNotEmpty) { if (filamentList.isNotEmpty) {
filamentList.clear(); filamentList.clear();
@@ -30,14 +30,18 @@ class ListController extends GetxController {
update(); update();
} }
void addNewFilament() {} void addNewFilament() async {
await Get.toNamed(EditPage.namedRoute);
loadListFillament();
}
void viewFilamentDetails(FilamentModel filament) { void viewFilamentDetails(FilamentModel filament) {
Get.toNamed(DetailsPage.namedRoute, arguments: {'filament': filament}); Get.toNamed(DetailsPage.namedRoute, arguments: {'filament': filament});
} }
void editFilament(FilamentModel filament) { void editFilament(FilamentModel filament) async {
Get.toNamed(EditPage.namedRoute, arguments: {'filament': filament}); await Get.toNamed(EditPage.namedRoute, arguments: {'filament': filament});
loadListFillament();
} }
void removeFilament(FilamentModel filament) { void removeFilament(FilamentModel filament) {

View File

@@ -7,6 +7,7 @@ import 'helpers/sample_routes.dart';
import 'pages/home_view.dart'; import 'pages/home_view.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Get.putAsync(() => FilamentRepository().init()); await Get.putAsync(() => FilamentRepository().init());
runApp(MyApp()); runApp(MyApp());
} }

View File

@@ -11,7 +11,7 @@ class FilamentModel {
final String? manufacturer; final String? manufacturer;
final String? purchaseDate; final String? purchaseDate;
final String? notes; final String? notes;
final int? pices; final int pices;
final int? printingTemp; final int? printingTemp;
final int? bedTemp; final int? bedTemp;
@@ -26,9 +26,9 @@ class FilamentModel {
this.manufacturer, this.manufacturer,
this.purchaseDate, this.purchaseDate,
this.notes, this.notes,
this.pices, required this.pices,
this.printingTemp, this.printingTemp,
this.bedTemp this.bedTemp,
}); });
// JSON Serialisierung // JSON Serialisierung
@@ -46,7 +46,7 @@ class FilamentModel {
'pices': pices, 'pices': pices,
'printingTemp': printingTemp, 'printingTemp': printingTemp,
'bedTemp': bedTemp, 'bedTemp': bedTemp,
'printWeightUsed': weightUsed, 'weightUsed': weightUsed,
}; };
} }
@@ -57,13 +57,13 @@ class FilamentModel {
name: json['name'] as String, name: json['name'] as String,
type: json['type'] as String, type: json['type'] as String,
color: json['color'] as String, color: json['color'] as String,
weight: (json['weight'] as num).toDouble(), weight: (json['weight'] as num?)?.toDouble() ?? 0.0,
weightUsed: (json['weightUsed'] as num).toDouble(), weightUsed: (json['weightUsed'] as num?)?.toDouble() ?? 0.0,
price: (json['price'] as num).toDouble(), price: (json['price'] as num).toDouble(),
manufacturer: json['manufacturer'] as String?, manufacturer: json['manufacturer'] as String?,
purchaseDate: json['purchaseDate'] as String?, purchaseDate: json['purchaseDate'] as String?,
notes: json['notes'] as String?, notes: json['notes'] as String?,
pices: json['pices'] as int?, pices: json['pices'] as int,
printingTemp: json['printingTemp'] as int?, printingTemp: json['printingTemp'] as int?,
bedTemp: json['bedTemp'] as int?, bedTemp: json['bedTemp'] as int?,
); );

View File

@@ -76,7 +76,9 @@ class EditPage extends GetView<EditController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
isNewFilament ? 'Neues Filament anlegen' : 'Filament bearbeiten', isNewFilament
? 'Neues Filament anlegen'
: 'Filament bearbeiten',
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -145,14 +147,14 @@ class EditPage extends GetView<EditController> {
SizedBox(height: 16), SizedBox(height: 16),
ColorSelector( Obx(
selectedColor: controller.colorController.text.isNotEmpty () => ColorSelector(
? controller.colorController.text selectedColor: controller.selectedColor.value,
: 'White', colors: controller.availableColors,
colors: controller.availableColors, onColorSelected: (color) {
onColorSelected: (color) { controller.selectedColor.value = color;
controller.colorController.text = color; },
}, ),
), ),
SizedBox(height: 24), SizedBox(height: 24),
@@ -193,6 +195,7 @@ class EditPage extends GetView<EditController> {
hint: '0', hint: '0',
icon: Icons.trending_down, icon: Icons.trending_down,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
readOnly: true,
validator: (value) { validator: (value) {
if (value != null && value.isNotEmpty) { if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) { if (double.tryParse(value) == null) {
@@ -208,6 +211,24 @@ class EditPage extends GetView<EditController> {
SizedBox(height: 16), SizedBox(height: 16),
CustomTextField(
controller: controller.currentUsageController,
label: 'Aktueller Verbrauch hinzufügen (g)',
hint: '0',
icon: Icons.add_circle_outline,
keyboardType: TextInputType.number,
validator: (value) {
if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) {
return 'Ungültige Zahl';
}
}
return null;
},
),
SizedBox(height: 16),
Row( Row(
children: [ children: [
Expanded( Expanded(
@@ -309,9 +330,7 @@ class EditPage extends GetView<EditController> {
builder: (context, child) { builder: (context, child) {
return Theme( return Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
colorScheme: ColorScheme.light( colorScheme: ColorScheme.light(primary: Colors.blue),
primary: Colors.blue,
),
), ),
child: child!, child: child!,
); );
@@ -319,10 +338,15 @@ class EditPage extends GetView<EditController> {
); );
if (date != null) { if (date != null) {
final formatter = DateFormat('dd.MM.yyyy'); final formatter = DateFormat('dd.MM.yyyy');
controller.purchaseDateController.text = formatter.format(date); controller.purchaseDateController.text = formatter.format(
date,
);
} }
}, },
suffix: Icon(Icons.arrow_drop_down, color: Colors.blue.shade400), suffix: Icon(
Icons.arrow_drop_down,
color: Colors.blue.shade400,
),
), ),
SizedBox(height: 16), SizedBox(height: 16),
@@ -338,48 +362,50 @@ class EditPage extends GetView<EditController> {
SizedBox(height: 32), SizedBox(height: 32),
// Save Button // Save Button
Obx(() => AnimatedContainer( Obx(
duration: Duration(milliseconds: 300), () => AnimatedContainer(
height: 56, duration: Duration(milliseconds: 300),
child: controller.isSaving.value height: 56,
? Container( child: controller.isSaving.value
decoration: BoxDecoration( ? Container(
color: Colors.blue.shade100, decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), color: Colors.blue.shade100,
), borderRadius: BorderRadius.circular(12),
child: Center( ),
child: Row( child: Center(
mainAxisAlignment: MainAxisAlignment.center, child: Row(
children: [ mainAxisAlignment: MainAxisAlignment.center,
SizedBox( children: [
width: 20, SizedBox(
height: 20, width: 20,
child: CircularProgressIndicator( height: 20,
strokeWidth: 2, child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>( strokeWidth: 2,
Colors.blue, valueColor: AlwaysStoppedAnimation<Color>(
Colors.blue,
),
), ),
), ),
), SizedBox(width: 12),
SizedBox(width: 12), Text(
Text( 'Wird gespeichert...',
'Wird gespeichert...', style: TextStyle(
style: TextStyle( color: Colors.blue,
color: Colors.blue, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, ),
), ),
), ],
], ),
), ),
)
: ActionButton(
icon: Icons.save,
label: isNewFilament ? 'Erstellen' : 'Speichern',
color: Colors.blue,
onPressed: controller.saveFilament,
), ),
) ),
: ActionButton( ),
icon: Icons.save,
label: isNewFilament ? 'Erstellen' : 'Speichern',
color: Colors.blue,
onPressed: controller.saveFilament,
),
)),
SizedBox(height: 16), SizedBox(height: 16),

View File

@@ -25,6 +25,7 @@ class ColorSelector extends StatelessWidget {
'pink': Colors.pink, 'pink': Colors.pink,
'grey': Colors.grey, 'grey': Colors.grey,
'brown': Colors.brown, 'brown': Colors.brown,
'wood' : Colors.brown[300]!,
}; };
return colorMap[colorName.toLowerCase()] ?? Colors.grey; return colorMap[colorName.toLowerCase()] ?? Colors.grey;
} }

View File

@@ -30,39 +30,46 @@ class DetailInfoCard extends StatelessWidget {
], ],
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color.withAlpha(10), color: color.withAlpha(10),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Icon(icon, color: color, size: 24), child: Icon(icon, color: color, size: 20),
), ),
SizedBox(width: 12), SizedBox(width: 10),
Expanded( Expanded(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
label, label,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 11,
color: Colors.grey.shade600, color: Colors.grey.shade600,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 4), SizedBox(height: 4),
Text( Text(
value, value,
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey.shade800, color: Colors.grey.shade800,
), ),
maxLines: 2,
overflow: TextOverflow.ellipsis,
), ),
], ],
), ),