2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-27 21:16:48 +00:00

Refresh fix (#436)

* Add notificationPredicate to improve scroll-to-reload

Ref: https://api.flutter.dev/flutter/material/RefreshIndicator-class.html

* Add scroll-to-refresh for paginated list
This commit is contained in:
Oliver 2023-10-23 21:59:05 +11:00 committed by GitHub
parent 8f1cd1cae1
commit b6ab9d5da5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 25 deletions

View File

@ -4,6 +4,7 @@
- Add ability to scan in received items using supplier barcodes - Add ability to scan in received items using supplier barcodes
- Store API token, rather than username:password - Store API token, rather than username:password
- Ensure that user will lose access if token is revoked by server - Ensure that user will lose access if token is revoked by server
- Improve scroll-to-refresh behaviour across multiple widgets
### 0.12.8 - September 2023 ### 0.12.8 - September 2023

View File

@ -394,31 +394,36 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta
children.add( children.add(
Expanded( Expanded(
child: CustomScrollView( child: CustomScrollView(
shrinkWrap: true, shrinkWrap: true,
physics: ClampingScrollPhysics(), physics: AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
slivers: <Widget>[ slivers: <Widget>[
PagedSliverList.separated( PagedSliverList.separated(
pagingController: _pagingController, pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<InvenTreeModel>( builderDelegate: PagedChildBuilderDelegate<InvenTreeModel>(
itemBuilder: (ctx, item, index) { itemBuilder: (ctx, item, index) {
return buildItem(ctx, item); return buildItem(ctx, item);
}, },
noItemsFoundIndicatorBuilder: (context) { noItemsFoundIndicatorBuilder: (context) {
return NoResultsWidget(noResultsText); return NoResultsWidget(noResultsText);
} }
), ),
separatorBuilder: (context, item) => const Divider(height: .1), separatorBuilder: (context, item) => const Divider(height: 1),
) )
] ]
)
) )
)
); );
return Column( return RefreshIndicator(
child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: children, children: children,
),
onRefresh: () async {
_pagingController.refresh();
},
); );
} }

View File

@ -21,7 +21,7 @@ mixin BaseWidgetProperties {
*/ */
List<Widget> appBarActions(BuildContext context) => []; List<Widget> appBarActions(BuildContext context) => [];
// Return a title for the appBar // Return a title for the appBar (placeholder)
String getAppBarTitle() { return "--- app bar ---"; } String getAppBarTitle() { return "--- app bar ---"; }
// Function to construct a drawer (override if needed) // Function to construct a drawer (override if needed)
@ -40,6 +40,7 @@ mixin BaseWidgetProperties {
// Default body calls getTiles() // Default body calls getTiles()
return SingleChildScrollView( return SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column( child: Column(
children: getTiles(context) children: getTiles(context)
) )
@ -202,7 +203,8 @@ mixin BaseWidgetProperties {
*/ */
abstract class RefreshableState<T extends StatefulWidget> extends State<T> with BaseWidgetProperties { abstract class RefreshableState<T extends StatefulWidget> extends State<T> with BaseWidgetProperties {
final refreshableKey = GlobalKey<ScaffoldState>(); final scaffoldKey = GlobalKey<ScaffoldState>();
final refreshKey = GlobalKey<RefreshIndicatorState>();
// Storage for context once "Build" is called // Storage for context once "Build" is called
late BuildContext? _context; late BuildContext? _context;
@ -265,19 +267,31 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> with
Widget body = tabs.isEmpty ? getBody(context) : TabBarView(children: getTabs(context)); Widget body = tabs.isEmpty ? getBody(context) : TabBarView(children: getTabs(context));
// predicateDepth needs to be different based on the child type
// hack, determined experimentally
int predicateDepth = 0;
if (tabs.isNotEmpty) {
predicateDepth = 1;
}
Scaffold view = Scaffold( Scaffold view = Scaffold(
key: refreshableKey, key: scaffoldKey,
appBar: buildAppBar(context, refreshableKey), appBar: buildAppBar(context, scaffoldKey),
drawer: getDrawer(context), drawer: getDrawer(context),
floatingActionButton: buildSpeedDial(context), floatingActionButton: buildSpeedDial(context),
floatingActionButtonLocation: FloatingActionButtonLocation.miniEndDocked, floatingActionButtonLocation: FloatingActionButtonLocation.miniEndDocked,
body: RefreshIndicator( body: RefreshIndicator(
key: refreshKey,
notificationPredicate: (ScrollNotification notification) {
return notification.depth == predicateDepth;
},
onRefresh: () async { onRefresh: () async {
refresh(context); refresh(context);
}, },
child: body child: body
), ),
bottomNavigationBar: buildBottomAppBar(context, refreshableKey), bottomNavigationBar: buildBottomAppBar(context, scaffoldKey),
); );
// Default implementation is *not* tabbed // Default implementation is *not* tabbed