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

201 lines
4.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/cart_provider.dart';
import '../models/product.dart';
import '../services/woocommerce_service.dart';
import '../widgets/product_card.dart';
import 'product_detail_screen.dart';
class ProductsScreen extends StatefulWidget {
final String? categoryId;
final String? categoryName;
const ProductsScreen({
super.key,
this.categoryId,
this.categoryName,
});
@override
State<ProductsScreen> createState() => _ProductsScreenState();
}
class _ProductsScreenState extends State<ProductsScreen> {
final WooCommerceService _wooCommerceService = WooCommerceService();
List<Product> _products = [];
bool _isLoading = true;
bool _isLoadingMore = false;
String? _error;
int _currentPage = 1;
final int _perPage = 20;
bool _hasMore = true;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_loadProducts();
_scrollController.addListener(_onScroll);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _onScroll() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent * 0.9) {
if (!_isLoadingMore && _hasMore) {
_loadMoreProducts();
}
}
}
Future<void> _loadProducts() async {
try {
setState(() {
_isLoading = true;
_error = null;
});
final products = await _wooCommerceService.getProducts(
perPage: _perPage,
page: 1,
category: widget.categoryId,
);
setState(() {
_products = products;
_isLoading = false;
_currentPage = 1;
_hasMore = products.length == _perPage;
});
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
}
}
Future<void> _loadMoreProducts() async {
if (_isLoadingMore || !_hasMore) return;
try {
setState(() {
_isLoadingMore = true;
});
final nextPage = _currentPage + 1;
final products = await _wooCommerceService.getProducts(
perPage: _perPage,
page: nextPage,
);
setState(() {
if (products.isEmpty) {
_hasMore = false;
} else {
_products.addAll(products);
_currentPage = nextPage;
_hasMore = products.length == _perPage;
}
_isLoadingMore = false;
});
} catch (e) {
setState(() {
_isLoadingMore = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.categoryName ?? 'Alle Produkte'),
),
body: _buildBody(),
);
}
Widget _buildBody() {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (_error != null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
Text(
'Fehler beim Laden der Produkte',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
_error!,
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _loadProducts,
child: const Text('Erneut versuchen'),
),
],
),
);
}
if (_products.isEmpty) {
return const Center(
child: Text('Keine Produkte verfügbar'),
);
}
return RefreshIndicator(
onRefresh: _loadProducts,
child: GridView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.75,
),
itemCount: _products.length + (_isLoadingMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == _products.length) {
return const Center(child: CircularProgressIndicator());
}
return ProductCard(
product: _products[index],
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(
product: _products[index],
),
),
);
},
);
},
),
);
}
}