playWith/apps/app/lib/screens/settings_screen.dart
2025-11-25 16:34:13 +09:00

187 lines
7.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:playwith_core/playwith_core.dart'; // AvatarWidget 포함됨
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
final _nickController = TextEditingController();
final _settings = SettingsNotifier();
@override
void initState() {
super.initState();
_nickController.text = _settings.nickname;
}
@override
void dispose() {
_nickController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("설정")),
body: ListenableBuilder(
listenable: _settings,
builder: (context, _) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
// 1. 프로필 설정 섹션
_buildSectionTitle("프로필 설정"),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// 아바타 변경 영역
GestureDetector(
onTap: () => _settings.pickProfileImage(),
child: Stack(
alignment: Alignment.bottomRight,
children: [
AvatarWidget(
base64Image: _settings.profileImageBase64,
colorValue: Colors.primaries[_settings.avatarIndex % Colors.primaries.length].value,
nickname: _nickController.text,
size: 100,
),
Container(
padding: const EdgeInsets.all(6),
decoration: const BoxDecoration(color: Colors.blue, shape: BoxShape.circle),
child: const Icon(Icons.edit, size: 16, color: Colors.white),
),
],
),
),
if (_settings.profileImageBase64 != null)
TextButton(
onPressed: () => _settings.clearProfileImage(),
child: const Text("이미지 삭제 (기본값 사용)", style: TextStyle(color: Colors.red)),
),
const SizedBox(height: 20),
// 닉네임 입력
TextField(
controller: _nickController,
decoration: const InputDecoration(
labelText: "닉네임",
border: OutlineInputBorder(),
helperText: "게임에서 사용할 이름을 입력하세요.",
),
onChanged: (val) => _settings.setProfile(val, _settings.avatarIndex),
),
const SizedBox(height: 10),
// 기본 아바타 색상 선택 (이미지 없을 때 사용)
const Align(alignment: Alignment.centerLeft, child: Text("기본 배경색")),
const SizedBox(height: 5),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(Colors.primaries.length, (index) {
final isSelected = _settings.avatarIndex == index;
return GestureDetector(
onTap: () => _settings.setProfile(_nickController.text, index),
child: Container(
margin: const EdgeInsets.only(right: 8),
width: 30,
height: 30,
decoration: BoxDecoration(
color: Colors.primaries[index],
shape: BoxShape.circle,
border: isSelected ? Border.all(color: Colors.black, width: 2) : null,
),
child: isSelected ? const Icon(Icons.check, size: 16, color: Colors.white) : null,
),
);
}),
),
),
],
),
),
),
const SizedBox(height: 20),
// 2. 디스플레이 설정 섹션
_buildSectionTitle("화면 설정"),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SwitchListTile(
title: const Text("다크 모드"),
value: _settings.isDarkMode,
onChanged: (val) => _settings.toggleDarkMode(val),
),
const Divider(),
const Text("글자 크기", style: TextStyle(fontWeight: FontWeight.bold)),
Slider(
value: _settings.fontScale,
min: 0.8,
max: 1.5,
divisions: 7,
label: "${(_settings.fontScale * 100).toInt()}%",
onChanged: (val) => _settings.setFontScale(val),
),
Text(
"이 크기로 보입니다.",
style: TextStyle(fontSize: 16 * _settings.fontScale),
),
const Divider(),
const Text("테마 색상", style: TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Wrap(
spacing: 10,
runSpacing: 10,
children: appColors.entries.map((entry) {
final isSelected = _settings.themeColorName == entry.key;
return GestureDetector(
onTap: () => _settings.setThemeColor(entry.key),
child: Container(
width: 40, height: 40,
decoration: BoxDecoration(
color: entry.value,
shape: BoxShape.circle,
border: isSelected ? Border.all(color: Colors.black, width: 3) : null,
boxShadow: [if(isSelected) const BoxShadow(blurRadius: 5, color: Colors.black26)],
),
child: isSelected ? const Icon(Icons.check, color: Colors.white) : null,
),
);
}).toList(),
),
],
),
),
),
],
);
},
),
);
}
Widget _buildSectionTitle(String title) {
return Padding(
padding: const EdgeInsets.only(left: 8, bottom: 8),
child: Text(title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.grey)),
);
}
}