diff --git a/assets/release_notes.md b/assets/release_notes.md index d1c05907..e49217b9 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -6,6 +6,7 @@ - Support "extra line items" for sales orders - Display start date for purchase orders - Display start date for sales orders +- Fix scrolling behaviour for some widgets - Updated search functionality - Updated translations diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index b10af546..f92fbb69 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -60,7 +60,9 @@ class _AttachmentWidgetState extends RefreshableState { prefix: widget.imagePrefix, ); FilePickerDialog.pickImageFromCamera().then((File? file) { - upload(context, file); + upload(context, file).then((_) { + refresh(context); + }); }); } ), @@ -68,7 +70,9 @@ class _AttachmentWidgetState extends RefreshableState { icon: Icon(TablerIcons.file_upload), onPressed: () async { FilePickerDialog.pickFileFromDevice().then((File? file) { - upload(context, file); + upload(context, file).then((_) { + refresh(context); + }); }); } ) diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index a16a0ef4..01507270 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import "package:flutter/material.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; @@ -254,6 +256,9 @@ abstract class PaginatedSearchState extends Sta // Text controller final TextEditingController searchController = TextEditingController(); + // Debounce timer + Timer? _debounceTimer; + // Pagination controller final PagingController _pagingController = PagingController(firstPageKey: 0); @@ -307,6 +312,9 @@ abstract class PaginatedSearchState extends Sta } params["search"] = "${_search}"; + } else { + // Remove search term if it is empty + params.remove("search"); } // Use custom query ordering if available @@ -368,11 +376,34 @@ abstract class PaginatedSearchState extends Sta // Callback function when the search term is updated void updateSearchTerm() { - searchTerm = searchController.text; - _pagingController.refresh(); - if (mounted) { - setState(() {}); + 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; + _pagingController.refresh(); + + if (mounted) { + setState(() {}); + } + }); } } @@ -465,12 +496,12 @@ abstract class PaginatedSearchState extends Sta icon: Icon(showSearchWidget ? Icons.zoom_out : Icons.search, size: icon_size) )); - _icons.add(IconButton( - onPressed: () async { - updateSearchTerm(); - }, - icon: Icon(Icons.refresh, size: icon_size), - )); + // _icons.add(IconButton( + // onPressed: () async { + // updateSearchTerm(); + // }, + // icon: Icon(Icons.refresh, size: icon_size), + // )); return ListTile( title: Text( diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 546c14dd..59e70fab 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -39,21 +39,14 @@ mixin BaseWidgetProperties { // Function to construct a body Widget getBody(BuildContext context) { - // Default body calls getTiles() - return SingleChildScrollView( + // Default implementation is to return a ListView + // Override getTiles to replace the internal context + return ListView( physics: AlwaysScrollableScrollPhysics(), - child: Column( - children: [ - ListView( - children: getTiles(context), - shrinkWrap: true, - ) - ], - ) + children: getTiles(context), ); } - /* * Construct the top AppBar for this view */ @@ -274,14 +267,6 @@ abstract class RefreshableState extends State with 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( key: scaffoldKey, appBar: buildAppBar(context, scaffoldKey), @@ -291,8 +276,9 @@ abstract class RefreshableState extends State with body: RefreshIndicator( key: refreshKey, notificationPredicate: (ScrollNotification notification) { - return notification.depth == predicateDepth; + return true; }, + onRefresh: () async { refresh(context); },