mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-11 17:30:00 +02:00
feat: implement IPTV PlayerScreen with embedded web player for live, VOD, and series streams.
This commit is contained in:
1 parent
e74aa822ad
commit
b6a0016c00
1 file changed
+89
-92
@@ -59,6 +59,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
bool _isSeeking = false;
|
||||
String _viewId = 'iptv-player';
|
||||
String? _currentStreamUrl;
|
||||
String _statusMessage = 'Loading...';
|
||||
String? _errorMessage;
|
||||
bool _isMuted = false;
|
||||
bool _ignoreStatusUpdates = false;
|
||||
@@ -347,59 +348,57 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
top: _showControls ? 24 : -100,
|
||||
left: 24,
|
||||
right: 24,
|
||||
child: PointerInterceptor(
|
||||
child: GlassContainer(
|
||||
height: 72,
|
||||
borderRadius: 24,
|
||||
opacity: 0.15,
|
||||
border: true,
|
||||
borderColor: Colors.white.withOpacity(0.1),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildGlassIconButton(
|
||||
icon: Icons.arrow_back_rounded,
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.channels != null
|
||||
? widget.channels![_currentIndex].name
|
||||
: widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: GlassContainer(
|
||||
height: 72,
|
||||
borderRadius: 24,
|
||||
opacity: 0.15,
|
||||
border: true,
|
||||
borderColor: Colors.white.withOpacity(0.1),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildGlassIconButton(
|
||||
icon: Icons.arrow_back_rounded,
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.channels != null
|
||||
? widget.channels![_currentIndex].name
|
||||
: widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
if (widget.channels != null)
|
||||
Text(
|
||||
'Live TV',
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.primary,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (widget.channels != null)
|
||||
Text(
|
||||
'Live TV',
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.primary,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
_buildGlassIconButton(
|
||||
icon: _isMuted
|
||||
? Icons.volume_off_rounded
|
||||
: Icons.volume_up_rounded,
|
||||
onTap: _toggleMute,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
_buildGlassIconButton(
|
||||
icon: _isMuted
|
||||
? Icons.volume_off_rounded
|
||||
: Icons.volume_up_rounded,
|
||||
onTap: _toggleMute,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -411,51 +410,49 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
bottom: 40,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: PointerInterceptor(
|
||||
child: Center(
|
||||
child: GlassContainer(
|
||||
borderRadius: 30,
|
||||
opacity: 0.15,
|
||||
border: true,
|
||||
borderColor: Colors.white.withOpacity(0.1),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24, vertical: 12),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Previous Channel
|
||||
if (widget.channels != null &&
|
||||
widget.channels!.length > 1) ...[
|
||||
_buildGlassIconButton(
|
||||
icon: Icons.skip_previous_rounded,
|
||||
onTap: _previousChannel,
|
||||
transparent: true,
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
],
|
||||
|
||||
// Play/Pause
|
||||
child: Center(
|
||||
child: GlassContainer(
|
||||
borderRadius: 30,
|
||||
opacity: 0.15,
|
||||
border: true,
|
||||
borderColor: Colors.white.withOpacity(0.1),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24, vertical: 12),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Previous Channel
|
||||
if (widget.channels != null &&
|
||||
widget.channels!.length > 1) ...[
|
||||
_buildGlassIconButton(
|
||||
icon: _isPlaying
|
||||
? Icons.pause_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
onTap: _togglePlayPause,
|
||||
size: 56,
|
||||
iconSize: 32,
|
||||
icon: Icons.skip_previous_rounded,
|
||||
onTap: _previousChannel,
|
||||
transparent: true,
|
||||
),
|
||||
|
||||
// Next Channel
|
||||
if (widget.channels != null &&
|
||||
widget.channels!.length > 1) ...[
|
||||
const SizedBox(width: 24),
|
||||
_buildGlassIconButton(
|
||||
icon: Icons.skip_next_rounded,
|
||||
onTap: _nextChannel,
|
||||
transparent: true,
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 24),
|
||||
],
|
||||
),
|
||||
|
||||
// Play/Pause
|
||||
_buildGlassIconButton(
|
||||
icon: _isPlaying
|
||||
? Icons.pause_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
onTap: _togglePlayPause,
|
||||
size: 56,
|
||||
iconSize: 32,
|
||||
),
|
||||
|
||||
// Next Channel
|
||||
if (widget.channels != null &&
|
||||
widget.channels!.length > 1) ...[
|
||||
const SizedBox(width: 24),
|
||||
_buildGlassIconButton(
|
||||
icon: Icons.skip_next_rounded,
|
||||
onTap: _nextChannel,
|
||||
transparent: true,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user