import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../providers/app_lock_provider.dart'; import '../providers/navigation_provider.dart'; import '../theme/app_colors.dart'; import '../routes/app_routes.dart'; import 'analysis_screen.dart'; import 'app_lock_screen.dart'; import 'settings_screen.dart'; import 'sms_scan_screen.dart'; import '../utils/animation_controller_helper.dart'; import '../widgets/floating_navigation_bar.dart'; import '../widgets/glassmorphic_scaffold.dart'; import '../widgets/home_content.dart'; class MainScreen extends StatefulWidget { const MainScreen({super.key}); @override State createState() => _MainScreenState(); } class _MainScreenState extends State with WidgetsBindingObserver, TickerProviderStateMixin { late AnimationController _fadeController; late AnimationController _scaleController; late AnimationController _rotateController; late AnimationController _slideController; late AnimationController _pulseController; late AnimationController _waveController; late ScrollController _scrollController; late FloatingNavBarScrollController _navBarScrollController; // 화면 목록 late final List _screens; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _checkAppLock(); // 애니메이션 컨트롤러 초기화 _fadeController = AnimationController(vsync: this); _scaleController = AnimationController(vsync: this); _rotateController = AnimationController(vsync: this); _slideController = AnimationController(vsync: this); _pulseController = AnimationController(vsync: this); _waveController = AnimationController(vsync: this); // 헬퍼 클래스를 사용해 애니메이션 컨트롤러 초기화 AnimationControllerHelper.initControllers( vsync: this, fadeController: _fadeController, scaleController: _scaleController, rotateController: _rotateController, slideController: _slideController, pulseController: _pulseController, waveController: _waveController, ); _scrollController = ScrollController(); _navBarScrollController = FloatingNavBarScrollController( scrollController: _scrollController, onHide: () {}, onShow: () {}, ); // 화면 목록 초기화 _screens = [ HomeContent( fadeController: _fadeController, rotateController: _rotateController, slideController: _slideController, pulseController: _pulseController, waveController: _waveController, scrollController: _scrollController, onAddPressed: () => _navigateToAddSubscription(context), ), const AnalysisScreen(), Container(), // 추가 버튼은 별도 처리 const SmsScanScreen(), const SettingsScreen(), ]; } @override void dispose() { WidgetsBinding.instance.removeObserver(this); // 헬퍼 클래스를 사용해 애니메이션 컨트롤러 해제 AnimationControllerHelper.disposeControllers( fadeController: _fadeController, scaleController: _scaleController, rotateController: _rotateController, slideController: _slideController, pulseController: _pulseController, waveController: _waveController, ); _scrollController.dispose(); _navBarScrollController.dispose(); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.paused) { // 앱이 백그라운드로 갈 때 final appLockProvider = context.read(); if (appLockProvider.isBiometricEnabled) { appLockProvider.lock(); } } else if (state == AppLifecycleState.resumed) { // 앱이 포그라운드로 돌아올 때 _checkAppLock(); _resetAnimations(); } } void _resetAnimations() { AnimationControllerHelper.resetAnimations( fadeController: _fadeController, scaleController: _scaleController, slideController: _slideController, pulseController: _pulseController, waveController: _waveController, ); } Future _checkAppLock() async { final appLockProvider = context.read(); if (appLockProvider.isLocked) { await Navigator.of(context).push( PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => const AppLockScreen(), transitionsBuilder: (context, animation, secondaryAnimation, child) { return FadeTransition( opacity: animation, child: child, ); }, ), ); } } void _navigateToAddSubscription(BuildContext context) { HapticFeedback.mediumImpact(); Navigator.pushNamed( context, AppRoutes.addSubscription, ).then((result) { _resetAnimations(); // 구독이 성공적으로 추가된 경우 if (result == true) { // 상단에 스낵바 표시 if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Row( children: [ Icon( Icons.check_circle, color: Colors.white, size: 20, ), SizedBox(width: 12), Text( '구독이 추가되었습니다', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, ), ), ], ), backgroundColor: const Color(0xFF10B981), // 초록색 behavior: SnackBarBehavior.floating, margin: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 16, // 상단 여백 left: 16, right: 16, bottom: MediaQuery.of(context).size.height - 120, // 상단에 위치하도록 bottom 마진 설정 ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), duration: const Duration(seconds: 3), dismissDirection: DismissDirection.horizontal, ), ); } }); } void _handleNavigation(int index, BuildContext context) { final navigationProvider = context.read(); // 이미 같은 인덱스면 무시 if (navigationProvider.currentIndex == index) { return; } // 추가 버튼은 별도 처리 if (index == 2) { _navigateToAddSubscription(context); return; } // 인덱스 업데이트 navigationProvider.updateCurrentIndex(index); } @override Widget build(BuildContext context) { final navigationProvider = context.watch(); final hour = DateTime.now().hour; List backgroundGradient; // 시간대별 배경 그라디언트 설정 if (hour >= 6 && hour < 10) { backgroundGradient = AppColors.morningGradient; } else if (hour >= 10 && hour < 17) { backgroundGradient = AppColors.dayGradient; } else if (hour >= 17 && hour < 20) { backgroundGradient = AppColors.eveningGradient; } else { backgroundGradient = AppColors.nightGradient; } // 현재 인덱스가 유효한지 확인 int currentIndex = navigationProvider.currentIndex; if (currentIndex == 2) { currentIndex = 0; // 추가 버튼은 홈으로 표시 } return GlassmorphicScaffold( body: IndexedStack( index: currentIndex == 3 ? 3 : currentIndex == 4 ? 4 : currentIndex, children: _screens, ), backgroundGradient: backgroundGradient, useFloatingNavBar: true, floatingNavBarIndex: navigationProvider.currentIndex, onFloatingNavBarTapped: (index) { _handleNavigation(index, context); }, enableParticles: false, enableWaveAnimation: false, ); } }