Video Player
import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; import 'package:flutter/services.dart'; // SystemChrome ke liye import 'dart:async'; // Timer ke liye class VideoPlayerApp extends StatelessWidget { const VideoPlayerApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'ExoPlayer-like Video Player', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const HomeScreen(), // HomeScreen ab bhi initial route hai ); } } // Screen 1: Home Screen class HomeScreen extends StatefulWidget { // Changed to StatefulWidget to use initState const HomeScreen({super.key}); @override StatecreateState() => _HomeScreenState(); } class _HomeScreenState extends State { // Hardcoded video URL jise hum pass karenge final String _hardcodedVideoUrl = 'https://cdn-st0.mootion.com/videos/7b73f8f78d7f40c6b1d7f35725ec3748.mp4'; @override void initState() { super.initState(); // Use addPostFrameCallback to navigate after the first frame is built WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.pushReplacement( // Use pushReplacement to remove HomeScreen from stack context, MaterialPageRoute( builder: (context) => VideoPlayerScreen(videoUrl: _hardcodedVideoUrl), ), ); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Video Player App'), ), body: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), // Show a loading indicator SizedBox(height: 16), Text('Loading video...', style: TextStyle(fontSize: 18)), ], ), ), ); } } // Screen 2: Video Player Screen (jo VideoPlayerWidget ko use karegi) class VideoPlayerScreen extends StatefulWidget { final String videoUrl; // Video URL ko receive karne ke liye const VideoPlayerScreen({super.key, required this.videoUrl}); @override State createState() => _VideoPlayerScreenState(); } class _VideoPlayerScreenState extends State { bool _isFullScreen = false; // VideoPlayerScreen mein fullscreen state rakhenge void _setFullScreen(bool isFullScreen) { setState(() { _isFullScreen = isFullScreen; }); } @override void dispose() { // Ye important hai: jab screen dispose ho to UI mode aur orientation restore karein SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // AppBar ko conditional hide/show karein appBar: _isFullScreen ? null // Fullscreen mein AppBar hide kar do : AppBar( title: const Text('Video Player'), ), // HERE IS THE CHANGE: Set background color to black when in full screen backgroundColor: _isFullScreen ? Colors.black : Theme.of(context).scaffoldBackgroundColor, body: Center( child: VideoPlayerWidget( videoUrl: widget.videoUrl, onFullScreenToggle: _setFullScreen, // Callback pass karo ), ), ); } } // Naya Widget: VideoPlayerWidget (jo player ka core logic aur UI rakhega) class VideoPlayerWidget extends StatefulWidget { final String videoUrl; final Function(bool) onFullScreenToggle; // Callback function added const VideoPlayerWidget({super.key, required this.videoUrl, required this.onFullScreenToggle}); @override State createState() => _VideoPlayerWidgetState(); } class _VideoPlayerWidgetState extends State { late VideoPlayerController _controller; bool _isControllerInitialized = false; bool _isControlsVisible = true; bool _isFullScreen = false; // VideoPlayerWidget mein bhi state rakhenge bool _hasError = false; double _seekPosition = 0.0; // Slider ke temporary seek position ke liye Timer? _hideControlsTimer; // For auto-hiding controls @override void initState() { super.initState(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); _initializeVideoPlayer(); } void _initializeVideoPlayer() { _controller = VideoPlayerController.networkUrl(Uri.parse(widget.videoUrl)) ..addListener(() { if (mounted) { setState(() { // Slider ko update karne ke liye current position ko bhi update karein _seekPosition = _controller.value.position.inMilliseconds.toDouble(); // Auto-hide controls jab video play ho aur controls visible hon if (_controller.value.isPlaying && _isControlsVisible) { _startHideControlsTimer(); } else { _hideControlsTimer?.cancel(); // Pause ya buffering pe timer cancel karo } }); } }) ..initialize().then((_) { setState(() { _isControllerInitialized = true; _controller.play(); // Video automatically plays here _isControlsVisible = true; // Initial controls visible _hasError = false; _startHideControlsTimer(); // Start timer after playing }); }).catchError((error) { print("Error initializing video: $error"); setState(() { _isControllerInitialized = false; _isControlsVisible = false; _hasError = true; }); }); } void _startHideControlsTimer() { _hideControlsTimer?.cancel(); // Puraane timer ko cancel karo _hideControlsTimer = Timer(const Duration(seconds: 3), () { if (mounted && _isControlsVisible) { // Check if mounted and controls are still visible setState(() { _isControlsVisible = false; }); } }); } void _toggleControlsVisibility() { setState(() { _isControlsVisible = !_isControlsVisible; if (_isControlsVisible) { _startHideControlsTimer(); // Controls visible hone pe timer reset karo } else { _hideControlsTimer?.cancel(); // Controls hidden hone pe timer cancel karo } }); } void _toggleFullscreen() { setState(() { _isFullScreen = !_isFullScreen; widget.onFullScreenToggle(_isFullScreen); // Parent ko notify karo if (_isFullScreen) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); } else { SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); } _startHideControlsTimer(); // Fullscreen toggle par timer reset karo }); } // Duration ko HH:MM:SS ya MM:SS format mein convert karne ke liye helper function String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, '0'); final hours = twoDigits(duration.inHours); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); if (duration.inHours > 0) { return '$hours:$minutes:$seconds'; } return '$minutes:$seconds'; } // Back button press ko handle karne ke liye Future _onWillPop() async { if (_isFullScreen) { _toggleFullscreen(); // Fullscreen se exit karo return false; // Pop ko block karo } return true; // Normal back button behavior } @override void dispose() { _controller.dispose(); _hideControlsTimer?.cancel(); // Timer ko dispose karna zaroori hai super.dispose(); } @override Widget build(BuildContext context) { return WillPopScope( // WillPopScope add kiya back button handling ke liye onWillPop: _onWillPop, child: _isControllerInitialized ? GestureDetector( onTap: _toggleControlsVisibility, child: Stack( // Wrap everything in a Stack to layer video and controls children: [ // Video Player _isFullScreen ? SizedBox.expand( child: FittedBox( fit: BoxFit.contain, child: SizedBox( width: _controller.value.size.width, height: _controller.value.size.height, child: VideoPlayer(_controller), // Only VideoPlayer here ), ), ) : AspectRatio( aspectRatio: _controller.value.aspectRatio, child: VideoPlayer(_controller), ), // Controls, positioned over the video if (_isControlsVisible) Positioned.fill( child: Container( color: Colors.black.withOpacity(0.3), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ // Current time and total duration Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Row( children: [ Text( _formatDuration(_controller.value.position), style: const TextStyle(color: Colors.white), ), Expanded( child: SliderTheme( data: SliderTheme.of(context).copyWith( activeTrackColor: Colors.red, inactiveTrackColor: Colors.grey, thumbColor: Colors.red, // Thumb ka color overlayColor: Colors.red.withOpacity(0.3), thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10.0), // Bada dot overlayShape: const RoundSliderOverlayShape(overlayRadius: 20.0), // Jab press karein to bada circle ), child: Slider( value: _seekPosition, min: 0.0, max: _controller.value.duration.inMilliseconds.toDouble(), onChanged: (value) { setState(() { _seekPosition = value; // Temporary update for visual feedback }); _startHideControlsTimer(); // User interaction, reset timer }, onChangeEnd: (value) { _controller.seekTo(Duration(milliseconds: value.toInt())); _startHideControlsTimer(); // User interaction, reset timer }, ), ), ), Text( _formatDuration(_controller.value.duration), style: const TextStyle(color: Colors.white), ), ], ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ IconButton( icon: Icon( _controller.value.isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.white, size: 30, // Keep a consistent size ), onPressed: () { setState(() { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }); _startHideControlsTimer(); // User interaction, reset timer }, ), IconButton( icon: const Icon(Icons.stop, color: Colors.white, size: 30), // Consistent size onPressed: () { setState(() { _controller.seekTo(Duration.zero); _controller.pause(); }); _startHideControlsTimer(); // User interaction, reset timer }, ), IconButton( icon: Icon( _controller.value.volume > 0 ? Icons.volume_up : Icons.volume_off, color: Colors.white, size: 30, // Consistent size ), onPressed: () { setState(() { _controller.setVolume(_controller.value.volume > 0 ? 0.0 : 1.0); }); _startHideControlsTimer(); // User interaction, reset timer }, ), // Fullscreen button IconButton( icon: Icon( _isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen, color: Colors.white, size: 30, // Consistent size ), onPressed: _toggleFullscreen, // This already calls _startHideControlsTimer ), ], ), const SizedBox(height: 10), ], ), ), ), ], ), ) : Container( height: _isFullScreen ? MediaQuery.of(context).size.height : 200, color: Colors.black, child: Center( // Replaced Text with CircularProgressIndicator child: _hasError ? const Text( 'Video load nahi ho paya.', style: TextStyle(color: Colors.white), ) : const CircularProgressIndicator( valueColor: AlwaysStoppedAnimation (Colors.white), ), ), ), ); } }
0 Comments