From bf94a490bbb4d88c028807522f636a349459160e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 6 Jan 2025 20:45:37 +0600 Subject: [PATCH] refactor: genres section --- lib/l10n/app_en.arb | 3 +- lib/modules/home/sections/genres.dart | 217 ++++++++++++++++++++------ lib/utils/service_utils.dart | 14 +- untranslated_messages.json | 78 ++++++--- 4 files changed, 236 insertions(+), 76 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 45a8d78f..c95ec54f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -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" } \ No newline at end of file diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index f0ed1fb3..57006b59 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -4,14 +4,16 @@ 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 { @@ -19,7 +21,8 @@ class HomeGenresSection extends HookConsumerWidget { @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( @@ -28,7 +31,9 @@ class HomeGenresSection extends HookConsumerWidget { .where((c) => (c.icons?.length ?? 0) > 0) .take(mediaQuery.mdAndDown ? 6 : 10) .toList() ?? - [], + [ + FakeData.category, + ], [mediaQuery.mdAndDown, categoriesQuery.asData?.value], ); @@ -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!, - fit: BoxFit.cover, - height: 50, - width: 50, + 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, ), - title: Text(category.name!), + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + colorFilter: ColorFilter.mode( + theme.colorScheme.background.withAlpha(125), + BlendMode.darken, + ), + fit: BoxFit.cover, + ), + ), + 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(), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ) + ], ), ); }, diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index bdc3877a..2abb98ef 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -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'; @@ -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'; @@ -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); } @@ -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); }, @@ -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); }, diff --git a/untranslated_messages.json b/untranslated_messages.json index a31de6a2..ddaf9ab0 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -8,7 +8,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "bn": [ @@ -20,7 +21,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ca": [ @@ -32,7 +34,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "cs": [ @@ -44,7 +47,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "de": [ @@ -56,7 +60,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "es": [ @@ -68,7 +73,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "eu": [ @@ -80,7 +86,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "fa": [ @@ -92,7 +99,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "fi": [ @@ -104,7 +112,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "fr": [ @@ -116,7 +125,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "hi": [ @@ -128,7 +138,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "id": [ @@ -140,7 +151,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "it": [ @@ -152,7 +164,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ja": [ @@ -164,7 +177,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ka": [ @@ -176,7 +190,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ko": [ @@ -188,7 +203,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ne": [ @@ -200,7 +216,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "nl": [ @@ -212,7 +229,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "pl": [ @@ -224,7 +242,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "pt": [ @@ -236,7 +255,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ru": [ @@ -248,7 +268,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "th": [ @@ -260,7 +281,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "tr": [ @@ -272,7 +294,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "uk": [ @@ -284,7 +307,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "vi": [ @@ -296,7 +320,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "zh": [ @@ -308,6 +333,7 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ] }