import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; import '../../../core/theme/colors.dart'; /// Skeleton loading card for albums/playlists/tracks class ContentCardSkeleton extends StatelessWidget { final double? width; final double? height; const ContentCardSkeleton({ super.key, this.width, this.height, }); @override Widget build(BuildContext context) { return Shimmer.fromColors( baseColor: AppColors.surfaceVariant, highlightColor: AppColors.surfaceElevated, child: Container( width: width, height: height, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Image placeholder Expanded( child: Container( width: double.infinity, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), ), ), ), const SizedBox(height: 12), // Title placeholder Container( width: double.infinity, height: 16, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), ), ), const SizedBox(height: 8), // Subtitle placeholder Container( width: 100, height: 14, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), ), ), ], ), ), ), ); } } /// Skeleton for list items (e.g., track list items) class ListItemSkeleton extends StatelessWidget { final bool showLeading; final bool showTrailing; const ListItemSkeleton({ super.key, this.showLeading = true, this.showTrailing = true, }); @override Widget build(BuildContext context) { return Shimmer.fromColors( baseColor: AppColors.surfaceVariant, highlightColor: AppColors.surfaceElevated, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ // Leading icon/image if (showLeading) ...[ Container( width: 48, height: 48, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(6), ), ), const SizedBox(width: 12), ], // Title and subtitle Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: double.infinity, height: 14, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), ), ), const SizedBox(height: 6), Container( width: 150, height: 12, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), ), ), ], ), ), // Trailing icon if (showTrailing) ...[ const SizedBox(width: 12), Container( width: 24, height: 24, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), ), ), ], ], ), ), ); } } /// Skeleton for search results grid class SearchGridSkeleton extends StatelessWidget { final int itemCount; const SearchGridSkeleton({ super.key, this.itemCount = 6, }); @override Widget build(BuildContext context) { return GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.2, crossAxisSpacing: 12, mainAxisSpacing: 12, ), itemCount: itemCount, itemBuilder: (context, index) => const ContentCardSkeleton(), ); } } /// Skeleton for horizontal scrolling lists class HorizontalListSkeleton extends StatelessWidget { final int itemCount; final double itemHeight; final double itemWidth; const HorizontalListSkeleton({ super.key, this.itemCount = 6, this.itemHeight = 160, this.itemWidth = 120, }); @override Widget build(BuildContext context) { return SizedBox( height: itemHeight, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: itemCount, separatorBuilder: (context, index) => const SizedBox(width: 12), itemBuilder: (context, index) => ContentCardSkeleton( width: itemWidth, height: itemHeight, ), ), ); } } /// Full page skeleton with multiple sections class PageSkeleton extends StatelessWidget { final bool showHero; final int sectionCount; const PageSkeleton({ super.key, this.showHero = true, this.sectionCount = 3, }); @override Widget build(BuildContext context) { return Shimmer.fromColors( baseColor: AppColors.surfaceVariant, highlightColor: AppColors.surfaceElevated, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Hero section if (showHero) ...[ Container( height: 180, margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), ), ], // Sections ...List.generate( sectionCount, (index) => Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Section title Container( width: 150, height: 24, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), ), ), const SizedBox(height: 12), // Horizontal list SizedBox( height: 160, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: 6, separatorBuilder: (context, index) => const SizedBox(width: 12), itemBuilder: (context, index) => Container( width: 120, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), ), ), ), ), ], ), ), ), ], ), ); } } /// Circular loading indicator with theme colors class ThemedCircularProgress extends StatelessWidget { final double? size; final double strokeWidth; const ThemedCircularProgress({ super.key, this.size, this.strokeWidth = 3.0, }); @override Widget build(BuildContext context) { return SizedBox( width: size, height: size, child: CircularProgressIndicator( strokeWidth: strokeWidth, valueColor: const AlwaysStoppedAnimation(AppColors.cyan), backgroundColor: AppColors.surfaceVariant, ), ); } }