94 lines
2.7 KiB
Dart
94 lines
2.7 KiB
Dart
|
|
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:lucide_icons/lucide_icons.dart';
|
||
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
|
import '../providers/sake_list_provider.dart';
|
||
|
|
import '../screens/sake_detail_screen.dart';
|
||
|
|
import 'dart:io';
|
||
|
|
|
||
|
|
class SakeSearchDelegate extends SearchDelegate {
|
||
|
|
final WidgetRef ref;
|
||
|
|
|
||
|
|
SakeSearchDelegate(this.ref);
|
||
|
|
|
||
|
|
@override
|
||
|
|
List<Widget>? buildActions(BuildContext context) {
|
||
|
|
return [
|
||
|
|
IconButton(
|
||
|
|
icon: const Icon(LucideIcons.x),
|
||
|
|
onPressed: () {
|
||
|
|
query = '';
|
||
|
|
},
|
||
|
|
),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget? buildLeading(BuildContext context) {
|
||
|
|
return IconButton(
|
||
|
|
icon: const Icon(LucideIcons.arrowLeft),
|
||
|
|
onPressed: () {
|
||
|
|
close(context, null);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget buildResults(BuildContext context) {
|
||
|
|
return _buildList(context);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget buildSuggestions(BuildContext context) {
|
||
|
|
return _buildList(context);
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildList(BuildContext context) {
|
||
|
|
// Access the RAW provider to search across all items, ignoring current filters
|
||
|
|
final rawListAsync = ref.read(rawSakeListItemsProvider);
|
||
|
|
|
||
|
|
return rawListAsync.when(
|
||
|
|
data: (list) {
|
||
|
|
final filtered = list.where((item) {
|
||
|
|
final q = query.toLowerCase();
|
||
|
|
return item.displayData.name.toLowerCase().contains(q) ||
|
||
|
|
item.displayData.brewery.toLowerCase().contains(q) ||
|
||
|
|
item.displayData.prefecture.toLowerCase().contains(q);
|
||
|
|
}).toList();
|
||
|
|
|
||
|
|
if (filtered.isEmpty) {
|
||
|
|
return const Center(child: Text('No results found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
return ListView.builder(
|
||
|
|
itemCount: filtered.length,
|
||
|
|
itemBuilder: (context, index) {
|
||
|
|
final sake = filtered[index];
|
||
|
|
return ListTile(
|
||
|
|
leading: SizedBox(
|
||
|
|
width: 40,
|
||
|
|
height: 40,
|
||
|
|
child: sake.displayData.imagePaths.isNotEmpty
|
||
|
|
? Image.file(File(sake.displayData.imagePaths.first), fit: BoxFit.cover)
|
||
|
|
: const Icon(LucideIcons.image),
|
||
|
|
),
|
||
|
|
title: Text(sake.displayData.name),
|
||
|
|
subtitle: Text('${sake.displayData.brewery} / ${sake.displayData.prefecture}'),
|
||
|
|
onTap: () {
|
||
|
|
close(context, null);
|
||
|
|
Navigator.of(context).push(
|
||
|
|
MaterialPageRoute(
|
||
|
|
builder: (context) => SakeDetailScreen(sake: sake),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
},
|
||
|
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||
|
|
error: (e, s) => Center(child: Text('Error: $e')),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|