From 864d3eb4a7fc6dc65f13d0a42bb95b00bf468d67 Mon Sep 17 00:00:00 2001 From: K9i-0 Date: Sat, 15 Jun 2024 13:27:17 +0900 Subject: [PATCH 1/2] chore: rename --- example/lib/main.dart | 4 +- example/lib/ui/first_page_error_screen.dart | 2 +- ...d_screen.dart => passing_args_screen.dart} | 14 ++-- ...reen.g.dart => passing_args_screen.g.dart} | 81 ++++++++++--------- example/lib/ui/second_page_error_screen.dart | 2 +- 5 files changed, 52 insertions(+), 51 deletions(-) rename example/lib/ui/{id_screen.dart => passing_args_screen.dart} (84%) rename example/lib/ui/{id_screen.g.dart => passing_args_screen.g.dart} (60%) diff --git a/example/lib/main.dart b/example/lib/main.dart index 785bb18..23f1c71 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,7 @@ import 'package:example/data/sample_item.dart'; import 'package:example/repository/sample_repository.dart'; import 'package:example/ui/first_page_error_screen.dart'; -import 'package:example/ui/id_screen.dart'; +import 'package:example/ui/passing_args_screen.dart'; import 'package:example/ui/second_page_error_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -98,7 +98,7 @@ class SampleScreen extends StatelessWidget { ListTile( title: const Text('Id screen'), onTap: () => Navigator.of(context).push( - IdScreen.route(), + PassingArgsScreen.route(), ), ), ], diff --git a/example/lib/ui/first_page_error_screen.dart b/example/lib/ui/first_page_error_screen.dart index 3601eed..194f241 100644 --- a/example/lib/ui/first_page_error_screen.dart +++ b/example/lib/ui/first_page_error_screen.dart @@ -46,7 +46,7 @@ class FirstPageErrorScreen extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('1st Page Error Screen'), + title: const Text('1st Page Error Sample'), ), body: PagingHelperView( provider: firstPageErrorNotifierProvider, diff --git a/example/lib/ui/id_screen.dart b/example/lib/ui/passing_args_screen.dart similarity index 84% rename from example/lib/ui/id_screen.dart rename to example/lib/ui/passing_args_screen.dart index eeb0e2b..90d1adc 100644 --- a/example/lib/ui/id_screen.dart +++ b/example/lib/ui/passing_args_screen.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; -part 'id_screen.g.dart'; +part 'passing_args_screen.g.dart'; @riverpod -class IdNotifier extends _$IdNotifier +class PassingArgsNotifier extends _$PassingArgsNotifier with CursorPagingNotifierMixin { @override Future> build({required String id}) => @@ -30,21 +30,21 @@ class IdNotifier extends _$IdNotifier } } -class IdScreen extends StatelessWidget { - const IdScreen._(); +class PassingArgsScreen extends StatelessWidget { + const PassingArgsScreen._(); static Route route() { return MaterialPageRoute( - builder: (context) => const IdScreen._(), + builder: (context) => const PassingArgsScreen._(), ); } @override Widget build(BuildContext context) { - final provider = idNotifierProvider(id: '1'); + final provider = passingArgsNotifierProvider(id: '1'); return Scaffold( appBar: AppBar( - title: const Text('Id Screen'), + title: const Text('Passing Args Sample'), ), body: PagingHelperView( provider: provider, diff --git a/example/lib/ui/id_screen.g.dart b/example/lib/ui/passing_args_screen.g.dart similarity index 60% rename from example/lib/ui/id_screen.g.dart rename to example/lib/ui/passing_args_screen.g.dart index b2e6493..c49aa25 100644 --- a/example/lib/ui/id_screen.g.dart +++ b/example/lib/ui/passing_args_screen.g.dart @@ -1,12 +1,13 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'id_screen.dart'; +part of 'passing_args_screen.dart'; // ************************************************************************** // RiverpodGenerator // ************************************************************************** -String _$idNotifierHash() => r'91c95ce77b18c23ad587a925e2df28905a89d96d'; +String _$passingArgsNotifierHash() => + r'c95fb6cad7afc1d3b99ca5ceaea44b673a86e912'; /// Copied from Dart SDK class _SystemHash { @@ -29,7 +30,7 @@ class _SystemHash { } } -abstract class _$IdNotifier +abstract class _$PassingArgsNotifier extends BuildlessAutoDisposeAsyncNotifier> { late final String id; @@ -38,28 +39,28 @@ abstract class _$IdNotifier }); } -/// See also [IdNotifier]. -@ProviderFor(IdNotifier) -const idNotifierProvider = IdNotifierFamily(); +/// See also [PassingArgsNotifier]. +@ProviderFor(PassingArgsNotifier) +const passingArgsNotifierProvider = PassingArgsNotifierFamily(); -/// See also [IdNotifier]. -class IdNotifierFamily +/// See also [PassingArgsNotifier]. +class PassingArgsNotifierFamily extends Family>> { - /// See also [IdNotifier]. - const IdNotifierFamily(); + /// See also [PassingArgsNotifier]. + const PassingArgsNotifierFamily(); - /// See also [IdNotifier]. - IdNotifierProvider call({ + /// See also [PassingArgsNotifier]. + PassingArgsNotifierProvider call({ required String id, }) { - return IdNotifierProvider( + return PassingArgsNotifierProvider( id: id, ); } @override - IdNotifierProvider getProviderOverride( - covariant IdNotifierProvider provider, + PassingArgsNotifierProvider getProviderOverride( + covariant PassingArgsNotifierProvider provider, ) { return call( id: provider.id, @@ -78,30 +79,30 @@ class IdNotifierFamily _allTransitiveDependencies; @override - String? get name => r'idNotifierProvider'; + String? get name => r'passingArgsNotifierProvider'; } -/// See also [IdNotifier]. -class IdNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< - IdNotifier, CursorPagingData> { - /// See also [IdNotifier]. - IdNotifierProvider({ +/// See also [PassingArgsNotifier]. +class PassingArgsNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< + PassingArgsNotifier, CursorPagingData> { + /// See also [PassingArgsNotifier]. + PassingArgsNotifierProvider({ required String id, }) : this._internal( - () => IdNotifier()..id = id, - from: idNotifierProvider, - name: r'idNotifierProvider', + () => PassingArgsNotifier()..id = id, + from: passingArgsNotifierProvider, + name: r'passingArgsNotifierProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : _$idNotifierHash, - dependencies: IdNotifierFamily._dependencies, + : _$passingArgsNotifierHash, + dependencies: PassingArgsNotifierFamily._dependencies, allTransitiveDependencies: - IdNotifierFamily._allTransitiveDependencies, + PassingArgsNotifierFamily._allTransitiveDependencies, id: id, ); - IdNotifierProvider._internal( + PassingArgsNotifierProvider._internal( super._createNotifier, { required super.name, required super.dependencies, @@ -115,7 +116,7 @@ class IdNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< @override FutureOr> runNotifierBuild( - covariant IdNotifier notifier, + covariant PassingArgsNotifier notifier, ) { return notifier.build( id: id, @@ -123,10 +124,10 @@ class IdNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< } @override - Override overrideWith(IdNotifier Function() create) { + Override overrideWith(PassingArgsNotifier Function() create) { return ProviderOverride( origin: this, - override: IdNotifierProvider._internal( + override: PassingArgsNotifierProvider._internal( () => create()..id = id, from: from, name: null, @@ -139,14 +140,14 @@ class IdNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< } @override - AutoDisposeAsyncNotifierProviderElement> createElement() { - return _IdNotifierProviderElement(this); + return _PassingArgsNotifierProviderElement(this); } @override bool operator ==(Object other) { - return other is IdNotifierProvider && other.id == id; + return other is PassingArgsNotifierProvider && other.id == id; } @override @@ -158,19 +159,19 @@ class IdNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< } } -mixin IdNotifierRef +mixin PassingArgsNotifierRef on AutoDisposeAsyncNotifierProviderRef> { /// The parameter `id` of this provider. String get id; } -class _IdNotifierProviderElement - extends AutoDisposeAsyncNotifierProviderElement> with IdNotifierRef { - _IdNotifierProviderElement(super.provider); +class _PassingArgsNotifierProviderElement + extends AutoDisposeAsyncNotifierProviderElement> with PassingArgsNotifierRef { + _PassingArgsNotifierProviderElement(super.provider); @override - String get id => (origin as IdNotifierProvider).id; + String get id => (origin as PassingArgsNotifierProvider).id; } // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/example/lib/ui/second_page_error_screen.dart b/example/lib/ui/second_page_error_screen.dart index 83324b2..ea2c100 100644 --- a/example/lib/ui/second_page_error_screen.dart +++ b/example/lib/ui/second_page_error_screen.dart @@ -55,7 +55,7 @@ class SecondPageErrorScreen extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return Scaffold( appBar: AppBar( - title: const Text('2nd Page Error Screen'), + title: const Text('2nd Page Error Sample'), actions: [ Tooltip( message: 'Toggle showSecondPageError', From 5bc0ac39cc0beddc0485e29ce173244ddafe6b9a Mon Sep 17 00:00:00 2001 From: K9i-0 Date: Sat, 15 Jun 2024 14:21:03 +0900 Subject: [PATCH 2/2] add: paging method sample screen --- example/lib/main.dart | 9 +- example/lib/repository/sample_repository.dart | 42 ++++ example/lib/ui/paging_method_screen.dart | 186 ++++++++++++++++++ example/lib/ui/paging_method_screen.g.dart | 63 ++++++ 4 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 example/lib/ui/paging_method_screen.dart create mode 100644 example/lib/ui/paging_method_screen.g.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 23f1c71..ed4445c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:example/data/sample_item.dart'; import 'package:example/repository/sample_repository.dart'; import 'package:example/ui/first_page_error_screen.dart'; +import 'package:example/ui/paging_method_screen.dart'; import 'package:example/ui/passing_args_screen.dart'; import 'package:example/ui/second_page_error_screen.dart'; import 'package:flutter/material.dart'; @@ -96,11 +97,17 @@ class SampleScreen extends StatelessWidget { ), ), ListTile( - title: const Text('Id screen'), + title: const Text('Passing args screen'), onTap: () => Navigator.of(context).push( PassingArgsScreen.route(), ), ), + ListTile( + title: const Text('Paging method screen'), + onTap: () => Navigator.of(context).push( + PagingMethodScreen.route(), + ), + ), ], ), ), diff --git a/example/lib/repository/sample_repository.dart b/example/lib/repository/sample_repository.dart index dec155a..7ac143f 100644 --- a/example/lib/repository/sample_repository.dart +++ b/example/lib/repository/sample_repository.dart @@ -10,6 +10,48 @@ SampleRepository sampleRepository(SampleRepositoryRef ref) => SampleRepository(); class SampleRepository { + Future<(List items, bool hasMore)> getByPage({ + required int page, + required int limit, + }) async { + await Future.delayed(const Duration(milliseconds: 500)); + + final items = _db + .sublist((page - 1) * limit, page * limit) + .mapRecord( + (id, name) => SampleItem(id: id.toString(), name: name), + ) + .toList(); + + final hasMore = _db.length > page * limit; + + return ( + items, + hasMore, + ); + } + + Future<(List items, bool hasMore)> getByOffset({ + required int offset, + required int limit, + }) async { + await Future.delayed(const Duration(milliseconds: 500)); + + final items = _db + .sublist(offset, offset + limit) + .mapRecord( + (id, name) => SampleItem(id: id.toString(), name: name), + ) + .toList(); + + final hasMore = _db.length > offset + limit; + + return ( + items, + hasMore, + ); + } + Future<(List items, String? nextCursor)> getByCursor( String? cursor, ) async { diff --git a/example/lib/ui/paging_method_screen.dart b/example/lib/ui/paging_method_screen.dart new file mode 100644 index 0000000..b13d6f0 --- /dev/null +++ b/example/lib/ui/paging_method_screen.dart @@ -0,0 +1,186 @@ +import 'package:example/data/sample_item.dart'; +import 'package:example/repository/sample_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; + +part 'paging_method_screen.g.dart'; + +@riverpod +class PageBasedNotifier extends _$PageBasedNotifier + with PagePagingNotifierMixin { + @override + Future> build() => fetch(page: 1); + + @override + Future> fetch({ + required int page, + }) async { + final repository = ref.read(sampleRepositoryProvider); + final (items, hasMore) = await repository.getByPage(page: page, limit: 50); + ref.keepAlive(); + + return PagePagingData( + items: items, + hasMore: hasMore, + page: page, + ); + } +} + +@riverpod +class OffsetBasedNotifier extends _$OffsetBasedNotifier + with OffsetPagingNotifierMixin { + @override + Future> build() => fetch(offset: 0); + + @override + Future> fetch({ + required int offset, + }) async { + final repository = ref.read(sampleRepositoryProvider); + final (items, hasMore) = + await repository.getByOffset(offset: offset, limit: 75); + ref.keepAlive(); + + return OffsetPagingData( + items: items, + hasMore: hasMore, + offset: offset + 75, + ); + } +} + +@riverpod +class CursorBasedNotifier extends _$CursorBasedNotifier + with CursorPagingNotifierMixin { + @override + Future> build() => fetch(cursor: null); + + @override + Future> fetch({ + required String? cursor, + }) async { + final repository = ref.read(sampleRepositoryProvider); + final (items, nextCursor) = await repository.getByCursor(cursor); + ref.keepAlive(); + final hasMore = nextCursor != null && nextCursor.isNotEmpty; + + return CursorPagingData( + items: items, + hasMore: hasMore, + nextCursor: nextCursor, + ); + } +} + +class PagingMethodScreen extends StatelessWidget { + const PagingMethodScreen._(); + + static Route route() { + return MaterialPageRoute( + builder: (context) => const PagingMethodScreen._(), + ); + } + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 3, + child: Scaffold( + appBar: AppBar( + title: const Text('Paging Method Sample'), + bottom: const TabBar( + tabs: [ + Tab( + text: 'Page', + ), + Tab( + text: 'Offset', + ), + Tab( + text: 'Cursor', + ), + ], + ), + ), + body: TabBarView( + children: [ + PagingHelperView( + provider: pageBasedNotifierProvider, + futureRefreshable: pageBasedNotifierProvider.future, + notifierRefreshable: pageBasedNotifierProvider.notifier, + contentBuilder: (data, widgetCount, endItemView) => + ListView.builder( + key: const PageStorageKey('page'), + itemCount: widgetCount, + itemBuilder: (context, index) { + // if the index is last, then + // return the end item view. + if (index == widgetCount - 1) { + return endItemView; + } + + // Otherwise, build a list tile for each sample item. + return ListTile( + key: ValueKey(data.items[index].id), + title: Text(data.items[index].name), + subtitle: Text(data.items[index].id), + ); + }, + ), + ), + PagingHelperView( + provider: offsetBasedNotifierProvider, + futureRefreshable: offsetBasedNotifierProvider.future, + notifierRefreshable: offsetBasedNotifierProvider.notifier, + contentBuilder: (data, widgetCount, endItemView) => + ListView.builder( + key: const PageStorageKey('offset'), + itemCount: widgetCount, + itemBuilder: (context, index) { + // if the index is last, then + // return the end item view. + if (index == widgetCount - 1) { + return endItemView; + } + + // Otherwise, build a list tile for each sample item. + return ListTile( + key: ValueKey(data.items[index].id), + title: Text(data.items[index].name), + subtitle: Text(data.items[index].id), + ); + }, + ), + ), + PagingHelperView( + provider: cursorBasedNotifierProvider, + futureRefreshable: cursorBasedNotifierProvider.future, + notifierRefreshable: cursorBasedNotifierProvider.notifier, + contentBuilder: (data, widgetCount, endItemView) => + ListView.builder( + key: const PageStorageKey('cursor'), + itemCount: widgetCount, + itemBuilder: (context, index) { + // if the index is last, then + // return the end item view. + if (index == widgetCount - 1) { + return endItemView; + } + + // Otherwise, build a list tile for each sample item. + return ListTile( + key: ValueKey(data.items[index].id), + title: Text(data.items[index].name), + subtitle: Text(data.items[index].id), + ); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/example/lib/ui/paging_method_screen.g.dart b/example/lib/ui/paging_method_screen.g.dart new file mode 100644 index 0000000..6ef80f1 --- /dev/null +++ b/example/lib/ui/paging_method_screen.g.dart @@ -0,0 +1,63 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'paging_method_screen.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$pageBasedNotifierHash() => r'eeebf31b5b48bad4f89f2a907865bca91c7ebf3a'; + +/// See also [PageBasedNotifier]. +@ProviderFor(PageBasedNotifier) +final pageBasedNotifierProvider = AutoDisposeAsyncNotifierProvider< + PageBasedNotifier, PagePagingData>.internal( + PageBasedNotifier.new, + name: r'pageBasedNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$pageBasedNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$PageBasedNotifier + = AutoDisposeAsyncNotifier>; +String _$offsetBasedNotifierHash() => + r'004f470d3f169dbb79b2af6b0c2427d0bdf7d434'; + +/// See also [OffsetBasedNotifier]. +@ProviderFor(OffsetBasedNotifier) +final offsetBasedNotifierProvider = AutoDisposeAsyncNotifierProvider< + OffsetBasedNotifier, OffsetPagingData>.internal( + OffsetBasedNotifier.new, + name: r'offsetBasedNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$offsetBasedNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$OffsetBasedNotifier + = AutoDisposeAsyncNotifier>; +String _$cursorBasedNotifierHash() => + r'558358c8a67bff5d73e5e809fab838b148c6bc35'; + +/// See also [CursorBasedNotifier]. +@ProviderFor(CursorBasedNotifier) +final cursorBasedNotifierProvider = AutoDisposeAsyncNotifierProvider< + CursorBasedNotifier, CursorPagingData>.internal( + CursorBasedNotifier.new, + name: r'cursorBasedNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$cursorBasedNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$CursorBasedNotifier + = AutoDisposeAsyncNotifier>; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member