ponshu-room-lite/lib/widgets/mbti/mbti_result_card.dart

191 lines
6.5 KiB
Dart
Raw Normal View History

import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../models/mbti_result.dart';
class MBTIResultCard extends StatelessWidget {
final MBTIResult result;
final VoidCallback? onShare;
final VoidCallback? onShowRecommendations;
const MBTIResultCard({
super.key,
required this.result,
this.onShare,
this.onShowRecommendations,
});
@override
Widget build(BuildContext context) {
final type = result.type;
final theme = Theme.of(context);
// Simple gradient based on Type Group logic or just random for now?
// Let's use the first letter to determine base tone.
// E (Energy) -> Warmer, I (Introvert) -> Cooler
final isE = type.code.startsWith('E');
final isF = type.code.contains('F');
// Gradient Colors
final Color topColor = isE
? (isF ? Colors.pink.shade300 : Colors.orange.shade300) // EF: Pink, ET: Orange
: (isF ? Colors.purple.shade300 : Colors.blue.shade300); // IF: Purple, IT: Blue
final Color bottomColor = theme.scaffoldBackgroundColor;
return Card(
elevation: 8,
margin: const EdgeInsets.all(16),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [topColor.withValues(alpha: 0.3), bottomColor],
),
),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header: Code
Text(
type.code,
style: theme.textTheme.headlineLarge?.copyWith(
fontWeight: FontWeight.bold,
letterSpacing: 2.0,
color: theme.colorScheme.primary,
),
),
const SizedBox(height: 8),
// Title
Text(
type.title,
style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
// Icon / Avatar Placeholder
CircleAvatar(
radius: 48,
backgroundColor: theme.colorScheme.primaryContainer,
child: Icon(
_getIconForType(type.code),
size: 48,
color: theme.colorScheme.onPrimaryContainer,
),
),
const SizedBox(height: 24),
// Catchphrase
Text(
"\"${type.catchphrase}\"",
style: theme.textTheme.bodyLarge?.copyWith(
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
// Description
Text(
type.description,
style: theme.textTheme.bodyMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 16),
// Recommended Styles
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(LucideIcons.wine, size: 16, color: theme.colorScheme.primary),
const SizedBox(width: 8),
Text("おすすめスタイル", style: theme.textTheme.labelLarge),
],
),
const SizedBox(height: 4),
Text(
type.recommendedStyles,
style: theme.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
],
),
if (result.isInsufficient) ...[
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: theme.colorScheme.errorContainer,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(LucideIcons.alertTriangle, size: 16, color: theme.colorScheme.error),
const SizedBox(width: 8),
Flexible(
child: Text(
"データ不足により精度が低いです (現在: ${result.sampleSize}件)",
style: theme.textTheme.bodySmall?.copyWith(color: theme.colorScheme.onErrorContainer),
),
),
],
),
),
],
const SizedBox(height: 32),
// Actions
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
OutlinedButton.icon(
onPressed: onShare,
icon: const Icon(LucideIcons.share2, size: 18),
label: const Text("シェア"),
),
// Only show Recommendation button if sufficient data or strictly required?
// Always show for fun.
FilledButton.icon(
onPressed: onShowRecommendations,
icon: const Icon(LucideIcons.save, size: 18),
label: const Text("保存"),
),
],
),
],
),
),
),
);
}
IconData _getIconForType(String code) {
if (code.startsWith('E')) {
if (code.contains('F')) return LucideIcons.partyPopper; // Party
return LucideIcons.users; // Social
} else {
if (code.contains('T')) return LucideIcons.microscope; // Lab/Logic
return LucideIcons.bookOpen; // Quiet/Read
}
}
}