mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 05:26:47 +00:00
Scroll fix (#633)
* Fix scrolling behaviuor * Debounce paginated search
This commit is contained in:
parent
72a78291b2
commit
1d5377ea20
@ -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,11 +376,34 @@ 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() {
|
||||||
searchTerm = searchController.text;
|
|
||||||
_pagingController.refresh();
|
|
||||||
|
|
||||||
if (mounted) {
|
if (searchTerm == searchController.text) {
|
||||||
setState(() {});
|
// 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<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: getTiles(context),
|
||||||
children: [
|
|
||||||
ListView(
|
|
||||||
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);
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user