Files
app-hyggecraftery/lib/screens/product_detail_screen.dart
2026-01-03 15:24:36 +01:00

260 lines
9.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../models/product.dart';
import '../providers/cart_provider.dart';
class ProductDetailScreen extends StatelessWidget {
final Product product;
const ProductDetailScreen({
super.key,
required this.product,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(product.name),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Produktbild
if (product.imageUrl != null)
SizedBox(
height: 300,
width: double.infinity,
child: CachedNetworkImage(
imageUrl: product.imageUrl!,
fit: BoxFit.cover,
placeholder: (context, url) => const Center(
child: CircularProgressIndicator(),
),
errorWidget: (context, url, error) => Container(
color: Colors.grey[300],
child: const Icon(Icons.image_not_supported, size: 64),
),
),
)
else
Container(
height: 300,
width: double.infinity,
color: Colors.grey[300],
child: const Icon(Icons.image_not_supported, size: 64),
),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Produktname
Text(
product.name,
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
// Preis
Row(
children: [
if (product.isOnSale) ...[
Text(
'${product.regularPrice}',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
decoration: TextDecoration.lineThrough,
color: Colors.grey,
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Sale',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
const Spacer(),
Text(
'${product.price}',
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: const Color(0xFF8B6F47),
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
// Verfügbarkeit
Row(
children: [
Icon(
product.inStock ? Icons.check_circle : Icons.cancel,
color: product.inStock ? Colors.green : Colors.red,
size: 20,
),
const SizedBox(width: 8),
Text(
product.inStock
? 'Auf Lager'
: 'Nicht verfügbar',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: product.inStock ? Colors.green : Colors.red,
),
),
],
),
const SizedBox(height: 24),
// Beschreibung
if (product.description.isNotEmpty) ...[
Text(
'Beschreibung',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
product.description.replaceAll(RegExp(r'<[^>]*>'), ''),
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 24),
],
// Zusätzliche Bilder
if (product.images.length > 1) ...[
Text(
'Weitere Bilder',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: product.images.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 8),
child: CachedNetworkImage(
imageUrl: product.images[index],
width: 100,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
width: 100,
color: Colors.grey[300],
child: const Center(
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Container(
width: 100,
color: Colors.grey[300],
child: const Icon(Icons.image_not_supported),
),
),
);
},
),
),
const SizedBox(height: 24),
],
],
),
),
],
),
),
bottomNavigationBar: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 4,
offset: const Offset(0, -2),
),
],
),
child: Consumer<CartProvider>(
builder: (context, cart, child) {
final cartItem = cart.items.firstWhere(
(item) => item.product.id == product.id,
orElse: () => CartItem(product: product, quantity: 0),
);
return Row(
children: [
if (cartItem.quantity > 0) ...[
IconButton(
icon: const Icon(Icons.remove_circle_outline),
onPressed: () => cart.removeItem(product),
),
Text(
'${cartItem.quantity}',
style: Theme.of(context).textTheme.titleLarge,
),
IconButton(
icon: const Icon(Icons.add_circle_outline),
onPressed: () => cart.addItem(product),
),
] else
Expanded(
child: ElevatedButton(
onPressed: product.inStock
? () {
cart.addItem(product);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${product.name} zum Warenkorb hinzugefügt'),
duration: const Duration(seconds: 2),
),
);
}
: null,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8B6F47),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Text(
product.inStock ? 'Zum Warenkorb hinzufügen' : 'Nicht verfügbar',
style: const TextStyle(fontSize: 16),
),
),
),
],
);
},
),
),
);
}
}