222 lines
6.7 KiB
Dart
222 lines
6.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:lucide_icons/lucide_icons.dart';
|
|
import '../../../models/sake_item.dart';
|
|
import '../../../providers/theme_provider.dart';
|
|
import '../../../services/mbti_compatibility_service.dart';
|
|
import '../../../theme/app_colors.dart';
|
|
import '../../../providers/license_provider.dart';
|
|
|
|
/// MBTI酒向スタンプセクション
|
|
///
|
|
/// Pro版: MBTI診断結果に基づく相性スタンプを表示
|
|
/// Lite版: Pro版限定機能のロック表示
|
|
class SakeMbtiStampSection extends ConsumerWidget {
|
|
final SakeItem sake;
|
|
|
|
const SakeMbtiStampSection({
|
|
super.key,
|
|
required this.sake,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final appColors = Theme.of(context).extension<AppColors>()!;
|
|
final isPro = ref.watch(isProProvider);
|
|
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(24),
|
|
decoration: BoxDecoration(
|
|
border: Border.all(
|
|
color: isPro
|
|
? appColors.brandPrimary.withValues(alpha: 0.3)
|
|
: appColors.divider,
|
|
style: BorderStyle.solid,
|
|
width: 2,
|
|
),
|
|
borderRadius: BorderRadius.circular(16),
|
|
color: Theme.of(context).cardColor.withValues(alpha: 0.5),
|
|
),
|
|
child: isPro
|
|
? _buildProContent(context, ref, appColors)
|
|
: _buildLiteContent(context, appColors),
|
|
);
|
|
}
|
|
|
|
/// Pro版: MBTI相性スタンプ表示
|
|
Widget _buildProContent(BuildContext context, WidgetRef ref, AppColors appColors) {
|
|
final userProfile = ref.watch(userProfileProvider);
|
|
final mbtiType = userProfile.mbti;
|
|
|
|
// MBTI未設定の場合
|
|
if (mbtiType == null || mbtiType.isEmpty) {
|
|
return Column(
|
|
children: [
|
|
Icon(LucideIcons.compass, color: appColors.brandAccent, size: 32),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
'MBTI酒向スタンプ',
|
|
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
|
color: appColors.brandPrimary,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: appColors.surfaceSubtle,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Text(
|
|
'ソムリエ画面でMBTI診断を完了すると\n相性スタンプが表示されます',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: appColors.textSecondary,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// MBTI相性計算
|
|
final result = MBTICompatibilityService.calculateCompatibility(mbtiType, sake);
|
|
|
|
if (!result.hasResult) {
|
|
return Column(
|
|
children: [
|
|
Icon(LucideIcons.helpCircle, color: appColors.textSecondary, size: 32),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
'相性データなし',
|
|
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
|
color: appColors.textSecondary,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// 相性レベルに応じた色
|
|
final stampColor = result.starRating >= 4
|
|
? appColors.brandPrimary
|
|
: result.starRating >= 3
|
|
? appColors.brandAccent
|
|
: appColors.textSecondary;
|
|
|
|
return Column(
|
|
children: [
|
|
// スタンプアイコン
|
|
Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
gradient: LinearGradient(
|
|
colors: [
|
|
stampColor.withValues(alpha: 0.2),
|
|
stampColor.withValues(alpha: 0.1),
|
|
],
|
|
),
|
|
border: Border.all(
|
|
color: stampColor.withValues(alpha: 0.5),
|
|
width: 2,
|
|
),
|
|
),
|
|
child: Text(
|
|
result.starDisplay,
|
|
style: TextStyle(
|
|
fontSize: 24,
|
|
color: stampColor,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// MBTIタイプと相性レベル
|
|
Text(
|
|
'$mbtiType x この日本酒',
|
|
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
|
color: appColors.brandPrimary,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
result.level,
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
color: stampColor,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
|
|
// パーセント表示
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: stampColor.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: Text(
|
|
'${(result.score * 100).round()}% マッチ',
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w600,
|
|
color: stampColor,
|
|
),
|
|
),
|
|
),
|
|
|
|
// マッチ理由
|
|
if (result.reasons.isNotEmpty) ...[
|
|
const SizedBox(height: 12),
|
|
...result.reasons.take(2).map((reason) => Padding(
|
|
padding: const EdgeInsets.only(bottom: 4),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(LucideIcons.check, size: 12, color: appColors.textSecondary),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
reason,
|
|
style: TextStyle(
|
|
fontSize: 11,
|
|
color: appColors.textSecondary,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)),
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/// Lite版: Pro版限定機能のロック表示
|
|
Widget _buildLiteContent(BuildContext context, AppColors appColors) {
|
|
return Column(
|
|
children: [
|
|
Icon(LucideIcons.lock, color: appColors.iconSubtle, size: 32),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
'Pro版限定機能',
|
|
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
|
color: appColors.textSecondary,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'MBTI酒向スタンプは\nPro版でご利用いただけます',
|
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: appColors.textTertiary),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|