import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'services/auth_service.dart'; import 'services/club_service.dart'; import 'services/member_service.dart'; import 'services/event_service.dart'; import 'services/score_service.dart'; import 'screens/auth/login_screen.dart'; import 'screens/auth/profile_screen.dart'; import 'screens/club/dashboard_screen.dart'; import 'screens/club/members_screen.dart'; import 'screens/club/events_screen.dart'; import 'screens/club/club_settings_screen.dart'; import 'screens/score/club_statistics_screen.dart'; // 전역 네비게이터 키 (인증 오류 처리용) final GlobalKey navigatorKey = GlobalKey(); void main() async { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => AuthService()), ChangeNotifierProvider(create: (_) => ClubService()), ChangeNotifierProvider(create: (_) => MemberService()), ChangeNotifierProvider(create: (_) => EventService()), ChangeNotifierProvider(create: (_) => ScoreService()), ], child: Consumer( builder: (context, authService, _) { // 앱 시작 시 인증 서비스 초기화 Future.delayed(Duration.zero, () { if (!authService.isInitialized) { authService.initialize(); } }); return MaterialApp( navigatorKey: navigatorKey, // 인증 오류 처리를 위한 전역 네비게이터 키 title: '볼링 매니저', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, appBarTheme: const AppBarTheme( backgroundColor: Colors.blue, foregroundColor: Colors.white, ), ), // 로케일 설정 추가 localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('ko', 'KR'), Locale('en', 'US'), ], locale: const Locale('ko', 'KR'), home: authService.isAuthenticated ? const HomeScreen() : const LoginScreen(), routes: { '/login': (context) => const LoginScreen(), '/profile': (context) => const ProfileScreen(), ClubSettingsScreen.routeName: (context) => const ClubSettingsScreen(), }, ); }, ), ); } } class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { int _selectedIndex = 0; bool _isInit = false; static final List _widgetOptions = [ const DashboardScreen(), const MembersScreen(), const EventsScreen(), const ClubStatisticsScreen(), const ProfileScreen(), ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } // 클럽 선택 다이얼로그 표시 Future _showClubSelectionDialog(BuildContext context) async { final clubService = Provider.of(context, listen: false); final authService = Provider.of(context, listen: false); // 사용자의 모든 클럽 가져오기 if (clubService.clubs.isEmpty) { try { await clubService.fetchUserClubs(); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('클럽 목록을 불러오는데 실패했습니다: $e')), ); return; } } if (clubService.clubs.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('소속된 클럽이 없습니다')), ); return; } if (!context.mounted) return; // 다이얼로그 표시 showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('클럽 선택'), content: SizedBox( width: double.maxFinite, child: ListView.builder( shrinkWrap: true, itemCount: clubService.clubs.length, itemBuilder: (context, index) { final club = clubService.clubs[index]; final isSelected = clubService.currentClub?.id == club.id; return ListTile( title: Text(club.name), subtitle: Text(club.description ?? ''), trailing: isSelected ? const Icon(Icons.check, color: Colors.blue) : null, onTap: () async { Navigator.of(context).pop(); if (!isSelected) { try { // 백엔드 세션에 clubId 저장하고 클럽 정보 가져오기 await clubService.selectClub(club.id); // 관련 서비스 초기화 final memberService = Provider.of(context, listen: false); final eventService = Provider.of(context, listen: false); final scoreService = Provider.of(context, listen: false); memberService.initialize(authService.token!); eventService.initialize(authService.token!); scoreService.initialize(authService.token!); // 데이터 다시 로드 await Future.wait([ memberService.fetchClubMembers(), eventService.fetchClubEvents(), ]); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('${club.name} 클럽으로 변경되었습니다')), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('클럽 변경 중 오류가 발생했습니다: $e')), ); } } } }, ); }, ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('취소'), ), ], ); }, ); } @override void didChangeDependencies() { super.didChangeDependencies(); if (!_isInit) { _initializeServices(); _isInit = true; } } Future _initializeServices() async { try { final authService = Provider.of(context, listen: false); final clubService = Provider.of(context, listen: false); final scoreService = Provider.of(context, listen: false); if (authService.isAuthenticated && authService.token != null) { // 클럽 서비스 초기화 await clubService.initialize(authService.token!); // 클럽이 선택된 경우 점수 서비스 초기화 if (clubService.currentClub != null) { scoreService.initialize(authService.token!); } else { // 현재 선택된 클럽이 없는 경우 // 사용자의 클럽 목록 가져오기 await clubService.fetchUserClubs(); // 클럽이 하나만 있으면 자동으로 선택 if (clubService.clubs.length == 1) { try { await clubService.selectClub(clubService.clubs[0].id); scoreService.initialize(authService.token!); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('${clubService.clubs[0].name} 클럽이 자동으로 선택되었습니다')), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('클럽 자동 선택 중 오류가 발생했습니다: $e')), ); } } } else if (clubService.clubs.isNotEmpty) { // 클럽이 여러 개 있으면 선택 다이얼로그 표시 Future.delayed(Duration.zero, () { if (context.mounted) { _showClubSelectionDialog(context); } }); } else { // 클럽이 없는 경우 메시지 표시 if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('소속된 클럽이 없습니다. 클럽을 생성하거나 초대를 요청하세요.')), ); } } } } } catch (e) { // 오류 처리 if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('서비스 초기화 중 오류가 발생했습니다: $e')), ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Consumer( builder: (context, clubService, child) { return InkWell( onTap: () => _showClubSelectionDialog(context), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text( clubService.currentClub?.name ?? '볼링 매니저', style: const TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(width: 4), const Icon(Icons.arrow_drop_down, size: 20), ], ), ); }, ), actions: [ IconButton( icon: const Icon(Icons.notifications), onPressed: () { // 알림 기능 (추후 구현) ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('알림 기능은 아직 개발 중입니다')), ); }, ), ], ), body: _widgetOptions.elementAt(_selectedIndex), bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, items: const [ BottomNavigationBarItem( icon: Icon(Icons.dashboard), label: '대시보드', ), BottomNavigationBarItem( icon: Icon(Icons.people), label: '회원', ), BottomNavigationBarItem( icon: Icon(Icons.event), label: '이벤트', ), BottomNavigationBarItem( icon: Icon(Icons.score), label: '통계', ), BottomNavigationBarItem( icon: Icon(Icons.person), label: '프로필', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.blue, onTap: _onItemTapped, ), ); } }