feat: add mobile-optimized IPTV player with HLS and MpegTS support

This commit is contained in:
Michael committed 2026-03-29 10:19:36 +02:00
1 parent 3c9a9c7be7
commit fa6ae90d8d
38 files changed
+1280 -895

No files matched your search

@@ -65,8 +65,11 @@ class MobilePlaylistSelectionScreen extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline,
size: 48, color: AppColors.error),
const Icon(
Icons.error_outline,
size: 48,
color: AppColors.error,
),
const SizedBox(height: 16),
Text('Error loading playlists', style: GoogleFonts.inter()),
TextButton(
@@ -82,12 +85,16 @@ class MobilePlaylistSelectionScreen extends ConsumerWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.playlist_remove,
size: 48, color: AppColors.textSecondary),
const Icon(
Icons.playlist_remove,
size: 48,
color: AppColors.textSecondary,
),
const SizedBox(height: 16),
Text('No playlists available',
style:
GoogleFonts.inter(color: AppColors.textSecondary)),
Text(
'No playlists available',
style: GoogleFonts.inter(color: AppColors.textSecondary),
),
],
),
);
@@ -158,8 +165,11 @@ class _MobilePlaylistCard extends StatelessWidget {
color: AppColors.primary.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(Icons.playlist_play,
color: AppColors.primary, size: 28),
child: const Icon(
Icons.playlist_play,
color: AppColors.primary,
size: 28,
),
),
const SizedBox(width: 16),
Expanded(
@@ -48,14 +48,16 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
const Text('Loading channels...', style: TextStyle(color: Colors.white70)),
const Text('Loading channels...',
style: TextStyle(color: Colors.white70)),
const SizedBox(height: 24),
FutureBuilder(
future: Future.delayed(const Duration(seconds: 8)),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return TextButton(
onPressed: () => ref.refresh(liveChannelsByPlaylistProvider(widget.playlist)),
onPressed: () => ref.refresh(
liveChannelsByPlaylistProvider(widget.playlist)),
child: const Text('Taking too long? Tap to retry'),
);
}
@@ -73,12 +75,19 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 48),
const SizedBox(height: 16),
Text('Failed to load channels', style: GoogleFonts.inter(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
Text('Failed to load channels',
style: GoogleFonts.inter(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
Text('$e', style: const TextStyle(color: Colors.white54), textAlign: TextAlign.center),
Text('$e',
style: const TextStyle(color: Colors.white54),
textAlign: TextAlign.center),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => ref.refresh(liveChannelsByPlaylistProvider(widget.playlist)),
onPressed: () => ref
.refresh(liveChannelsByPlaylistProvider(widget.playlist)),
child: const Text('Retry'),
),
],
@@ -285,7 +294,10 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
channel: channel,
playlist: widget.playlist,
onTap: () => _playChannel(
context, channel, displayedChannels),
context,
channel,
displayedChannels,
),
);
},
),
@@ -299,7 +311,10 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
}
void _playChannel(
BuildContext context, Channel channel, List<Channel> channels) {
BuildContext context,
Channel channel,
List<Channel> channels,
) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MobilePlayerScreen(