import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../app/theme.dart'; import '../../audio/player_providers.dart'; import '../../core/models.dart'; import '../../shared/widgets/artwork.dart'; import '../../shared/widgets/catalog_builder.dart'; import '../../shared/widgets/mini_player.dart'; import '../../shared/widgets/section_header.dart'; import '../../shared/widgets/track_tile.dart'; class ArtistScreen extends ConsumerWidget { const ArtistScreen({super.key, required this.artistId}); final String artistId; @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( bottomNavigationBar: const SafeArea(child: MiniPlayer()), body: CatalogBuilder(builder: (catalog) { final artist = catalog.artistsById[artistId]; if (artist == null) { return const SafeArea( child: EmptyState(icon: Icons.person_off_outlined, title: 'Singer not found'), ); } final songs = catalog.byArtist(artistId); final controller = ref.read(playerControllerProvider); final subtitle = ['Singer', ...songs.map((s) => s.occasion.label).toSet(), ?artist.hatti].join(' · '); return CustomScrollView( slivers: [ SliverAppBar( pinned: true, expandedHeight: 320, backgroundColor: NkColors.ground, flexibleSpace: FlexibleSpaceBar( background: Stack( fit: StackFit.expand, children: [ if (artist.photoUrl != null) CachedNetworkImage(imageUrl: artist.photoUrl!, fit: BoxFit.cover) else Image.asset('assets/images/nilgiris_tea.jpg', fit: BoxFit.cover, alignment: const Alignment(0, -0.2)), const PhotoScrim(stops: [0.3, 1]), if (artist.photoUrl == null) Positioned( right: 16, top: MediaQuery.paddingOf(context).top + 12, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: NkColors.ground.withValues(alpha: 0.7), borderRadius: BorderRadius.circular(14), border: Border.all(color: NkColors.teaLeaf), ), child: const Text('Singer photo pending', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w700)), ), ), Positioned( left: 20, right: 20, bottom: 16, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(artist.name, style: Theme.of(context).textTheme.headlineLarge), const SizedBox(height: 6), Text(subtitle, style: const TextStyle(color: NkColors.mutedOnPhoto, fontSize: 15)), ], ), ), ], ), ), ), SliverPadding( padding: const EdgeInsets.fromLTRB(20, 12, 20, 8), sliver: SliverToBoxAdapter( child: Row( children: [ Text('${songs.length} songs', style: const TextStyle(color: NkColors.muted)), const Spacer(), IconButton( tooltip: 'Shuffle', icon: const Icon(Icons.shuffle, color: NkColors.sun), onPressed: songs.isEmpty ? null : () => controller.playTracks(songs, shuffle: true), ), IconButton.filled( tooltip: 'Play all', style: IconButton.styleFrom(fixedSize: const Size(56, 56)), onPressed: songs.isEmpty ? null : () => controller.playTracks(songs), icon: const Icon(Icons.play_arrow_rounded, size: 30), ), ], ), ), ), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 20), sliver: SliverList.builder( itemCount: songs.length, itemBuilder: (_, i) => TrackTile( track: songs[i], subtitle: '${songs[i].occasion.label} · ${formatDuration(songs[i].duration)}', onTap: () => controller.playTracks(songs, index: i), ), ), ), if (artist.bio != null) SliverPadding( padding: const EdgeInsets.all(20), sliver: SliverToBoxAdapter( child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration(color: NkColors.surface, borderRadius: BorderRadius.circular(16)), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('About', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 6), Text(artist.bio!, style: const TextStyle(color: Color(0xFFC9D6CE), height: 1.5)), ], ), ), ), ), ], ); }), ); } }