From 12e04c94ffa3ae3777d1dad46bbe2ceee46df0d9 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 26 Mar 2026 20:52:27 +0100 Subject: [PATCH] feat: add playlist selection screen with interactive playlist cards and API fetching. --- .../screens/playlist_selection_screen.dart | 199 ------------------ 1 file changed, 199 deletions(-) diff --git a/lib/features/iptv/screens/playlist_selection_screen.dart b/lib/features/iptv/screens/playlist_selection_screen.dart index 9ec9b7e..dabf61a 100644 --- a/lib/features/iptv/screens/playlist_selection_screen.dart +++ b/lib/features/iptv/screens/playlist_selection_screen.dart @@ -15,205 +15,6 @@ final playlistsProvider = FutureProvider>((ref) async { }); class PlaylistSelectionScreen extends ConsumerWidget { - const PlaylistSelectionScreen({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final currentUser = ref.watch(authProvider).currentUser; - final playlistsAsync = ref.watch(playlistsProvider); - final scrollController = ScrollController(); - - return Scaffold( - extendBodyBehindAppBar: true, - appBar: AppBar( - title: Text( - 'Select Playlist', - style: GoogleFonts.roboto( - fontWeight: FontWeight.w600, - color: AppColors.textPrimary, - ), - ), - backgroundColor: Colors.transparent, - elevation: 0, - actions: [ - if (currentUser?.isAdmin ?? false) - IconButton( - icon: const Icon(Icons.admin_panel_settings, - color: AppColors.textSecondary), - onPressed: () => context.go('/admin'), - tooltip: 'Admin Panel', - ), - IconButton( - icon: const Icon(Icons.logout, color: AppColors.textSecondary), - onPressed: () async { - await ref.read(authProvider.notifier).logout(); - if (context.mounted) { - context.go('/login'); - } - }, - tooltip: 'Logout', - ), - ], - ), - body: Stack( - fit: StackFit.expand, - children: [ - // Background with glows - Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xFF050505), - AppColors.background, - Color(0xFF0A0A0A), - ], - ), - ), - ), - // Ambient Glow Top-Left - Teal - Positioned( - top: -200, - left: -200, - child: Container( - width: 600, - height: 600, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [ - AppColors.primary.withOpacity(0.3), - AppColors.primary.withOpacity(0.05), - Colors.transparent, - ], - ), - ), - ), - ), - // Ambient Glow Bottom-Right - Blue - Positioned( - bottom: -200, - right: -200, - child: Container( - width: 600, - height: 600, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [ - AppColors.info.withOpacity(0.25), - AppColors.info.withOpacity(0.05), - Colors.transparent, - ], - ), - ), - ), - ), - // Content - Explicitly filled to provide bounded constraints - Positioned.fill( - child: playlistsAsync.when( - loading: () => const Center( - child: CircularProgressIndicator(color: AppColors.primary), - ), - error: (error, stack) => Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.error_outline, - size: 64, color: AppColors.error), - const SizedBox(height: 16), - Text( - 'Error loading playlists', - style: GoogleFonts.outfit( - fontSize: 18, - color: AppColors.textSecondary, - ), - ), - const SizedBox(height: 8), - ElevatedButton( - onPressed: () => ref.refresh(playlistsProvider), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.primary, - foregroundColor: AppColors.textPrimary, - ), - child: Text('Retry', style: GoogleFonts.inter()), - ), - ], - ), - ), - data: (playlists) { - if (playlists.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.playlist_remove, - size: 64, - color: Colors.white24, - ), - const SizedBox(height: 16), - Text( - 'No playlists available', - style: GoogleFonts.outfit( - fontSize: 18, - color: Colors.white60, - ), - ), - const SizedBox(height: 8), - Text( - currentUser?.isAdmin ?? false - ? 'Add playlists in Admin Panel' - : 'Contact administrator', - style: GoogleFonts.inter( - fontSize: 14, - color: Colors.white38, - ), - ), - ], - ), - ); - } - - // GridView needs a controller in some Flutter Web environments - // to avoid NaN scroll offset issues during initial layout - return GridView.builder( - controller: scrollController, - padding: const EdgeInsets.fromLTRB( - 48, - 120, // Increased top padding for AppBar - 48, - 48, - ), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: - MediaQuery.of(context).size.width > 1200 ? 4 : 3, - crossAxisSpacing: 32, - mainAxisSpacing: 32, - childAspectRatio: 1.4, - ), - itemCount: playlists.length, - itemBuilder: (context, index) { - final playlist = playlists[index]; - return _PlaylistCard( - playlist: playlist, - onTap: () { - ref.read(selectedPlaylistProvider.notifier).state = - playlist; - context.go('/dashboard'); - }, - ); - }, - ); - }, - ), - ), - ], - ), - ); - } -} class _PlaylistCard extends StatefulWidget { final PlaylistConfig playlist;