175 lines
7.0 KiB
Dart
175 lines
7.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:sudoku_app/models/sudoku_game_dto.dart';
|
|
import 'package:sudoku_app/models/sudoku_theme.dart';
|
|
import 'package:sudoku_app/screens/game_screen.dart';
|
|
import 'package:sudoku_app/screens/ranking_screen.dart';
|
|
import 'package:sudoku_app/services/puzzle_service.dart';
|
|
import 'package:sudoku_app/services/identity_service.dart'; // 👈 ID 서비스 임포트
|
|
import 'package:sudoku_app/widgets/ad_banner_widget.dart';
|
|
|
|
class HomeScreen extends StatefulWidget {
|
|
const HomeScreen({super.key});
|
|
|
|
@override
|
|
State<HomeScreen> createState() => _HomeScreenState();
|
|
}
|
|
|
|
class _HomeScreenState extends State<HomeScreen> {
|
|
// 8단계 난이도
|
|
double _difficultyLevel = 4.0; // 1.0 ~ 8.0 (기본값 Level 4: 중급 9x9)
|
|
final List<String> levelLabels = [
|
|
"입문 (4x4)", "초급 (4x4)",
|
|
"쉬움 (9x9)", "중급 (9x9)", "어려움 (9x9)",
|
|
"전문가 (16x16)", "마스터 (16x16)", "지옥 (16x16)"
|
|
];
|
|
|
|
late String _selectedThemeName;
|
|
bool isLoading = false;
|
|
final PuzzleService _puzzleService = PuzzleService();
|
|
final IdentityService _identityService = IdentityService(); // 👈 ID 서비스 초기화
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_selectedThemeName = AppThemes.random; // 기본 테마 '랜덤'
|
|
}
|
|
|
|
Future<void> _startGame() async {
|
|
setState(() { isLoading = true; });
|
|
|
|
try {
|
|
// 1. 난이도 값(String) 전달
|
|
final String difficulty = _difficultyLevel.round().toString();
|
|
|
|
// 2. 서버에서 게임 데이터 가져오기
|
|
final SudokuGameDto gameData = await _puzzleService.startGame(difficulty);
|
|
|
|
// 3. 로컬에서 앱-고유 ID와 저장된 이름 가져오기
|
|
final String userId = await _identityService.getOrCreateUserId();
|
|
final String? userName = await _identityService.getSavedUserName();
|
|
|
|
if (mounted) {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => GameScreen(
|
|
gameData: gameData,
|
|
themeName: _selectedThemeName,
|
|
userId: userId, // 👈 ID 전달
|
|
userName: userName, // 👈 이름 전달
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} catch (e) {
|
|
if (mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text('게임 로딩 실패: $e')),
|
|
);
|
|
}
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() { isLoading = false; });
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('스도쿠 게임')),
|
|
body: LayoutBuilder( // 비율 기반 레이아웃
|
|
builder: (context, constraints) {
|
|
// 너비/높이 비율 변수 (0.6 = 너비가 높이의 60%를 넘지 않도록 함)
|
|
const double maxContentRatio = 0.6;
|
|
final double constrainedWidth = constraints.maxHeight * maxContentRatio;
|
|
|
|
return Center(
|
|
child: ConstrainedBox(
|
|
constraints: BoxConstraints(maxWidth: constrainedWidth),
|
|
child: Column(
|
|
children: [
|
|
Expanded(
|
|
child: Center(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
// 1. 난이도 선택 (8단계)
|
|
const Text("난이도", style: TextStyle(fontSize: 18)),
|
|
Text(
|
|
levelLabels[_difficultyLevel.round() - 1],
|
|
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.blue),
|
|
),
|
|
Slider(
|
|
value: _difficultyLevel,
|
|
min: 1.0, max: 8.0, divisions: 7, // 8단계
|
|
label: levelLabels[_difficultyLevel.round() - 1],
|
|
onChanged: (newValue) => setState(() { _difficultyLevel = newValue; }),
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// 2. 테마 선택 (String 기반)
|
|
const Text("테마", style: TextStyle(fontSize: 18)),
|
|
DropdownButton<String>(
|
|
value: _selectedThemeName,
|
|
items: AppThemes.selectableThemeNames.map((themeName) {
|
|
return DropdownMenuItem<String>(
|
|
value: themeName,
|
|
child: Text(themeName, style: const TextStyle(fontSize: 20)),
|
|
);
|
|
}).toList(),
|
|
onChanged: (themeName) {
|
|
if (themeName != null) {
|
|
setState(() { _selectedThemeName = themeName; });
|
|
}
|
|
},
|
|
),
|
|
|
|
const SizedBox(height: 30),
|
|
|
|
if (isLoading)
|
|
const CircularProgressIndicator()
|
|
else
|
|
ElevatedButton(
|
|
onPressed: _startGame,
|
|
style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15)),
|
|
child: const Text('게임 시작', style: TextStyle(fontSize: 18)),
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
// "랭킹 보기" 버튼
|
|
TextButton(
|
|
onPressed: () {
|
|
// 현재 슬라이더의 난이도 이름(String)을 가져옴
|
|
final String currentDifficultyName = levelLabels[_difficultyLevel.round() - 1];
|
|
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => RankingScreen(
|
|
initialDifficultyName: currentDifficultyName,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
child: const Text('랭킹 보기'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const AdBannerWidget(),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
} |