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
State createState() => _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