mirror of
https://gitlab.com/foxixus/neomovies_mobile.git
synced 2025-10-27 23:18:49 +05:00
Initial commit
This commit is contained in:
368
lib/presentation/providers/player/player_provider.dart
Normal file
368
lib/presentation/providers/player/player_provider.dart
Normal file
@@ -0,0 +1,368 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
import 'package:chewie/chewie.dart';
|
||||
import 'package:neomovies_mobile/data/models/player/video_source.dart';
|
||||
import 'package:neomovies_mobile/data/models/player/video_quality.dart';
|
||||
import 'package:neomovies_mobile/data/models/player/audio_track.dart';
|
||||
import 'package:neomovies_mobile/data/models/player/subtitle.dart';
|
||||
import 'package:neomovies_mobile/data/models/player/player_settings.dart';
|
||||
|
||||
class PlayerProvider with ChangeNotifier {
|
||||
// Controller instances
|
||||
VideoPlayerController? _videoPlayerController;
|
||||
ChewieController? _chewieController;
|
||||
|
||||
// Player state
|
||||
bool _isInitialized = false;
|
||||
bool _isPlaying = false;
|
||||
bool _isBuffering = false;
|
||||
bool _isFullScreen = false;
|
||||
bool _showControls = true;
|
||||
Duration _position = Duration.zero;
|
||||
Duration _duration = Duration.zero;
|
||||
|
||||
// Media info
|
||||
String? _mediaId;
|
||||
String? _mediaType;
|
||||
String? _title;
|
||||
String? _subtitle;
|
||||
String? _posterUrl;
|
||||
|
||||
// Player settings
|
||||
PlayerSettings _settings;
|
||||
|
||||
// Available options
|
||||
List<VideoSource> _sources = [];
|
||||
List<VideoQuality> _qualities = [];
|
||||
List<AudioTrack> _audioTracks = [];
|
||||
List<Subtitle> _subtitles = [];
|
||||
|
||||
// Selected options
|
||||
VideoSource? _selectedSource;
|
||||
VideoQuality? _selectedQuality;
|
||||
AudioTrack? _selectedAudioTrack;
|
||||
Subtitle? _selectedSubtitle;
|
||||
|
||||
// Playback state
|
||||
double _volume = 1.0;
|
||||
bool _isMuted = false;
|
||||
double _playbackSpeed = 1.0;
|
||||
|
||||
// Getters
|
||||
bool get isInitialized => _isInitialized;
|
||||
bool get isPlaying => _isPlaying;
|
||||
bool get isBuffering => _isBuffering;
|
||||
bool get isFullScreen => _isFullScreen;
|
||||
bool get showControls => _showControls;
|
||||
Duration get position => _position;
|
||||
Duration get duration => _duration;
|
||||
String? get mediaId => _mediaId;
|
||||
String? get mediaType => _mediaType;
|
||||
String? get title => _title;
|
||||
String? get subtitle => _subtitle;
|
||||
String? get posterUrl => _posterUrl;
|
||||
PlayerSettings get settings => _settings;
|
||||
List<VideoSource> get sources => _sources;
|
||||
List<VideoQuality> get qualities => _qualities;
|
||||
List<AudioTrack> get audioTracks => _audioTracks;
|
||||
List<Subtitle> get subtitles => _subtitles;
|
||||
VideoSource? get selectedSource => _selectedSource;
|
||||
VideoQuality? get selectedQuality => _selectedQuality;
|
||||
AudioTrack? get selectedAudioTrack => _selectedAudioTrack;
|
||||
Subtitle? get selectedSubtitle => _selectedSubtitle;
|
||||
double get volume => _volume;
|
||||
bool get isMuted => _isMuted;
|
||||
double get playbackSpeed => _playbackSpeed;
|
||||
|
||||
// Controllers
|
||||
VideoPlayerController? get videoPlayerController => _videoPlayerController;
|
||||
ChewieController? get chewieController => _chewieController;
|
||||
|
||||
// Constructor
|
||||
PlayerProvider({PlayerSettings? initialSettings})
|
||||
: _settings = initialSettings ?? PlayerSettings.defaultSettings();
|
||||
|
||||
// Initialize the player with media
|
||||
Future<void> initialize({
|
||||
required String mediaId,
|
||||
required String mediaType,
|
||||
String? title,
|
||||
String? subtitle,
|
||||
String? posterUrl,
|
||||
List<VideoSource>? sources,
|
||||
List<VideoQuality>? qualities,
|
||||
List<AudioTrack>? audioTracks,
|
||||
List<Subtitle>? subtitles,
|
||||
}) async {
|
||||
_mediaId = mediaId;
|
||||
_mediaType = mediaType;
|
||||
_title = title;
|
||||
_subtitle = subtitle;
|
||||
_posterUrl = posterUrl;
|
||||
|
||||
// Set available options
|
||||
_sources = sources ?? [];
|
||||
_qualities = qualities ?? VideoQuality.defaultQualities;
|
||||
_audioTracks = audioTracks ?? [];
|
||||
_subtitles = subtitles ?? [];
|
||||
|
||||
// Set default selections
|
||||
_selectedSource = _sources.isNotEmpty ? _sources.first : null;
|
||||
_selectedQuality = _qualities.isNotEmpty ? _qualities.first : null;
|
||||
_selectedAudioTrack = _audioTracks.isNotEmpty ? _audioTracks.first : null;
|
||||
_selectedSubtitle = _subtitles.firstWhere(
|
||||
(s) => s.id == 'none',
|
||||
orElse: () => _subtitles.first,
|
||||
);
|
||||
|
||||
// Initialize video player with the first source and quality
|
||||
if (_selectedSource != null && _selectedQuality != null) {
|
||||
await _initializeVideoPlayer();
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Initialize video player with current source and quality
|
||||
Future<void> _initializeVideoPlayer() async {
|
||||
if (_selectedSource == null || _selectedQuality == null) return;
|
||||
|
||||
// Dispose of previous controllers if they exist
|
||||
await dispose();
|
||||
|
||||
try {
|
||||
// In a real app, you would fetch the actual video URL based on source and quality
|
||||
final videoUrl = _getVideoUrl(_selectedSource!, _selectedQuality!);
|
||||
|
||||
_videoPlayerController = VideoPlayerController.networkUrl(
|
||||
Uri.parse(videoUrl),
|
||||
videoPlayerOptions: VideoPlayerOptions(
|
||||
mixWithOthers: true,
|
||||
),
|
||||
);
|
||||
|
||||
await _videoPlayerController!.initialize();
|
||||
|
||||
// Setup position listener
|
||||
_videoPlayerController!.addListener(_videoPlayerListener);
|
||||
|
||||
// Setup chewie controller
|
||||
_setupChewieController();
|
||||
|
||||
// Start playing if autoplay is enabled
|
||||
if (_settings.autoPlay) {
|
||||
await _videoPlayerController!.play();
|
||||
_isPlaying = true;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint('Error initializing video player: $e');
|
||||
// Handle error appropriately
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Chewie controller with custom options
|
||||
void _setupChewieController() {
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _videoPlayerController!,
|
||||
autoPlay: _settings.autoPlay,
|
||||
looping: false,
|
||||
allowFullScreen: true,
|
||||
allowMuting: true,
|
||||
allowPlaybackSpeedChanging: true,
|
||||
showControls: _settings.showControlsOnStart,
|
||||
showControlsOnInitialize: _settings.showControlsOnStart,
|
||||
placeholder: _posterUrl != null ? Image.network(_posterUrl!) : null,
|
||||
aspectRatio: _videoPlayerController!.value.aspectRatio,
|
||||
// Custom options can be added here
|
||||
);
|
||||
|
||||
// Listen to Chewie events
|
||||
_chewieController!.addListener(() {
|
||||
if (_chewieController!.isFullScreen != _isFullScreen) {
|
||||
_isFullScreen = _chewieController!.isFullScreen;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
if (_chewieController!.isPlaying != _isPlaying) {
|
||||
_isPlaying = _chewieController!.isPlaying;
|
||||
notifyListeners();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Video player listener
|
||||
void _videoPlayerListener() {
|
||||
if (!_videoPlayerController!.value.isInitialized) return;
|
||||
|
||||
final controller = _videoPlayerController!;
|
||||
|
||||
// Update buffering state
|
||||
final isBuffering = controller.value.isBuffering;
|
||||
if (_isBuffering != isBuffering) {
|
||||
_isBuffering = isBuffering;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Update position and duration
|
||||
if (controller.value.duration != _duration) {
|
||||
_duration = controller.value.duration;
|
||||
}
|
||||
|
||||
if (controller.value.position != _position) {
|
||||
_position = controller.value.position;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Get video URL based on source and quality
|
||||
// In a real app, this would make an API call to get the stream URL
|
||||
String _getVideoUrl(VideoSource source, VideoQuality quality) {
|
||||
// This is a placeholder - replace with actual logic to get the video URL
|
||||
return 'https://example.com/stream/$mediaType/$mediaId?source=${source.name.toLowerCase()}&quality=${quality.name}';
|
||||
}
|
||||
|
||||
// Toggle play/pause
|
||||
Future<void> togglePlayPause() async {
|
||||
if (_videoPlayerController == null) return;
|
||||
|
||||
if (_isPlaying) {
|
||||
await _videoPlayerController!.pause();
|
||||
} else {
|
||||
await _videoPlayerController!.play();
|
||||
}
|
||||
|
||||
_isPlaying = !_isPlaying;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Seek to a specific position
|
||||
Future<void> seekTo(Duration position) async {
|
||||
if (_videoPlayerController == null) return;
|
||||
|
||||
await _videoPlayerController!.seekTo(position);
|
||||
_position = position;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Set volume (0.0 to 1.0)
|
||||
Future<void> setVolume(double volume) async {
|
||||
if (_videoPlayerController == null) return;
|
||||
|
||||
_volume = volume.clamp(0.0, 1.0);
|
||||
await _videoPlayerController!.setVolume(_isMuted ? 0.0 : _volume);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Toggle mute
|
||||
Future<void> toggleMute() async {
|
||||
if (_videoPlayerController == null) return;
|
||||
|
||||
_isMuted = !_isMuted;
|
||||
await _videoPlayerController!.setVolume(_isMuted ? 0.0 : _volume);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Set playback speed
|
||||
Future<void> setPlaybackSpeed(double speed) async {
|
||||
if (_videoPlayerController == null) return;
|
||||
|
||||
_playbackSpeed = speed;
|
||||
await _videoPlayerController!.setPlaybackSpeed(speed);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Change video source
|
||||
Future<void> setSource(VideoSource source) async {
|
||||
if (_selectedSource == source) return;
|
||||
|
||||
_selectedSource = source;
|
||||
await _initializeVideoPlayer();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Change video quality
|
||||
Future<void> setQuality(VideoQuality quality) async {
|
||||
if (_selectedQuality == quality) return;
|
||||
|
||||
_selectedQuality = quality;
|
||||
await _initializeVideoPlayer();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Change audio track
|
||||
void setAudioTrack(AudioTrack track) {
|
||||
if (_selectedAudioTrack == track) return;
|
||||
|
||||
_selectedAudioTrack = track;
|
||||
// In a real implementation, you would update the audio track on the video player
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Change subtitle
|
||||
void setSubtitle(Subtitle subtitle) {
|
||||
if (_selectedSubtitle == subtitle) return;
|
||||
|
||||
_selectedSubtitle = subtitle;
|
||||
// In a real implementation, you would update the subtitle on the video player
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Toggle fullscreen
|
||||
void toggleFullScreen() {
|
||||
if (_chewieController == null) return;
|
||||
|
||||
_isFullScreen = !_isFullScreen;
|
||||
if (_isFullScreen) {
|
||||
_chewieController!.enterFullScreen();
|
||||
} else {
|
||||
_chewieController!.exitFullScreen();
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Toggle controls visibility
|
||||
void toggleControls() {
|
||||
_showControls = !_showControls;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Update player settings
|
||||
void updateSettings(PlayerSettings newSettings) {
|
||||
_settings = newSettings;
|
||||
|
||||
// Apply settings that affect the current playback
|
||||
if (_videoPlayerController != null) {
|
||||
_videoPlayerController!.setPlaybackSpeed(_settings.playbackSpeed);
|
||||
// Apply other settings as needed
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Clean up resources
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
_videoPlayerController?.removeListener(_videoPlayerListener);
|
||||
await _videoPlayerController?.dispose();
|
||||
await _chewieController?.dispose();
|
||||
|
||||
_videoPlayerController = null;
|
||||
_chewieController = null;
|
||||
|
||||
_isInitialized = false;
|
||||
_isPlaying = false;
|
||||
_isBuffering = false;
|
||||
_isFullScreen = false;
|
||||
_position = Duration.zero;
|
||||
_duration = Duration.zero;
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user