167 lines
5.5 KiB
Dart
167 lines
5.5 KiB
Dart
|
|
import 'dart:io';
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:permission_handler/permission_handler.dart';
|
||
|
|
import 'package:playwith_core/playwith_core.dart';
|
||
|
|
import 'lobby_screen.dart';
|
||
|
|
import 'screens/settings_screen.dart';
|
||
|
|
|
||
|
|
class LoginScreen extends StatefulWidget {
|
||
|
|
const LoginScreen({super.key});
|
||
|
|
|
||
|
|
@override
|
||
|
|
State<LoginScreen> createState() => _LoginScreenState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _LoginScreenState extends State<LoginScreen> {
|
||
|
|
final _nicknameController = TextEditingController();
|
||
|
|
final _settings = SettingsNotifier();
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
// 저장된 닉네임 반영
|
||
|
|
Future.delayed(const Duration(milliseconds: 100), () {
|
||
|
|
if (mounted && _settings.nickname.isNotEmpty) {
|
||
|
|
setState(() {
|
||
|
|
_nicknameController.text = _settings.nickname;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
_settings.addListener(_syncSettings);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void dispose() {
|
||
|
|
_settings.removeListener(_syncSettings);
|
||
|
|
_nicknameController.dispose();
|
||
|
|
super.dispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
void _syncSettings() {
|
||
|
|
if (_nicknameController.text != _settings.nickname) {
|
||
|
|
if (mounted) {
|
||
|
|
setState(() {
|
||
|
|
_nicknameController.text = _settings.nickname;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (mounted) setState(() {});
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> _enterLobby() async {
|
||
|
|
final inputNick = _nicknameController.text.trim();
|
||
|
|
if (inputNick.isEmpty) {
|
||
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("닉네임을 입력해주세요.")));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 안드로이드 권한 체크
|
||
|
|
if (Platform.isAndroid) {
|
||
|
|
Map<Permission, PermissionStatus> statuses = await [
|
||
|
|
Permission.location,
|
||
|
|
Permission.nearbyWifiDevices,
|
||
|
|
].request();
|
||
|
|
|
||
|
|
bool isNearby = statuses[Permission.nearbyWifiDevices]?.isGranted ?? false;
|
||
|
|
bool isLocation = statuses[Permission.location]?.isGranted ?? false;
|
||
|
|
if (!isNearby && !isLocation) {
|
||
|
|
if (!mounted) return;
|
||
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("⚠️ 권한 허용이 필요합니다.")));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 변경 사항 저장
|
||
|
|
if (inputNick != _settings.nickname) {
|
||
|
|
await _settings.setProfile(inputNick, _settings.avatarIndex);
|
||
|
|
}
|
||
|
|
|
||
|
|
// [수정] 초기화 시 닉네임과 이미지를 함께 전달
|
||
|
|
NetworkManager().initialize(
|
||
|
|
nickname: _settings.nickname,
|
||
|
|
profileImage: _settings.profileImageBase64, // [추가]
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!mounted) return;
|
||
|
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const LobbyScreen()));
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
return Scaffold(
|
||
|
|
appBar: AppBar(
|
||
|
|
backgroundColor: Colors.transparent,
|
||
|
|
elevation: 0,
|
||
|
|
actions: [
|
||
|
|
IconButton(
|
||
|
|
icon: const Icon(Icons.settings, color: Colors.grey),
|
||
|
|
tooltip: "설정",
|
||
|
|
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const SettingsScreen())),
|
||
|
|
)
|
||
|
|
],
|
||
|
|
),
|
||
|
|
body: Center(
|
||
|
|
child: SingleChildScrollView(
|
||
|
|
padding: const EdgeInsets.all(32.0),
|
||
|
|
child: Column(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
children: [
|
||
|
|
const Text('PlayWith', style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)),
|
||
|
|
const SizedBox(height: 40),
|
||
|
|
|
||
|
|
// [핵심] AvatarWidget 사용 (Core 컴포넌트)
|
||
|
|
ListenableBuilder(
|
||
|
|
listenable: _settings,
|
||
|
|
builder: (context, _) {
|
||
|
|
return GestureDetector(
|
||
|
|
onTap: () => _settings.pickProfileImage(),
|
||
|
|
child: Stack(
|
||
|
|
children: [
|
||
|
|
AvatarWidget(
|
||
|
|
base64Image: _settings.profileImageBase64,
|
||
|
|
colorValue: Colors.primaries[_settings.avatarIndex % Colors.primaries.length].value,
|
||
|
|
nickname: _nicknameController.text,
|
||
|
|
size: 120,
|
||
|
|
),
|
||
|
|
Positioned(
|
||
|
|
right: 0, bottom: 0,
|
||
|
|
child: Container(
|
||
|
|
padding: const EdgeInsets.all(8),
|
||
|
|
decoration: const BoxDecoration(color: Colors.blue, shape: BoxShape.circle),
|
||
|
|
child: const Icon(Icons.camera_alt, size: 20, color: Colors.white),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
},
|
||
|
|
),
|
||
|
|
|
||
|
|
const SizedBox(height: 30),
|
||
|
|
|
||
|
|
TextField(
|
||
|
|
controller: _nicknameController,
|
||
|
|
textAlign: TextAlign.center,
|
||
|
|
decoration: const InputDecoration(
|
||
|
|
labelText: '닉네임',
|
||
|
|
border: OutlineInputBorder(),
|
||
|
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
|
||
|
|
const SizedBox(height: 30),
|
||
|
|
|
||
|
|
ElevatedButton(
|
||
|
|
onPressed: _enterLobby,
|
||
|
|
style: ElevatedButton.styleFrom(
|
||
|
|
minimumSize: const Size(double.infinity, 50),
|
||
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||
|
|
),
|
||
|
|
child: const Text('입장하기', style: TextStyle(fontSize: 18)),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|