mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-08 16:24:36 +00:00
feat: use providers on library page
This commit is contained in:
parent
786342912b
commit
4ae530d29d
@ -4,7 +4,6 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
import 'package:fuzzywuzzy/fuzzywuzzy.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';
|
||||||
@ -15,7 +14,7 @@ import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart';
|
|||||||
import 'package:spotube/components/shared/waypoint.dart';
|
import 'package:spotube/components/shared/waypoint.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.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';
|
||||||
|
|
||||||
@ -25,32 +24,28 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final auth = ref.watch(AuthenticationNotifier.provider);
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
final albumsQuery = useQueries.album.ofMine(ref);
|
final albumsQuery = ref.watch(favoriteAlbumsProvider);
|
||||||
|
final albumsQueryNotifier = ref.watch(favoriteAlbumsProvider.notifier);
|
||||||
|
|
||||||
final controller = useScrollController();
|
final controller = useScrollController();
|
||||||
|
|
||||||
final searchText = useState('');
|
final searchText = useState('');
|
||||||
|
|
||||||
final allAlbums = useMemoized(
|
|
||||||
() => albumsQuery.pages
|
|
||||||
.expand((element) => element.items ?? <AlbumSimple>[]),
|
|
||||||
[albumsQuery.pages],
|
|
||||||
);
|
|
||||||
|
|
||||||
final albums = useMemoized(() {
|
final albums = useMemoized(() {
|
||||||
if (searchText.value.isEmpty) {
|
if (searchText.value.isEmpty) {
|
||||||
return allAlbums;
|
return albumsQuery.value?.items ?? [];
|
||||||
}
|
}
|
||||||
return allAlbums
|
return albumsQuery.value?.items
|
||||||
.map((e) => (
|
.map((e) => (
|
||||||
weightedRatio(e.name!, searchText.value),
|
weightedRatio(e.name!, searchText.value),
|
||||||
e,
|
e,
|
||||||
))
|
))
|
||||||
.sorted((a, b) => b.$1.compareTo(a.$1))
|
.sorted((a, b) => b.$1.compareTo(a.$1))
|
||||||
.where((e) => e.$1 > 50)
|
.where((e) => e.$1 > 50)
|
||||||
.map((e) => e.$2)
|
.map((e) => e.$2)
|
||||||
.toList();
|
.toList() ??
|
||||||
}, [allAlbums, searchText.value]);
|
[];
|
||||||
|
}, [albumsQuery.value, searchText.value]);
|
||||||
|
|
||||||
if (auth == null) {
|
if (auth == null) {
|
||||||
return const AnonymousFallback();
|
return const AnonymousFallback();
|
||||||
@ -60,7 +55,7 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await albumsQuery.refresh();
|
ref.invalidate(favoriteAlbumsProvider);
|
||||||
},
|
},
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
@ -85,7 +80,7 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: Skeletonizer(
|
child: Skeletonizer(
|
||||||
enabled: albumsQuery.pages.isEmpty,
|
enabled: albumsQuery.isLoadingAndEmpty,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
runSpacing: 20,
|
runSpacing: 20,
|
||||||
@ -93,7 +88,8 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
runAlignment: WrapAlignment.center,
|
runAlignment: WrapAlignment.center,
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (albumsQuery.pages.isEmpty)
|
if (albumsQuery.value == null ||
|
||||||
|
albumsQuery.value!.items.isEmpty)
|
||||||
...List.generate(
|
...List.generate(
|
||||||
10,
|
10,
|
||||||
(index) => AlbumCard(FakeData.album),
|
(index) => AlbumCard(FakeData.album),
|
||||||
@ -107,11 +103,12 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
AlbumCard(
|
AlbumCard(
|
||||||
TypeConversionUtils.simpleAlbum_X_Album(album),
|
TypeConversionUtils.simpleAlbum_X_Album(album),
|
||||||
),
|
),
|
||||||
if (albums.isNotEmpty && albumsQuery.hasNextPage)
|
if (albums.isNotEmpty &&
|
||||||
|
albumsQuery.value?.hasMore == true)
|
||||||
Waypoint(
|
Waypoint(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
isGrid: true,
|
isGrid: true,
|
||||||
onTouchEdge: albumsQuery.fetchNext,
|
onTouchEdge: albumsQueryNotifier.fetchMore,
|
||||||
child: AlbumCard(FakeData.album),
|
child: AlbumCard(FakeData.album),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import 'package:spotube/components/shared/fallbacks/not_found.dart';
|
|||||||
import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart';
|
import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class UserArtists extends HookConsumerWidget {
|
class UserArtists extends HookConsumerWidget {
|
||||||
const UserArtists({super.key});
|
const UserArtists({super.key});
|
||||||
@ -23,12 +23,12 @@ class UserArtists extends HookConsumerWidget {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final auth = ref.watch(AuthenticationNotifier.provider);
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
|
|
||||||
final artistQuery = useQueries.artist.followedByMeAll(ref);
|
final artistQuery = ref.watch(followedArtistsProvider);
|
||||||
|
|
||||||
final searchText = useState('');
|
final searchText = useState('');
|
||||||
|
|
||||||
final filteredArtists = useMemoized(() {
|
final filteredArtists = useMemoized(() {
|
||||||
final artists = artistQuery.data ?? [];
|
final artists = artistQuery.value?.items ?? [];
|
||||||
|
|
||||||
if (searchText.value.isEmpty) {
|
if (searchText.value.isEmpty) {
|
||||||
return artists.toList();
|
return artists.toList();
|
||||||
@ -42,7 +42,7 @@ class UserArtists extends HookConsumerWidget {
|
|||||||
.where((e) => e.$1 > 50)
|
.where((e) => e.$1 > 50)
|
||||||
.map((e) => e.$2)
|
.map((e) => e.$2)
|
||||||
.toList();
|
.toList();
|
||||||
}, [artistQuery.data, searchText.value]);
|
}, [artistQuery.value?.items, searchText.value]);
|
||||||
|
|
||||||
final controller = useScrollController();
|
final controller = useScrollController();
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ class UserArtists extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: theme.scaffoldBackgroundColor,
|
backgroundColor: theme.scaffoldBackgroundColor,
|
||||||
body: artistQuery.data?.isEmpty == true
|
body: artistQuery.value?.items.isEmpty == true
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -80,7 +80,7 @@ class UserArtists extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
: RefreshIndicator(
|
: RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await artistQuery.refresh();
|
ref.invalidate(followedArtistsProvider);
|
||||||
},
|
},
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
@ -109,8 +109,9 @@ class UserArtists extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
: filteredArtists
|
: filteredArtists
|
||||||
.mapIndexed((index, artist) =>
|
.mapIndexed(
|
||||||
ArtistCard(artist))
|
(index, artist) => ArtistCard(artist),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -217,7 +217,7 @@ class UserLocalTracks extends HookConsumerWidget {
|
|||||||
FilledButton(
|
FilledButton(
|
||||||
child: const Icon(SpotubeIcons.refresh),
|
child: const Icon(SpotubeIcons.refresh),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref.refresh(localTracksProvider);
|
ref.invalidate(localTracksProvider);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -269,7 +269,7 @@ class UserLocalTracks extends HookConsumerWidget {
|
|||||||
return Expanded(
|
return Expanded(
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
ref.refresh(localTracksProvider);
|
ref.invalidate(localTracksProvider);
|
||||||
},
|
},
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import 'package:spotube/components/shared/waypoint.dart';
|
|||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class UserPlaylists extends HookConsumerWidget {
|
class UserPlaylists extends HookConsumerWidget {
|
||||||
const UserPlaylists({super.key});
|
const UserPlaylists({super.key});
|
||||||
@ -28,13 +28,9 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
|
|
||||||
final auth = ref.watch(AuthenticationNotifier.provider);
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
|
|
||||||
final playlistsQuery = useQueries.playlist.ofMine(ref);
|
final playlistsQuery = ref.watch(favoritePlaylistsProvider);
|
||||||
|
final playlistsQueryNotifier =
|
||||||
final pagePlaylists = useMemoized(
|
ref.watch(favoritePlaylistsProvider.notifier);
|
||||||
() => playlistsQuery.pages
|
|
||||||
.expand((page) => page.items?.toList() ?? <PlaylistSimple>[]),
|
|
||||||
[playlistsQuery.pages],
|
|
||||||
);
|
|
||||||
|
|
||||||
final likedTracksPlaylist = useMemoized(
|
final likedTracksPlaylist = useMemoized(
|
||||||
() => PlaylistSimple()
|
() => PlaylistSimple()
|
||||||
@ -58,12 +54,12 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
if (searchText.value.isEmpty) {
|
if (searchText.value.isEmpty) {
|
||||||
return [
|
return [
|
||||||
likedTracksPlaylist,
|
likedTracksPlaylist,
|
||||||
...pagePlaylists,
|
...?playlistsQuery.value?.items,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
likedTracksPlaylist,
|
likedTracksPlaylist,
|
||||||
...pagePlaylists,
|
...?playlistsQuery.value?.items,
|
||||||
]
|
]
|
||||||
.map((e) => (weightedRatio(e.name!, searchText.value), e))
|
.map((e) => (weightedRatio(e.name!, searchText.value), e))
|
||||||
.sorted((a, b) => b.$1.compareTo(a.$1))
|
.sorted((a, b) => b.$1.compareTo(a.$1))
|
||||||
@ -71,7 +67,7 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
.map((e) => e.$2)
|
.map((e) => e.$2)
|
||||||
.toList();
|
.toList();
|
||||||
},
|
},
|
||||||
[pagePlaylists, searchText.value],
|
[playlistsQuery, searchText.value],
|
||||||
);
|
);
|
||||||
|
|
||||||
final controller = useScrollController();
|
final controller = useScrollController();
|
||||||
@ -81,7 +77,9 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: playlistsQuery.refresh,
|
onRefresh: () async {
|
||||||
|
ref.invalidate(favoritePlaylistsProvider);
|
||||||
|
},
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
@ -132,14 +130,14 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (playlists.isNotEmpty && index == playlists.length) {
|
if (playlists.isNotEmpty && index == playlists.length) {
|
||||||
if (!playlistsQuery.hasNextPage) {
|
if (playlistsQuery.value?.hasMore != true) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Waypoint(
|
return Waypoint(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
isGrid: true,
|
isGrid: true,
|
||||||
onTouchEdge: playlistsQuery.fetchNext,
|
onTouchEdge: playlistsQueryNotifier.fetchMore,
|
||||||
child: Skeletonizer(
|
child: Skeletonizer(
|
||||||
enabled: true,
|
enabled: true,
|
||||||
child: PlaylistCard(FakeData.playlistSimple),
|
child: PlaylistCard(FakeData.playlistSimple),
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
|
import 'package:spotube/provider/spotify_provider.dart';
|
||||||
import 'package:spotube/services/custom_spotify_endpoints/spotify_endpoints.dart';
|
import 'package:spotube/services/custom_spotify_endpoints/spotify_endpoints.dart';
|
||||||
|
|
||||||
final customSpotifyEndpointProvider = Provider<CustomSpotifyEndpoints>((ref) {
|
final customSpotifyEndpointProvider = Provider<CustomSpotifyEndpoints>((ref) {
|
||||||
|
ref.watch(spotifyProvider);
|
||||||
final auth = ref.watch(AuthenticationNotifier.provider);
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
return CustomSpotifyEndpoints(auth?.accessToken ?? "");
|
return CustomSpotifyEndpoints(auth?.accessToken ?? "");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
class FollowedArtistsState extends CursorPaginatedState<ArtistSimple> {
|
class FollowedArtistsState extends CursorPaginatedState<Artist> {
|
||||||
FollowedArtistsState({
|
FollowedArtistsState({
|
||||||
required super.items,
|
required super.items,
|
||||||
required super.offset,
|
required super.offset,
|
||||||
@ -10,7 +10,7 @@ class FollowedArtistsState extends CursorPaginatedState<ArtistSimple> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
FollowedArtistsState copyWith({
|
FollowedArtistsState copyWith({
|
||||||
List<ArtistSimple>? items,
|
List<Artist>? items,
|
||||||
String? offset,
|
String? offset,
|
||||||
int? limit,
|
int? limit,
|
||||||
bool? hasMore,
|
bool? hasMore,
|
||||||
@ -25,7 +25,7 @@ class FollowedArtistsState extends CursorPaginatedState<ArtistSimple> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FollowedArtistsNotifier
|
class FollowedArtistsNotifier
|
||||||
extends CursorPaginatedAsyncNotifier<ArtistSimple, FollowedArtistsState> {
|
extends CursorPaginatedAsyncNotifier<Artist, FollowedArtistsState> {
|
||||||
FollowedArtistsNotifier() : super();
|
FollowedArtistsNotifier() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -95,7 +95,7 @@ final followedArtistsProvider =
|
|||||||
() => FollowedArtistsNotifier(),
|
() => FollowedArtistsNotifier(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final allFollowedArtistsProvider = FutureProvider<List<ArtistSimple>>(
|
final allFollowedArtistsProvider = FutureProvider<List<Artist>>(
|
||||||
(ref) async {
|
(ref) async {
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final spotify = ref.watch(spotifyProvider);
|
||||||
final artists = await spotify.me.following(FollowingType.artist).all();
|
final artists = await spotify.me.following(FollowingType.artist).all();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user