mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-08 16:24:36 +00:00
feat: use providers in artist page
This commit is contained in:
parent
84cb8d7988
commit
786342912b
@ -12,7 +12,7 @@ import 'package:spotube/pages/artist/section/footer.dart';
|
|||||||
import 'package:spotube/pages/artist/section/header.dart';
|
import 'package:spotube/pages/artist/section/header.dart';
|
||||||
import 'package:spotube/pages/artist/section/related_artists.dart';
|
import 'package:spotube/pages/artist/section/related_artists.dart';
|
||||||
import 'package:spotube/pages/artist/section/top_tracks.dart';
|
import 'package:spotube/pages/artist/section/top_tracks.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class ArtistPage extends HookConsumerWidget {
|
class ArtistPage extends HookConsumerWidget {
|
||||||
final String artistId;
|
final String artistId;
|
||||||
@ -24,7 +24,7 @@ class ArtistPage extends HookConsumerWidget {
|
|||||||
final scrollController = useScrollController();
|
final scrollController = useScrollController();
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
final artistQuery = useQueries.artist.get(ref, artistId);
|
final artistQuery = ref.watch(artistProvider(artistId));
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
@ -35,11 +35,11 @@ class ArtistPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
body: Builder(builder: (context) {
|
body: Builder(builder: (context) {
|
||||||
if (artistQuery.hasError && artistQuery.data == null) {
|
if (artistQuery.hasError && artistQuery.value == null) {
|
||||||
return Center(child: Text(artistQuery.error.toString()));
|
return Center(child: Text(artistQuery.error.toString()));
|
||||||
}
|
}
|
||||||
return Skeletonizer(
|
return Skeletonizer(
|
||||||
enabled: artistQuery.isLoading,
|
enabled: artistQuery.isLoadingAndEmpty,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
@ -66,11 +66,11 @@ class ArtistPage extends HookConsumerWidget {
|
|||||||
SliverSafeArea(
|
SliverSafeArea(
|
||||||
sliver: ArtistPageRelatedArtists(artistId: artistId),
|
sliver: ArtistPageRelatedArtists(artistId: artistId),
|
||||||
),
|
),
|
||||||
if (artistQuery.data != null)
|
if (artistQuery.value != null)
|
||||||
SliverSafeArea(
|
SliverSafeArea(
|
||||||
top: false,
|
top: false,
|
||||||
sliver: SliverToBoxAdapter(
|
sliver: SliverToBoxAdapter(
|
||||||
child: ArtistPageFooter(artist: artistQuery.data!),
|
child: ArtistPageFooter(artist: artistQuery.value!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -5,11 +5,11 @@ import 'package:spotify/spotify.dart';
|
|||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class ArtistPageFooter extends HookConsumerWidget {
|
class ArtistPageFooter extends ConsumerWidget {
|
||||||
final Artist artist;
|
final Artist artist;
|
||||||
const ArtistPageFooter({super.key, required this.artist});
|
const ArtistPageFooter({super.key, required this.artist});
|
||||||
|
|
||||||
@ -22,8 +22,9 @@ class ArtistPageFooter extends HookConsumerWidget {
|
|||||||
artist.images,
|
artist.images,
|
||||||
placeholder: ImagePlaceholder.artist,
|
placeholder: ImagePlaceholder.artist,
|
||||||
);
|
);
|
||||||
final summary = useQueries.artist.wikipediaSummary(artist);
|
final summary = ref.watch(artistWikipediaSummaryProvider(artist));
|
||||||
if (summary.hasError || !summary.hasData) return const SizedBox.shrink();
|
if (summary.value == null) return const SizedBox.shrink();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.all(16),
|
margin: const EdgeInsets.all(16),
|
||||||
padding: mediaQuery.smAndDown
|
padding: mediaQuery.smAndDown
|
||||||
@ -38,9 +39,9 @@ class ArtistPageFooter extends HookConsumerWidget {
|
|||||||
BlendMode.darken,
|
BlendMode.darken,
|
||||||
),
|
),
|
||||||
image: UniversalImage.imageProvider(
|
image: UniversalImage.imageProvider(
|
||||||
summary.data!.thumbnail?.source_ ?? artistImage,
|
summary.value!.thumbnail?.source_ ?? artistImage,
|
||||||
height: summary.data!.thumbnail?.height.toDouble(),
|
height: summary.value!.thumbnail?.height.toDouble(),
|
||||||
width: summary.data!.thumbnail?.width.toDouble(),
|
width: summary.value!.thumbnail?.width.toDouble(),
|
||||||
),
|
),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@ -69,7 +70,7 @@ class ArtistPageFooter extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
const TextSpan(text: '\n\n'),
|
const TextSpan(text: '\n\n'),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: summary.data!.extract,
|
text: summary.value!.extract,
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: '\n...read more at wikipedia',
|
text: '\n...read more at wikipedia',
|
||||||
@ -81,7 +82,7 @@ class ArtistPageFooter extends HookConsumerWidget {
|
|||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () async {
|
..onTap = () async {
|
||||||
await launchUrlString(
|
await launchUrlString(
|
||||||
"http://en.wikipedia.org/wiki?curid=${summary.data?.pageid}",
|
"http://en.wikipedia.org/wiki?curid=${summary.value?.pageid}",
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import 'package:fl_query_hooks/fl_query_hooks.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
|
||||||
import 'package:spotube/collections/fake.dart';
|
import 'package:spotube/collections/fake.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
@ -14,8 +11,7 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/hooks/utils/use_breakpoint_value.dart';
|
import 'package:spotube/hooks/utils/use_breakpoint_value.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/provider/blacklist_provider.dart';
|
import 'package:spotube/provider/blacklist_provider.dart';
|
||||||
import 'package:spotube/provider/spotify_provider.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
|
||||||
import 'package:spotube/utils/primitive_utils.dart';
|
import 'package:spotube/utils/primitive_utils.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
@ -25,9 +21,8 @@ class ArtistPageHeader extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final queryClient = useQueryClient();
|
final artistQuery = ref.watch(artistProvider(artistId));
|
||||||
final artistQuery = useQueries.artist.get(ref, artistId);
|
final artist = artistQuery.value ?? FakeData.artist;
|
||||||
final artist = artistQuery.data ?? FakeData.artist;
|
|
||||||
|
|
||||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
@ -43,7 +38,6 @@ class ArtistPageHeader extends HookConsumerWidget {
|
|||||||
xxl: textTheme.titleMedium,
|
xxl: textTheme.titleMedium,
|
||||||
);
|
);
|
||||||
|
|
||||||
final spotify = ref.read(spotifyProvider);
|
|
||||||
final auth = ref.watch(AuthenticationNotifier.provider);
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
final blacklist = ref.watch(BlackListNotifier.provider);
|
final blacklist = ref.watch(BlackListNotifier.provider);
|
||||||
final isBlackListed = blacklist.contains(
|
final isBlackListed = blacklist.contains(
|
||||||
@ -143,53 +137,41 @@ class ArtistPageHeader extends HookConsumerWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (auth != null)
|
if (auth != null)
|
||||||
HookBuilder(
|
Consumer(
|
||||||
builder: (context) {
|
builder: (context, ref, _) {
|
||||||
final isFollowingQuery =
|
final isFollowingQuery = ref
|
||||||
useQueries.artist.doIFollow(ref, artistId);
|
.watch(artistIsFollowingProvider(artist.id!));
|
||||||
|
final followingArtistNotifier =
|
||||||
|
ref.watch(followedArtistsProvider.notifier);
|
||||||
|
|
||||||
final followUnfollow = useCallback(() async {
|
return switch (isFollowingQuery) {
|
||||||
try {
|
AsyncData(value: final following) => Builder(
|
||||||
isFollowingQuery.data!
|
builder: (context) {
|
||||||
? await spotify.me.unfollow(
|
if (following) {
|
||||||
FollowingType.artist,
|
return OutlinedButton(
|
||||||
[artistId],
|
onPressed: () async {
|
||||||
)
|
await followingArtistNotifier
|
||||||
: await spotify.me.follow(
|
.removeArtists([artist.id!]);
|
||||||
FollowingType.artist,
|
},
|
||||||
[artistId],
|
child: Text(context.l10n.following),
|
||||||
);
|
);
|
||||||
await isFollowingQuery.refresh();
|
}
|
||||||
|
|
||||||
queryClient.refreshInfiniteQueryAllPages(
|
return FilledButton(
|
||||||
"user-following-artists");
|
onPressed: () async {
|
||||||
} finally {
|
await followingArtistNotifier
|
||||||
queryClient.refreshQuery(
|
.saveArtists([artist.id!]);
|
||||||
"user-follows-artists-query/$artistId",
|
},
|
||||||
);
|
child: Text(context.l10n.follow),
|
||||||
}
|
);
|
||||||
}, [isFollowingQuery]);
|
},
|
||||||
|
),
|
||||||
if (isFollowingQuery.isLoading ||
|
AsyncError() => const SizedBox(),
|
||||||
!isFollowingQuery.hasData) {
|
_ => const SizedBox.square(
|
||||||
return const SizedBox(
|
dimension: 20,
|
||||||
height: 20,
|
child: CircularProgressIndicator(),
|
||||||
width: 20,
|
)
|
||||||
child: CircularProgressIndicator(),
|
};
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFollowingQuery.data!) {
|
|
||||||
return OutlinedButton(
|
|
||||||
onPressed: followUnfollow,
|
|
||||||
child: Text(context.l10n.following),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FilledButton(
|
|
||||||
onPressed: followUnfollow,
|
|
||||||
child: Text(context.l10n.follow),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotube/components/artist/artist_card.dart';
|
import 'package:spotube/components/artist/artist_card.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class ArtistPageRelatedArtists extends HookConsumerWidget {
|
class ArtistPageRelatedArtists extends ConsumerWidget {
|
||||||
final String artistId;
|
final String artistId;
|
||||||
const ArtistPageRelatedArtists({
|
const ArtistPageRelatedArtists({
|
||||||
super.key,
|
super.key,
|
||||||
@ -12,38 +12,34 @@ class ArtistPageRelatedArtists extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final relatedArtists = useQueries.artist.relatedArtistsOf(
|
final relatedArtists = ref.watch(relatedArtistsProvider(artistId));
|
||||||
ref,
|
|
||||||
artistId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (relatedArtists.isLoading || !relatedArtists.hasData) {
|
return switch (relatedArtists) {
|
||||||
return const SliverToBoxAdapter(
|
AsyncData(value: final artists) => SliverPadding(
|
||||||
child: Center(child: CircularProgressIndicator()));
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
} else if (relatedArtists.hasError) {
|
sliver: SliverGrid.builder(
|
||||||
return SliverToBoxAdapter(
|
itemCount: artists.length,
|
||||||
child: Center(
|
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
child: Text(relatedArtists.error.toString()),
|
maxCrossAxisExtent: 200,
|
||||||
|
mainAxisExtent: 250,
|
||||||
|
mainAxisSpacing: 10,
|
||||||
|
crossAxisSpacing: 10,
|
||||||
|
childAspectRatio: 0.8,
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final artist = artists.elementAt(index);
|
||||||
|
return ArtistCard(artist);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
AsyncError(:final error) => SliverToBoxAdapter(
|
||||||
}
|
child: Center(
|
||||||
|
child: Text(error.toString()),
|
||||||
return SliverPadding(
|
),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
||||||
sliver: SliverGrid.builder(
|
|
||||||
itemCount: relatedArtists.data!.length,
|
|
||||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent: 200,
|
|
||||||
mainAxisExtent: 250,
|
|
||||||
mainAxisSpacing: 10,
|
|
||||||
crossAxisSpacing: 10,
|
|
||||||
childAspectRatio: 0.8,
|
|
||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
_ => const SliverToBoxAdapter(
|
||||||
final artist = relatedArtists.data!.elementAt(index);
|
child: Center(child: CircularProgressIndicator()),
|
||||||
return ArtistCard(artist);
|
),
|
||||||
},
|
};
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import 'package:spotube/collections/spotube_icons.dart';
|
|||||||
import 'package:spotube/components/shared/track_tile/track_tile.dart';
|
import 'package:spotube/components/shared/track_tile/track_tile.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class ArtistPageTopTracks extends HookConsumerWidget {
|
class ArtistPageTopTracks extends HookConsumerWidget {
|
||||||
final String artistId;
|
final String artistId;
|
||||||
@ -20,13 +20,10 @@ class ArtistPageTopTracks extends HookConsumerWidget {
|
|||||||
|
|
||||||
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
|
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
|
||||||
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
|
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
|
||||||
final topTracksQuery = useQueries.artist.topTracksOf(
|
final topTracksQuery = ref.watch(artistTopTracksProvider(artistId));
|
||||||
ref,
|
|
||||||
artistId,
|
|
||||||
);
|
|
||||||
|
|
||||||
final isPlaylistPlaying = playlist.containsTracks(
|
final isPlaylistPlaying = playlist.containsTracks(
|
||||||
topTracksQuery.data ?? <Track>[],
|
topTracksQuery.value ?? <Track>[],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (topTracksQuery.hasError) {
|
if (topTracksQuery.hasError) {
|
||||||
@ -38,7 +35,7 @@ class ArtistPageTopTracks extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final topTracks =
|
final topTracks =
|
||||||
topTracksQuery.data ?? List.generate(10, (index) => FakeData.track);
|
topTracksQuery.value ?? List.generate(10, (index) => FakeData.track);
|
||||||
|
|
||||||
void playPlaylist(List<Track> tracks, {Track? currentTrack}) async {
|
void playPlaylist(List<Track> tracks, {Track? currentTrack}) async {
|
||||||
currentTrack ??= tracks.first;
|
currentTrack ??= tracks.first;
|
||||||
|
|||||||
@ -64,6 +64,29 @@ class FollowedArtistsNotifier
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (final id in artistIds) {
|
||||||
|
ref.invalidate(artistIsFollowingProvider(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeArtists(List<String> artistIds) async {
|
||||||
|
if (state.value == null) return;
|
||||||
|
await spotify.me.unfollow(FollowingType.artist, artistIds);
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(() async {
|
||||||
|
final artists = state.value!.items.where((artist) {
|
||||||
|
return !artistIds.contains(artist.id);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
return state.value!.copyWith(
|
||||||
|
items: artists,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (final id in artistIds) {
|
||||||
|
ref.invalidate(artistIsFollowingProvider(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
lib/provider/spotify/artist/related.dart
Normal file
9
lib/provider/spotify/artist/related.dart
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
part of '../spotify.dart';
|
||||||
|
|
||||||
|
final relatedArtistsProvider =
|
||||||
|
FutureProvider.family<List<Artist>, String>((ref, artistId) async {
|
||||||
|
final spotify = ref.watch(spotifyProvider);
|
||||||
|
final artists = await spotify.artists.relatedArtists(artistId);
|
||||||
|
|
||||||
|
return artists.toList();
|
||||||
|
});
|
||||||
@ -1,6 +1,6 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
final artistTopTracksProvider = FutureProviderFamily<List<TrackSimple>, String>(
|
final artistTopTracksProvider = FutureProviderFamily<List<Track>, String>(
|
||||||
(ref, artistId) async {
|
(ref, artistId) async {
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final spotify = ref.watch(spotifyProvider);
|
||||||
final market = ref
|
final market = ref
|
||||||
|
|||||||
12
lib/provider/spotify/artist/wikipedia.dart
Normal file
12
lib/provider/spotify/artist/wikipedia.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
part of '../spotify.dart';
|
||||||
|
|
||||||
|
final artistWikipediaSummaryProvider = FutureProvider.autoDispose
|
||||||
|
.family<Summary?, ArtistSimple>((ref, artist) async {
|
||||||
|
final query = artist.name!.replaceAll(" ", "_");
|
||||||
|
final res = await wikipedia.pageContent.pageSummaryTitleGet(query);
|
||||||
|
|
||||||
|
if (res?.type != "standard") {
|
||||||
|
return await wikipedia.pageContent.pageSummaryTitleGet("${query}_(singer)");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
@ -18,9 +18,11 @@ import 'package:spotube/models/spotify_friends.dart';
|
|||||||
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
|
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
|
||||||
import 'package:spotube/provider/spotify_provider.dart';
|
import 'package:spotube/provider/spotify_provider.dart';
|
||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
|
import 'package:spotube/services/wikipedia/wikipedia.dart';
|
||||||
import 'package:spotube/utils/persisted_state_notifier.dart';
|
import 'package:spotube/utils/persisted_state_notifier.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
import 'package:wikipedia_api/wikipedia_api.dart';
|
||||||
|
|
||||||
part 'album/favorite.dart';
|
part 'album/favorite.dart';
|
||||||
part 'album/tracks.dart';
|
part 'album/tracks.dart';
|
||||||
@ -32,6 +34,8 @@ part 'artist/is_following.dart';
|
|||||||
part 'artist/following.dart';
|
part 'artist/following.dart';
|
||||||
part 'artist/top_tracks.dart';
|
part 'artist/top_tracks.dart';
|
||||||
part 'artist/albums.dart';
|
part 'artist/albums.dart';
|
||||||
|
part 'artist/wikipedia.dart';
|
||||||
|
part 'artist/related.dart';
|
||||||
|
|
||||||
part 'category/genres.dart';
|
part 'category/genres.dart';
|
||||||
part 'category/categories.dart';
|
part 'category/categories.dart';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user