mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
chore: add back pull down to refresh
This commit is contained in:
parent
c82b68a513
commit
30bf0bed62
@ -40,6 +40,8 @@ class PlaybuttonView extends StatelessWidget {
|
|||||||
final VoidCallback onRequestMore;
|
final VoidCallback onRequestMore;
|
||||||
final ScrollController controller;
|
final ScrollController controller;
|
||||||
|
|
||||||
|
final Widget? leading;
|
||||||
|
|
||||||
const PlaybuttonView({
|
const PlaybuttonView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.itemCount,
|
required this.itemCount,
|
||||||
@ -49,6 +51,7 @@ class PlaybuttonView extends StatelessWidget {
|
|||||||
required this.isLoading,
|
required this.isLoading,
|
||||||
required this.onRequestMore,
|
required this.onRequestMore,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
|
this.leading,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -74,6 +77,7 @@ class PlaybuttonView extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
if (leading != null) leading!,
|
||||||
Toggle(
|
Toggle(
|
||||||
value: isGrid.value,
|
value: isGrid.value,
|
||||||
style:
|
style:
|
||||||
|
@ -224,6 +224,11 @@ class Spotube extends HookConsumerWidget {
|
|||||||
surfaceBlur: 10,
|
surfaceBlur: 10,
|
||||||
),
|
),
|
||||||
materialTheme: material.ThemeData(
|
materialTheme: material.ThemeData(
|
||||||
|
brightness: switch (themeMode) {
|
||||||
|
ThemeMode.system => MediaQuery.platformBrightnessOf(context),
|
||||||
|
ThemeMode.light => Brightness.light,
|
||||||
|
ThemeMode.dark => Brightness.dark,
|
||||||
|
},
|
||||||
splashFactory: material.NoSplash.splashFactory,
|
splashFactory: material.NoSplash.splashFactory,
|
||||||
appBarTheme: const material.AppBarTheme(
|
appBarTheme: const material.AppBarTheme(
|
||||||
surfaceTintColor: Colors.transparent,
|
surfaceTintColor: Colors.transparent,
|
||||||
|
@ -52,6 +52,7 @@ class ConnectPageLocalDevices extends HookWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
const SliverGap(200)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
@ -27,44 +28,51 @@ class AlbumPage extends HookConsumerWidget {
|
|||||||
final favoriteAlbumsNotifier = ref.watch(favoriteAlbumsProvider.notifier);
|
final favoriteAlbumsNotifier = ref.watch(favoriteAlbumsProvider.notifier);
|
||||||
final isSavedAlbum = ref.watch(albumsIsSavedProvider(album.id!));
|
final isSavedAlbum = ref.watch(albumsIsSavedProvider(album.id!));
|
||||||
|
|
||||||
return TrackPresentation(
|
return material.RefreshIndicator.adaptive(
|
||||||
options: TrackPresentationOptions(
|
onRefresh: () async {
|
||||||
collection: album,
|
ref.invalidate(albumTracksProvider(album));
|
||||||
image: album.images.asUrlString(
|
ref.invalidate(favoriteAlbumsProvider);
|
||||||
placeholder: ImagePlaceholder.albumArt,
|
ref.invalidate(albumsIsSavedProvider(album.id!));
|
||||||
|
},
|
||||||
|
child: TrackPresentation(
|
||||||
|
options: TrackPresentationOptions(
|
||||||
|
collection: album,
|
||||||
|
image: album.images.asUrlString(
|
||||||
|
placeholder: ImagePlaceholder.albumArt,
|
||||||
|
),
|
||||||
|
title: album.name!,
|
||||||
|
description:
|
||||||
|
"${context.l10n.released} • ${album.releaseDate} • ${album.artists!.first.name}",
|
||||||
|
tracks: tracks.asData?.value.items ?? [],
|
||||||
|
pagination: PaginationProps(
|
||||||
|
hasNextPage: tracks.asData?.value.hasMore ?? false,
|
||||||
|
isLoading: tracks.isLoading || tracks.isLoadingNextPage,
|
||||||
|
onFetchMore: () async {
|
||||||
|
await tracksNotifier.fetchMore();
|
||||||
|
},
|
||||||
|
onFetchAll: () async {
|
||||||
|
return tracksNotifier.fetchAll();
|
||||||
|
},
|
||||||
|
onRefresh: () async {
|
||||||
|
ref.invalidate(albumTracksProvider(album));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
routePath: "/album/${album.id}",
|
||||||
|
shareUrl: album.externalUrls?.spotify ??
|
||||||
|
"https://open.spotify.com/album/${album.id}",
|
||||||
|
isLiked: isSavedAlbum.asData?.value ?? false,
|
||||||
|
owner: album.artists!.first.name,
|
||||||
|
onHeart: isSavedAlbum.asData?.value == null
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
if (isSavedAlbum.asData!.value) {
|
||||||
|
await favoriteAlbumsNotifier.removeFavorites([album.id!]);
|
||||||
|
} else {
|
||||||
|
await favoriteAlbumsNotifier.addFavorites([album.id!]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
title: album.name!,
|
|
||||||
description:
|
|
||||||
"${context.l10n.released} • ${album.releaseDate} • ${album.artists!.first.name}",
|
|
||||||
tracks: tracks.asData?.value.items ?? [],
|
|
||||||
pagination: PaginationProps(
|
|
||||||
hasNextPage: tracks.asData?.value.hasMore ?? false,
|
|
||||||
isLoading: tracks.isLoading || tracks.isLoadingNextPage,
|
|
||||||
onFetchMore: () async {
|
|
||||||
await tracksNotifier.fetchMore();
|
|
||||||
},
|
|
||||||
onFetchAll: () async {
|
|
||||||
return tracksNotifier.fetchAll();
|
|
||||||
},
|
|
||||||
onRefresh: () async {
|
|
||||||
ref.invalidate(albumTracksProvider(album));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
routePath: "/album/${album.id}",
|
|
||||||
shareUrl: album.externalUrls?.spotify ??
|
|
||||||
"https://open.spotify.com/album/${album.id}",
|
|
||||||
isLiked: isSavedAlbum.asData?.value ?? false,
|
|
||||||
owner: album.artists!.first.name,
|
|
||||||
onHeart: isSavedAlbum.asData?.value == null
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
if (isSavedAlbum.asData!.value) {
|
|
||||||
await favoriteAlbumsNotifier.removeFavorites([album.id!]);
|
|
||||||
} else {
|
|
||||||
await favoriteAlbumsNotifier.addFavorites([album.id!]);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
@ -42,45 +43,59 @@ class ArtistPage extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
floatingHeader: true,
|
floatingHeader: true,
|
||||||
child: Builder(builder: (context) {
|
child: material.RefreshIndicator.adaptive(
|
||||||
if (artistQuery.hasError && artistQuery.asData?.value == null) {
|
onRefresh: () async {
|
||||||
return Center(child: Text(artistQuery.error.toString()));
|
ref.invalidate(artistProvider(artistId));
|
||||||
}
|
ref.invalidate(relatedArtistsProvider(artistId));
|
||||||
return Skeletonizer(
|
ref.invalidate(artistAlbumsProvider(artistId));
|
||||||
enabled: artistQuery.isLoading,
|
ref.invalidate(artistIsFollowingProvider(artistId));
|
||||||
child: CustomScrollView(
|
ref.invalidate(artistTopTracksProvider(artistId));
|
||||||
controller: scrollController,
|
if (artistQuery.hasValue) {
|
||||||
slivers: [
|
ref.invalidate(
|
||||||
SliverToBoxAdapter(
|
artistWikipediaSummaryProvider(artistQuery.asData!.value));
|
||||||
child: SafeArea(
|
}
|
||||||
bottom: false,
|
},
|
||||||
child: ArtistPageHeader(artistId: artistId),
|
child: Builder(builder: (context) {
|
||||||
),
|
if (artistQuery.hasError && artistQuery.asData?.value == null) {
|
||||||
),
|
return Center(child: Text(artistQuery.error.toString()));
|
||||||
const SliverGap(20),
|
}
|
||||||
ArtistPageTopTracks(artistId: artistId),
|
return Skeletonizer(
|
||||||
const SliverGap(20),
|
enabled: artistQuery.isLoading,
|
||||||
SliverToBoxAdapter(child: ArtistAlbumList(artistId)),
|
child: CustomScrollView(
|
||||||
SliverPadding(
|
controller: scrollController,
|
||||||
padding: const EdgeInsets.all(8.0),
|
slivers: [
|
||||||
sliver: SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Text(
|
child: SafeArea(
|
||||||
context.l10n.fans_also_like,
|
bottom: false,
|
||||||
style: theme.typography.h4,
|
child: ArtistPageHeader(artistId: artistId),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SliverGap(20),
|
||||||
ArtistPageRelatedArtists(artistId: artistId),
|
ArtistPageTopTracks(artistId: artistId),
|
||||||
const SliverGap(20),
|
const SliverGap(20),
|
||||||
if (artistQuery.asData?.value != null)
|
SliverToBoxAdapter(child: ArtistAlbumList(artistId)),
|
||||||
SliverToBoxAdapter(
|
SliverPadding(
|
||||||
child: ArtistPageFooter(artist: artistQuery.asData!.value),
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: Text(
|
||||||
|
context.l10n.fans_also_like,
|
||||||
|
style: theme.typography.h4,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SliverSafeArea(sliver: SliverGap(10)),
|
ArtistPageRelatedArtists(artistId: artistId),
|
||||||
],
|
const SliverGap(20),
|
||||||
),
|
if (artistQuery.asData?.value != null)
|
||||||
);
|
SliverToBoxAdapter(
|
||||||
}),
|
child:
|
||||||
|
ArtistPageFooter(artist: artistQuery.asData!.value),
|
||||||
|
),
|
||||||
|
const SliverSafeArea(sliver: SliverGap(10)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,13 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
const TitleBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
surfaceBlur: 0,
|
||||||
|
height: 32,
|
||||||
),
|
),
|
||||||
const Gap(10),
|
const Gap(10),
|
||||||
],
|
],
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:flutter_undraw/flutter_undraw.dart';
|
import 'package:flutter_undraw/flutter_undraw.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image;
|
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
@ -55,10 +56,10 @@ class UserAlbumsPage extends HookConsumerWidget {
|
|||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
child: RefreshTrigger(
|
child: material.RefreshIndicator.adaptive(
|
||||||
// onRefresh: () async {
|
onRefresh: () async {
|
||||||
// ref.invalidate(favoriteAlbumsProvider);
|
ref.invalidate(favoriteAlbumsProvider);
|
||||||
// },
|
},
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_undraw/flutter_undraw.dart';
|
import 'package:flutter_undraw/flutter_undraw.dart';
|
||||||
@ -60,10 +61,10 @@ class UserArtistsPage extends HookConsumerWidget {
|
|||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
child: RefreshTrigger(
|
child: material.RefreshIndicator.adaptive(
|
||||||
// onRefresh: () async {
|
onRefresh: () async {
|
||||||
// ref.invalidate(followedArtistsProvider);
|
ref.invalidate(followedArtistsProvider);
|
||||||
// },
|
},
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
@ -342,9 +343,9 @@ class LocalLibraryPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: RefreshTrigger(
|
child: material.RefreshIndicator.adaptive(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
// ref.invalidate(localTracksProvider);
|
ref.invalidate(localTracksProvider);
|
||||||
},
|
},
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import 'package:flutter/material.dart' show kToolbarHeight;
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
@ -17,7 +17,6 @@ import 'package:spotube/modules/playlist/playlist_card.dart';
|
|||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/authentication/authentication.dart';
|
import 'package:spotube/provider/authentication/authentication.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
@ -79,10 +78,10 @@ class UserPlaylistsPage extends HookConsumerWidget {
|
|||||||
return const AnonymousFallback();
|
return const AnonymousFallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
return RefreshTrigger(
|
return material.RefreshIndicator.adaptive(
|
||||||
// onRefresh: () async {
|
onRefresh: () async {
|
||||||
// ref.invalidate(favoritePlaylistsProvider);
|
ref.invalidate(favoritePlaylistsProvider);
|
||||||
// },
|
},
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: InterScrollbar(
|
child: InterScrollbar(
|
||||||
@ -103,30 +102,27 @@ class UserPlaylistsPage extends HookConsumerWidget {
|
|||||||
leading: const Icon(SpotubeIcons.filter),
|
leading: const Icon(SpotubeIcons.filter),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottom: PreferredSize(
|
|
||||||
preferredSize:
|
|
||||||
Size.fromHeight(kIsDesktop ? 35 : kToolbarHeight),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Gap(10),
|
|
||||||
const PlaylistCreateDialogButton(),
|
|
||||||
const Gap(10),
|
|
||||||
Button.primary(
|
|
||||||
leading: const Icon(SpotubeIcons.magic),
|
|
||||||
child: Text(context.l10n.generate),
|
|
||||||
onPressed: () {
|
|
||||||
context.navigateTo(const PlaylistGeneratorRoute());
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Gap(10),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SliverGap(10),
|
const SliverGap(10),
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
sliver: PlaybuttonView(
|
sliver: PlaybuttonView(
|
||||||
|
leading: Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const PlaylistCreateDialogButton(),
|
||||||
|
const Gap(10),
|
||||||
|
Button.primary(
|
||||||
|
leading: const Icon(SpotubeIcons.magic),
|
||||||
|
child: Text(context.l10n.generate),
|
||||||
|
onPressed: () {
|
||||||
|
context.navigateTo(const PlaylistGeneratorRoute());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Gap(10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
controller: controller,
|
controller: controller,
|
||||||
hasMore: playlistsQuery.asData?.value.hasMore == true,
|
hasMore: playlistsQuery.asData?.value.hasMore == true,
|
||||||
isLoading: playlistsQuery.isLoading,
|
isLoading: playlistsQuery.isLoading,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
@ -22,29 +23,34 @@ class LikedPlaylistPage extends HookConsumerWidget {
|
|||||||
final likedTracks = ref.watch(likedTracksProvider);
|
final likedTracks = ref.watch(likedTracksProvider);
|
||||||
final tracks = likedTracks.asData?.value ?? <Track>[];
|
final tracks = likedTracks.asData?.value ?? <Track>[];
|
||||||
|
|
||||||
return TrackPresentation(
|
return material.RefreshIndicator.adaptive(
|
||||||
options: TrackPresentationOptions(
|
onRefresh: () async {
|
||||||
collection: playlist,
|
ref.invalidate(likedTracksProvider);
|
||||||
image: "assets/liked-tracks.jpg",
|
},
|
||||||
pagination: PaginationProps(
|
child: TrackPresentation(
|
||||||
hasNextPage: false,
|
options: TrackPresentationOptions(
|
||||||
isLoading: likedTracks.isLoading,
|
collection: playlist,
|
||||||
onFetchMore: () {},
|
image: "assets/liked-tracks.jpg",
|
||||||
onFetchAll: () async {
|
pagination: PaginationProps(
|
||||||
return tracks.toList();
|
hasNextPage: false,
|
||||||
},
|
isLoading: likedTracks.isLoading,
|
||||||
onRefresh: () async {
|
onFetchMore: () {},
|
||||||
ref.invalidate(likedTracksProvider);
|
onFetchAll: () async {
|
||||||
},
|
return tracks.toList();
|
||||||
|
},
|
||||||
|
onRefresh: () async {
|
||||||
|
ref.invalidate(likedTracksProvider);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: playlist.name!,
|
||||||
|
description: playlist.description,
|
||||||
|
tracks: tracks,
|
||||||
|
routePath: '/playlist/${playlist.id}',
|
||||||
|
isLiked: false,
|
||||||
|
shareUrl: null,
|
||||||
|
onHeart: null,
|
||||||
|
owner: playlist.owner?.displayName,
|
||||||
),
|
),
|
||||||
title: playlist.name!,
|
|
||||||
description: playlist.description,
|
|
||||||
tracks: tracks,
|
|
||||||
routePath: '/playlist/${playlist.id}',
|
|
||||||
isLiked: false,
|
|
||||||
shareUrl: null,
|
|
||||||
onHeart: null,
|
|
||||||
owner: playlist.owner?.displayName,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart' as material;
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@ -49,51 +50,58 @@ class PlaylistPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
final isUserPlaylist = useIsUserPlaylist(ref, playlist.id!);
|
final isUserPlaylist = useIsUserPlaylist(ref, playlist.id!);
|
||||||
|
|
||||||
return TrackPresentation(
|
return material.RefreshIndicator.adaptive(
|
||||||
options: TrackPresentationOptions(
|
onRefresh: () async {
|
||||||
collection: playlist,
|
ref.invalidate(playlistTracksProvider(playlist.id!));
|
||||||
image: playlist.images.asUrlString(
|
ref.invalidate(isFavoritePlaylistProvider(playlist.id!));
|
||||||
placeholder: ImagePlaceholder.collection,
|
ref.invalidate(favoritePlaylistsProvider);
|
||||||
),
|
},
|
||||||
pagination: PaginationProps(
|
child: TrackPresentation(
|
||||||
hasNextPage: tracks.asData?.value.hasMore ?? false,
|
options: TrackPresentationOptions(
|
||||||
isLoading: tracks.isLoading || tracks.isLoadingNextPage,
|
collection: playlist,
|
||||||
onFetchMore: tracksNotifier.fetchMore,
|
image: playlist.images.asUrlString(
|
||||||
onRefresh: () async {
|
placeholder: ImagePlaceholder.collection,
|
||||||
ref.invalidate(playlistTracksProvider(playlist.id!));
|
),
|
||||||
},
|
pagination: PaginationProps(
|
||||||
onFetchAll: () async {
|
hasNextPage: tracks.asData?.value.hasMore ?? false,
|
||||||
return await tracksNotifier.fetchAll();
|
isLoading: tracks.isLoading || tracks.isLoadingNextPage,
|
||||||
},
|
onFetchMore: tracksNotifier.fetchMore,
|
||||||
),
|
onRefresh: () async {
|
||||||
title: playlist.name!,
|
ref.invalidate(playlistTracksProvider(playlist.id!));
|
||||||
description: playlist.description,
|
},
|
||||||
owner: playlist.owner?.displayName,
|
onFetchAll: () async {
|
||||||
ownerImage: playlist.owner?.images?.lastOrNull?.url,
|
return await tracksNotifier.fetchAll();
|
||||||
tracks: tracks.asData?.value.items ?? [],
|
},
|
||||||
routePath: '/playlist/${playlist.id}',
|
),
|
||||||
isLiked: isFavoritePlaylist.asData?.value ?? false,
|
title: playlist.name!,
|
||||||
shareUrl: playlist.externalUrls?.spotify ??
|
description: playlist.description,
|
||||||
"https://open.spotify.com/playlist/${playlist.id}",
|
owner: playlist.owner?.displayName,
|
||||||
onHeart: isFavoritePlaylist.asData?.value == null
|
ownerImage: playlist.owner?.images?.lastOrNull?.url,
|
||||||
? null
|
tracks: tracks.asData?.value.items ?? [],
|
||||||
: () async {
|
routePath: '/playlist/${playlist.id}',
|
||||||
final confirmed = isUserPlaylist
|
isLiked: isFavoritePlaylist.asData?.value ?? false,
|
||||||
? await showPromptDialog(
|
shareUrl: playlist.externalUrls?.spotify ??
|
||||||
context: context,
|
"https://open.spotify.com/playlist/${playlist.id}",
|
||||||
title: context.l10n.delete_playlist,
|
onHeart: isFavoritePlaylist.asData?.value == null
|
||||||
message: context.l10n.delete_playlist_confirmation,
|
? null
|
||||||
)
|
: () async {
|
||||||
: true;
|
final confirmed = isUserPlaylist
|
||||||
if (!confirmed) return null;
|
? await showPromptDialog(
|
||||||
|
context: context,
|
||||||
|
title: context.l10n.delete_playlist,
|
||||||
|
message: context.l10n.delete_playlist_confirmation,
|
||||||
|
)
|
||||||
|
: true;
|
||||||
|
if (!confirmed) return null;
|
||||||
|
|
||||||
if (isFavoritePlaylist.asData!.value) {
|
if (isFavoritePlaylist.asData!.value) {
|
||||||
await favoritePlaylistsNotifier.removeFavorite(playlist);
|
await favoritePlaylistsNotifier.removeFavorite(playlist);
|
||||||
} else {
|
} else {
|
||||||
await favoritePlaylistsNotifier.addFavorite(playlist);
|
await favoritePlaylistsNotifier.addFavorite(playlist);
|
||||||
}
|
}
|
||||||
return isUserPlaylist;
|
return isUserPlaylist;
|
||||||
},
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -111,14 +111,17 @@ class TrackPage extends HookConsumerWidget {
|
|||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
runAlignment: WrapAlignment.center,
|
runAlignment: WrapAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Padding(
|
||||||
borderRadius: BorderRadius.circular(10),
|
padding: const EdgeInsets.only(top: 20),
|
||||||
child: UniversalImage(
|
child: ClipRRect(
|
||||||
path: track.album!.images.asUrlString(
|
borderRadius: BorderRadius.circular(10),
|
||||||
placeholder: ImagePlaceholder.albumArt,
|
child: UniversalImage(
|
||||||
|
path: track.album!.images.asUrlString(
|
||||||
|
placeholder: ImagePlaceholder.albumArt,
|
||||||
|
),
|
||||||
|
height: 200,
|
||||||
|
width: 200,
|
||||||
),
|
),
|
||||||
height: 200,
|
|
||||||
width: 200,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -376,7 +376,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "4.10.1"
|
version: "4.10.1"
|
||||||
collection:
|
collection:
|
||||||
dependency: "direct overridden"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||||
|
@ -144,6 +144,7 @@ dependencies:
|
|||||||
git:
|
git:
|
||||||
url: https://github.com/KRTirtho/flutter_new_pipe_extractor.git
|
url: https://github.com/KRTirtho/flutter_new_pipe_extractor.git
|
||||||
http_parser: ^4.1.2
|
http_parser: ^4.1.2
|
||||||
|
collection: any
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.13
|
build_runner: ^2.4.13
|
||||||
|
Loading…
Reference in New Issue
Block a user