feat: implement IPTV player screen for live, VOD, and series playback.

This commit is contained in:
Michael committed 2025-12-07 16:31:04 +01:00
1 parent 6b992d3b2e
commit 6028811b53
1 file changed
+43 -7
+43 -7
View File
@@ -61,6 +61,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
double _totalDuration = 1; double _totalDuration = 1;
double _volume = 1.0; double _volume = 1.0;
double _previousVolume = 1.0;
Timer? _controlsTimer; Timer? _controlsTimer;
StreamSubscription? _messageSubscription; StreamSubscription? _messageSubscription;
@@ -208,11 +209,32 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
void _setVolume(double value) { void _setVolume(double value) {
setState(() { setState(() {
_volume = value; _volume = value;
if (value > 0) {
_previousVolume = value;
}
}); });
_sendMessage({'type': 'set_volume', 'value': value}); _sendMessage({'type': 'set_volume', 'value': value});
_onHover(); _onHover();
} }
void _toggleMute() {
if (_volume > 0) {
// Mute
setState(() {
_previousVolume = _volume;
_volume = 0;
});
_sendMessage({'type': 'set_volume', 'value': 0.0});
} else {
// Unmute (restore previous volume)
setState(() {
_volume = _previousVolume > 0 ? _previousVolume : 0.5;
});
_sendMessage({'type': 'set_volume', 'value': _volume});
}
_onHover();
}
void _playNext() { void _playNext() {
if (widget.channels == null || widget.channels!.isEmpty) return; if (widget.channels == null || widget.channels!.isEmpty) return;
final nextIndex = (_currentIndex + 1) % widget.channels!.length; final nextIndex = (_currentIndex + 1) % widget.channels!.length;
@@ -724,7 +746,19 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
child: Column( child: Column(
children: [ children: [
const Icon(Icons.volume_up, color: Colors.white, size: 20), PointerInterceptor(
child: IconButton(
icon: Icon(
_volume == 0
? Icons.volume_off
: _volume < 0.5 ? Icons.volume_down : Icons.volume_up,
color: Colors.white,
size: 20
),
onPressed: _toggleMute,
tooltip: _volume == 0 ? 'Unmute' : 'Mute',
),
),
const SizedBox(height: 8), const SizedBox(height: 8),
Expanded( Expanded(
child: RotatedBox( child: RotatedBox(
@@ -764,7 +798,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
onTap: _togglePlayPause, onTap: _togglePlayPause,
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
child: Container( child: Container(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5), color: Colors.black.withOpacity(0.5),
shape: BoxShape.circle, shape: BoxShape.circle,
@@ -773,7 +807,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
child: Icon( child: Icon(
_isPlaying ? Icons.pause : Icons.play_arrow, _isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white, color: Colors.white,
size: 64, size: 48,
), ),
), ),
), ),
@@ -896,10 +930,12 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
// Clock Widget (Always visible if enabled, or only with controls? User asked "met l'heure dans les options") // Clock Widget (Always visible if enabled, or only with controls? User asked "met l'heure dans les options")
// Positioned in top right // Positioned in top right
if (settings.showClock) if (settings.showClock)
const Positioned( AnimatedPositioned(
top: 24, duration: const Duration(milliseconds: 300),
right: 24, curve: Curves.easeInOut,
child: IgnorePointer( top: _showControls ? 80 : 24,
right: 24,
child: const IgnorePointer(
child: ClockWidget( child: ClockWidget(
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,