100 lines
2.9 KiB
Dart
100 lines
2.9 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';
|
|
import 'common/error_retry_widget.dart';
|
|
|
|
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) {
|
|
// Phase D6: Use filteredByModeProvider to respect personal/business mode filtering
|
|
final rawListAsync = ref.read(filteredByModeProvider);
|
|
|
|
return rawListAsync.when(
|
|
data: (list) {
|
|
final filtered = list.where((item) {
|
|
final q = query.toLowerCase();
|
|
return item.displayData.displayName.toLowerCase().contains(q) ||
|
|
item.displayData.displayBrewery.toLowerCase().contains(q) ||
|
|
item.displayData.displayPrefecture.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.displayName),
|
|
subtitle: Text('${sake.displayData.displayBrewery} / ${sake.displayData.displayPrefecture}'),
|
|
onTap: () {
|
|
close(context, null);
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (context) => SakeDetailScreen(sake: sake),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
},
|
|
loading: () => const Center(child: CircularProgressIndicator()),
|
|
error: (e, s) => ErrorRetryWidget(
|
|
message: '検索に失敗しました',
|
|
details: e.toString(),
|
|
onRetry: () => ref.refresh(filteredByModeProvider),
|
|
compact: true,
|
|
),
|
|
);
|
|
}
|
|
}
|