games/packages/feature_common/lib/screens/settings_screen.dart

264 lines
9.1 KiB
Dart
Raw Normal View History

2025-11-14 18:03:50 +09:00
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:service_api/service_api.dart';
import 'package:url_launcher/url_launcher.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
Future<void> _launchHomepage() async {
final Uri url = Uri.parse('https://lunaticbum.kr');
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
debugPrint('Could not launch $url');
}
}
2025-12-15 18:18:17 +09:00
// 🔽 [신규] 기록 삭제 확인 다이얼로그
Future<void> _confirmClearHistory(BuildContext context) async {
final bool? confirmed = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('진단 기록 삭제'),
content: const Text('저장된 모든 두뇌 진단 기록을 삭제하시겠습니까?\n삭제된 데이터는 복구할 수 없습니다.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('취소'),
),
TextButton(
onPressed: () => Navigator.pop(ctx, true),
style: TextButton.styleFrom(foregroundColor: Colors.red),
child: const Text('삭제'),
),
],
),
);
if (confirmed == true && context.mounted) {
final identityService = context.read<IdentityService>();
await identityService.clearAssessmentHistory();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('진단 기록이 삭제되었습니다.')),
);
}
}
}
2025-11-14 18:03:50 +09:00
@override
Widget build(BuildContext context) {
final themeNotifier = context.watch<ThemeNotifier>();
final sessionNotifier = context.watch<SessionNotifier>();
return Scaffold(
2025-12-15 18:18:17 +09:00
appBar: AppBar(title: const Text('설정')),
2025-11-14 18:03:50 +09:00
body: ListView(
children: [
ListTile(
leading: Icon(
sessionNotifier.isGuest
? Icons.person_outline
: Icons.person_rounded
),
title: Text(
sessionNotifier.isLoading
? '계정 정보 로딩 중...'
: (sessionNotifier.isGuest
? '게스트 계정'
: sessionNotifier.session?.userName ?? '로그인됨')
),
subtitle: Text(
sessionNotifier.isLoading
? ''
: (sessionNotifier.isGuest
? '진행 상황을 저장하려면 로그인하세요.'
: (sessionNotifier.session?.email ?? '소셜 계정'))
),
),
if (!sessionNotifier.isLoading)
if (sessionNotifier.isGuest)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [
Expanded(
child: OutlinedButton.icon(
2025-12-15 18:18:17 +09:00
icon: const Icon(Icons.g_mobiledata),
2025-11-14 18:03:50 +09:00
label: const Text('Google 로그인'),
onPressed: () {
sessionNotifier.login('google');
},
),
),
const SizedBox(width: 10),
Expanded(
child: OutlinedButton.icon(
icon: const Icon(Icons.apple),
label: const Text('Apple 로그인'),
onPressed: () {
sessionNotifier.login('apple');
},
),
),
],
),
)
else
ListTile(
title: const Text('로그아웃', style: TextStyle(color: Colors.red)),
leading: const Icon(Icons.logout, color: Colors.red),
onTap: () {
sessionNotifier.logout();
},
),
const Divider(),
SwitchListTile(
title: const Text('다크 모드'),
secondary: const Icon(Icons.dark_mode_outlined),
value: themeNotifier.isDarkMode,
onChanged: (newValue) {
themeNotifier.toggleTheme(newValue);
},
),
2025-12-15 18:18:17 +09:00
// 🔽 [신규] 글자 크기 조절 섹션
ListTile(
title: const Text('글자 크기'),
subtitle: Text(_getScaleLabel(themeNotifier.textScaleFactor)),
leading: const Icon(Icons.format_size),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
children: [
Slider(
value: themeNotifier.textScaleFactor,
min: 0.85,
max: 1.5,
divisions: 4,
label: _getScaleLabel(themeNotifier.textScaleFactor),
onChanged: (value) {
themeNotifier.setTextScale(value);
},
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text("작게", style: TextStyle(fontSize: 12)),
Text("표준", style: TextStyle(fontSize: 12)),
Text("크게", style: TextStyle(fontSize: 12)),
Text("더 크게", style: TextStyle(fontSize: 12)),
Text("완전 크게", style: TextStyle(fontSize: 12)),
],
),
const SizedBox(height: 16),
],
),
),
const Divider(),
// 🔽 [신규] 데이터 관리 섹션
const Padding(
padding: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0),
child: Text(
'데이터 관리',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
ListTile(
leading: const Icon(Icons.delete_outline, color: Colors.red),
title: const Text('진단 기록 삭제', style: TextStyle(color: Colors.red)),
subtitle: const Text('저장된 두뇌 건강 진단 기록을 모두 지웁니다.'),
onTap: () => _confirmClearHistory(context),
),
2025-11-14 18:03:50 +09:00
const Divider(),
const Padding(
padding: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0),
child: Text(
'앱 테마 색상',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
...appColors.entries.map((entry) {
final String colorName = entry.key;
final MaterialColor color = entry.value;
return ListTile(
leading: CircleAvatar(
backgroundColor: color,
),
title: Text(colorName),
trailing: (themeNotifier.currentColor == color)
? Icon(Icons.check, color: Theme.of(context).colorScheme.secondary)
: null,
onTap: () {
themeNotifier.setTheme(colorName);
},
);
}),
const Divider(),
ListTile(
leading: const Icon(Icons.description_outlined),
title: const Text('오픈소스 라이선스'),
onTap: () {
showLicensePage(
context: context,
applicationName: '스도쿠 게임',
applicationVersion: '1.0.0',
applicationIcon: const Icon(Icons.apps_rounded, size: 64),
);
},
),
ListTile(
leading: const Icon(Icons.info_outline),
title: const Text('앱 정보'),
onTap: () {
showAboutDialog(
context: context,
applicationName: '스도쿠 게임',
applicationVersion: '1.0.0',
applicationIcon: const Icon(Icons.apps_rounded, size: 48),
children: [
const SizedBox(height: 16),
InkWell(
onTap: _launchHomepage,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'© 2025 lunaticbum',
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
decoration: TextDecoration.underline,
),
),
),
),
],
);
},
),
],
),
);
}
2025-12-15 18:18:17 +09:00
String _getScaleLabel(double scale) {
if (scale <= 0.9) return "작게";
if (scale <= 1.05) return "표준";
if (scale <= 1.2) return "크게";
if (scale <= 1.3) return "더 크게";
return "완전 크게";
}
2025-11-14 18:03:50 +09:00
}