mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00

- Implemented ErrorBox for displaying error messages with retry functionality and log viewing. - Created NoDefaultMetadataPlugin to inform users about missing default metadata providers and provide navigation to manage them.
105 lines
3.8 KiB
Dart
105 lines
3.8 KiB
Dart
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:flutter_undraw/flutter_undraw.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
|
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
|
|
import 'package:skeletonizer/skeletonizer.dart';
|
|
import 'package:spotube/collections/fake.dart';
|
|
import 'package:spotube/components/fallbacks/error_box.dart';
|
|
import 'package:spotube/components/waypoint.dart';
|
|
import 'package:spotube/extensions/constrains.dart';
|
|
import 'package:spotube/extensions/context.dart';
|
|
import 'package:spotube/modules/artist/artist_card.dart';
|
|
import 'package:spotube/modules/search/loading.dart';
|
|
import 'package:spotube/pages/search/search.dart';
|
|
import 'package:spotube/provider/metadata_plugin/search/artists.dart';
|
|
|
|
class SearchPageArtistsTab extends HookConsumerWidget {
|
|
const SearchPageArtistsTab({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, ref) {
|
|
final controller = useScrollController();
|
|
|
|
final searchTerm = ref.watch(searchTermStateProvider);
|
|
final searchArtistsSnapshot =
|
|
ref.watch(metadataPluginSearchArtistsProvider(searchTerm));
|
|
final searchArtistsNotifier =
|
|
ref.read(metadataPluginSearchArtistsProvider(searchTerm).notifier);
|
|
final searchArtists = searchArtistsSnapshot.asData?.value.items ?? [];
|
|
|
|
if (searchArtistsSnapshot.hasError) {
|
|
return ErrorBox(
|
|
error: searchArtistsSnapshot.error!,
|
|
onRetry: () {
|
|
ref.invalidate(metadataPluginSearchArtistsProvider(searchTerm));
|
|
},
|
|
);
|
|
}
|
|
|
|
return SearchPlaceholder(
|
|
snapshot: searchArtistsSnapshot,
|
|
child: AnimatedSwitcher(
|
|
duration: const Duration(milliseconds: 300),
|
|
child: LayoutBuilder(builder: (context, constrains) {
|
|
if (searchArtistsSnapshot.hasValue && searchArtists.isEmpty) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
spacing: 10,
|
|
children: [
|
|
Undraw(
|
|
height: 200 * context.theme.scaling,
|
|
illustration: UndrawIllustration.taken,
|
|
color: Theme.of(context).colorScheme.primary,
|
|
),
|
|
Text(
|
|
context.l10n.nothing_found,
|
|
textAlign: TextAlign.center,
|
|
).muted().small()
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
return GridView.builder(
|
|
padding: const EdgeInsets.all(16),
|
|
itemCount: searchArtists.length + 1,
|
|
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
|
maxCrossAxisExtent: 200,
|
|
mainAxisExtent: constrains.smAndDown ? 225 : 250,
|
|
crossAxisSpacing: 8,
|
|
mainAxisSpacing: 8,
|
|
),
|
|
itemBuilder: (context, index) {
|
|
if (searchArtists.isNotEmpty && index == searchArtists.length) {
|
|
if (searchArtistsSnapshot.asData?.value.hasMore != true) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
return Waypoint(
|
|
controller: controller,
|
|
isGrid: true,
|
|
onTouchEdge: searchArtistsNotifier.fetchMore,
|
|
child: Skeletonizer(
|
|
enabled: true,
|
|
child: ArtistCard(FakeData.artist),
|
|
),
|
|
);
|
|
}
|
|
|
|
return Skeletonizer(
|
|
enabled: searchArtistsSnapshot.isLoading,
|
|
child: ArtistCard(
|
|
searchArtists.elementAtOrNull(index) ?? FakeData.artist,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
}
|