mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-23 15:08:07 +02:00
feat: introduce LitePlayerView for video playback with custom zapping controls and mobile fullscreen support.
This commit is contained in:
1 parent
c57273be2c
commit
12b799a7fd
2 files changed
+39
-8
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
import 'package:chewie/chewie.dart';
|
import 'package:chewie/chewie.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -46,7 +47,8 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
Future<void> _initializePlayer() async {
|
Future<void> _initializePlayer() async {
|
||||||
try {
|
try {
|
||||||
setState(() => _error = false);
|
setState(() => _error = false);
|
||||||
_videoController = VideoPlayerController.networkUrl(Uri.parse(widget.streamUrl));
|
_videoController =
|
||||||
|
VideoPlayerController.networkUrl(Uri.parse(widget.streamUrl));
|
||||||
await _videoController.initialize();
|
await _videoController.initialize();
|
||||||
|
|
||||||
_chewieController = ChewieController(
|
_chewieController = ChewieController(
|
||||||
@@ -54,7 +56,9 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
autoPlay: true,
|
autoPlay: true,
|
||||||
looping: false,
|
looping: false,
|
||||||
isLive: widget.isLive,
|
isLive: widget.isLive,
|
||||||
aspectRatio: _videoController.value.aspectRatio > 0 ? _videoController.value.aspectRatio : 16/9,
|
aspectRatio: _videoController.value.aspectRatio > 0
|
||||||
|
? _videoController.value.aspectRatio
|
||||||
|
: 16 / 9,
|
||||||
materialProgressColors: ChewieProgressColors(
|
materialProgressColors: ChewieProgressColors(
|
||||||
playedColor: AppColors.primary,
|
playedColor: AppColors.primary,
|
||||||
handleColor: Colors.white,
|
handleColor: Colors.white,
|
||||||
@@ -62,6 +66,20 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
bufferedColor: Colors.white54,
|
bufferedColor: Colors.white54,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Fullscreen configuration for Mobile
|
||||||
|
allowFullScreen: true,
|
||||||
|
allowMuting: true,
|
||||||
|
showControls: true,
|
||||||
|
deviceOrientationsOnEnterFullScreen: [
|
||||||
|
DeviceOrientation.landscapeLeft,
|
||||||
|
DeviceOrientation.landscapeRight,
|
||||||
|
],
|
||||||
|
deviceOrientationsAfterFullScreen: [
|
||||||
|
DeviceOrientation.portraitUp,
|
||||||
|
],
|
||||||
|
systemOverlaysOnEnterFullScreen: [], // Full immersive
|
||||||
|
systemOverlaysAfterFullScreen: SystemUiOverlay.values,
|
||||||
|
|
||||||
// Custom Controls to include Zapping
|
// Custom Controls to include Zapping
|
||||||
additionalOptions: (context) {
|
additionalOptions: (context) {
|
||||||
return <OptionItem>[
|
return <OptionItem>[
|
||||||
@@ -86,6 +104,11 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
];
|
];
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_chewieController!.addListener(() {
|
||||||
|
if (mounted) setState(() {});
|
||||||
|
});
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Error initializing Lite Player: $e');
|
debugPrint('Error initializing Lite Player: $e');
|
||||||
@@ -114,7 +137,8 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Icons.error_outline, color: Colors.red, size: 48),
|
const Icon(Icons.error_outline, color: Colors.red, size: 48),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const Text('Error loading video', style: TextStyle(color: Colors.white)),
|
const Text('Error loading video',
|
||||||
|
style: TextStyle(color: Colors.white)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -128,13 +152,16 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_chewieController != null && _chewieController!.videoPlayerController.value.isInitialized) {
|
if (_chewieController != null &&
|
||||||
|
_chewieController!.videoPlayerController.value.isInitialized) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Chewie(controller: _chewieController!),
|
Chewie(controller: _chewieController!),
|
||||||
|
|
||||||
// Overlay Zapping Controls for easy access (since Chewie hides controls)
|
// Overlay Zapping Controls for easy access (since Chewie hides controls)
|
||||||
if (widget.onPrevious != null || widget.onNext != null)
|
// Hide them during fullscreen to avoid clutter
|
||||||
|
if ((widget.onPrevious != null || widget.onNext != null) &&
|
||||||
|
!(_chewieController?.isFullScreen ?? false))
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 20,
|
bottom: 20,
|
||||||
right: 80,
|
right: 80,
|
||||||
@@ -144,7 +171,8 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
if (widget.onPrevious != null) ...[
|
if (widget.onPrevious != null) ...[
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: widget.onPrevious,
|
onPressed: widget.onPrevious,
|
||||||
icon: const Icon(Icons.navigate_before, color: Colors.white, size: 32),
|
icon: const Icon(Icons.navigate_before,
|
||||||
|
color: Colors.white, size: 32),
|
||||||
tooltip: 'Previous Channel',
|
tooltip: 'Previous Channel',
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
@@ -152,7 +180,8 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
if (widget.onNext != null)
|
if (widget.onNext != null)
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: widget.onNext,
|
onPressed: widget.onNext,
|
||||||
icon: const Icon(Icons.navigate_next, color: Colors.white, size: 32),
|
icon: const Icon(Icons.navigate_next,
|
||||||
|
color: Colors.white, size: 32),
|
||||||
tooltip: 'Next Channel',
|
tooltip: 'Next Channel',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -162,6 +191,7 @@ class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return const Center(child: CircularProgressIndicator(color: AppColors.primary));
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(color: AppColors.primary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,7 @@ Refonte du Guide TV pour inclure les catégories et corriger l'EPG.
|
|||||||
- [x] Correction Chemins HLS Relatifs (Bug chemins absolus FFmpeg)
|
- [x] Correction Chemins HLS Relatifs (Bug chemins absolus FFmpeg)
|
||||||
- [x] Résolution Erreur 502 Proxy (Nettoyage Headers + API Buffer)
|
- [x] Résolution Erreur 502 Proxy (Nettoyage Headers + API Buffer)
|
||||||
- [x] Optimisation HLS iOS (Force Keyframes + Anti-Empty Playlist)
|
- [x] Optimisation HLS iOS (Force Keyframes + Anti-Empty Playlist)
|
||||||
|
- [x] Support Plein Écran Mobile (Orientations Landscape + UI Auto-hide)
|
||||||
|
|
||||||
## Progress Log
|
## Progress Log
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user