176 lines
6.8 KiB
Dart
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(),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
} |