import 'package:flutter/material.dart'; import 'package:splash_video/splash_video.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); // Initialize SplashVideo: defer first frame & setup MediaKit // This is safe because our first screen IS a SplashVideoPage SplashVideo.initialize(); runApp(const MyApp()); } // Cyberpunk color palette class CyberpunkColors { static const neonPink = Color(0xFFFF006E); static const neonCyan = Color(0xFF00F5FF); static const neonPurple = Color(0xFFB76CFF); static const neonYellow = Color(0xFFFFED4E); static const darkBg = Color(0xFF0A0E27); static const darkerBg = Color(0xFF050816); static const glowBlue = Color(0xFF1B1464); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Splash Video Example', debugShowCheckedModeBanner: false, theme: ThemeData( scaffoldBackgroundColor: CyberpunkColors.darkBg, colorScheme: ColorScheme.dark( primary: CyberpunkColors.neonCyan, secondary: CyberpunkColors.neonPink, // surface: CyberpunkColors.darkBg, surface: CyberpunkColors.glowBlue, ), textTheme: const TextTheme( bodyLarge: TextStyle(color: Colors.white, fontWeight: FontWeight.w300), bodyMedium: TextStyle(color: Colors.white70, fontWeight: FontWeight.w300), ), useMaterial3: true, ), // Show splash video first, then auto-navigate to selector home: const InitialSplashExample(), ); } } /// Initial splash screen shown on app startup class InitialSplashExample extends StatelessWidget { const InitialSplashExample({super.key}); @override Widget build(BuildContext context) { return SplashVideo( source: AssetSource(ExampleSelector.kFilePath), backgroundColor: Colors.black, nextScreen: const ExampleSelector(), videoConfig: const VideoConfig( videoVisibilityEnum: VideoAspectRatio.useFullScreen, ), onVideoError: (error) { debugPrint('Initial Splash Video Error: $error'); // Navigate to selector even on error Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => const ExampleSelector(), ), ); }, ); } } /// Example selector screen to choose different splash examples class ExampleSelector extends StatelessWidget { const ExampleSelector({super.key}); static const kFilePath = 'assets/splash.mp4'; static const backgroundColor = Colors.white; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: CyberpunkColors.darkerBg, body: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ CyberpunkColors.darkerBg, CyberpunkColors.darkBg, CyberpunkColors.glowBlue.withValues(alpha: 0.3), ], ), ), child: SafeArea( child: Column( children: [ const SizedBox(height: 40), // Cyberpunk header ShaderMask( shaderCallback: (bounds) => LinearGradient( colors: [CyberpunkColors.neonCyan, CyberpunkColors.neonPink], ).createShader(bounds), child: const Text( '⚡ SPLASH VIDEO ⚡', style: TextStyle( fontSize: 32, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 3, ), ), ), const SizedBox(height: 10), const Text( 'CYBERPUNK EDITION', style: TextStyle( fontSize: 14, color: CyberpunkColors.neonYellow, letterSpacing: 4, fontWeight: FontWeight.w300, ), ), const SizedBox(height: 40), Expanded( child: ListView( padding: const EdgeInsets.symmetric(horizontal: 20), children: [ _buildCyberpunkTile( context, 'AUTO-NAVIGATE', 'Video plays then auto-navigates to home', Icons.rocket_launch, CyberpunkColors.neonCyan, () => Navigator.push( context, MaterialPageRoute( builder: (_) => const AutoNavigateExample(), ), ), ), const SizedBox(height: 16), _buildCyberpunkTile( context, 'MANUAL CONTROL', 'Use onVideoComplete for custom logic', Icons.control_camera, CyberpunkColors.neonPurple, () => Navigator.push( context, MaterialPageRoute( builder: (_) => const ManualControlExample(), ), ), ), const SizedBox(height: 16), _buildCyberpunkTile( context, 'INFINITE LOOP', 'Video loops until user taps skip', Icons.all_inclusive, CyberpunkColors.neonPink, () => Navigator.push( context, MaterialPageRoute( builder: (_) => const LoopingExample(), ), ), ), const SizedBox(height: 16), _buildCyberpunkTile( context, 'OVERLAY MODE', 'Title, footer, and custom overlays', Icons.layers, CyberpunkColors.neonYellow, () => Navigator.push( context, MaterialPageRoute( builder: (_) => const OverlayExample(), ), ), ), ], ), ), ], ), ), ), ); } Widget _buildCyberpunkTile( BuildContext context, String title, String subtitle, IconData icon, Color accentColor, VoidCallback onTap, ) { return InkWell( onTap: onTap, child: Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: CyberpunkColors.darkBg.withValues(alpha: 0.6), borderRadius: BorderRadius.circular(16), border: Border.all( color: accentColor.withValues(alpha: 0.5), width: 2, ), boxShadow: [ BoxShadow( color: accentColor.withValues(alpha: 0.3), blurRadius: 20, spreadRadius: -5, ), ], ), child: Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: accentColor.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: accentColor.withValues(alpha: 0.5), blurRadius: 15, ), ], ), child: Icon( icon, color: accentColor, size: 32, ), ), const SizedBox(width: 20), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: accentColor, letterSpacing: 1.5, ), ), const SizedBox(height: 6), Text( subtitle, style: const TextStyle( fontSize: 13, color: Colors.white70, fontWeight: FontWeight.w300, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: accentColor.withValues(alpha: 0.7), size: 20, ), ], ), ), ); } } /// Example 1: Auto-navigate to next screen when video completes class AutoNavigateExample extends StatelessWidget { const AutoNavigateExample({super.key}); @override Widget build(BuildContext context) { return SplashVideo( source: AssetSource(ExampleSelector.kFilePath), nextScreen: const HomeScreen(title: 'Auto-Navigate Example'), backgroundColor: Colors.black, videoConfig: const VideoConfig( videoVisibilityEnum: VideoAspectRatio.useFullScreen, ), onVideoError: (error) { debugPrint('Video Error in AutoNavigateExample: $error'); Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => const HomeScreen(title: 'Auto-Navigate (Error)'), ), ); }, ); } } /// Example 2: Manual control with onVideoComplete callback class ManualControlExample extends StatelessWidget { const ManualControlExample({super.key}); @override Widget build(BuildContext context) { return SplashVideo( source: AssetSource(ExampleSelector.kFilePath), backgroundColor: Colors.black, onVideoError: (error) { debugPrint('Video Error in ManualControlExample: $error'); Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => const HomeScreen(title: 'Manual Control (Error)'), ), ); }, onVideoComplete: () { // Custom logic before navigation debugPrint('Video completed!'); Navigator.pushReplacement( context, MaterialPageRoute( builder: (_) => const HomeScreen(title: 'Manual Control Example'), ), ); }, ); } } /// Example 3: Looping video with manual skip class LoopingExample extends StatefulWidget { const LoopingExample({super.key}); @override State createState() => _LoopingExampleState(); } class _LoopingExampleState extends State { late final SplashVideoController controller; @override void initState() { super.initState(); controller = SplashVideoController(loopVideo: true); } @override void dispose() { controller.dispose(); super.dispose(); } void _onSkip() { controller.skip(); Navigator.pushReplacement( context, MaterialPageRoute( builder: (_) => const HomeScreen(title: 'Looping Example'), ), ); } @override Widget build(BuildContext context) { return SplashVideo( source: AssetSource(ExampleSelector.kFilePath), controller: controller, backgroundColor: Colors.black, onVideoError: (error) { debugPrint('LoopingExample - Video Error: $error'); // Navigate to home screen on error Navigator.pushReplacement( context, MaterialPageRoute( builder: (_) => const HomeScreen(title: 'Looping Example (Error)'), ), ); }, footerWidget: Padding( padding: const EdgeInsets.all(20.0), child: Center( child: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [CyberpunkColors.neonCyan, CyberpunkColors.neonPurple], ), borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( color: CyberpunkColors.neonCyan.withValues(alpha: 0.5), blurRadius: 20, spreadRadius: 2, ), ], ), child: ElevatedButton.icon( onPressed: _onSkip, icon: const Icon(Icons.skip_next, color: Colors.black), label: const Text( 'SKIP', style: TextStyle( color: Colors.black, fontWeight: FontWeight.bold, letterSpacing: 2, ), ), style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15), ), ), ), ), ), ); } } /// Example 4: Video with title, footer, and custom overlay class OverlayExample extends StatelessWidget { const OverlayExample({super.key}); @override Widget build(BuildContext context) { return SplashVideo( source: AssetSource(ExampleSelector.kFilePath), nextScreen: const HomeScreen(title: 'Overlay Example'), backgroundColor: Colors.black, onVideoError: (error) { debugPrint('OverlayExample - Video Error: $error'); // Navigate to home screen on error Navigator.pushReplacement( context, MaterialPageRoute( builder: (_) => const HomeScreen(title: 'Overlay Example (Error)'), ), ); }, titleWidget: const Padding( padding: EdgeInsets.all(20.0), child: Center( child: _CyberpunkTitle(), ), ), footerWidget: Padding( padding: const EdgeInsets.all(20.0), child: Center( child: Container( padding: const EdgeInsets.all(3), decoration: BoxDecoration( gradient: LinearGradient( colors: [CyberpunkColors.neonPink, CyberpunkColors.neonCyan], ), borderRadius: BorderRadius.circular(50), ), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: CyberpunkColors.darkerBg, borderRadius: BorderRadius.circular(50), ), child: const CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(CyberpunkColors.neonCyan), strokeWidth: 3, ), ), ), ), ), overlayBuilder: (context) => Positioned( right: 20, top: 100, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( gradient: LinearGradient( colors: [ CyberpunkColors.neonPurple.withValues(alpha: 0.3), CyberpunkColors.neonCyan.withValues(alpha: 0.3), ], ), borderRadius: BorderRadius.circular(8), border: Border.all( color: CyberpunkColors.neonCyan.withValues(alpha: 0.5), width: 1, ), boxShadow: [ BoxShadow( color: CyberpunkColors.neonCyan.withValues(alpha: 0.5), blurRadius: 10, ), ], ), child: const Text( 'v1.0.0', style: TextStyle( color: CyberpunkColors.neonCyan, fontSize: 12, fontWeight: FontWeight.bold, letterSpacing: 1, ), ), ), ), ); } } /// Home screen that's shown after splash class HomeScreen extends StatelessWidget { const HomeScreen({super.key, required this.title}); final String title; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: CyberpunkColors.darkerBg, body: Container( decoration: BoxDecoration( gradient: RadialGradient( center: Alignment.center, radius: 1.5, colors: [ CyberpunkColors.glowBlue.withValues(alpha: 0.3), CyberpunkColors.darkerBg, ], ), ), child: SafeArea( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Success icon with glow Container( padding: const EdgeInsets.all(30), decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ CyberpunkColors.neonCyan.withValues(alpha: 0.3), Colors.transparent, ], ), boxShadow: [ BoxShadow( color: CyberpunkColors.neonCyan.withValues(alpha: 0.5), blurRadius: 50, spreadRadius: 10, ), ], ), child: const Icon( Icons.check_circle, size: 100, color: CyberpunkColors.neonCyan, ), ), const SizedBox(height: 40), ShaderMask( shaderCallback: (bounds) => LinearGradient( colors: [CyberpunkColors.neonCyan, CyberpunkColors.neonPink], ).createShader(bounds), child: Text( title.toUpperCase(), textAlign: TextAlign.center, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white, letterSpacing: 2, ), ), ), const SizedBox(height: 20), Text( 'SPLASH VIDEO COMPLETED', style: TextStyle( fontSize: 16, color: CyberpunkColors.neonYellow, letterSpacing: 3, fontWeight: FontWeight.w300, ), ), const SizedBox(height: 60), Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [CyberpunkColors.neonPink, CyberpunkColors.neonPurple], ), borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow( color: CyberpunkColors.neonPink.withValues(alpha: 0.5), blurRadius: 20, spreadRadius: 2, ), ], ), child: ElevatedButton.icon( onPressed: () => Navigator.pop(context), icon: const Icon(Icons.arrow_back, color: Colors.black), label: const Text( 'BACK TO EXAMPLES', style: TextStyle( color: Colors.black, fontWeight: FontWeight.bold, letterSpacing: 2, ), ), style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 18), ), ), ), ], ), ), ), ), ); } } // Animated cyberpunk title widget class _CyberpunkTitle extends StatefulWidget { const _CyberpunkTitle(); @override State<_CyberpunkTitle> createState() => _CyberpunkTitleState(); } class _CyberpunkTitleState extends State<_CyberpunkTitle> with SingleTickerProviderStateMixin { late AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, )..repeat(reverse: true); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, child) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [ CyberpunkColors.neonCyan.withValues(alpha: 0.2 + _controller.value * 0.3), CyberpunkColors.neonPink.withValues(alpha: 0.2 + _controller.value * 0.3), ], ), borderRadius: BorderRadius.circular(16), border: Border.all( color: CyberpunkColors.neonCyan.withValues(alpha: 0.5 + _controller.value * 0.5), width: 2, ), boxShadow: [ BoxShadow( color: CyberpunkColors.neonCyan.withValues(alpha: 0.3 + _controller.value * 0.4), blurRadius: 20 + _controller.value * 10, spreadRadius: 5, ), ], ), child: ShaderMask( shaderCallback: (bounds) => LinearGradient( colors: [CyberpunkColors.neonCyan, CyberpunkColors.neonPink], ).createShader(bounds), child: const Text( '⚡ WELCOME TO THE FUTURE ⚡', textAlign: TextAlign.center, style: TextStyle( fontSize: 28, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 2, ), ), ), ); }, ); } }