fix: use CustomScrollView for personalized page

This commit is contained in:
Kingkor Roy Tirtho 2023-11-22 10:02:11 +06:00
parent 88b8785cb8
commit 7d05c40dc0
5 changed files with 85 additions and 45 deletions

View File

@ -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!);
}

View File

@ -46,47 +46,64 @@ class PersonalizedPage extends HookConsumerWidget {
[newReleases.pages], [newReleases.pages],
); );
return ListView( return CustomScrollView(
controller: controller, controller: controller,
children: [ slivers: [
if (!featuredPlaylistsQuery.hasPageData && SliverList.list(
!featuredPlaylistsQuery.isLoadingNextPage) children: [
const ShimmerCategories() AnimatedSwitcher(
else duration: const Duration(milliseconds: 300),
HorizontalPlaybuttonCardView<PlaylistSimple>( child: !featuredPlaylistsQuery.hasPageData &&
items: playlists.toList(), !featuredPlaylistsQuery.isLoadingNextPage
title: Text(context.l10n.featured), ? const ShimmerCategories()
isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, : HorizontalPlaybuttonCardView<PlaylistSimple>(
hasNextPage: featuredPlaylistsQuery.hasNextPage, items: playlists.toList(),
onFetchMore: featuredPlaylistsQuery.fetchNext, 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<Album>(
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<PlaylistSimple>() ??
<PlaylistSimple>[];
if (playlists.isEmpty) return const SizedBox.shrink();
return HorizontalPlaybuttonCardView<PlaylistSimple>(
items: playlists,
title: Text(item["name"] ?? ""),
hasNextPage: false,
isLoadingNextPage: false,
onFetchMore: () {},
);
},
), ),
if (auth != null && ),
newReleases.hasPageData &&
userArtistsQuery.hasData &&
!newReleases.isLoadingNextPage)
HorizontalPlaybuttonCardView<Album>(
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<PlaylistSimple>() ??
<PlaylistSimple>[];
if (playlists.isEmpty) return const SizedBox.shrink();
return HorizontalPlaybuttonCardView<PlaylistSimple>(
items: playlists,
title: Text(item["name"] ?? ""),
hasNextPage: false,
isLoadingNextPage: false,
onFetchMore: () {},
);
})
], ],
); );
} }

View File

@ -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/models/source_map.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart';
import 'package:jiosaavn/jiosaavn.dart'; import 'package:jiosaavn/jiosaavn.dart';
import 'package:spotube/extensions/string.dart';
final jiosaavnClient = JioSaavnClient(); final jiosaavnClient = JioSaavnClient();
@ -74,14 +75,14 @@ class JioSaavnSourcedTrack extends SourcedTrack {
result.primaryArtists, result.primaryArtists,
if (result.featuredArtists.isNotEmpty) ", ", if (result.featuredArtists.isNotEmpty) ", ",
result.featuredArtists result.featuredArtists
].join("").replaceAll("&amp;", "&"), ].join("").unescapeHtml(),
artistUrl: artistUrl:
"https://www.jiosaavn.com/artist/${result.primaryArtistsId.split(",").firstOrNull ?? ""}", "https://www.jiosaavn.com/artist/${result.primaryArtistsId.split(",").firstOrNull ?? ""}",
duration: Duration(seconds: int.parse(result.duration)), duration: Duration(seconds: int.parse(result.duration)),
id: result.id, id: result.id,
pageUrl: result.url, pageUrl: result.url,
thumbnail: result.image?.last.link ?? "", thumbnail: result.image?.last.link ?? "",
title: result.name!, title: result.name!.unescapeHtml(),
album: result.album.name, album: result.album.name,
), ),
source: SourceMap( source: SourceMap(
@ -115,10 +116,12 @@ class JioSaavnSourcedTrack extends SourcedTrack {
return results return results
.where( .where(
(s) { (s) {
final sameName = s.name?.replaceAll("&amp;", "&") == track.name; final sameName = s.name?.unescapeHtml() == track.name;
final artistNames = final artistNames = [
"${s.primaryArtists}${s.featuredArtists.isNotEmpty ? ", " : ""}${s.featuredArtists}" s.primaryArtists,
.replaceAll("&amp;", "&"); if (s.featuredArtists.isNotEmpty) ", ",
s.featuredArtists
].join("").unescapeHtml();
final sameArtists = artistNames.split(", ").any( final sameArtists = artistNames.split(", ").any(
(artist) => (artist) =>
trackArtistNames?.any((ar) => artist == ar) ?? false, trackArtistNames?.any((ar) => artist == ar) ?? false,

View File

@ -1058,6 +1058,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.15.4" 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: http:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -118,6 +118,7 @@ dependencies:
dart_discord_rpc: dart_discord_rpc:
git: git:
url: https://github.com/Tommypop2/dart_discord_rpc.git url: https://github.com/Tommypop2/dart_discord_rpc.git
html_unescape: ^2.0.0
dev_dependencies: dev_dependencies:
build_runner: ^2.3.2 build_runner: ^2.3.2