feat: align player controls with EPG at bottom of screen

This commit is contained in:
Michael committed 2025-12-16 22:52:51 +01:00
1 parent 626a3a1774
commit 77d074e412
1 file changed
+85 -80
@@ -987,104 +987,109 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
children: [ children: [
// Removed Duplicate Back Button (Top Left) - handled by Top Bar now // Removed Duplicate Back Button (Top Left) - handled by Top Bar now
// Center Controls // Bottom Controls (Aligned with EPG)
Center( Positioned(
child: Row( bottom: 80,
mainAxisSize: MainAxisSize.min, left: 0,
children: [ right: 0,
// Prev Channel / Replay 10s child: Center(
if (widget.streamType == StreamType.live && child: Row(
widget.channels != null && mainAxisSize: MainAxisSize.min,
widget.channels!.isNotEmpty) children: [
TVFocusable( // Prev Channel / Replay 10s
focusNode: _prevFocusNode, if (widget.streamType == StreamType.live &&
onPressed: _playPrevious, widget.channels != null &&
onFocus: _resetControlsTimer, widget.channels!.isNotEmpty)
borderRadius: BorderRadius.circular(50), TVFocusable(
child: IconButton( focusNode: _prevFocusNode,
icon: const Icon(Icons.skip_previous,
color: Colors.white, size: 48),
onPressed: _playPrevious, onPressed: _playPrevious,
), onFocus: _resetControlsTimer,
) borderRadius: BorderRadius.circular(50),
else if (widget.streamType != StreamType.live) child: IconButton(
TVFocusable( icon: const Icon(Icons.skip_previous,
focusNode: _prevFocusNode, color: Colors.white, size: 48),
onPressed: () async { onPressed: _playPrevious,
final pos = await _player.stream.position.first; ),
_player.seek(pos - const Duration(seconds: 5)); )
_resetControlsTimer(); else if (widget.streamType != StreamType.live)
}, TVFocusable(
onFocus: _resetControlsTimer, focusNode: _prevFocusNode,
borderRadius: BorderRadius.circular(50),
child: IconButton(
icon: const Icon(Icons.replay_10,
color: Colors.white, size: 48),
onPressed: () async { onPressed: () async {
final pos = await _player.stream.position.first; final pos = await _player.stream.position.first;
_player.seek(pos - const Duration(seconds: 5)); _player.seek(pos - const Duration(seconds: 5));
_resetControlsTimer();
}, },
onFocus: _resetControlsTimer,
borderRadius: BorderRadius.circular(50),
child: IconButton(
icon: const Icon(Icons.replay_10,
color: Colors.white, size: 48),
onPressed: () async {
final pos = await _player.stream.position.first;
_player.seek(pos - const Duration(seconds: 5));
},
),
), ),
),
const SizedBox(width: 32), const SizedBox(width: 32),
// Play/Pause // Play/Pause
TVFocusable( TVFocusable(
focusNode: _playPauseFocusNode, focusNode: _playPauseFocusNode,
onPressed: _togglePlayPause,
onFocus: _resetControlsTimer,
scale: 1.1, // Larger scale for main button
borderRadius: BorderRadius.circular(50),
child: IconButton(
iconSize: 72,
icon: Icon(
_isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_filled,
color: Colors.white,
),
onPressed: _togglePlayPause, onPressed: _togglePlayPause,
),
),
const SizedBox(width: 32),
// Next Channel / Forward 10s
if (widget.streamType == StreamType.live &&
widget.channels != null &&
widget.channels!.isNotEmpty)
TVFocusable(
focusNode: _nextFocusNode,
onPressed: _playNext,
onFocus: _resetControlsTimer, onFocus: _resetControlsTimer,
scale: 1.1, // Larger scale for main button
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
child: IconButton( child: IconButton(
icon: const Icon(Icons.skip_next, iconSize: 72,
color: Colors.white, size: 48), icon: Icon(
onPressed: _playNext, _isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_filled,
color: Colors.white,
),
onPressed: _togglePlayPause,
), ),
) ),
else if (widget.streamType != StreamType.live)
TVFocusable( const SizedBox(width: 32),
focusNode: _nextFocusNode,
onPressed: () async { // Next Channel / Forward 10s
final pos = await _player.stream.position.first; if (widget.streamType == StreamType.live &&
_player.seek(pos + const Duration(seconds: 5)); widget.channels != null &&
_resetControlsTimer(); widget.channels!.isNotEmpty)
}, TVFocusable(
onFocus: _resetControlsTimer, focusNode: _nextFocusNode,
borderRadius: BorderRadius.circular(50), onPressed: _playNext,
child: IconButton( onFocus: _resetControlsTimer,
icon: const Icon(Icons.forward_10, borderRadius: BorderRadius.circular(50),
color: Colors.white, size: 48), child: IconButton(
icon: const Icon(Icons.skip_next,
color: Colors.white, size: 48),
onPressed: _playNext,
),
)
else if (widget.streamType != StreamType.live)
TVFocusable(
focusNode: _nextFocusNode,
onPressed: () async { onPressed: () async {
final pos = await _player.stream.position.first; final pos = await _player.stream.position.first;
_player.seek(pos + const Duration(seconds: 5)); _player.seek(pos + const Duration(seconds: 5));
_resetControlsTimer();
}, },
onFocus: _resetControlsTimer,
borderRadius: BorderRadius.circular(50),
child: IconButton(
icon: const Icon(Icons.forward_10,
color: Colors.white, size: 48),
onPressed: () async {
final pos = await _player.stream.position.first;
_player.seek(pos + const Duration(seconds: 5));
},
),
), ),
), ],
], ),
), ),
), ),