2026-01-29 15:54:22 +00:00
|
|
|
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,
|
2026-02-15 15:13:12 +00:00
|
|
|
icon: const Icon(LucideIcons.save, size: 18),
|
|
|
|
|
label: const Text("保存"),
|
2026-01-29 15:54:22 +00:00
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|