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

202 lines
7.2 KiB
Dart

import 'package:flutter/material.dart';
import '../models/product.dart';
import '../services/woocommerce_service.dart';
import '../services/analytics_service.dart';
import '../widgets/product_card.dart';
import '../widgets/loading_widget.dart';
import '../widgets/retry_widget.dart';
import '../utils/error_handler.dart';
import 'product_detail_screen.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({super.key});
@override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
final WooCommerceService _wooCommerceService = WooCommerceService();
final TextEditingController _searchController = TextEditingController();
List<Product> _products = [];
bool _isLoading = false;
String? _error;
String _lastSearchQuery = '';
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
Future<void> _performSearch(String query) async {
if (query.trim().isEmpty) {
setState(() {
_products = [];
_error = null;
});
return;
}
setState(() {
_isLoading = true;
_error = null;
_lastSearchQuery = query;
});
// Track Search
AnalyticsService.trackSearch(query);
try {
final products = await _wooCommerceService.getProducts(
search: query,
perPage: 50,
);
setState(() {
_products = products;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
ErrorHandler.showError(context, e);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Suche'),
),
body: Column(
children: [
// Suchleiste
Padding(
padding: const EdgeInsets.all(16),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Produkte suchen...',
prefixIcon: const Icon(Icons.search),
suffixIcon: _searchController.text.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
_searchController.clear();
_performSearch('');
},
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
fillColor: Colors.grey[100],
),
textInputAction: TextInputAction.search,
onSubmitted: _performSearch,
onChanged: (value) {
setState(() {});
// Optional: Live-Suche mit Debounce
// _debounceSearch(value);
},
),
),
// Ergebnisse
Expanded(
child: _isLoading
? const LoadingWidget(message: 'Suche läuft...')
: _error != null
? RetryWidget(
message: 'Fehler bei der Suche',
onRetry: () => _performSearch(_lastSearchQuery),
)
: _products.isEmpty && _lastSearchQuery.isNotEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.search_off,
size: 64,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'Keine Ergebnisse gefunden',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.grey[600],
),
),
const SizedBox(height: 8),
Text(
'Versuche es mit anderen Suchbegriffen',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey[500],
),
),
],
),
)
: _products.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.search,
size: 64,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'Suche nach Produkten',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.grey[600],
),
),
],
),
)
: GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.75,
),
itemCount: _products.length,
itemBuilder: (context, index) {
return ProductCard(
product: _products[index],
onTap: () {
AnalyticsService.trackProductView(
_products[index].id,
_products[index].name,
);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(
product: _products[index],
),
),
);
},
);
},
),
),
],
),
);
}
}