mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-30 21:05:42 +00:00 
			
		
		
		
	Scroll fix (#633)
* Fix scrolling behaviuor * Debounce paginated search
This commit is contained in:
		| @@ -6,6 +6,7 @@ | |||||||
| - Support "extra line items" for sales orders | - Support "extra line items" for sales orders | ||||||
| - Display start date for purchase orders | - Display start date for purchase orders | ||||||
| - Display start date for sales orders | - Display start date for sales orders | ||||||
|  | - Fix scrolling behaviour for some widgets | ||||||
| - Updated search functionality | - Updated search functionality | ||||||
| - Updated translations | - Updated translations | ||||||
|  |  | ||||||
|   | |||||||
| @@ -60,7 +60,9 @@ class _AttachmentWidgetState extends RefreshableState<AttachmentWidget> { | |||||||
|             prefix: widget.imagePrefix, |             prefix: widget.imagePrefix, | ||||||
|           ); |           ); | ||||||
|           FilePickerDialog.pickImageFromCamera().then((File? file) { |           FilePickerDialog.pickImageFromCamera().then((File? file) { | ||||||
|             upload(context, file); |             upload(context, file).then((_) { | ||||||
|  |               refresh(context); | ||||||
|  |             }); | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
|       ), |       ), | ||||||
| @@ -68,7 +70,9 @@ class _AttachmentWidgetState extends RefreshableState<AttachmentWidget> { | |||||||
|         icon: Icon(TablerIcons.file_upload), |         icon: Icon(TablerIcons.file_upload), | ||||||
|         onPressed: () async { |         onPressed: () async { | ||||||
|           FilePickerDialog.pickFileFromDevice().then((File? file) { |           FilePickerDialog.pickFileFromDevice().then((File? file) { | ||||||
|             upload(context, file); |             upload(context, file).then((_) { | ||||||
|  |               refresh(context); | ||||||
|  |             }); | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
|       ) |       ) | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import "dart:async"; | ||||||
|  |  | ||||||
| import "package:flutter/material.dart"; | import "package:flutter/material.dart"; | ||||||
|  |  | ||||||
| import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; | import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; | ||||||
| @@ -254,6 +256,9 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta | |||||||
|   // Text controller |   // Text controller | ||||||
|   final TextEditingController searchController = TextEditingController(); |   final TextEditingController searchController = TextEditingController(); | ||||||
|  |  | ||||||
|  |   // Debounce timer | ||||||
|  |   Timer? _debounceTimer; | ||||||
|  |  | ||||||
|   // Pagination controller |   // Pagination controller | ||||||
|   final PagingController<int, InvenTreeModel> _pagingController = PagingController(firstPageKey: 0); |   final PagingController<int, InvenTreeModel> _pagingController = PagingController(firstPageKey: 0); | ||||||
|  |  | ||||||
| @@ -307,6 +312,9 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         params["search"] = "${_search}"; |         params["search"] = "${_search}"; | ||||||
|  |       } else { | ||||||
|  |         // Remove search term if it is empty | ||||||
|  |         params.remove("search"); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       // Use custom query ordering if available |       // Use custom query ordering if available | ||||||
| @@ -368,12 +376,35 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta | |||||||
|  |  | ||||||
|   // Callback function when the search term is updated |   // Callback function when the search term is updated | ||||||
|   void updateSearchTerm() { |   void updateSearchTerm() { | ||||||
|  |  | ||||||
|  |     if (searchTerm == searchController.text) { | ||||||
|  |       // No change | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Debounce the search term | ||||||
|  |     if (_debounceTimer?.isActive ?? false) { | ||||||
|  |       _debounceTimer?.cancel(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (searchController.text.isEmpty) { | ||||||
|  |       // An empty search term evaluates immediately | ||||||
|  |       searchTerm = ""; | ||||||
|  |       _pagingController.refresh(); | ||||||
|  |  | ||||||
|  |       if (mounted) { | ||||||
|  |         setState(() {}); | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       _debounceTimer = Timer(const Duration(milliseconds: 500), () { | ||||||
|         searchTerm = searchController.text; |         searchTerm = searchController.text; | ||||||
|         _pagingController.refresh(); |         _pagingController.refresh(); | ||||||
|  |  | ||||||
|         if (mounted) { |         if (mounted) { | ||||||
|           setState(() {}); |           setState(() {}); | ||||||
|         } |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Function to construct a single paginated item |   // Function to construct a single paginated item | ||||||
| @@ -465,12 +496,12 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta | |||||||
|         icon: Icon(showSearchWidget ? Icons.zoom_out : Icons.search, size: icon_size) |         icon: Icon(showSearchWidget ? Icons.zoom_out : Icons.search, size: icon_size) | ||||||
|     )); |     )); | ||||||
|  |  | ||||||
|     _icons.add(IconButton( |     // _icons.add(IconButton( | ||||||
|       onPressed: () async { |     //   onPressed: () async { | ||||||
|         updateSearchTerm(); |     //     updateSearchTerm(); | ||||||
|       }, |     //   }, | ||||||
|       icon: Icon(Icons.refresh, size: icon_size), |     //   icon: Icon(Icons.refresh, size: icon_size), | ||||||
|     )); |     // )); | ||||||
|  |  | ||||||
|     return ListTile( |     return ListTile( | ||||||
|       title: Text( |       title: Text( | ||||||
|   | |||||||
| @@ -39,21 +39,14 @@ mixin BaseWidgetProperties { | |||||||
|   // Function to construct a body |   // Function to construct a body | ||||||
|   Widget getBody(BuildContext context) { |   Widget getBody(BuildContext context) { | ||||||
|  |  | ||||||
|     // Default body calls getTiles() |     // Default implementation is to return a ListView | ||||||
|     return SingleChildScrollView( |     // Override getTiles to replace the internal context | ||||||
|  |     return ListView( | ||||||
|       physics: AlwaysScrollableScrollPhysics(), |       physics: AlwaysScrollableScrollPhysics(), | ||||||
|       child: Column( |  | ||||||
|         children: [ |  | ||||||
|           ListView( |  | ||||||
|       children: getTiles(context), |       children: getTiles(context), | ||||||
|             shrinkWrap: true, |  | ||||||
|           ) |  | ||||||
|         ], |  | ||||||
|       ) |  | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   /* |   /* | ||||||
|    * Construct the top AppBar for this view |    * Construct the top AppBar for this view | ||||||
|    */ |    */ | ||||||
| @@ -274,14 +267,6 @@ 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: scaffoldKey, |       key: scaffoldKey, | ||||||
|       appBar: buildAppBar(context, scaffoldKey), |       appBar: buildAppBar(context, scaffoldKey), | ||||||
| @@ -291,8 +276,9 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> with | |||||||
|       body: RefreshIndicator( |       body: RefreshIndicator( | ||||||
|         key: refreshKey, |         key: refreshKey, | ||||||
|         notificationPredicate: (ScrollNotification notification) { |         notificationPredicate: (ScrollNotification notification) { | ||||||
|           return notification.depth == predicateDepth; |           return true; | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         onRefresh: () async { |         onRefresh: () async { | ||||||
|           refresh(context); |           refresh(context); | ||||||
|         }, |         }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user