import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../app/theme.dart'; import '../../core/env.dart'; import '../../audio/player_providers.dart'; import '../../core/models.dart'; import '../../data/user_library.dart'; import '../../shared/widgets/artwork.dart'; import '../../shared/widgets/catalog_builder.dart'; import '../../shared/widgets/section_header.dart'; import '../../shared/widgets/track_tile.dart'; enum _LibraryView { liked, recent, singers } class LibraryScreen extends ConsumerStatefulWidget { const LibraryScreen({super.key}); @override ConsumerState createState() => _LibraryScreenState(); } class _LibraryScreenState extends ConsumerState { _LibraryView _view = _LibraryView.liked; @override Widget build(BuildContext context) { return SafeArea( bottom: false, child: CatalogBuilder(builder: (catalog) { final liked = ref.watch(likedSongsProvider); final recent = ref.watch(recentlyPlayedProvider); final controller = ref.read(playerControllerProvider); List resolve(Iterable ids) => ids.map(catalog.trackById).whereType().toList(); final Widget content = switch (_view) { _LibraryView.liked => _TrackList( tracks: resolve(liked), empty: const EmptyState( icon: Icons.favorite_border, title: 'No liked songs yet', message: 'Tap the heart on any song to keep it here.', ), onPlay: controller.playTracks, ), _LibraryView.recent => _TrackList( tracks: resolve(recent), empty: const EmptyState(icon: Icons.history, title: 'Nothing played yet'), onPlay: controller.playTracks, ), _LibraryView.singers => ListView( padding: const EdgeInsets.symmetric(horizontal: 18), children: [ for (final a in catalog.artists) ListTile( contentPadding: EdgeInsets.zero, leading: SingerAvatar(artist: a, size: 52), title: Text(a.name, style: const TextStyle(fontWeight: FontWeight.w700)), subtitle: Text('${catalog.byArtist(a.id).length} songs', style: const TextStyle(color: NkColors.muted)), onTap: () => context.push('/artist/${a.id}'), ), ], ), }; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(18, 12, 8, 12), child: Row( children: [ Expanded(child: Text('Your library', style: Theme.of(context).textTheme.headlineMedium)), IconButton( tooltip: 'Settings & help', icon: const Icon(Icons.settings_outlined), onPressed: () => context.push('/settings'), ), if (Env.hasSupabase) IconButton( tooltip: 'Your profile', icon: const Icon(Icons.account_circle_outlined), onPressed: () => context.push('/profile'), ), ], ), ), SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 18), child: Row( children: [ for (final (view, label) in const [ (_LibraryView.liked, 'Liked songs'), (_LibraryView.recent, 'Recently played'), (_LibraryView.singers, 'Singers'), ]) Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(label), selected: _view == view, onSelected: (_) => setState(() => _view = view), ), ), ], ), ), const SizedBox(height: 8), Expanded(child: content), ], ); }), ); } } class _TrackList extends StatelessWidget { const _TrackList({required this.tracks, required this.empty, required this.onPlay}); final List tracks; final Widget empty; final Future Function(List, {int index, bool shuffle}) onPlay; @override Widget build(BuildContext context) { if (tracks.isEmpty) return Center(child: SingleChildScrollView(child: empty)); return ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 18), itemCount: tracks.length, itemBuilder: (_, i) => TrackTile(track: tracks[i], onTap: () => onPlay(tracks, index: i)), ); } }