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