feat: introduce LitePlayerView for video playback with custom zapping controls and mobile fullscreen support.

This commit is contained in:
Michael committed 2026-03-09 14:18:51 +01:00
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));
} }
} }
+1
View File
@@ -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