Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
natsuk4ze committed Jan 29, 2024
1 parent 9163d2b commit 3eee1aa
Showing 1 changed file with 94 additions and 1 deletion.
95 changes: 94 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,97 @@ This will depend on the project, but I find it best to put things close together
This project is minimal and even if you create a layered folder, only one file can go in that folder.
Putting them in a folder then would only needlessly add to the hierarchy and make it harder to see.
This should be best suited for the size of the project.
This should be best suited for the size of the project.
### Should Providers and UI always be placed in separate files?
I don't think so. Look at this for example.
```dart
@riverpod
class Sort extends _$Sort {
@override
ScoreType? build() => null;

void update(ScoreType type) => state = type;
}

@riverpod
Future<List<Package>> sortedPackages(SortedPackagesRef ref,
{required String search}) async {
final packages = await ref.watch(packagesProvider(search: search).future);
final sort = ref.watch(sortProvider);

return sort == null
? List.of(packages)
: packages.sortedByCompare(
(package) => sort.getValue(package.score), (a, b) => b.compareTo(a));
}

// ...PackagesPage

class _SortPanel extends ConsumerWidget {
const _SortPanel();

@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = ref.watch(l10nProvider);
final sort = ref.watch(sortProvider);

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.packagesPage.sortPackages,
style: Theme.of(context).textTheme.labelLarge,
),
const Gap(8),
for (var score in ScoreType.values)
ScoreRadioTile(
type: score,
groupeType: sort,
onTap: (type) => sort == type
? ref.invalidate(sortProvider)
: ref.read(sortProvider.notifier).update(type),
),
],
);
}
}

class _PackageItems extends ConsumerWidget {
const _PackageItems({required this.searchText});

final String searchText;

@override
Widget build(BuildContext context, WidgetRef ref) {
final packages = ref.watch(sortedPackagesProvider(search: searchText));
final l10n = ref.watch(l10nProvider);

return switch (packages) {
AsyncData(:final value) => value.isEmpty
? SingleChildScrollView(
child: EmptyImage(text: l10n.packagesPage.packageNotFound),
)
: RefreshIndicator(
onRefresh: () => ref.refresh(packagesProvider(
search: searchText,
debounce: false,
).future),
child: ListView.separated(
separatorBuilder: (_, __) => const Divider(),
itemCount: value.length,
itemBuilder: (_, int i) => PackageItem(value[i]),
),
),
AsyncError(:final error) => Text(error.toString()),
_ => const Center(child: CircularProgressIndicator()),
};
}
}
```

This is the codes of [packages_page.dart](https://github.com/natsuk4ze/npm/blob/master/lib/features/packages/packages_page.dart), which is a UI file, but with providers.
My basic idea is **put things close to each other in close proximity.**
I don't think it's necessary to put them in a data (domain) layer file, since all the providers here are only for this *packages page*.
However, this should also be changed depending on the project. If it is a large project, these providers might be placed in a file called ~controller. But this seems a bit far from the declarative UI philosophy.

0 comments on commit 3eee1aa

Please sign in to comment.