ponshu-room-lite/lib/screens/sake_detail/sections/sake_basic_info_section.dart

231 lines
8.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../../models/sake_item.dart';
import '../../../theme/app_colors.dart';
import '../../../constants/app_constants.dart';
import '../../../providers/theme_provider.dart';
import '../../../services/mbti_compatibility_service.dart';
/// 銘柄名・蔵元/都道府県・タグ・AI確信度バッジ・MBTI相性バッジ・キャッチコピーを表示するセクション
class SakeBasicInfoSection extends ConsumerWidget {
final SakeItem sake;
final VoidCallback onTapName;
final VoidCallback onTapBrewery;
final VoidCallback onTapTags;
final void Function(BuildContext context, CompatibilityResult result, AppColors appColors) onTapMbtiCompatibility;
const SakeBasicInfoSection({
super.key,
required this.sake,
required this.onTapName,
required this.onTapBrewery,
required this.onTapTags,
required this.onTapMbtiCompatibility,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final appColors = Theme.of(context).extension<AppColors>()!;
// AI Confidence Logic (Theme Aware)
final score = sake.metadata.aiConfidence ?? 0;
final Color confidenceColor = score >= AppConstants.confidenceScoreHigh
? appColors.brandPrimary
: score >= AppConstants.confidenceScoreMedium
? appColors.textSecondary
: appColors.textTertiary;
// MBTI Compatibility
final userProfile = ref.watch(userProfileProvider);
final mbtiType = userProfile.mbti;
final mbtiResult = (mbtiType != null && mbtiType.isNotEmpty)
? MBTICompatibilityService.calculateCompatibility(mbtiType, sake)
: null;
final showMbti = mbtiResult != null && mbtiResult.hasResult;
final badgeColor = showMbti
? (mbtiResult.starRating >= 4
? appColors.brandPrimary
: mbtiResult.starRating >= 3
? appColors.textSecondary
: appColors.textTertiary)
: null;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Confidence Badge
if (sake.metadata.aiConfidence != null && sake.itemType != ItemType.set)
Center(
child: Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: confidenceColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: confidenceColor.withValues(alpha: 0.5)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(LucideIcons.sparkles, size: 14, color: confidenceColor),
const SizedBox(width: 6),
Text(
'AI確信度: $score%',
style: TextStyle(
color: confidenceColor,
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
],
),
),
),
// MBTI Compatibility Badge
if (showMbti)
Center(
child: GestureDetector(
onTap: () => onTapMbtiCompatibility(context, mbtiResult, appColors),
child: Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: badgeColor!.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(24),
border: Border.all(color: badgeColor.withValues(alpha: 0.3)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'$mbtiType相性: ',
style: TextStyle(
color: appColors.textSecondary,
fontSize: 12,
),
),
Text(
mbtiResult.starDisplay,
style: TextStyle(
color: badgeColor,
fontSize: 14,
letterSpacing: 1,
),
),
const SizedBox(width: 4),
Icon(
LucideIcons.info,
size: 12,
color: appColors.iconSubtle,
),
],
),
),
),
),
// Brand Name
Center(
child: InkWell(
onTap: onTapName,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Text(
sake.displayData.displayName,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
),
textAlign: TextAlign.center,
),
),
const SizedBox(width: 8),
Icon(LucideIcons.pencil, size: 18, color: appColors.iconSubtle),
],
),
),
),
const SizedBox(height: 8),
// Brand / Prefecture
if (sake.itemType != ItemType.set)
Center(
child: InkWell(
onTap: onTapBrewery,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Text(
'${sake.displayData.displayBrewery} / ${sake.displayData.displayPrefecture}',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: appColors.textSecondary,
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(width: 8),
Icon(LucideIcons.pencil, size: 16, color: appColors.iconSubtle),
],
),
),
),
const SizedBox(height: 16),
// Tags Row
if (sake.hiddenSpecs.flavorTags.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTapTags,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
alignment: WrapAlignment.center,
spacing: 8,
children: sake.hiddenSpecs.flavorTags
.map((tag) => Chip(
label: Text(tag, style: const TextStyle(fontSize: 10)),
visualDensity: VisualDensity.compact,
backgroundColor:
Theme.of(context).primaryColor.withValues(alpha: 0.1),
))
.toList(),
),
),
),
),
),
const SizedBox(height: 24),
// AI Catchcopy (Mincho)
if (sake.displayData.catchCopy != null && sake.itemType != ItemType.set)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
sake.displayData.catchCopy!,
style: GoogleFonts.zenOldMincho(
fontSize: 24,
height: 1.5,
fontWeight: FontWeight.w500,
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Theme.of(context).primaryColor,
),
textAlign: TextAlign.center,
),
),
],
);
}
}