flutter_sudoku/lib/screens/home_screen.dart
2025-11-07 17:07:22 +09:00

176 lines
6.8 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/widgets/ad_banner_widget.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// 난이도
double _difficultyLevel = 2.0;
final List<String> levelLabels = ["Easy", "Normal", "Medium", "Hard", "Expert"];
// 그리드 크기
double _blockSize = 3.0;
// 🔽 [수정] 16x16, 25x25 옵션 제거
final List<String> sizeLabels = ["4x4", "9x9"];
// 테마 이름
late String _selectedThemeName;
bool isLoading = false;
final PuzzleService _puzzleService = PuzzleService();
@override
void initState() {
super.initState();
// 기본 테마를 '랜덤' 이름으로 설정
_selectedThemeName = AppThemes.random;
}
Future<void> _startGame() async {
setState(() { isLoading = true; });
try {
final String level = _difficultyLevel.round().toString();
final String blockSize = _blockSize.round().toString();
final SudokuGameDto gameData = await _puzzleService.startGame(level, blockSize);
// 선택된 '테마 이름(String)'을 그대로 전달
if (mounted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GameScreen(
gameData: gameData,
themeName: _selectedThemeName,
),
),
);
}
} 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) {
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. 난이도 선택
const Text("난이도", style: TextStyle(fontSize: 18)),
Slider(
value: _difficultyLevel,
min: 1.0, max: 5.0, divisions: 4,
label: levelLabels[_difficultyLevel.round() - 1],
onChanged: (newValue) => setState(() { _difficultyLevel = newValue; }),
),
const SizedBox(height: 20),
// 2. 그리드 크기 선택
const Text("그리드 크기", style: TextStyle(fontSize: 18)),
Text(
// 🔽 [수정] 인덱스 매핑 변경 (2.0 -> index 0)
sizeLabels[_blockSize.round() - 2],
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.deepOrange),
),
Slider(
value: _blockSize,
// 🔽 [수정] 최대값을 3.0으로, divisions를 1로 변경
min: 2.0, max: 3.0, divisions: 1,
label: sizeLabels[_blockSize.round() - 2],
activeColor: Colors.deepOrange,
onChanged: (newValue) => setState(() { _blockSize = newValue; }),
),
const SizedBox(height: 20),
// 3. 테마 선택 (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: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const RankingScreen()),
);
},
child: const Text('랭킹 보기'),
),
],
),
),
),
),
const AdBannerWidget(),
],
),
),
);
},
),
);
}
}