spotube/lib/modules/home/sections/genres/genre_card.dart
2025-01-10 19:51:21 +06:00

115 lines
3.8 KiB
Dart

import 'dart:math';
import 'dart:ui';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:spotify/spotify.dart' hide Offset;
import 'package:spotube/collections/fake.dart';
import 'package:spotube/collections/gradients.dart';
import 'package:spotube/components/image/universal_image.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/modules/home/sections/genres/genre_card_playlist_card.dart';
import 'package:spotube/pages/home/genres/genre_playlists.dart';
import 'package:spotube/provider/spotify/spotify.dart';
final random = Random();
final gradientState = StateProvider.family(
(ref, String id) => gradients[random.nextInt(gradients.length)],
);
class GenreSectionCard extends HookConsumerWidget {
final Category category;
const GenreSectionCard({
super.key,
required this.category,
});
@override
Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final playlists = category == FakeData.category
? null
: ref.watch(categoryPlaylistsProvider(category.id!));
final playlistsData = playlists?.asData?.value.items.take(8) ??
List.generate(5, (index) => FakeData.playlistSimple);
final randomGradient = ref.watch(gradientState(category.id!));
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
borderRadius: theme.borderRadiusXxl,
boxShadow: [
BoxShadow(
color: theme.colorScheme.foreground,
offset: const Offset(0, 5),
blurRadius: 7,
spreadRadius: -5,
),
],
image: DecorationImage(
image: UniversalImage.imageProvider(
category.icons!.first.url!,
),
fit: BoxFit.cover,
),
),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: theme.borderRadiusXxl,
gradient: randomGradient
.withOpacity(theme.brightness == Brightness.dark ? 0.2 : 0.7),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
category.name!,
style: const TextStyle(color: Colors.white),
).h3(),
Button.link(
onPressed: () {
context.pushNamed(
GenrePlaylistsPage.name,
pathParameters: {'categoryId': category.id!},
extra: category,
);
},
child: Text(
context.l10n.view_all,
style: const TextStyle(color: Colors.white),
).muted(),
),
],
),
Expanded(
child: Skeleton.ignore(
child: Skeletonizer(
enabled: playlists?.isLoading ?? false,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: playlistsData.length,
separatorBuilder: (context, index) => const Gap(12),
itemBuilder: (context, index) {
final playlist = playlistsData.elementAt(index);
return GenreSectionCardPlaylistCard(playlist: playlist);
},
),
),
),
)
],
),
),
);
}
}