import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'dart:io'; import '../../models/sake_item.dart'; import '../../providers/menu_providers.dart'; import '../../screens/sake_detail_screen.dart'; import '../../theme/app_theme.dart'; import '../../theme/app_colors.dart'; import '../../providers/ui_experiment_provider.dart'; import 'package:lucide_icons/lucide_icons.dart'; class SakeGridItem extends ConsumerWidget { final SakeItem sake; final bool isMenuMode; const SakeGridItem({ super.key, required this.sake, required this.isMenuMode, }); @override Widget build(BuildContext context, WidgetRef ref) { final isSelected = ref.watch(selectedMenuSakeIdsProvider).contains(sake.id); final appColors = Theme.of(context).extension()!; return Card( clipBehavior: Clip.antiAlias, // Highlight selected shape: isMenuMode && isSelected ? RoundedRectangleBorder(side: BorderSide(color: appColors.brandAccent, width: 3), borderRadius: BorderRadius.circular(6)) : RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)), // Reverted to 6px as requested child: InkWell( onTap: () { if (isMenuMode) { ref.read(selectedMenuSakeIdsProvider.notifier).toggle(sake.id); return; } Navigator.of(context).push( MaterialPageRoute( builder: (context) => SakeDetailScreen(sake: sake), ), ); }, child: Stack( fit: StackFit.expand, children: [ Hero( tag: sake.id, child: sake.displayData.imagePaths.isNotEmpty ? Image.file( File(sake.displayData.imagePaths.first), fit: BoxFit.cover, cacheWidth: 300, // 元の設定に戻す(画質優先) cacheHeight: 450, // 元の設定に戻す // 段階的に画像を表示(体感速度向上) frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded) return child; return AnimatedOpacity( opacity: frame == null ? 0 : 1, duration: const Duration(milliseconds: 200), curve: Curves.easeOut, child: child, ); }, errorBuilder: (context, error, stackTrace) { return Container( color: appColors.surfaceSubtle, child: Center( child: Icon( LucideIcons.imageOff, color: appColors.iconSubtle, ), ), ); }, ) : (sake.itemType == ItemType.set ? Image.asset( 'assets/images/set_placeholder.png', fit: BoxFit.cover, ) : Container( color: appColors.surfaceSubtle, child: Center( child: Icon( LucideIcons.image, size: 50, color: appColors.iconSubtle, ), ), )), ), // Gradient Overlay for Text Visibility if (ref.watch(uiExperimentProvider).showGridText) Positioned( bottom: 0, left: 0, right: 0, child: Container( padding: const EdgeInsets.all(AppTheme.spacingSmall), color: Colors.black54, // Changed from gradient to solid for "Transparent Black" underlay request child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // セット商品バッジ if (sake.itemType == ItemType.set) Container( margin: const EdgeInsets.only(bottom: 4), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: appColors.brandAccent, borderRadius: BorderRadius.circular(4), ), child: Text( 'セット', style: TextStyle( color: appColors.surfaceElevated, fontSize: 10, fontWeight: FontWeight.bold, ), ), ), Text( sake.displayData.displayName, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), // 通常銘柄のみ酒蔵/都道府県を表示 if (sake.itemType != ItemType.set && (sake.displayData.displayBrewery.isNotEmpty || sake.displayData.displayPrefecture.isNotEmpty)) Text( '${sake.displayData.displayBrewery} / ${sake.displayData.displayPrefecture}', style: const TextStyle( color: Colors.white70, fontSize: 10, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), // セット商品の説明文 if (sake.itemType == ItemType.set && sake.displayData.catchCopy != null) Text( sake.displayData.catchCopy!, style: const TextStyle( color: Colors.white70, fontSize: 10, fontStyle: FontStyle.italic, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ), // Selection Checkbox Overlay if (isMenuMode) Positioned( top: AppTheme.spacingSmall, left: AppTheme.spacingSmall, child: Container( width: 32, height: 32, decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.2), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Icon( isSelected ? Icons.check_circle : Icons.check_circle_outline, color: isSelected ? appColors.brandPrimary : appColors.iconSubtle, size: 32, ), ), ), // Favorite Icon if (sake.userData.isFavorite && !isMenuMode) const Positioned( top: AppTheme.spacingSmall, right: AppTheme.spacingSmall, child: Icon( LucideIcons.heart, color: Colors.pink, size: 20, ), ), ], ), ), ); } }