✨ Extended refresh indicator (keyboard based)
This commit is contained in:
		| @@ -9,6 +9,7 @@ import 'package:island/widgets/poll/poll_feedback.dart'; | |||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
| part 'poll_list.g.dart'; | part 'poll_list.g.dart'; | ||||||
|  |  | ||||||
| @@ -86,7 +87,7 @@ class CreatorPollListScreen extends HookConsumerWidget { | |||||||
|         onPressed: () => _createPoll(context), |         onPressed: () => _createPoll(context), | ||||||
|         child: const Icon(Icons.add), |         child: const Icon(Icons.add), | ||||||
|       ), |       ), | ||||||
|       body: RefreshIndicator( |       body: ExtendedRefreshIndicator( | ||||||
|         onRefresh: () => ref.refresh(pollListNotifierProvider(pubName).future), |         onRefresh: () => ref.refresh(pollListNotifierProvider(pubName).future), | ||||||
|         child: CustomScrollView( |         child: CustomScrollView( | ||||||
|           slivers: [ |           slivers: [ | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; | |||||||
| import 'package:island/pods/webfeed.dart'; | import 'package:island/pods/webfeed.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/empty_state.dart'; | import 'package:island/widgets/empty_state.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  |  | ||||||
| class WebFeedListScreen extends ConsumerWidget { | class WebFeedListScreen extends ConsumerWidget { | ||||||
| @@ -20,7 +21,10 @@ class WebFeedListScreen extends ConsumerWidget { | |||||||
|       floatingActionButton: FloatingActionButton( |       floatingActionButton: FloatingActionButton( | ||||||
|         child: const Icon(Symbols.add), |         child: const Icon(Symbols.add), | ||||||
|         onPressed: () { |         onPressed: () { | ||||||
|           context.pushNamed('creatorFeedNew', pathParameters: {'name': pubName}); |           context.pushNamed( | ||||||
|  |             'creatorFeedNew', | ||||||
|  |             pathParameters: {'name': pubName}, | ||||||
|  |           ); | ||||||
|         }, |         }, | ||||||
|       ), |       ), | ||||||
|       body: feedsAsync.when( |       body: feedsAsync.when( | ||||||
| @@ -32,7 +36,7 @@ class WebFeedListScreen extends ConsumerWidget { | |||||||
|               description: 'Add a new web feed to get started', |               description: 'Add a new web feed to get started', | ||||||
|             ); |             ); | ||||||
|           } |           } | ||||||
|           return RefreshIndicator( |           return ExtendedRefreshIndicator( | ||||||
|             onRefresh: () => ref.refresh(webFeedListProvider(pubName).future), |             onRefresh: () => ref.refresh(webFeedListProvider(pubName).future), | ||||||
|             child: ListView.builder( |             child: ListView.builder( | ||||||
|               padding: EdgeInsets.only(top: 8), |               padding: EdgeInsets.only(top: 8), | ||||||
| @@ -62,7 +66,10 @@ class WebFeedListScreen extends ConsumerWidget { | |||||||
|                     ), |                     ), | ||||||
|                     trailing: const Icon(Symbols.chevron_right), |                     trailing: const Icon(Symbols.chevron_right), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
|                       context.pushNamed('creatorFeedEdit', pathParameters: {'name': pubName, 'feedId': feed.id}); |                       context.pushNamed( | ||||||
|  |                         'creatorFeedEdit', | ||||||
|  |                         pathParameters: {'name': pubName, 'feedId': feed.id}, | ||||||
|  |                       ); | ||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|                 ); |                 ); | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import 'package:island/widgets/content/cloud_files.dart'; | |||||||
| import 'package:island/widgets/response.dart'; | import 'package:island/widgets/response.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
| part 'bots.g.dart'; | part 'bots.g.dart'; | ||||||
|  |  | ||||||
| @@ -60,7 +61,7 @@ class BotsScreen extends HookConsumerWidget { | |||||||
|             ), |             ), | ||||||
|           ); |           ); | ||||||
|         } |         } | ||||||
|         return RefreshIndicator( |         return ExtendedRefreshIndicator( | ||||||
|           onRefresh: |           onRefresh: | ||||||
|               () => ref.refresh(botsProvider(publisherName, projectId).future), |               () => ref.refresh(botsProvider(publisherName, projectId).future), | ||||||
|           child: ListView.builder( |           child: ListView.builder( | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ import 'package:island/pods/network.dart'; | |||||||
| import 'package:island/widgets/realm/realm_card.dart'; | import 'package:island/widgets/realm/realm_card.dart'; | ||||||
| import 'package:island/widgets/publisher/publisher_card.dart'; | import 'package:island/widgets/publisher/publisher_card.dart'; | ||||||
| import 'package:island/widgets/web_article_card.dart'; | import 'package:island/widgets/web_article_card.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
| part 'explore.g.dart'; | part 'explore.g.dart'; | ||||||
| @@ -368,7 +369,7 @@ class ExploreScreen extends HookConsumerWidget { | |||||||
|  |  | ||||||
|     final isWide = isWideScreen(context); |     final isWide = isWideScreen(context); | ||||||
|  |  | ||||||
|     return RefreshIndicator( |     return ExtendedRefreshIndicator( | ||||||
|       onRefresh: () => Future.sync(activitiesNotifier.forceRefresh), |       onRefresh: () => Future.sync(activitiesNotifier.forceRefresh), | ||||||
|       child: PagingHelperView( |       child: PagingHelperView( | ||||||
|         provider: activityListNotifierProvider(filter), |         provider: activityListNotifierProvider(filter), | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ import 'package:material_symbols_icons/symbols.dart'; | |||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| import 'package:island/widgets/realm/realm_list_tile.dart'; | import 'package:island/widgets/realm/realm_list_tile.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
| part 'realms.g.dart'; | part 'realms.g.dart'; | ||||||
|  |  | ||||||
| @@ -90,7 +91,7 @@ class RealmListScreen extends HookConsumerWidget { | |||||||
|         }, |         }, | ||||||
|       ), |       ), | ||||||
|       floatingActionButtonLocation: TabbedFabLocation(context), |       floatingActionButtonLocation: TabbedFabLocation(context), | ||||||
|       body: RefreshIndicator( |       body: ExtendedRefreshIndicator( | ||||||
|         child: realms.when( |         child: realms.when( | ||||||
|           data: |           data: | ||||||
|               (value) => Column( |               (value) => Column( | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import 'package:island/widgets/content/sheet.dart'; | |||||||
| import 'package:island/widgets/response.dart'; | import 'package:island/widgets/response.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
| part 'account_devices.g.dart'; | part 'account_devices.g.dart'; | ||||||
|  |  | ||||||
| @@ -177,7 +178,7 @@ class AccountSessionSheet extends HookConsumerWidget { | |||||||
|       titleText: 'authSessions'.tr(), |       titleText: 'authSessions'.tr(), | ||||||
|       child: authDevices.when( |       child: authDevices.when( | ||||||
|         data: |         data: | ||||||
|             (data) => RefreshIndicator( |             (data) => ExtendedRefreshIndicator( | ||||||
|               onRefresh: |               onRefresh: | ||||||
|                   () => Future.sync(() => ref.invalidate(authDevicesProvider)), |                   () => Future.sync(() => ref.invalidate(authDevicesProvider)), | ||||||
|               child: ListView.builder( |               child: ListView.builder( | ||||||
|   | |||||||
							
								
								
									
										67
									
								
								lib/widgets/extended_refresh_indicator.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								lib/widgets/extended_refresh_indicator.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
|  |  | ||||||
|  | class RefreshIntent extends Intent { | ||||||
|  |   const RefreshIntent(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class ExtendedRefreshIndicator extends StatefulWidget { | ||||||
|  |   final Widget child; | ||||||
|  |   final RefreshCallback onRefresh; | ||||||
|  |  | ||||||
|  |   const ExtendedRefreshIndicator({ | ||||||
|  |     super.key, | ||||||
|  |     required this.child, | ||||||
|  |     required this.onRefresh, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<ExtendedRefreshIndicator> createState() => | ||||||
|  |       _ExtendedRefreshIndicatorState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _ExtendedRefreshIndicatorState extends State<ExtendedRefreshIndicator> { | ||||||
|  |   late final FocusNode _focusNode; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     _focusNode = FocusNode(); | ||||||
|  |     WidgetsBinding.instance.addPostFrameCallback((_) { | ||||||
|  |       _focusNode.requestFocus(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _focusNode.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Shortcuts( | ||||||
|  |       shortcuts: <LogicalKeySet, Intent>{ | ||||||
|  |         LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyR): | ||||||
|  |             const RefreshIntent(), | ||||||
|  |         LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyR): | ||||||
|  |             const RefreshIntent(), | ||||||
|  |         LogicalKeySet(LogicalKeyboardKey.f5): const RefreshIntent(), | ||||||
|  |       }, | ||||||
|  |       child: Actions( | ||||||
|  |         actions: <Type, Action<Intent>>{ | ||||||
|  |           RefreshIntent: CallbackAction<RefreshIntent>( | ||||||
|  |             onInvoke: (RefreshIntent intent) => widget.onRefresh(), | ||||||
|  |           ), | ||||||
|  |         }, | ||||||
|  |         child: Focus( | ||||||
|  |           focusNode: _focusNode, | ||||||
|  |           child: RefreshIndicator( | ||||||
|  |             onRefresh: widget.onRefresh, | ||||||
|  |             child: widget.child, | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -12,6 +12,7 @@ import 'package:material_symbols_icons/symbols.dart'; | |||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| import 'package:flutter_popup_card/flutter_popup_card.dart'; | import 'package:flutter_popup_card/flutter_popup_card.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
| part 'picker.g.dart'; | part 'picker.g.dart'; | ||||||
|  |  | ||||||
| @@ -208,7 +209,7 @@ class _PackSwitcherState extends State<_PackSwitcher> { | |||||||
|  |  | ||||||
|         // Content |         // Content | ||||||
|         Expanded( |         Expanded( | ||||||
|           child: RefreshIndicator( |           child: ExtendedRefreshIndicator( | ||||||
|             onRefresh: widget.onRefresh, |             onRefresh: widget.onRefresh, | ||||||
|             child: _StickersGrid( |             child: _StickersGrid( | ||||||
|               pack: selectedPack, |               pack: selectedPack, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user