Skip to content

Commit

Permalink
refactor: genres section
Browse files Browse the repository at this point in the history
  • Loading branch information
KRTirtho committed Jan 6, 2025
1 parent 6dd9b75 commit bf94a49
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 75 deletions.
3 changes: 2 additions & 1 deletion lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -408,5 +408,6 @@
"add_all_to_playlist": "Add all to playlist",
"add_all_to_queue": "Add all to queue",
"play_all_next": "Play all next",
"pause": "Pause"
"pause": "Pause",
"view_all": "View all"
}
215 changes: 172 additions & 43 deletions lib/modules/home/sections/genres.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,25 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/collections/fake.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/image/universal_image.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/extensions/image.dart';
import 'package:spotube/extensions/string.dart';
import 'package:spotube/pages/home/genres/genre_playlists.dart';
import 'package:spotube/pages/home/genres/genres.dart';
import 'package:spotube/pages/playlist/playlist.dart';
import 'package:spotube/provider/spotify/spotify.dart';

class HomeGenresSection extends HookConsumerWidget {
const HomeGenresSection({super.key});

@override
Widget build(BuildContext context, ref) {
final mediaQuery = MediaQuery.of(context);
final theme = context.theme;
final mediaQuery = MediaQuery.sizeOf(context);

final categoriesQuery = ref.watch(categoriesProvider);
final categories = useMemoized(
Expand All @@ -28,7 +31,9 @@ class HomeGenresSection extends HookConsumerWidget {
.where((c) => (c.icons?.length ?? 0) > 0)
.take(mediaQuery.mdAndDown ? 6 : 10)
.toList() ??
<Category>[],
[
FakeData.category,
],
[mediaQuery.mdAndDown, categoriesQuery.asData?.value],
);

Expand Down Expand Up @@ -61,51 +66,175 @@ class HomeGenresSection extends HookConsumerWidget {
),
),
const SliverGap(8),
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: Skeletonizer.sliver(
enabled: categoriesQuery.isLoading,
child: SliverGrid.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: mediaQuery.mdAndDown ? 200 : 250,
mainAxisExtent: 50,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
SliverToBoxAdapter(
child: SizedBox(
height: 280 * theme.scaling,
child: Carousel(
transition: const CarouselTransition.sliding(gap: 24),
sizeConstraint: CarouselSizeConstraint.fixed(
mediaQuery.mdAndUp
? mediaQuery.width * .6
: mediaQuery.width * .95,
),
itemCount: categoriesQuery.isLoading
? mediaQuery.mdAndDown
? 6
: 10
: categories.length,
itemCount: categories.length,
autoplaySpeed: const Duration(seconds: 2),
duration: const Duration(seconds: 5),
pauseOnHover: true,
direction: Axis.horizontal,
itemBuilder: (context, index) {
final category =
categories.elementAtOrNull(index) ?? FakeData.category;
final category = categories[index];
final playlists =
ref.watch(categoryPlaylistsProvider(category.id!));
final playlistsData = playlists.asData?.value.items.take(8) ??
List.generate(5, (index) => FakeData.playlistSimple);

return Button(
style: ButtonVariance.secondary.copyWith(
padding: (context, states, value) {
return EdgeInsets.zero;
},
),
onPressed: () {},
child: CardImage(
onPressed: () {
context.pushNamed(
GenrePlaylistsPage.name,
pathParameters: {
"categoryId": category.id!,
},
extra: category,
);
},
direction: Axis.horizontal,
image: UniversalImage(
path: category.icons!.first.url!,
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: theme.borderRadiusXxl,
border: Border.all(
color: theme.colorScheme.border,
width: 1,
),
image: DecorationImage(
image: UniversalImage.imageProvider(
category.icons!.first.url!,
),
colorFilter: ColorFilter.mode(
theme.colorScheme.background.withAlpha(125),
BlendMode.darken,
),
fit: BoxFit.cover,
height: 50,
width: 50,
),
title: Text(category.name!),
),
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,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
spacing: 12,
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (final playlist in playlistsData)
Container(
width: 115 * theme.scaling,
decoration: BoxDecoration(
color: theme.colorScheme.background
.withAlpha(75),
borderRadius: theme.borderRadiusMd,
),
child: SurfaceBlur(
borderRadius: theme.borderRadiusMd,
surfaceBlur: theme.surfaceBlur,
child: Button(
style:
ButtonVariance.secondary.copyWith(
padding: (context, states, value) =>
const EdgeInsets.all(8),
decoration:
(context, states, value) {
final decoration = ButtonVariance
.secondary
.decoration(
context, states)
as BoxDecoration;

if (states.isNotEmpty) {
return decoration;
}

return decoration.copyWith(
color: decoration.color
?.withAlpha(180),
);
},
),
onPressed: () {
context.pushNamed(
PlaylistPage.name,
pathParameters: {
"id": playlist.id!,
},
extra: playlist,
);
},
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
spacing: 5,
children: [
ClipRRect(
borderRadius:
theme.borderRadiusSm,
child: UniversalImage(
path: (playlist.images)!
.asUrlString(
placeholder:
ImagePlaceholder
.collection,
index: 1,
),
fit: BoxFit.cover,
height: 100 * theme.scaling,
width: 100 * theme.scaling,
),
),
Text(
playlist.name!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
).semiBold().small(),
if (playlist.description != null)
Text(
playlist.description
?.unescapeHtml()
.cleanHtml() ??
"",
maxLines: 2,
overflow:
TextOverflow.ellipsis,
).xSmall().muted(),
],
),
),
),
),
],
),
),
),
),
)
],
),
);
},
Expand Down
14 changes: 9 additions & 5 deletions lib/utils/service_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:dio/dio.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:go_router/go_router.dart';
import 'package:html/dom.dart' hide Text;
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element;
import 'package:spotify/spotify.dart';
import 'package:spotube/modules/library/user_local_tracks.dart';
import 'package:spotube/modules/root/update_dialog.dart';
Expand All @@ -20,7 +21,6 @@ import 'package:html/parser.dart' as parser;

import 'dart:async';

import 'package:flutter/material.dart' hide Element;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:spotube/collections/env.dart';
Expand Down Expand Up @@ -304,7 +304,9 @@ abstract class ServiceUtils {
.map((e) => e.matchedLocation);

if (routerState.matchedLocation == location ||
routerStack.contains(location)) return;
routerStack.contains(location)) {
return;
}
router.push(location, extra: extra);
}

Expand Down Expand Up @@ -418,7 +420,7 @@ abstract class ServiceUtils {
await showDialog(
context: context,
barrierDismissible: true,
barrierColor: Colors.black26,
barrierColor: Colors.black.withAlpha(66),
builder: (context) {
return RootAppUpdateDialog.nightly(nightlyBuildNum: buildNum);
},
Expand All @@ -439,14 +441,16 @@ abstract class ServiceUtils {
if (currentVersion == null ||
latestVersion == null ||
(latestVersion.isPreRelease && !currentVersion.isPreRelease) ||
(!latestVersion.isPreRelease && currentVersion.isPreRelease)) return;
(!latestVersion.isPreRelease && currentVersion.isPreRelease)) {
return;
}

if (latestVersion <= currentVersion || !context.mounted) return;

showDialog(
context: context,
barrierDismissible: true,
barrierColor: Colors.black26,
barrierColor: Colors.black.withAlpha(66),
builder: (context) {
return RootAppUpdateDialog(version: latestVersion);
},
Expand Down
Loading

0 comments on commit bf94a49

Please sign in to comment.