mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 20:48:24 +00:00
123 lines
4.1 KiB
Dart
123 lines
4.1 KiB
Dart
import 'package:collection/collection.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:gap/gap.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:purplebase/purplebase.dart';
|
|
import 'package:zapstore/main.data.dart';
|
|
import 'package:zapstore/models/app.dart';
|
|
import 'package:zapstore/models/app_curation_set.dart';
|
|
import 'package:zapstore/models/user.dart';
|
|
import 'package:zapstore/widgets/app_card.dart';
|
|
import 'package:zapstore/widgets/author_container.dart';
|
|
import 'package:zapstore/widgets/pill_widget.dart';
|
|
|
|
class AppCurationContainer extends HookConsumerWidget {
|
|
const AppCurationContainer({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final scrollController = useScrollController();
|
|
final selectedAppCurationSet = ref.watch(_selectedIdProvider);
|
|
final appCurationSets = ref.appCurationSets.findAllLocal();
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
controller: scrollController,
|
|
child: Row(
|
|
children: [
|
|
for (final appCurationSet in appCurationSets)
|
|
Padding(
|
|
padding: const EdgeInsets.only(right: 12),
|
|
child: GestureDetector(
|
|
onTap: () => ref.read(_selectedIdProvider.notifier).state =
|
|
appCurationSet.getReplaceableEventLink(),
|
|
child: PillWidget(
|
|
text: appCurationSet.name,
|
|
color: appCurationSet.getReplaceableEventLink() ==
|
|
selectedAppCurationSet
|
|
? Colors.blue[700]!
|
|
: Colors.grey[800]!,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Gap(12),
|
|
Consumer(
|
|
builder: (context, ref, _) {
|
|
final state =
|
|
ref.watch(appCurationSetProvider(selectedAppCurationSet));
|
|
return switch (state) {
|
|
AsyncData(value: final set) => Column(
|
|
children: [
|
|
if (set.signer.isPresent)
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 6, bottom: 10),
|
|
child: AuthorContainer(
|
|
user: set.signer.value!,
|
|
text:
|
|
'${set.name} (${set.apps.length} apps) curated by'),
|
|
),
|
|
HorizontalGrid(apps: set.apps.toList()),
|
|
],
|
|
),
|
|
_ => HorizontalGrid(apps: []),
|
|
};
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class HorizontalGrid extends StatelessWidget {
|
|
final List<App> apps;
|
|
|
|
HorizontalGrid({super.key, required this.apps});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SizedBox(
|
|
height: 220,
|
|
child: GridView.builder(
|
|
scrollDirection: Axis.horizontal,
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
childAspectRatio: 1.2,
|
|
crossAxisSpacing: 8,
|
|
mainAxisSpacing: 8,
|
|
),
|
|
itemCount: apps.isEmpty ? 8 : apps.length,
|
|
itemBuilder: (context, i) => TinyAppCard(app: apps.elementAtOrNull(i)),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Providers
|
|
|
|
class AppCurationSetNotifier
|
|
extends FamilyAsyncNotifier<AppCurationSet, ReplaceableEventLink> {
|
|
@override
|
|
Future<AppCurationSet> build(ReplaceableEventLink arg) async {
|
|
final appCurationSet = ref.appCurationSets.findOneLocalById(arg.formatted)!;
|
|
await ref.apps
|
|
.findAll(params: {'#d': appCurationSet.appIds}); // TODO: since
|
|
// await appCurationSet.signer.load();
|
|
return appCurationSet;
|
|
}
|
|
}
|
|
|
|
final appCurationSetProvider = AsyncNotifierProvider.family<
|
|
AppCurationSetNotifier,
|
|
AppCurationSet,
|
|
ReplaceableEventLink>(AppCurationSetNotifier.new);
|
|
|
|
final _selectedIdProvider = StateProvider<ReplaceableEventLink>(
|
|
(_) => (30267, kZapstorePubkey, 'nostr'));
|