import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lucide_icons/lucide_icons.dart'; import 'package:intl/intl.dart'; import '../providers/theme_provider.dart'; import '../widgets/settings/app_settings_section.dart'; import '../widgets/settings/other_settings_section.dart'; import '../widgets/settings/backup_settings_section.dart'; import '../widgets/gamification/level_title_card.dart'; import '../widgets/gamification/activity_stats.dart'; import '../widgets/gamification/badge_case.dart'; class SoulScreen extends ConsumerStatefulWidget { const SoulScreen({super.key}); @override ConsumerState createState() => _SoulScreenState(); } class _SoulScreenState extends ConsumerState { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { final userProfile = ref.watch(userProfileProvider); return Scaffold( appBar: AppBar( title: const Text('マイページ'), centerTitle: true, ), body: ListView( padding: const EdgeInsets.all(16), children: [ // Gamification Section (v1.3) const LevelTitleCard(), const SizedBox(height: 16), const ActivityStats(), const SizedBox(height: 16), const BadgeCase(), const SizedBox(height: 32), // Identity Section _buildSectionHeader('プロフィール (ID)', LucideIcons.fingerprint), Card( child: Column( children: [ ListTile( leading: Icon(LucideIcons.user, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[400] : null), title: const Text('ニックネーム'), subtitle: Text(userProfile.nickname ?? '未設定'), trailing: Icon(LucideIcons.chevronRight, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[600] : null), onTap: () => _showNicknameDialog(context, userProfile.nickname), ), const Divider(height: 1), ListTile( leading: Icon(LucideIcons.personStanding, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[400] : null), title: const Text('性別'), subtitle: Text(_getGenderLabel(userProfile.gender)), trailing: Icon(LucideIcons.chevronRight, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[600] : null), onTap: () => _showGenderDialog(context, userProfile.gender), ), const Divider(height: 1), ListTile( leading: Icon(LucideIcons.calendar, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[400] : null), title: const Text('生年月日'), subtitle: Text(userProfile.birthdate != null ? DateFormat('yyyy/MM/dd').format(userProfile.birthdate!) : '未設定 (四柱推命用)'), trailing: Icon(LucideIcons.chevronRight, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[600] : null), onTap: () => _pickBirthDate(context, userProfile.birthdate), ), const Divider(height: 1), ListTile( leading: Icon(LucideIcons.brainCircuit, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[400] : null), title: const Text('MBTI診断'), subtitle: Text(userProfile.mbti ?? '未設定'), trailing: Icon(LucideIcons.chevronRight, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[600] : null), onTap: () => _showMbtiDialog(context, userProfile.mbti), ), const Divider(height: 1), ], ), ), const SizedBox(height: 24), // App Settings const AppearanceSettingsSection(), const SizedBox(height: 24), // other Settings const OtherSettingsSection( title: 'データ・その他', ), const SizedBox(height: 24), BackupSettingsSection(), // Roadmap Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primaryContainer.withValues(alpha: 0.1), // Lighter background borderRadius: BorderRadius.circular(12), border: Border.all( color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.2), ), ), child: Row( children: [ Icon(LucideIcons.heartHandshake, color: Theme.of(context).colorScheme.onSurface), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Future Update', style: Theme.of(context).textTheme.labelSmall?.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface, ), ), const SizedBox(height: 4), const Text('カップル共有機能 (開発中)'), ], ), ), ], ), ), const SizedBox(height: 40), ], ), ); } Widget _buildSectionHeader(String title, IconData icon) { final isDark = Theme.of(context).brightness == Brightness.dark; return Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), child: Row( children: [ Icon(icon, size: 20, color: isDark ? Colors.orange[300] : Theme.of(context).primaryColor), const SizedBox(width: 8), Text( title, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, color: isDark ? Colors.grey[300] : Theme.of(context).primaryColor, ), ), ], ), ); } void _showMbtiDialog(BuildContext context, String? current) { const typesWithLabels = { 'INTJ': '建築家', 'INTP': '論理学者', 'ENTJ': '指揮官', 'ENTP': '討論者', 'INFJ': '提唱者', 'INFP': '仲介者', 'ENFJ': '主人公', 'ENFP': '広報運動家', 'ISTJ': '管理者', 'ISFJ': '擁護者', 'ESTJ': '幹部', 'ESFJ': '領事官', 'ISTP': '巨匠', 'ISFP': '冒険家', 'ESTP': '起業家', 'ESFP': 'エンターテイナー', }; showDialog( context: context, builder: (context) => SimpleDialog( title: const Text('MBTI タイプ選択'), children: [ SizedBox( width: double.maxFinite, height: 400, child: ListView( children: typesWithLabels.entries.map((entry) => SimpleDialogOption( onPressed: () { ref.read(userProfileProvider.notifier).setIdentity(mbti: entry.key); Navigator.pop(context); }, child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ Icon( entry.key == current ? Icons.check : Icons.circle_outlined, size: 20, color: entry.key == current ? Theme.of(context).primaryColor : Colors.grey[400], ), const SizedBox(width: 16), Expanded( child: RichText( text: TextSpan( style: DefaultTextStyle.of(context).style.copyWith(fontSize: 16), children: [ TextSpan( text: entry.key, style: const TextStyle(fontWeight: FontWeight.bold), ), TextSpan( text: ' (${entry.value})', style: TextStyle( fontSize: 14, color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[500] : Colors.grey[600], ), ), ], ), ), ), ], ), ), )).toList(), ), ), const Padding( padding: EdgeInsets.all(16.0), child: Text( '※AIによる独自の相性診断です。遊び心としてお楽しみください', style: TextStyle(fontSize: 10, color: Colors.grey), textAlign: TextAlign.center, ), ), ], ), ); } Future _pickBirthDate(BuildContext context, DateTime? current) async { final picked = await showDatePicker( context: context, initialDate: current ?? DateTime(2000), firstDate: DateTime(1900), lastDate: DateTime.now(), locale: const Locale('ja'), // Ensure Japanese locale if initialized ); if (picked != null) { ref.read(userProfileProvider.notifier).setIdentity(birthdate: picked); } } void _showNicknameDialog(BuildContext context, String? current) { final controller = TextEditingController(text: current); showDialog( context: context, builder: (context) => AlertDialog( title: const Text('ニックネーム変更'), content: TextField( controller: controller, decoration: const InputDecoration(hintText: '呼び名を入力'), autofocus: true, ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('キャンセル'), ), TextButton( onPressed: () { ref.read(userProfileProvider.notifier).setIdentity(nickname: controller.text); Navigator.pop(context); }, child: const Text('保存'), ), ], ), ); } void _showGenderDialog(BuildContext context, String? current) { showDialog( context: context, builder: (context) => SimpleDialog( title: const Text('性別を選択'), children: [ _buildGenderOption(context, 'male', '男性', current), _buildGenderOption(context, 'female', '女性', current), _buildGenderOption(context, 'other', 'その他', current), _buildGenderOption(context, '', '回答しない', current), ], ), ); } Widget _buildGenderOption(BuildContext context, String? value, String label, String? current) { return SimpleDialogOption( onPressed: () { ref.read(userProfileProvider.notifier).setIdentity(gender: value); Navigator.pop(context); }, child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ Icon( value == current ? Icons.check_circle : Icons.circle_outlined, color: value == current ? Theme.of(context).primaryColor : Colors.grey, ), const SizedBox(width: 16), Text(label), ], ), ), ); } String _getGenderLabel(String? gender) { switch (gender) { case 'male': return '男性'; case 'female': return '女性'; case 'other': return 'その他'; default: return '未設定'; } } }