import 'package:flutter/material.dart'; import 'package:sudoku_app/models/game_level.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'; import 'package:sudoku_app/widgets/ad_banner_widget.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { // '์ตœ๋Œ€ ์ž ๊ธˆ ํ•ด์ œ ๋ ˆ๋ฒจ' ์ƒํƒœ int _maxUnlockedLevel = 1; late String _selectedThemeName; bool _isLoading = false; final PuzzleService _puzzleService = PuzzleService(); final IdentityService _identityService = IdentityService(); @override void initState() { super.initState(); _selectedThemeName = AppThemes.random; _loadProgress(); // ๐Ÿ‘ˆ ์ €์žฅ๋œ ์ง„ํ–‰ ์ƒํ™ฉ ๋กœ๋“œ } // ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ํด๋ฆฌ์–ด ๋ ˆ๋ฒจ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ Future _loadProgress() async { final maxLevel = await _identityService.getMaxUnlockedLevel(); if (mounted) { setState(() { _maxUnlockedLevel = maxLevel; }); } } // ๊ฒŒ์ž„ ์‹œ์ž‘ ๋กœ์ง Future _startGame(GameLevel level) async { setState(() { _isLoading = true; }); try { // 1. ์„ ํƒํ•œ ๋ ˆ๋ฒจ์˜ '์ธ๋ฑ์Šค'(1-11)๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ „๋‹ฌ final String difficulty = level.levelIndex.toString(); final SudokuGameDto gameData = await _puzzleService.startGame(difficulty); final String userId = await _identityService.getOrCreateUserId(); final String? userName = await _identityService.getSavedUserName(); if (mounted) { // 2. GameScreen์œผ๋กœ ์ด๋™ (๊ฒŒ์ž„ ํด๋ฆฌ์–ด ํ›„ ๋Œ์•„์˜ค๋ฉด _loadProgress() ํ˜ธ์ถœ) await Navigator.push( context, MaterialPageRoute( builder: (context) => GameScreen( gameData: gameData, themeName: _selectedThemeName, // ๐Ÿ‘ˆ '๋žœ๋ค' ๋˜๋Š” '๊ณผ์ผ' ๋“ฑ userId: userId, userName: userName, levelIndex: level.levelIndex, // ๐Ÿ‘ˆ 1~11 ), ), ); // 3. GameScreen์—์„œ ๋Œ์•„์™”์„ ๋•Œ, ์ง„ํ–‰ ์ƒํ™ฉ(ํด๋ฆฌ์–ด)์„ ๋‹ค์‹œ ๋กœ๋“œ _loadProgress(); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('๊ฒŒ์ž„ ๋กœ๋”ฉ ์‹คํŒจ: $e')), ); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } @override Widget build(BuildContext context) { // 99 = ๋ชจ๋“  ๋ ˆ๋ฒจ ํด๋ฆฌ์–ด final bool allLevelsUnlocked = _maxUnlockedLevel >= 99; return Scaffold( appBar: AppBar(title: const Text('์Šค๋„์ฟ  ๊ฒŒ์ž„')), body: LayoutBuilder( builder: (context, constraints) { const double maxContentRatio = 0.6; // ๐Ÿ”ฝ [์ˆ˜์ •] ํƒœ๋ธ”๋ฆฟ ๋“ฑ์—์„œ ๋„ˆ๋ฌด ์ปค์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ (์ตœ๋Œ€ 500px) final double constrainedWidth = (constraints.maxHeight * maxContentRatio) > 500 ? 500 : (constraints.maxHeight * maxContentRatio); return Center( child: ConstrainedBox( constraints: BoxConstraints(maxWidth: constrainedWidth), child: Column( children: [ // 1. ํ…Œ๋งˆ ์„ ํƒ Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("ํ…Œ๋งˆ: ", style: TextStyle(fontSize: 18)), DropdownButton( value: _selectedThemeName, items: AppThemes.selectableThemeNames.map((themeName) { return DropdownMenuItem( value: themeName, child: Text(themeName, style: const TextStyle(fontSize: 20)), ); }).toList(), onChanged: (themeName) { if (themeName != null) { setState(() { _selectedThemeName = themeName; }); } }, ), ], ), ), // 2. ๐Ÿ”ฝ [์ˆ˜์ •] ๋ ˆ๋ฒจ ์„ ํƒ ๋ฆฌ์ŠคํŠธ (Slider ๋Œ€์ฒด) Expanded( child: ListView.builder( itemCount: AppLevels.allLevels.length, itemBuilder: (context, index) { final GameLevel level = AppLevels.allLevels[index]; // 3. ์ž ๊ธˆ ํ•ด์ œ ๋กœ์ง final bool isUnlocked = allLevelsUnlocked || level.levelIndex <= _maxUnlockedLevel; return Card( margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), child: ListTile( leading: Icon( isUnlocked ? Icons.lock_open_rounded : Icons.lock_rounded, color: isUnlocked ? Colors.blue : Colors.grey, ), title: Text(level.name, style: TextStyle( fontSize: 18, fontWeight: isUnlocked ? FontWeight.bold : FontWeight.normal, color: isUnlocked ? Colors.black : Colors.grey, )), trailing: isUnlocked ? const Icon(Icons.play_arrow_rounded) : null, onTap: isUnlocked && !_isLoading ? () => _startGame(level) : null, // ์ž ๊ฒผ๊ฑฐ๋‚˜ ๋กœ๋”ฉ ์ค‘์ด๋ฉด ํƒญ ๋น„ํ™œ์„ฑํ™” ), ); }, ), ), // 3. ๋žญํ‚น ๋ณด๊ธฐ ๋ฒ„ํŠผ TextButton( onPressed: () { // ํ˜„์žฌ ์ตœ๊ณ  ๋ ˆ๋ฒจ์„ ๋žญํ‚น ํ™”๋ฉด์˜ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ „๋‹ฌ final String currentDifficultyName = AppLevels.getLevel(_maxUnlockedLevel).name; Navigator.push( context, MaterialPageRoute( builder: (context) => RankingScreen( initialDifficultyName: currentDifficultyName, ), ), ); }, child: const Text('์ „์ฒด ๋žญํ‚น ๋ณด๊ธฐ'), ), ], ), ), ); }, ), bottomNavigationBar: const AdBannerWidget(), // ๐Ÿ‘ˆ [์ˆ˜์ •] body -> bottomNavigationBar ); } }