import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '/audio/audio_manager.dart'; const String privacyKey = 'privacy_accepted_v2'; class StartScreen extends StatefulWidget { const StartScreen({super.key}); @override State createState() => _StartScreenState(); } class _StartScreenState extends State with SingleTickerProviderStateMixin { bool privacyVisible = false; bool privacyConfirmVisible = false; bool privacyAccepted = false; late final AnimationController _scaleController; late final Animation _scaleAnimation; @override void initState() { super.initState(); _initPrivacyState(); _playBgm(); _scaleController = AnimationController( vsync: this, duration: const Duration(milliseconds: 900), ); _scaleAnimation = Tween(begin: 1.0, end: 1.08).animate( CurvedAnimation(parent: _scaleController, curve: Curves.easeInOut), ); _scaleController.repeat(reverse: true); } Future _initPrivacyState() async { var accepted = false; try { final prefs = await SharedPreferences.getInstance(); accepted = prefs.getString(privacyKey) == '1'; } catch (_) {} if (!mounted) return; setState(() { privacyAccepted = accepted; privacyConfirmVisible = !accepted; }); } Future _playBgm() async { try { AudioManager.instance.playBgm(); debugPrint('BGM started'); } catch (e) { debugPrint('Failed to play BGM: $e'); } } void goGame() { Navigator.of( context, ).pushReplacementNamed('/game', arguments: {'levelId': 1}); } void onStart() { if (!privacyAccepted) { setState(() { privacyConfirmVisible = true; }); return; } goGame(); } Future onAcceptPrivacy() async { try { final prefs = await SharedPreferences.getInstance(); await prefs.setString(privacyKey, '1'); } catch (_) {} if (!mounted) return; setState(() { privacyAccepted = true; privacyConfirmVisible = false; }); goGame(); } @override void dispose() { _scaleController.dispose(); super.dispose(); } Widget _buildBackground() { return Positioned.fill( child: DecoratedBox( decoration: const BoxDecoration(color: Colors.black), child: Image.asset( 'assets/images/5523c88dd347d1b7cc617f632b7efdb7.png', fit: BoxFit.cover, alignment: Alignment.center, ), ), ); } Widget _buildMainContent() { return SafeArea( child: SizedBox.expand( child: Column( children: [ const Spacer(), Padding( padding: const EdgeInsets.only(bottom: 48), child: ScaleTransition( scale: _scaleAnimation, child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: onStart, child: Image.asset( 'assets/images/c9f9d7dd806cf4122041837a80f47c64.png', width: 260, height: 90, fit: BoxFit.contain, ), ), ), ), ], ), ), ); } Widget _buildPrivacyDialog() { return Dialog( insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), backgroundColor: Colors.transparent, child: ClipRRect( borderRadius: BorderRadius.circular(12), child: Container( color: Colors.white, width: double.infinity, height: MediaQuery.of(context).size.height * 0.82, child: Column( children: [ Container( height: 48, padding: const EdgeInsets.symmetric(horizontal: 12), decoration: const BoxDecoration( color: Colors.white, border: Border( bottom: BorderSide(color: Color(0xFFDDDDDD), width: 0.5), ), ), child: Row( children: [ const Expanded( child: Text( 'Privacy Policy', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.black, ), ), ), GestureDetector( onTap: () { setState(() { privacyVisible = false; }); }, child: const Padding( padding: EdgeInsets.symmetric( vertical: 6, horizontal: 10, ), child: Text( 'Close', style: TextStyle( fontSize: 14, color: Color(0xFF007AFF), ), ), ), ), ], ), ), const Expanded(child: _PrivacyInAppWebView()), ], ), ), ), ); } Widget _buildPrivacyConfirmDialog() { return Center( child: Container( width: double.infinity, constraints: const BoxConstraints(maxWidth: 420), margin: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color.fromRGBO(20, 24, 60, 0.96), borderRadius: BorderRadius.circular(18), border: Border.all( color: const Color.fromRGBO(120, 255, 255, 0.25), width: 2, ), boxShadow: const [ BoxShadow( color: Color.fromRGBO(0, 0, 0, 0.35), blurRadius: 18, offset: Offset(0, 8), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text( 'Privacy Notice', textAlign: TextAlign.center, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 1, ), ), const SizedBox(height: 10), const Text( 'Please read and agree to the Privacy Policy before starting the game.', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, height: 1.45, color: Color.fromRGBO(255, 255, 255, 0.9), ), ), const SizedBox(height: 10), GestureDetector( onTap: () { setState(() { privacyVisible = true; }); }, child: const Padding( padding: EdgeInsets.symmetric(vertical: 8, horizontal: 10), child: Text( 'View Privacy Policy', style: TextStyle( color: Color(0xFF56F0FF), fontSize: 14, fontWeight: FontWeight.w800, decoration: TextDecoration.underline, ), ), ), ), const SizedBox(height: 12), Row( children: [ Expanded( child: SizedBox( height: 46, child: OutlinedButton( onPressed: () { setState(() { privacyConfirmVisible = false; }); }, style: OutlinedButton.styleFrom( backgroundColor: const Color.fromRGBO( 255, 255, 255, 0.08, ), side: const BorderSide( color: Color.fromRGBO(255, 255, 255, 0.18), width: 2, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), ), ), child: const Text( 'Cancel', style: TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w900, letterSpacing: 0.5, ), ), ), ), ), const SizedBox(width: 12), Expanded( child: SizedBox( height: 46, child: OutlinedButton( onPressed: onAcceptPrivacy, style: OutlinedButton.styleFrom( backgroundColor: const Color.fromRGBO( 50, 160, 255, 0.9, ), side: const BorderSide( color: Color.fromRGBO(255, 255, 255, 0.22), width: 2, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), ), ), child: const Text( 'Agree & Start', style: TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w900, letterSpacing: 0.5, ), ), ), ), ), ], ), ], ), ), ); } Widget _buildPrivacyConfirmOverlay() { return Positioned.fill( child: ColoredBox( color: const Color.fromRGBO(0, 0, 0, 0.65), child: SafeArea(child: _buildPrivacyConfirmDialog()), ), ); } Widget _buildPrivacyOverlay() { return Positioned.fill( child: ColoredBox( color: Colors.black54, child: SafeArea(child: Center(child: _buildPrivacyDialog())), ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: SizedBox.expand( child: Stack( fit: StackFit.expand, children: [ _buildBackground(), _buildMainContent(), if (privacyConfirmVisible) _buildPrivacyConfirmOverlay(), if (privacyVisible) _buildPrivacyOverlay(), ], ), ), ); } } class _PrivacyInAppWebView extends StatefulWidget { const _PrivacyInAppWebView(); @override State<_PrivacyInAppWebView> createState() => _PrivacyInAppWebViewState(); } class _PrivacyInAppWebViewState extends State<_PrivacyInAppWebView> { @override Widget build(BuildContext context) { return InAppWebView( initialSettings: InAppWebViewSettings( javaScriptEnabled: true, transparentBackground: false, supportZoom: true, useShouldOverrideUrlLoading: true, ), onWebViewCreated: (controller) async { await controller.loadFile(assetFilePath: 'assets/html/privacy.html'); }, shouldOverrideUrlLoading: (controller, navigationAction) async { return NavigationActionPolicy.ALLOW; }, onLoadStop: (controller, url) async { debugPrint('Privacy page loaded: $url'); }, onReceivedError: (controller, request, error) { debugPrint('Privacy page load error: ${error.description}'); }, onConsoleMessage: (controller, consoleMessage) { debugPrint('WebView console: ${consoleMessage.message}'); }, ); } }