/// Search tab: query field plus a [ListView.builder] of matching items. library; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/item.dart'; import '../providers/item_provider.dart'; import '../widgets/empty_state.dart'; import '../widgets/item_card.dart'; import '../widgets/responsive_body.dart'; class SearchScreen extends StatefulWidget { const SearchScreen({super.key}); @override State createState() => _SearchScreenState(); } class _SearchScreenState extends State { final _query = TextEditingController(); @override void dispose() { _query.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final results = context.watch().search(_query.text); return Scaffold( appBar: AppBar(title: const Text('Search')), body: ResponsiveBody( child: Column( children: [ const SizedBox(height: 8), TextField( controller: _query, textInputAction: TextInputAction.search, onChanged: (_) => setState(() {}), decoration: InputDecoration( hintText: 'Title, summary, or category', prefixIcon: const Icon(Icons.search), suffixIcon: _query.text.isEmpty ? null : IconButton( tooltip: 'Clear', onPressed: () { _query.clear(); setState(() {}); }, icon: const Icon(Icons.close), ), ), ), const SizedBox(height: 8), Align( alignment: Alignment.centerLeft, child: Text( '${results.length} result${results.length == 1 ? '' : 's'}', style: Theme.of(context).textTheme.labelMedium, ), ), const SizedBox(height: 8), Expanded(child: _ResultsList(results: results, query: _query.text)), ], ), ), ); } } class _ResultsList extends StatelessWidget { const _ResultsList({required this.results, required this.query}); final List results; final String query; @override Widget build(BuildContext context) { if (results.isEmpty) { return EmptyState( icon: Icons.search_off, title: query.trim().isEmpty ? 'Start typing' : 'No matches', message: query.trim().isEmpty ? 'Search the catalog by title, summary, or category.' : 'Try a different keyword.', ); } return ListView.builder( padding: const EdgeInsets.only(bottom: 24), itemCount: results.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: ItemCard(item: results[index], heroScope: 'search'), ); }, ); } }