Files
zapstore/lib/widgets/app_curation_container.dart
T
2024-10-13 17:28:52 -03:00

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'));