mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
expanded Cached netwrok request support
This commit is contained in:
parent
20ada95312
commit
9224b4c316
@ -18,6 +18,7 @@ import 'package:spotube/hooks/useForceUpdate.dart';
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/provider/Playback.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
import 'package:spotube/provider/SpotifyRequests.dart';
|
||||
|
||||
class ArtistProfile extends HookConsumerWidget {
|
||||
final String artistId;
|
||||
@ -49,296 +50,283 @@ class ArtistProfile extends HookConsumerWidget {
|
||||
final breakpoint = useBreakpoints();
|
||||
final update = useForceUpdate();
|
||||
|
||||
final Playback playback = ref.watch(playbackProvider);
|
||||
|
||||
final artistsSnapshot = ref.watch(artistProfileQuery(artistId));
|
||||
final isFollowingSnapshot =
|
||||
ref.watch(currentUserFollowsArtistQuery(artistId));
|
||||
final topTracksSnapshot = ref.watch(artistTopTracksQuery(artistId));
|
||||
final albums = ref.watch(artistAlbumsQuery(artistId));
|
||||
final relatedArtists = ref.watch(artistRelatedArtistsQuery(artistId));
|
||||
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
leading: BackButton(),
|
||||
),
|
||||
body: FutureBuilder<Artist>(
|
||||
future: spotify.artists.get(artistId),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
controller: parentScrollController,
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
runAlignment: WrapAlignment.center,
|
||||
children: [
|
||||
const SizedBox(width: 50),
|
||||
CircleAvatar(
|
||||
radius: avatarWidth,
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
imageToUrlString(snapshot.data!.images),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.circular(50)),
|
||||
child: Text(snapshot.data!.type!.toUpperCase(),
|
||||
style: chipTextVariant?.copyWith(
|
||||
color: Colors.white)),
|
||||
),
|
||||
Text(
|
||||
snapshot.data!.name!,
|
||||
style: breakpoint.isSm
|
||||
? textTheme.headline4
|
||||
: textTheme.headline2,
|
||||
),
|
||||
Text(
|
||||
"${toReadableNumber(snapshot.data!.followers!.total!.toDouble())} followers",
|
||||
style: breakpoint.isSm
|
||||
? textTheme.bodyText1
|
||||
: textTheme.headline5,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
FutureBuilder<List<bool>>(
|
||||
future: spotify.me.isFollowing(
|
||||
FollowingType.artist,
|
||||
[artistId],
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
final isFollowing =
|
||||
snapshot.data?.first == true;
|
||||
return OutlinedButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
isFollowing
|
||||
? await spotify.me.unfollow(
|
||||
FollowingType.artist,
|
||||
[artistId],
|
||||
)
|
||||
: await spotify.me.follow(
|
||||
FollowingType.artist,
|
||||
[artistId],
|
||||
);
|
||||
} catch (e, stack) {
|
||||
logger.e(
|
||||
"FollowButton.onPressed",
|
||||
e,
|
||||
stack,
|
||||
);
|
||||
} finally {
|
||||
update();
|
||||
}
|
||||
},
|
||||
child: snapshot.hasData
|
||||
? Text(isFollowing
|
||||
? "Following"
|
||||
: "Follow")
|
||||
: const CircularProgressIndicator
|
||||
.adaptive(),
|
||||
);
|
||||
}),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.share_rounded),
|
||||
onPressed: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: snapshot
|
||||
.data?.externalUrls?.spotify),
|
||||
).then((val) {
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(
|
||||
const SnackBar(
|
||||
width: 300,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
content: Text(
|
||||
"Artist URL copied to clipboard",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
FutureBuilder<Iterable<Track>>(
|
||||
future:
|
||||
spotify.artists.getTopTracks(snapshot.data!.id!, "US"),
|
||||
builder: (context, trackSnapshot) {
|
||||
if (!trackSnapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
Playback playback = ref.watch(playbackProvider);
|
||||
var isPlaylistPlaying =
|
||||
playback.currentPlaylist?.id == snapshot.data?.id;
|
||||
playPlaylist(List<Track> tracks,
|
||||
{Track? currentTrack}) async {
|
||||
currentTrack ??= tracks.first;
|
||||
if (!isPlaylistPlaying) {
|
||||
playback.setCurrentPlaylist = CurrentPlaylist(
|
||||
tracks: tracks,
|
||||
id: snapshot.data!.id!,
|
||||
name: "${snapshot.data!.name!} To Tracks",
|
||||
thumbnail: imageToUrlString(snapshot.data?.images),
|
||||
);
|
||||
playback.setCurrentTrack = currentTrack;
|
||||
} else if (isPlaylistPlaying &&
|
||||
currentTrack.id != null &&
|
||||
currentTrack.id != playback.currentTrack?.id) {
|
||||
playback.setCurrentTrack = currentTrack;
|
||||
}
|
||||
await playback.startPlaying();
|
||||
}
|
||||
|
||||
return Column(children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"Top Tracks",
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
child: IconButton(
|
||||
icon: Icon(isPlaylistPlaying
|
||||
? Icons.stop_rounded
|
||||
: Icons.play_arrow_rounded),
|
||||
color: Colors.white,
|
||||
onPressed: trackSnapshot.hasData
|
||||
? () => playPlaylist(
|
||||
trackSnapshot.data!.toList())
|
||||
: null,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
...trackSnapshot.data
|
||||
?.toList()
|
||||
.asMap()
|
||||
.entries
|
||||
.map((track) {
|
||||
String duration =
|
||||
"${track.value.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}";
|
||||
String? thumbnailUrl = imageToUrlString(
|
||||
track.value.album?.images,
|
||||
index:
|
||||
(track.value.album?.images?.length ?? 1) -
|
||||
1);
|
||||
return TrackTile(
|
||||
playback,
|
||||
duration: duration,
|
||||
track: track,
|
||||
thumbnailUrl: thumbnailUrl,
|
||||
onTrackPlayButtonPressed: (currentTrack) =>
|
||||
playPlaylist(
|
||||
trackSnapshot.data!.toList(),
|
||||
currentTrack: track.value,
|
||||
),
|
||||
);
|
||||
}) ??
|
||||
[],
|
||||
]);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Albums",
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text("See All"),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).push(
|
||||
"/artist-album/$artistId",
|
||||
extra: snapshot.data?.name ?? "KRTX",
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder<List<Album>>(
|
||||
future: spotify.artists
|
||||
.albums(snapshot.data!.id!)
|
||||
.getPage(5, 0)
|
||||
.then((al) => al.items?.toList() ?? []),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
return Scrollbar(
|
||||
controller: scrollController,
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: snapshot.data
|
||||
?.map((album) => AlbumCard(album))
|
||||
.toList() ??
|
||||
[],
|
||||
body: artistsSnapshot.when<Widget>(
|
||||
data: (data) {
|
||||
return SingleChildScrollView(
|
||||
controller: parentScrollController,
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
runAlignment: WrapAlignment.center,
|
||||
children: [
|
||||
const SizedBox(width: 50),
|
||||
CircleAvatar(
|
||||
radius: avatarWidth,
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
imageToUrlString(data.images),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Fans also likes",
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder<Iterable<Artist>>(
|
||||
future: spotify.artists.getRelatedArtists(artistId),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: Wrap(
|
||||
spacing: 20,
|
||||
runSpacing: 20,
|
||||
children: snapshot.data
|
||||
?.map((artist) => ArtistCard(artist))
|
||||
.toList() ??
|
||||
[],
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.circular(50)),
|
||||
child: Text(data.type!.toUpperCase(),
|
||||
style: chipTextVariant?.copyWith(
|
||||
color: Colors.white)),
|
||||
),
|
||||
Text(
|
||||
data.name!,
|
||||
style: breakpoint.isSm
|
||||
? textTheme.headline4
|
||||
: textTheme.headline2,
|
||||
),
|
||||
Text(
|
||||
"${toReadableNumber(data.followers!.total!.toDouble())} followers",
|
||||
style: breakpoint.isSm
|
||||
? textTheme.bodyText1
|
||||
: textTheme.headline5,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
isFollowingSnapshot.when(
|
||||
data: (isFollowing) {
|
||||
return OutlinedButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
isFollowing
|
||||
? await spotify.me.unfollow(
|
||||
FollowingType.artist,
|
||||
[artistId],
|
||||
)
|
||||
: await spotify.me.follow(
|
||||
FollowingType.artist,
|
||||
[artistId],
|
||||
);
|
||||
} catch (e, stack) {
|
||||
logger.e(
|
||||
"FollowButton.onPressed",
|
||||
e,
|
||||
stack,
|
||||
);
|
||||
} finally {
|
||||
ref.refresh(
|
||||
currentUserFollowsArtistQuery(
|
||||
artistId),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
isFollowing
|
||||
? "Following"
|
||||
: "Follow",
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) => Container(),
|
||||
loading: () =>
|
||||
const CircularProgressIndicator
|
||||
.adaptive()),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.share_rounded),
|
||||
onPressed: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: data.externalUrls?.spotify),
|
||||
).then((val) {
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(
|
||||
const SnackBar(
|
||||
width: 300,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
content: Text(
|
||||
"Artist URL copied to clipboard",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
topTracksSnapshot.when(
|
||||
data: (topTracks) {
|
||||
final isPlaylistPlaying =
|
||||
playback.currentPlaylist?.id == data.id;
|
||||
playPlaylist(List<Track> tracks,
|
||||
{Track? currentTrack}) async {
|
||||
currentTrack ??= tracks.first;
|
||||
if (!isPlaylistPlaying) {
|
||||
playback.setCurrentPlaylist = CurrentPlaylist(
|
||||
tracks: tracks,
|
||||
id: data.id!,
|
||||
name: "${data.name!} To Tracks",
|
||||
thumbnail: imageToUrlString(data.images),
|
||||
);
|
||||
playback.setCurrentTrack = currentTrack;
|
||||
} else if (isPlaylistPlaying &&
|
||||
currentTrack.id != null &&
|
||||
currentTrack.id != playback.currentTrack?.id) {
|
||||
playback.setCurrentTrack = currentTrack;
|
||||
}
|
||||
await playback.startPlaying();
|
||||
}
|
||||
|
||||
return Column(children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"Top Tracks",
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
Container(
|
||||
margin:
|
||||
const EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
child: IconButton(
|
||||
icon: Icon(isPlaylistPlaying
|
||||
? Icons.stop_rounded
|
||||
: Icons.play_arrow_rounded),
|
||||
color: Colors.white,
|
||||
onPressed: () =>
|
||||
playPlaylist(topTracks.toList()),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
...topTracks.toList().asMap().entries.map((track) {
|
||||
String duration =
|
||||
"${track.value.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}";
|
||||
String? thumbnailUrl = imageToUrlString(
|
||||
track.value.album?.images,
|
||||
index:
|
||||
(track.value.album?.images?.length ?? 1) -
|
||||
1);
|
||||
return TrackTile(
|
||||
playback,
|
||||
duration: duration,
|
||||
track: track,
|
||||
thumbnailUrl: thumbnailUrl,
|
||||
onTrackPlayButtonPressed: (currentTrack) =>
|
||||
playPlaylist(
|
||||
topTracks.toList(),
|
||||
currentTrack: track.value,
|
||||
),
|
||||
);
|
||||
}),
|
||||
]);
|
||||
},
|
||||
error: (error, stack) =>
|
||||
Text("Failed to find top tracks $error"),
|
||||
loading: () => const Center(
|
||||
child: CircularProgressIndicator.adaptive()),
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Albums",
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text("See All"),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).push(
|
||||
"/artist-album/$artistId",
|
||||
extra: data.name ?? "KRTX",
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
albums.when(
|
||||
data: (albums) {
|
||||
return Scrollbar(
|
||||
controller: scrollController,
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: albums.items
|
||||
?.map((album) => AlbumCard(album))
|
||||
.toList() ??
|
||||
[],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (error, stackTrack) =>
|
||||
Text("Failed to get Artist albums $error"),
|
||||
loading: () => const CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Fans also likes",
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
relatedArtists.when(
|
||||
data: (artists) {
|
||||
return Center(
|
||||
child: Wrap(
|
||||
spacing: 20,
|
||||
runSpacing: 20,
|
||||
children: artists
|
||||
.map((artist) => ArtistCard(artist))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (error, stackTrack) =>
|
||||
Text("Failed to get Artist albums $error"),
|
||||
loading: () => const CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (_, __) => const Text("Life's miserable"),
|
||||
loading: () =>
|
||||
const Center(child: CircularProgressIndicator.adaptive())),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -34,11 +34,10 @@ class CategoryCard extends HookConsumerWidget {
|
||||
),
|
||||
ref: ref,
|
||||
firstPageKey: 0,
|
||||
onData: (data, pagingController, pageKey) {
|
||||
onData: (page, pagingController, pageKey) {
|
||||
if (playlists != null && playlists?.isNotEmpty == true && mounted()) {
|
||||
return pagingController.appendLastPage(playlists!.toList());
|
||||
}
|
||||
final page = data.value;
|
||||
if (page.isLast && page.items != null) {
|
||||
pagingController.appendLastPage(page.items!.toList());
|
||||
} else if (page.items != null) {
|
||||
|
@ -114,8 +114,7 @@ class Home extends HookConsumerWidget {
|
||||
(pageKey) => categoriesQuery(pageKey),
|
||||
ref: ref,
|
||||
firstPageKey: 0,
|
||||
onData: (data, pagingController, pageKey) {
|
||||
final categories = data.value;
|
||||
onData: (categories, pagingController, pageKey) {
|
||||
final items = categories.items?.toList();
|
||||
if (pageKey == 0) {
|
||||
Category category = Category();
|
||||
|
@ -18,8 +18,7 @@ class UserArtists extends HookConsumerWidget {
|
||||
(pageKey) => currentUserFollowingArtistsQuery(pageKey),
|
||||
ref: ref,
|
||||
firstPageKey: "",
|
||||
onData: (data, pagingController, pageKey) {
|
||||
final artists = data.value;
|
||||
onData: (artists, pagingController, pageKey) {
|
||||
final items = artists.items!.toList();
|
||||
|
||||
if (artists.items != null && items.length < 15) {
|
||||
|
@ -8,13 +8,13 @@ PagingController<P, ItemType> usePaginatedFutureProvider<T, P, ItemType>(
|
||||
required P firstPageKey,
|
||||
required WidgetRef ref,
|
||||
void Function(
|
||||
AsyncData<T>,
|
||||
T,
|
||||
PagingController<P, ItemType> pagingController,
|
||||
P pageKey,
|
||||
)?
|
||||
onData,
|
||||
void Function(AsyncError<T>)? onError,
|
||||
void Function(AsyncLoading<T>)? onLoading,
|
||||
void Function(Object)? onError,
|
||||
void Function()? onLoading,
|
||||
}) {
|
||||
final currentPageKey = useState(firstPageKey);
|
||||
final snapshot = ref.watch(createSnapshot(currentPageKey.value));
|
||||
@ -32,10 +32,10 @@ PagingController<P, ItemType> usePaginatedFutureProvider<T, P, ItemType>(
|
||||
}, [snapshot, currentPageKey]);
|
||||
|
||||
useEffect(() {
|
||||
snapshot.mapOrNull(
|
||||
snapshot.whenOrNull(
|
||||
data: (data) =>
|
||||
onData?.call(data, pagingController, currentPageKey.value),
|
||||
error: (error) {
|
||||
error: (error, _) {
|
||||
pagingController.error = error;
|
||||
return onError?.call(error);
|
||||
},
|
||||
|
@ -50,3 +50,44 @@ final currentUserFollowingArtistsQuery =
|
||||
return spotify.me.following(FollowingType.artist).getPage(15, pageKey);
|
||||
},
|
||||
);
|
||||
|
||||
final artistProfileQuery = FutureProvider.autoDispose.family<Artist, String>(
|
||||
(ref, id) {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return spotify.artists.get(id);
|
||||
},
|
||||
);
|
||||
|
||||
final currentUserFollowsArtistQuery =
|
||||
FutureProvider.autoDispose.family<bool, String>(
|
||||
(ref, artistId) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
final result = await spotify.me.isFollowing(
|
||||
FollowingType.artist,
|
||||
[artistId],
|
||||
);
|
||||
return result.first;
|
||||
},
|
||||
);
|
||||
|
||||
final artistTopTracksQuery =
|
||||
FutureProvider.autoDispose.family<Iterable<Track>, String>((ref, id) {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return spotify.artists.getTopTracks(id, "US");
|
||||
});
|
||||
|
||||
final artistAlbumsQuery =
|
||||
FutureProvider.autoDispose.family<Page<Album>, String>(
|
||||
(ref, id) {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return spotify.artists.albums(id).getPage(5, 0);
|
||||
},
|
||||
);
|
||||
|
||||
final artistRelatedArtistsQuery =
|
||||
FutureProvider.autoDispose.family<Iterable<Artist>, String>(
|
||||
(ref, id) {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return spotify.artists.getRelatedArtists(id);
|
||||
},
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user