From 7d05c40dc0d04208b059f2483c1e4de199c8b51d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 10:02:11 +0600 Subject: [PATCH] fix: use CustomScrollView for personalized page --- lib/extensions/string.dart | 11 +++ lib/pages/home/personalized.dart | 95 +++++++++++-------- .../sourced_track/sources/jiosaavn.dart | 15 +-- pubspec.lock | 8 ++ pubspec.yaml | 1 + 5 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 lib/extensions/string.dart diff --git a/lib/extensions/string.dart b/lib/extensions/string.dart new file mode 100644 index 000000000..b7ab75146 --- /dev/null +++ b/lib/extensions/string.dart @@ -0,0 +1,11 @@ +import 'package:html_unescape/html_unescape.dart'; + +final htmlEscape = HtmlUnescape(); + +extension UnescapeHtml on String { + String unescapeHtml() => htmlEscape.convert(this); +} + +extension NullableUnescapeHtml on String? { + String? unescapeHtml() => this == null ? null : htmlEscape.convert(this!); +} diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 16cfc3a8d..7fbd27aee 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -46,47 +46,64 @@ class PersonalizedPage extends HookConsumerWidget { [newReleases.pages], ); - return ListView( + return CustomScrollView( controller: controller, - children: [ - if (!featuredPlaylistsQuery.hasPageData && - !featuredPlaylistsQuery.isLoadingNextPage) - const ShimmerCategories() - else - HorizontalPlaybuttonCardView( - items: playlists.toList(), - title: Text(context.l10n.featured), - isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, - hasNextPage: featuredPlaylistsQuery.hasNextPage, - onFetchMore: featuredPlaylistsQuery.fetchNext, + slivers: [ + SliverList.list( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: !featuredPlaylistsQuery.hasPageData && + !featuredPlaylistsQuery.isLoadingNextPage + ? const ShimmerCategories() + : HorizontalPlaybuttonCardView( + items: playlists.toList(), + title: Text(context.l10n.featured), + isLoadingNextPage: + featuredPlaylistsQuery.isLoadingNextPage, + hasNextPage: featuredPlaylistsQuery.hasNextPage, + onFetchMore: featuredPlaylistsQuery.fetchNext, + ), + ), + if (auth != null) + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: newReleases.hasPageData && + userArtistsQuery.hasData && + !newReleases.isLoadingNextPage + ? HorizontalPlaybuttonCardView( + items: albums, + title: Text(context.l10n.new_releases), + isLoadingNextPage: newReleases.isLoadingNextPage, + hasNextPage: newReleases.hasNextPage, + onFetchMore: newReleases.fetchNext, + ) + : const ShimmerCategories(), + ), + ], + ), + SliverSafeArea( + sliver: SliverList.builder( + itemCount: madeForUser.data?["content"]?["items"]?.length ?? 0, + itemBuilder: (context, index) { + final item = madeForUser.data?["content"]?["items"]?[index]; + final playlists = item["content"]?["items"] + ?.where((itemL2) => itemL2["type"] == "playlist") + .map((itemL2) => PlaylistSimple.fromJson(itemL2)) + .toList() + .cast() ?? + []; + if (playlists.isEmpty) return const SizedBox.shrink(); + return HorizontalPlaybuttonCardView( + items: playlists, + title: Text(item["name"] ?? ""), + hasNextPage: false, + isLoadingNextPage: false, + onFetchMore: () {}, + ); + }, ), - if (auth != null && - newReleases.hasPageData && - userArtistsQuery.hasData && - !newReleases.isLoadingNextPage) - HorizontalPlaybuttonCardView( - items: albums, - title: Text(context.l10n.new_releases), - isLoadingNextPage: newReleases.isLoadingNextPage, - hasNextPage: newReleases.hasNextPage, - onFetchMore: newReleases.fetchNext, - ), - ...?madeForUser.data?["content"]?["items"]?.map((item) { - final playlists = item["content"]?["items"] - ?.where((itemL2) => itemL2["type"] == "playlist") - .map((itemL2) => PlaylistSimple.fromJson(itemL2)) - .toList() - .cast() ?? - []; - if (playlists.isEmpty) return const SizedBox.shrink(); - return HorizontalPlaybuttonCardView( - items: playlists, - title: Text(item["name"] ?? ""), - hasNextPage: false, - isLoadingNextPage: false, - onFetchMore: () {}, - ); - }) + ), ], ); } diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index 01c041adc..a447b0c19 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -8,6 +8,7 @@ import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/source_map.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:jiosaavn/jiosaavn.dart'; +import 'package:spotube/extensions/string.dart'; final jiosaavnClient = JioSaavnClient(); @@ -74,14 +75,14 @@ class JioSaavnSourcedTrack extends SourcedTrack { result.primaryArtists, if (result.featuredArtists.isNotEmpty) ", ", result.featuredArtists - ].join("").replaceAll("&", "&"), + ].join("").unescapeHtml(), artistUrl: "https://www.jiosaavn.com/artist/${result.primaryArtistsId.split(",").firstOrNull ?? ""}", duration: Duration(seconds: int.parse(result.duration)), id: result.id, pageUrl: result.url, thumbnail: result.image?.last.link ?? "", - title: result.name!, + title: result.name!.unescapeHtml(), album: result.album.name, ), source: SourceMap( @@ -115,10 +116,12 @@ class JioSaavnSourcedTrack extends SourcedTrack { return results .where( (s) { - final sameName = s.name?.replaceAll("&", "&") == track.name; - final artistNames = - "${s.primaryArtists}${s.featuredArtists.isNotEmpty ? ", " : ""}${s.featuredArtists}" - .replaceAll("&", "&"); + final sameName = s.name?.unescapeHtml() == track.name; + final artistNames = [ + s.primaryArtists, + if (s.featuredArtists.isNotEmpty) ", ", + s.featuredArtists + ].join("").unescapeHtml(); final sameArtists = artistNames.split(", ").any( (artist) => trackArtistNames?.any((ar) => artist == ar) ?? false, diff --git a/pubspec.lock b/pubspec.lock index 19b52a8d1..6c822604c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1058,6 +1058,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.4" + html_unescape: + dependency: "direct main" + description: + name: html_unescape + sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" + url: "https://pub.dev" + source: hosted + version: "2.0.0" http: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index eb26c94f6..6a33d294b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -118,6 +118,7 @@ dependencies: dart_discord_rpc: git: url: https://github.com/Tommypop2/dart_discord_rpc.git + html_unescape: ^2.0.0 dev_dependencies: build_runner: ^2.3.2