mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
fix: user_playlists layout, track tile index,
This commit is contained in:
parent
5633367397
commit
487c2ed6bd
@ -1,6 +1,7 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
|
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
|
||||||
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';
|
||||||
|
|
||||||
@ -8,6 +9,7 @@ import 'package:spotify/spotify.dart';
|
|||||||
import 'package:spotube/components/playlist/playlist_card.dart';
|
import 'package:spotube/components/playlist/playlist_card.dart';
|
||||||
import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart';
|
import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart';
|
||||||
import 'package:spotube/components/shared/waypoint.dart';
|
import 'package:spotube/components/shared/waypoint.dart';
|
||||||
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/models/logger.dart';
|
import 'package:spotube/models/logger.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/services/queries/queries.dart';
|
||||||
|
|
||||||
@ -28,16 +30,23 @@ class CategoryCard extends HookConsumerWidget {
|
|||||||
category.id!,
|
category.id!,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final playlists = useMemoized(
|
||||||
|
() => playlistQuery.pages.expand(
|
||||||
|
(page) {
|
||||||
|
return page.items?.where((i) => i != null) ?? const Iterable.empty();
|
||||||
|
},
|
||||||
|
).toList(),
|
||||||
|
[playlistQuery.pages],
|
||||||
|
);
|
||||||
|
|
||||||
if (playlistQuery.hasErrors &&
|
if (playlistQuery.hasErrors &&
|
||||||
!playlistQuery.hasPageData &&
|
!playlistQuery.hasPageData &&
|
||||||
!playlistQuery.isLoadingNextPage) {
|
!playlistQuery.isLoadingNextPage) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
final playlists = playlistQuery.pages.expand(
|
|
||||||
(page) {
|
final mediaQuery = MediaQuery.of(context);
|
||||||
return page.items?.where((i) => i != null) ?? const Iterable.empty();
|
|
||||||
},
|
|
||||||
).toList();
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -48,29 +57,35 @@ class CategoryCard extends HookConsumerWidget {
|
|||||||
category.name!,
|
category.name!,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
ScrollConfiguration(
|
SizedBox(
|
||||||
behavior: ScrollConfiguration.of(context).copyWith(
|
height: mediaQuery.smAndDown ? 226 : 266,
|
||||||
dragDevices: {
|
child: ScrollConfiguration(
|
||||||
PointerDeviceKind.touch,
|
behavior: ScrollConfiguration.of(context).copyWith(
|
||||||
PointerDeviceKind.mouse,
|
dragDevices: {
|
||||||
},
|
PointerDeviceKind.touch,
|
||||||
),
|
PointerDeviceKind.mouse,
|
||||||
child: Waypoint(
|
},
|
||||||
controller: scrollController,
|
|
||||||
onTouchEdge: playlistQuery.fetchNext,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
controller: scrollController,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
...playlists.map((playlist) => PlaylistCard(playlist)),
|
|
||||||
if (playlistQuery.hasNextPage)
|
|
||||||
const ShimmerPlaybuttonCard(count: 1),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: scrollController,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
itemCount: playlists.length + 1,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == playlists.length) {
|
||||||
|
if (!playlistQuery.hasNextPage) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return Waypoint(
|
||||||
|
controller: scrollController,
|
||||||
|
onTouchEdge: playlistQuery.fetchNext,
|
||||||
|
isGrid: true,
|
||||||
|
child: const ShimmerPlaybuttonCard(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final playlist = playlists[index];
|
||||||
|
return PlaylistCard(playlist);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart' hide Image;
|
import 'package:flutter/material.dart' hide Image;
|
||||||
|
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
|
||||||
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';
|
||||||
@ -8,7 +9,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/playlist/playlist_create_dialog.dart';
|
import 'package:spotube/components/playlist/playlist_create_dialog.dart';
|
||||||
import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart';
|
|
||||||
import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart';
|
import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart';
|
||||||
import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart';
|
import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart';
|
||||||
import 'package:spotube/components/playlist/playlist_card.dart';
|
import 'package:spotube/components/playlist/playlist_card.dart';
|
||||||
@ -80,20 +80,13 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: playlistsQuery.refresh,
|
onRefresh: playlistsQuery.refresh,
|
||||||
child: InterScrollbar(
|
child: SafeArea(
|
||||||
controller: controller,
|
child: CustomScrollView(
|
||||||
child: SingleChildScrollView(
|
|
||||||
controller: controller,
|
controller: controller,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
slivers: [
|
||||||
child: Waypoint(
|
SliverToBoxAdapter(
|
||||||
controller: controller,
|
|
||||||
onTouchEdge: () {
|
|
||||||
if (playlistsQuery.hasNextPage) {
|
|
||||||
playlistsQuery.fetchNext();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: SafeArea(
|
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
@ -103,42 +96,53 @@ class UserPlaylists extends HookConsumerWidget {
|
|||||||
leading: const Icon(SpotubeIcons.filter),
|
leading: const Icon(SpotubeIcons.filter),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
AnimatedCrossFade(
|
Row(
|
||||||
duration: const Duration(milliseconds: 300),
|
children: [
|
||||||
crossFadeState: !playlistsQuery.hasPageData &&
|
const SizedBox(width: 10),
|
||||||
!playlistsQuery.hasPageError &&
|
const PlaylistCreateDialogButton(),
|
||||||
!playlistsQuery.isLoadingNextPage
|
const SizedBox(width: 10),
|
||||||
? CrossFadeState.showFirst
|
ElevatedButton.icon(
|
||||||
: CrossFadeState.showSecond,
|
icon: const Icon(SpotubeIcons.magic),
|
||||||
firstChild:
|
label: Text(context.l10n.generate_playlist),
|
||||||
const Center(child: ShimmerPlaybuttonCard(count: 7)),
|
onPressed: () {
|
||||||
secondChild: Wrap(
|
GoRouter.of(context).push("/library/generate");
|
||||||
runSpacing: 10,
|
},
|
||||||
alignment: WrapAlignment.center,
|
),
|
||||||
children: [
|
const SizedBox(width: 10),
|
||||||
Row(
|
],
|
||||||
children: [
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
const PlaylistCreateDialogButton(),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
ElevatedButton.icon(
|
|
||||||
icon: const Icon(SpotubeIcons.magic),
|
|
||||||
label: Text(context.l10n.generate_playlist),
|
|
||||||
onPressed: () {
|
|
||||||
GoRouter.of(context).push("/library/generate");
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
...playlists.map((playlist) => PlaylistCard(playlist))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SliverToBoxAdapter(
|
||||||
|
child: SizedBox(height: 10),
|
||||||
|
),
|
||||||
|
SliverGrid.builder(
|
||||||
|
itemCount: playlists.length + 1,
|
||||||
|
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
|
maxCrossAxisExtent: 200,
|
||||||
|
mainAxisExtent: DesktopTools.platform.isMobile ? 225 : 250,
|
||||||
|
crossAxisSpacing: 8,
|
||||||
|
mainAxisSpacing: 8,
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == playlists.length) {
|
||||||
|
if (!playlistsQuery.hasNextPage) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Waypoint(
|
||||||
|
controller: controller,
|
||||||
|
isGrid: true,
|
||||||
|
onTouchEdge: playlistsQuery.fetchNext,
|
||||||
|
child: const ShimmerPlaybuttonCard(count: 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlaylistCard(playlists[index]);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -113,7 +113,7 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
child: Text(
|
child: Text(
|
||||||
'$index',
|
'${(index ?? 0) + 1}',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: theme.textTheme.bodySmall,
|
style: theme.textTheme.bodySmall,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
@ -10,6 +10,7 @@ import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart';
|
|||||||
import 'package:spotube/components/shared/shimmers/shimmer_categories.dart';
|
import 'package:spotube/components/shared/shimmers/shimmer_categories.dart';
|
||||||
import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart';
|
import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart';
|
||||||
import 'package:spotube/components/shared/waypoint.dart';
|
import 'package:spotube/components/shared/waypoint.dart';
|
||||||
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/models/logger.dart';
|
import 'package:spotube/models/logger.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
@ -38,6 +39,7 @@ class PersonalizedItemCard extends HookWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scrollController = useScrollController();
|
final scrollController = useScrollController();
|
||||||
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
@ -52,36 +54,48 @@ class PersonalizedItemCard extends HookWidget {
|
|||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ScrollConfiguration(
|
SizedBox(
|
||||||
behavior: ScrollConfiguration.of(context).copyWith(
|
height: mediaQuery.smAndDown ? 226 : 266,
|
||||||
dragDevices: {
|
child: ScrollConfiguration(
|
||||||
PointerDeviceKind.touch,
|
behavior: ScrollConfiguration.of(context).copyWith(
|
||||||
PointerDeviceKind.mouse,
|
dragDevices: {
|
||||||
},
|
PointerDeviceKind.touch,
|
||||||
),
|
PointerDeviceKind.mouse,
|
||||||
child: Scrollbar(
|
},
|
||||||
controller: scrollController,
|
),
|
||||||
interactive: false,
|
child: Scrollbar(
|
||||||
child: Waypoint(
|
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
onTouchEdge: hasNextPage ? onFetchMore : null,
|
interactive: false,
|
||||||
child: SingleChildScrollView(
|
child: ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
itemCount: (playlists?.length ?? albums?.length)! + 1,
|
||||||
controller: scrollController,
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Row(
|
scrollDirection: Axis.horizontal,
|
||||||
mainAxisSize: MainAxisSize.min,
|
itemBuilder: (context, index) {
|
||||||
children: [
|
if (index == (playlists?.length ?? albums?.length)!) {
|
||||||
...?playlists?.map((playlist) => PlaylistCard(playlist)),
|
if (!hasNextPage) return const SizedBox.shrink();
|
||||||
...?albums?.map(
|
|
||||||
(album) => AlbumCard(
|
return Waypoint(
|
||||||
TypeConversionUtils.simpleAlbum_X_Album(album),
|
controller: scrollController,
|
||||||
|
onTouchEdge: onFetchMore,
|
||||||
|
isGrid: true,
|
||||||
|
child: const ShimmerPlaybuttonCard(count: 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final item = playlists == null
|
||||||
|
? albums!.elementAt(index)
|
||||||
|
: playlists!.elementAt(index);
|
||||||
|
|
||||||
|
if (playlists == null) {
|
||||||
|
return AlbumCard(
|
||||||
|
TypeConversionUtils.simpleAlbum_X_Album(
|
||||||
|
item as AlbumSimple,
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
if (hasNextPage) const ShimmerPlaybuttonCard(count: 1),
|
}
|
||||||
],
|
|
||||||
),
|
return PlaylistCard(item as PlaylistSimple);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user