import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../api/endpoints/likes.dart'; import '../models/album.dart'; import '../likes/like_button.dart'; import '../player/player_provider.dart'; import '../shared/widgets/server_image.dart'; import '../theme/theme_extension.dart'; import 'library_providers.dart'; import 'widgets/track_row.dart'; class AlbumDetailScreen extends ConsumerWidget { const AlbumDetailScreen({required this.id, this.seed, super.key}); final String id; /// Optional album reference passed by the caller (typically the /// tile they tapped) so the header can render immediately while /// the full provider loads tracks. Hydration only — provider data /// still wins once it arrives. final AlbumRef? seed; @override Widget build(BuildContext context, WidgetRef ref) { final fs = Theme.of(context).extension()!; final live = ref.watch(albumProvider(id)); // Pick the best header info available: live data > seed > nothing. final headerTitle = live.value?.album.title.isNotEmpty == true ? live.value!.album.title : seed?.title ?? ''; final headerArtist = live.value?.album.artistName.isNotEmpty == true ? live.value!.album.artistName : seed?.artistName ?? ''; Widget header() => Padding( padding: const EdgeInsets.all(16), child: Row(children: [ ClipRRect( borderRadius: BorderRadius.circular(6), child: SizedBox( width: 96, height: 96, child: ServerImage( url: '/api/albums/$id/cover', fit: BoxFit.cover, fallback: Container(color: fs.slate), ), ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( headerTitle, style: TextStyle( color: fs.parchment, fontFamily: fs.display.fontFamily, fontSize: 22, ), ), if (headerArtist.isNotEmpty) Text(headerArtist, style: TextStyle(color: fs.ash)), ], ), ), ]), ); return Scaffold( appBar: AppBar(), backgroundColor: fs.obsidian, body: live.when( error: (e, _) => Center(child: Text('$e', style: TextStyle(color: fs.error))), loading: () => seed != null ? ListView(children: [ header(), const Padding( padding: EdgeInsets.symmetric(vertical: 24), child: Center(child: CircularProgressIndicator()), ), ]) : const Center(child: CircularProgressIndicator()), data: (r) => ListView(children: [ Padding( padding: const EdgeInsets.all(16), child: Row(children: [ ClipRRect( borderRadius: BorderRadius.circular(6), child: SizedBox( width: 96, height: 96, child: ServerImage( url: '/api/albums/$id/cover', fit: BoxFit.cover, fallback: Container(color: fs.slate), ), ), ), const SizedBox(width: 16), Expanded(child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(r.album.title, style: TextStyle( color: fs.parchment, fontFamily: fs.display.fontFamily, fontSize: 22, )), Text(r.album.artistName, style: TextStyle(color: fs.ash)), ], )), Container( width: 48, height: 48, decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle), child: IconButton( icon: Icon(LucideIcons.play, color: fs.parchment), onPressed: () => ref.read(playerActionsProvider).playTracks(r.tracks), ), ), LikeButton(kind: LikeKind.album, id: r.album.id, size: 28), ]), ), for (final t in r.tracks) TrackRow( track: t, onTap: () { final start = r.tracks.indexOf(t); ref.read(playerActionsProvider).playTracks(r.tracks, initialIndex: start); }, trailing: LikeButton(kind: LikeKind.track, id: t.id), ), ]), ), ); } }