refactor: use singleton for Queries and Mutations service classes

This commit is contained in:
Kingkor Roy Tirtho 2023-02-24 15:27:13 +06:00
parent d85867a245
commit 3d9da8b4e3
31 changed files with 161 additions and 146 deletions

View File

@ -21,7 +21,7 @@ class ArtistAlbumList extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final scrollController = useScrollController();
final albumsQuery = Queries.artist.useAlbumsOfQuery(ref, artistId);
final albumsQuery = useQueries.artist.albumsOf(ref, artistId);
final albums = useMemoized(() {
return albumsQuery.pages

View File

@ -24,7 +24,7 @@ class CategoryCard extends HookConsumerWidget {
Widget build(BuildContext context, ref) {
final scrollController = useScrollController();
final spotify = ref.watch(spotifyProvider);
final playlistQuery = Queries.category.usePlaylistsOf(
final playlistQuery = useQueries.category.playlistsOf(
ref,
category.id!,
);

View File

@ -22,7 +22,7 @@ class UserAlbums extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final auth = ref.watch(AuthenticationNotifier.provider);
final albumsQuery = Queries.album.useOfMineQuery(ref);
final albumsQuery = useQueries.album.ofMine(ref);
final spacing = useBreakpointValue<double>(
sm: 0,

View File

@ -20,7 +20,7 @@ class UserArtists extends HookConsumerWidget {
Widget build(BuildContext context, ref) {
final auth = ref.watch(AuthenticationNotifier.provider);
final artistQuery = Queries.artist.useFollowedByMeQuery(ref);
final artistQuery = useQueries.artist.followedByMe(ref);
final hasNextPage = artistQuery.pages.isEmpty
? false

View File

@ -33,7 +33,7 @@ class UserPlaylists extends HookConsumerWidget {
: PlaybuttonCardViewType.square;
final auth = ref.watch(AuthenticationNotifier.provider);
final playlistsQuery = Queries.playlist.useOfMineQuery(ref);
final playlistsQuery = useQueries.playlist.ofMine(ref);
Image image = Image();
image.height = 300;

View File

@ -68,7 +68,7 @@ class PlaylistCard extends HookConsumerWidget {
List<Track> fetchedTracks = await queryBowl.fetchQuery(
"playlist-tracks/${playlist.id}",
() => Queries.playlist.tracksOf(playlist.id!, spotify),
() => useQueries.playlist.tracksOf(playlist.id!, spotify),
) ??
[];
@ -86,7 +86,7 @@ class PlaylistCard extends HookConsumerWidget {
if (isPlaylistPlaying) return;
List<Track> fetchedTracks = await queryBowl.fetchQuery(
"playlist-tracks/${playlist.id}",
() => Queries.playlist.tracksOf(playlist.id!, spotify),
() => useQueries.playlist.tracksOf(playlist.id!, spotify),
) ??
[];

View File

@ -11,7 +11,6 @@ import 'package:spotube/components/shared/image/universal_image.dart';
import 'package:spotube/hooks/use_breakpoints.dart';
import 'package:spotube/provider/authentication_provider.dart';
import 'package:spotube/provider/downloader_provider.dart';
import 'package:spotube/provider/spotify_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/services/queries/queries.dart';
@ -194,8 +193,7 @@ class SidebarFooter extends HookConsumerWidget {
width: 256,
child: HookBuilder(
builder: (context) {
var spotify = ref.watch(spotifyProvider);
final me = Queries.user.useMe(ref);
final me = useQueries.user.me(ref);
final data = me.data;
final avatarImg = TypeConversionUtils.image_X_UrlString(

View File

@ -16,8 +16,8 @@ class PlaylistAddTrackDialog extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final spotify = ref.watch(spotifyProvider);
final userPlaylists = Queries.playlist.useOfMineQuery(ref);
final me = Queries.user.useMe(ref);
final userPlaylists = useQueries.playlist.ofMine(ref);
final me = useQueries.user.me(ref);
final filteredPlaylists = userPlaylists.data?.where(
(playlist) =>
playlist.owner?.id != null && playlist.owner!.id == me.data?.id,

View File

@ -47,17 +47,17 @@ class HeartButton extends ConsumerWidget {
Tuple3<bool, Mutation<bool, dynamic, bool>, Query<User, dynamic>>
useTrackToggleLike(Track track, WidgetRef ref) {
final me = Queries.user.useMe(ref);
final me = useQueries.user.me(ref);
final savedTracks =
Queries.playlist.useTracksOfQuery(ref, "user-liked-tracks");
useQueries.playlist.tracksOfQuery(ref, "user-liked-tracks");
final isLiked =
savedTracks.data?.map((track) => track.id).contains(track.id) ?? false;
final mounted = useIsMounted();
final toggleTrackLike = Mutations.track.useToggleFavorite(
final toggleTrackLike = useMutations.track.toggleFavorite(
ref,
track.id!,
onMutate: (variables) {
@ -92,7 +92,7 @@ class TrackHeartButton extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final savedTracks =
Queries.playlist.useTracksOfQuery(ref, "user-liked-tracks");
useQueries.playlist.tracksOfQuery(ref, "user-liked-tracks");
final toggler = useTrackToggleLike(track, ref);
if (toggler.item3.isLoading || !toggler.item3.hasData) {
return const PlatformCircularProgressIndicator();
@ -120,15 +120,15 @@ class PlaylistHeartButton extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final me = Queries.user.useMe(ref);
final me = useQueries.user.me(ref);
final isLikedQuery = Queries.playlist.useDoesUserFollowQuery(
final isLikedQuery = useQueries.playlist.doesUserFollow(
ref,
playlist.id!,
me.data!.id!,
);
final togglePlaylistLike = Mutations.playlist.useToggleFavorite(
final togglePlaylistLike = useMutations.playlist.toggleFavorite(
ref,
playlist.id!,
refreshQueries: [
@ -178,12 +178,12 @@ class AlbumHeartButton extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final me = Queries.user.useMe(ref);
final me = useQueries.user.me(ref);
final albumIsSaved = Queries.album.useIsSavedForMeQuery(ref, album.id!);
final albumIsSaved = useQueries.album.isSavedForMe(ref, album.id!);
final isLiked = albumIsSaved.data ?? false;
final toggleAlbumLike = Mutations.album.useToggleFavorite(
final toggleAlbumLike = useMutations.album.toggleFavorite(
ref,
album.id!,
refreshQueries: [

View File

@ -73,7 +73,7 @@ class TrackTile extends HookConsumerWidget {
final playlistQueueNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final removingTrack = useState<String?>(null);
final removeTrack = Mutations.playlist.useRemoveTrackOf(
final removeTrack = useMutations.playlist.removeTrackOf(
ref,
playlistId ?? "",
);

View File

@ -1,4 +1,3 @@
import 'package:fl_query_hooks/fl_query_hooks.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@ -12,7 +11,6 @@ import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:spotube/provider/spotify_provider.dart';
class AlbumPage extends HookConsumerWidget {
final AlbumSimple album;
@ -47,7 +45,7 @@ class AlbumPage extends HookConsumerWidget {
ref.watch(PlaylistQueueNotifier.provider);
final playback = ref.watch(PlaylistQueueNotifier.notifier);
final tracksSnapshot = Queries.album.useTracksOfQuery(ref, album.id!);
final tracksSnapshot = useQueries.album.tracksOf(ref, album.id!);
final albumArt = useMemoized(
() => TypeConversionUtils.image_X_UrlString(

View File

@ -64,7 +64,7 @@ class ArtistPage extends HookConsumerWidget {
),
body: HookBuilder(
builder: (context) {
final artistsQuery = Queries.artist.useGetArtist(ref, artistId);
final artistsQuery = useQueries.artist.get(ref, artistId);
if (artistsQuery.isLoading || !artistsQuery.hasData) {
return const ShimmerArtistProfile();
@ -162,8 +162,8 @@ class ArtistPage extends HookConsumerWidget {
if (auth != null)
HookBuilder(
builder: (context) {
final isFollowingQuery = Queries.artist
.useDoIFollowQuery(ref, artistId);
final isFollowingQuery = useQueries.artist
.doIFollow(ref, artistId);
if (isFollowingQuery.isLoading ||
!isFollowingQuery.hasData) {
@ -268,7 +268,7 @@ class ArtistPage extends HookConsumerWidget {
const SizedBox(height: 50),
HookBuilder(
builder: (context) {
final topTracksQuery = Queries.artist.useTopTracksOfQuery(
final topTracksQuery = useQueries.artist.topTracksOf(
ref,
artistId,
);
@ -378,8 +378,7 @@ class ArtistPage extends HookConsumerWidget {
const SizedBox(height: 10),
HookBuilder(
builder: (context) {
final relatedArtists =
Queries.artist.useRelatedArtistsOfQuery(
final relatedArtists = useQueries.artist.relatedArtistsOf(
ref,
artistId,
);

View File

@ -22,11 +22,10 @@ class GenrePage extends HookConsumerWidget {
final recommendationMarket = ref.watch(
userPreferencesProvider.select((s) => s.recommendationMarket),
);
final categoriesQuery = Queries.category.useList(ref, recommendationMarket);
final categoriesQuery = useQueries.category.list(ref, recommendationMarket);
final isMounted = useIsMounted();
return HookBuilder(builder: (context) {
final searchText = useState("");
final categories = useMemoized(
() {
@ -83,6 +82,7 @@ class GenrePage extends HookConsumerWidget {
),
),
);
return Stack(
children: [
Positioned.fill(child: list),
@ -93,6 +93,5 @@ class GenrePage extends HookConsumerWidget {
),
],
);
});
}
}

View File

@ -102,9 +102,9 @@ class PersonalizedPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final featuredPlaylistsQuery = Queries.playlist.useFeaturedQuery(ref);
final featuredPlaylistsQuery = useQueries.playlist.featured(ref);
final newReleases = Queries.album.useNewReleasesQuery(ref);
final newReleases = useQueries.album.newReleases(ref);
return ListView(
children: [

View File

@ -22,7 +22,7 @@ class GeniusLyrics extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final playlist = ref.watch(PlaylistQueueNotifier.provider);
final geniusLyricsQuery = Queries.lyrics.useStatic(
final geniusLyricsQuery = useQueries.lyrics.static(
playlist?.activeTrack,
ref.watch(userPreferencesProvider).geniusAccessToken,
);

View File

@ -44,7 +44,7 @@ class SyncedLyrics extends HookConsumerWidget {
final breakpoint = useBreakpoints();
final controller = useAutoScrollController();
final timedLyricsQuery = Queries.lyrics.useSynced(playlist?.activeTrack);
final timedLyricsQuery = useQueries.lyrics.synced(playlist?.activeTrack);
final lyricValue = timedLyricsQuery.data;
final lyricsMap = useMemoized(
() =>

View File

@ -47,8 +47,8 @@ class PlaylistView extends HookConsumerWidget {
final breakpoint = useBreakpoints();
final meSnapshot = Queries.user.useMe(ref);
final tracksSnapshot = Queries.playlist.useTracksOfQuery(ref, playlist.id!);
final meSnapshot = useQueries.user.me(ref);
final tracksSnapshot = useQueries.playlist.tracksOfQuery(ref, playlist.id!);
final isPlaylistPlaying =
playlistNotifier.isPlayingPlaylist(tracksSnapshot.data ?? []);

View File

@ -4,13 +4,11 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:platform_ui/platform_ui.dart';
import 'package:spotube/collections/side_bar_tiles.dart';
import 'package:spotube/components/shared/dialogs/replace_downloaded_dialog.dart';
import 'package:spotube/components/root/bottom_player.dart';
import 'package:spotube/components/root/sidebar.dart';
import 'package:spotube/components/root/spotube_navigation_bar.dart';
import 'package:spotube/components/shared/page_window_title_bar.dart';
import 'package:spotube/hooks/use_breakpoints.dart';
import 'package:spotube/hooks/use_update_checker.dart';
import 'package:spotube/provider/downloader_provider.dart';

View File

@ -52,19 +52,19 @@ class SearchPage extends HookConsumerWidget {
);
final searchTrack = useInfiniteQuery(
job: Queries.search.get(SearchType.track.key),
job: useQueries.search.get(SearchType.track.key),
externalData: Tuple2("", spotify),
);
final searchAlbum = useInfiniteQuery(
job: Queries.search.get(SearchType.album.key),
job: useQueries.search.get(SearchType.album.key),
externalData: Tuple2("", spotify),
);
final searchPlaylist = useInfiniteQuery(
job: Queries.search.get(SearchType.playlist.key),
job: useQueries.search.get(SearchType.playlist.key),
externalData: Tuple2("", spotify),
);
final searchArtist = useInfiniteQuery(
job: Queries.search.get(SearchType.artist.key),
job: useQueries.search.get(SearchType.artist.key),
externalData: Tuple2("", spotify),
);

View File

@ -3,7 +3,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/hooks/use_spotify_mutation.dart';
class AlbumMutations {
Mutation<bool, dynamic, bool> useToggleFavorite(
const AlbumMutations();
Mutation<bool, dynamic, bool> toggleFavorite(
WidgetRef ref,
String albumId, {
List<String>? refreshQueries,

View File

@ -2,8 +2,11 @@ import 'package:spotube/services/mutations/album.dart';
import 'package:spotube/services/mutations/playlist.dart';
import 'package:spotube/services/mutations/track.dart';
abstract class Mutations {
static final playlist = PlaylistMutations();
static final album = AlbumMutations();
static final track = TrackMutations();
class _UseMutations {
const _UseMutations._();
final playlist = const PlaylistMutations();
final album = const AlbumMutations();
final track = const TrackMutations();
}
const useMutations = _UseMutations._();

View File

@ -3,7 +3,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/hooks/use_spotify_mutation.dart';
class PlaylistMutations {
Mutation<bool, dynamic, bool> useToggleFavorite(
const PlaylistMutations();
Mutation<bool, dynamic, bool> toggleFavorite(
WidgetRef ref,
String playlistId, {
List<String>? refreshQueries,
@ -23,7 +25,7 @@ class PlaylistMutations {
);
}
Mutation<bool, dynamic, String> useRemoveTrackOf(
Mutation<bool, dynamic, String> removeTrackOf(
WidgetRef ref,
String playlistId,
) {

View File

@ -3,7 +3,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/hooks/use_spotify_mutation.dart';
class TrackMutations {
Mutation<bool, dynamic, bool> useToggleFavorite(
const TrackMutations();
Mutation<bool, dynamic, bool> toggleFavorite(
WidgetRef ref,
String trackId, {
MutationOnMutationFn<bool, bool>? onMutate,

View File

@ -7,7 +7,9 @@ import 'package:spotube/hooks/use_spotify_infinite_query.dart';
import 'package:spotube/hooks/use_spotify_query.dart';
class AlbumQueries {
Query<Iterable<AlbumSimple>, dynamic> useOfMineQuery(WidgetRef ref) {
const AlbumQueries();
Query<Iterable<AlbumSimple>, dynamic> ofMine(WidgetRef ref) {
return useSpotifyQuery<Iterable<AlbumSimple>, dynamic>(
"current-user-albums",
(spotify) {
@ -17,7 +19,7 @@ class AlbumQueries {
);
}
Query<List<TrackSimple>, dynamic> useTracksOfQuery(
Query<List<TrackSimple>, dynamic> tracksOf(
WidgetRef ref,
String albumId,
) {
@ -33,7 +35,7 @@ class AlbumQueries {
);
}
Query<bool, dynamic> useIsSavedForMeQuery(
Query<bool, dynamic> isSavedForMe(
WidgetRef ref,
String album,
) {
@ -46,8 +48,7 @@ class AlbumQueries {
);
}
InfiniteQuery<Page<AlbumSimple>, dynamic, int> useNewReleasesQuery(
WidgetRef ref) {
InfiniteQuery<Page<AlbumSimple>, dynamic, int> newReleases(WidgetRef ref) {
return useSpotifyInfiniteQuery<Page<AlbumSimple>, dynamic, int>(
"new-releases",
(pageParam, spotify) async {

View File

@ -6,7 +6,9 @@ import 'package:spotube/hooks/use_spotify_infinite_query.dart';
import 'package:spotube/hooks/use_spotify_query.dart';
class ArtistQueries {
Query<Artist, dynamic> useGetArtist(
const ArtistQueries();
Query<Artist, dynamic> get(
WidgetRef ref,
String artist,
) {
@ -17,7 +19,7 @@ class ArtistQueries {
);
}
InfiniteQuery<CursorPage<Artist>, dynamic, String> useFollowedByMeQuery(
InfiniteQuery<CursorPage<Artist>, dynamic, String> followedByMe(
WidgetRef ref) {
return useSpotifyInfiniteQuery<CursorPage<Artist>, dynamic, String>(
"user-following-artists",
@ -35,7 +37,7 @@ class ArtistQueries {
);
}
Query<bool, dynamic> useDoIFollowQuery(
Query<bool, dynamic> doIFollow(
WidgetRef ref,
String artist,
) {
@ -52,7 +54,7 @@ class ArtistQueries {
);
}
Query<Iterable<Track>, dynamic> useTopTracksOfQuery(
Query<Iterable<Track>, dynamic> topTracksOf(
WidgetRef ref,
String artist,
) {
@ -65,7 +67,7 @@ class ArtistQueries {
);
}
InfiniteQuery<Page<Album>, dynamic, int> useAlbumsOfQuery(
InfiniteQuery<Page<Album>, dynamic, int> albumsOf(
WidgetRef ref,
String artist,
) {
@ -86,7 +88,7 @@ class ArtistQueries {
);
}
Query<Iterable<Artist>, dynamic> useRelatedArtistsOfQuery(
Query<Iterable<Artist>, dynamic> relatedArtistsOf(
WidgetRef ref,
String artist,
) {

View File

@ -4,7 +4,9 @@ import 'package:spotify/spotify.dart';
import 'package:spotube/hooks/use_spotify_infinite_query.dart';
class CategoryQueries {
InfiniteQuery<Page<Category>, dynamic, int> useList(
const CategoryQueries();
InfiniteQuery<Page<Category>, dynamic, int> list(
WidgetRef ref, String recommendationMarket) {
return useSpotifyInfiniteQuery<Page<Category>, dynamic, int>(
"category-playlists",
@ -26,7 +28,7 @@ class CategoryQueries {
);
}
InfiniteQuery<Page<PlaylistSimple>, dynamic, int> usePlaylistsOf(
InfiniteQuery<Page<PlaylistSimple>, dynamic, int> playlistsOf(
WidgetRef ref,
String category,
) {

View File

@ -7,7 +7,9 @@ import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/utils/service_utils.dart';
class LyricsQueries {
Query<String, dynamic> useStatic(
const LyricsQueries();
Query<String, dynamic> static(
Track? track,
String geniusAccessToken,
) {
@ -30,7 +32,7 @@ class LyricsQueries {
);
}
Query<SubtitleSimple, dynamic> useSynced(
Query<SubtitleSimple, dynamic> synced(
Track? track,
) {
return useQuery<SubtitleSimple, dynamic>(

View File

@ -6,7 +6,9 @@ import 'package:spotube/hooks/use_spotify_infinite_query.dart';
import 'package:spotube/hooks/use_spotify_query.dart';
class PlaylistQueries {
Query<bool, dynamic> useDoesUserFollowQuery(
const PlaylistQueries();
Query<bool, dynamic> doesUserFollow(
WidgetRef ref,
String playlistId,
String userId,
@ -21,7 +23,7 @@ class PlaylistQueries {
);
}
Query<Iterable<PlaylistSimple>, dynamic> useOfMineQuery(WidgetRef ref) {
Query<Iterable<PlaylistSimple>, dynamic> ofMine(WidgetRef ref) {
return useSpotifyQuery<Iterable<PlaylistSimple>, dynamic>(
"current-user-playlists",
(spotify) {
@ -42,7 +44,7 @@ class PlaylistQueries {
);
}
Query<List<Track>, dynamic> useTracksOfQuery(
Query<List<Track>, dynamic> tracksOfQuery(
WidgetRef ref,
String playlistId,
) {
@ -53,7 +55,7 @@ class PlaylistQueries {
);
}
InfiniteQuery<Page<PlaylistSimple>, dynamic, int> useFeaturedQuery(
InfiniteQuery<Page<PlaylistSimple>, dynamic, int> featured(
WidgetRef ref,
) {
return useSpotifyInfiniteQuery<Page<PlaylistSimple>, dynamic, int>(

View File

@ -6,12 +6,15 @@ import 'package:spotube/services/queries/playlist.dart';
import 'package:spotube/services/queries/search.dart';
import 'package:spotube/services/queries/user.dart';
abstract class Queries {
static final album = AlbumQueries();
static final artist = ArtistQueries();
static final category = CategoryQueries();
static final lyrics = LyricsQueries();
static final playlist = PlaylistQueries();
static final search = SearchQueries();
static final user = UserQueries();
class Queries {
const Queries._();
final album = const AlbumQueries();
final artist = const ArtistQueries();
final category = const CategoryQueries();
final lyrics = const LyricsQueries();
final playlist = const PlaylistQueries();
final search = const SearchQueries();
final user = const UserQueries();
}
const useQueries = Queries._();

View File

@ -4,7 +4,8 @@ import 'package:spotify/spotify.dart';
import 'package:spotube/hooks/use_spotify_infinite_query.dart';
class SearchQueries {
InfiniteQuery<List<Page>, dynamic, int> useSearchQuery(
const SearchQueries();
InfiniteQuery<List<Page>, dynamic, int> query(
WidgetRef ref,
String query,
SearchType searchType,

View File

@ -5,7 +5,8 @@ import 'package:spotube/hooks/use_spotify_query.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
class UserQueries {
Query<User, dynamic> useMe(WidgetRef ref) {
const UserQueries();
Query<User, dynamic> me(WidgetRef ref) {
return useSpotifyQuery<User, dynamic>(
"current-user",
(spotify) async {