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/models.dart'; import '../../data/catalog_repository.dart'; import '../../shared/widgets/artwork.dart'; import '../../shared/widgets/section_header.dart'; import '../album/album_screen.dart'; /// Landscape photos used for some occasion tiles; the rest use their occasion colour. const occasionPhotos = { Occasion.folk: ('assets/images/nilgiris_village.jpg', Alignment(-0.3, 0.2)), Occasion.habba: ('assets/images/nilgiris_valley.jpg', Alignment(0.6, 0.7)), Occasion.huttu: ('assets/images/nilgiris_tea.jpg', Alignment(0, 0.4)), }; class ExploreScreen extends ConsumerWidget { const ExploreScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final catalog = ref.watch(catalogProvider).value; final albums = catalog?.albums ?? const []; return SafeArea( bottom: false, child: CustomScrollView( slivers: [ SliverPadding( padding: const EdgeInsets.fromLTRB(18, 12, 8, 8), sliver: SliverToBoxAdapter( child: Row( children: [ Expanded(child: Text('Explore', style: Theme.of(context).textTheme.headlineMedium)), IconButton(tooltip: 'Search', icon: const Icon(Icons.search), onPressed: () => context.push('/search')), ], ), ), ), SliverPadding( padding: const EdgeInsets.fromLTRB(18, 8, 18, 24), sliver: SliverGrid.count( crossAxisCount: 2, mainAxisSpacing: 12, crossAxisSpacing: 12, childAspectRatio: 1.08, children: [for (final o in Occasion.values) _CategoryTile(occasion: o)], ), ), if (albums.isNotEmpty) ...[ const SliverPadding( padding: EdgeInsets.fromLTRB(18, 0, 18, 8), sliver: SliverToBoxAdapter(child: SectionHeader('All albums')), ), SliverPadding( padding: const EdgeInsets.fromLTRB(18, 0, 18, 24), sliver: SliverGrid.builder( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 180, mainAxisSpacing: 16, crossAxisSpacing: 12, childAspectRatio: 0.78, ), itemCount: albums.length, itemBuilder: (_, i) => LayoutBuilder( builder: (context, box) => AlbumCard( album: albums[i], size: box.maxWidth, songCount: catalog!.byAlbum(albums[i].id).length, onTap: () => context.push('/album/${albums[i].id}'), ), ), ), ), ], ], ), ); } } class _CategoryTile extends StatelessWidget { const _CategoryTile({required this.occasion}); final Occasion occasion; @override Widget build(BuildContext context) { final photo = occasionPhotos[occasion]; return ClipRRect( borderRadius: BorderRadius.circular(18), child: Material( color: occasion.color, child: InkWell( onTap: () => context.push('/occasion/${occasion.id}'), child: Stack( fit: StackFit.expand, children: [ if (photo != null) ...[ Image.asset(photo.$1, fit: BoxFit.cover, alignment: photo.$2, cacheWidth: 500), const PhotoScrim(stops: [0.35, 1]), ] else Positioned( right: 12, top: 12, child: Icon(occasion.icon, size: 52, color: NkColors.cream.withValues(alpha: 0.5)), ), Positioned( left: 14, right: 14, bottom: 12, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(occasion.label, style: Theme.of(context).textTheme.titleLarge?.copyWith(fontSize: 18)), Text(occasion.subtitle, style: const TextStyle(fontSize: 13, color: NkColors.mutedOnPhoto)), ], ), ), ], ), ), ), ); } }