mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 13:36:50 +00:00
Keyboard fix (#306)
* Remove focusNode in search widget - Was causing some issues in iOS in particular * Improve search UX by cancelling previous query - Prevent successive search queries from being displayed * Update release notes * Add "type" for cancelable operation
This commit is contained in:
parent
020cc4497c
commit
efb7ff4170
@ -1,6 +1,13 @@
|
||||
## InvenTree App Release Notes
|
||||
---
|
||||
|
||||
### 0.11.1 - April 2023
|
||||
---
|
||||
|
||||
- Fixes keyboard bug in search widget
|
||||
- Adds ability to create new purchase orders directly from the app
|
||||
- Adds support for the "contact" field to purchase orders
|
||||
|
||||
### 0.11.0 - April 2023
|
||||
---
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import "dart:async";
|
||||
|
||||
import "package:async/async.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:font_awesome_flutter/font_awesome_flutter.dart";
|
||||
|
||||
@ -40,16 +40,10 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
|
||||
final bool hasAppBar;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_focusNode = FocusNode();
|
||||
}
|
||||
CancelableOperation<void>? _search_query;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -99,8 +93,6 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
int nSupplierResults = 0;
|
||||
int nPurchaseOrderResults = 0;
|
||||
|
||||
late FocusNode _focusNode;
|
||||
|
||||
// Callback when the text is being edited
|
||||
// Incorporates a debounce timer to restrict search frequency
|
||||
void onSearchTextChanged(String text, {bool immediate = false}) {
|
||||
@ -114,9 +106,6 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
} else {
|
||||
debounceTimer = Timer(Duration(milliseconds: 250), () {
|
||||
search(text);
|
||||
if (!_focusNode.hasFocus) {
|
||||
_focusNode.requestFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -147,12 +136,36 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
return count;
|
||||
}
|
||||
|
||||
// Actually perform the search query
|
||||
Future<void> _perform_search(Map<String, dynamic> body) async {
|
||||
InvenTreeAPI().post(
|
||||
"search/",
|
||||
body: body,
|
||||
expectedStatusCode: 200).then((APIResponse response) {
|
||||
decrementPendingSearches();
|
||||
|
||||
|
||||
Map<String, dynamic> results = {};
|
||||
|
||||
if (response.data is Map<String, dynamic>) {
|
||||
results = response.data as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
nPartResults = getSearchResultCount(results, "part");
|
||||
nCategoryResults = getSearchResultCount(results, "partcategory");
|
||||
nStockResults = getSearchResultCount(results, "stockitem");
|
||||
nLocationResults = getSearchResultCount(results, "stocklocation");
|
||||
nSupplierResults = 0; //getSearchResultCount(results, "")
|
||||
nPurchaseOrderResults = getSearchResultCount(results, "purchaseorder");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate multiple search requests to the server.
|
||||
* Each request returns at *some point* in the future,
|
||||
* by which time the search input may have changed, giving unexpected results.
|
||||
*
|
||||
* So, each request only causes an update *if* the search term is still the same when it completes
|
||||
* Callback when the search input is changed
|
||||
*/
|
||||
Future<void> search(String term) async {
|
||||
var api = InvenTreeAPI();
|
||||
@ -173,6 +186,15 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
nPendingSearches = 0;
|
||||
});
|
||||
|
||||
// Cancel the previous search query (if in progress)
|
||||
if (_search_query != null) {
|
||||
if (!_search_query!.isCanceled) {
|
||||
_search_query!.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
_search_query = null;
|
||||
|
||||
if (term.isEmpty) {
|
||||
return;
|
||||
}
|
||||
@ -216,29 +238,9 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
if (body.isNotEmpty) {
|
||||
nPendingSearches++;
|
||||
|
||||
api.post(
|
||||
"search/",
|
||||
body: body,
|
||||
expectedStatusCode: 200).then((APIResponse response) {
|
||||
decrementPendingSearches();
|
||||
|
||||
Map<String, dynamic> results = {};
|
||||
|
||||
if (response.data is Map<String, dynamic>) {
|
||||
results = response.data as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
nPartResults = getSearchResultCount(results, "part");
|
||||
nCategoryResults = getSearchResultCount(results, "partcategory");
|
||||
nStockResults = getSearchResultCount(results, "stockitem");
|
||||
nLocationResults = getSearchResultCount(results, "stocklocation");
|
||||
nSupplierResults = 0; //getSearchResultCount(results, "")
|
||||
nPurchaseOrderResults = getSearchResultCount(results, "purchaseorder");
|
||||
});
|
||||
}
|
||||
});
|
||||
_search_query = CancelableOperation.fromFuture(
|
||||
_perform_search(body),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
legacySearch(term);
|
||||
@ -344,16 +346,13 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
),
|
||||
key: _formKey,
|
||||
readOnly: false,
|
||||
autofocus: false,
|
||||
autofocus: true,
|
||||
autocorrect: false,
|
||||
focusNode: _focusNode,
|
||||
controller: searchController,
|
||||
onChanged: (String text) {
|
||||
onSearchTextChanged(text);
|
||||
_focusNode.requestFocus();
|
||||
},
|
||||
onFieldSubmitted: (String text) {
|
||||
_focusNode.requestFocus();
|
||||
},
|
||||
),
|
||||
trailing: GestureDetector(
|
||||
@ -363,7 +362,6 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
),
|
||||
onTap: () {
|
||||
searchController.clear();
|
||||
_focusNode.requestFocus();
|
||||
onSearchTextChanged("", immediate: true);
|
||||
},
|
||||
),
|
||||
@ -541,10 +539,6 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
|
||||
}
|
||||
}
|
||||
|
||||
if (!_focusNode.hasFocus) {
|
||||
_focusNode.requestFocus();
|
||||
}
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user