diff --git a/lib/api_form.dart b/lib/api_form.dart index 6b59f927..750aea6c 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -187,6 +187,7 @@ class APIFormField { label: label, hint: helpText, onChanged: null, + autoFocusSearchBox: true, showClearButton: !required, itemAsString: (dynamic item) { return item['display_name']; diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index f7e53adb..62d2fae0 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -285,11 +285,17 @@ class InvenTreeModel { return results; } - // TODO - handle possible error cases: - // - No data receieved - // - Data is not a list of maps + dynamic data; - for (var d in response.data) { + if (response.data is List) { + data = response.data; + } else if (response.data.containsKey('results')) { + data = response.data['results']; + } else { + data = []; + } + + for (var d in data) { // Create a new object (of the current class type InvenTreeModel obj = createFromJson(d); diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index 3592ea49..75abe85e 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:inventree/api.dart'; - import 'package:inventree/l10.dart'; import 'dart:async'; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 009c94cc..d04bfb3f 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -1,4 +1,5 @@ import 'package:inventree/barcode.dart'; +import 'package:inventree/inventree/model.dart'; import 'package:inventree/inventree/stock.dart'; import 'package:inventree/inventree/part.dart'; import 'package:inventree/widget/dialogs.dart'; @@ -17,7 +18,7 @@ import 'package:inventree/l10.dart'; import 'package:inventree/api.dart'; -import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:dropdown_search/dropdown_search.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import '../api_form.dart'; @@ -270,7 +271,7 @@ class _StockItemDisplayState extends RefreshableState { } - void _transferStock(InvenTreeStockLocation location) async { + void _transferStock(int locationId) async { double quantity = double.tryParse(_quantityController.text) ?? item.quantity; String notes = _notesController.text; @@ -278,7 +279,7 @@ class _StockItemDisplayState extends RefreshableState { _quantityController.clear(); _notesController.clear(); - var result = await item.transferStock(location.pk, quantity: quantity, notes: notes); + var result = await item.transferStock(locationId, quantity: quantity, notes: notes); refresh(); @@ -287,22 +288,22 @@ class _StockItemDisplayState extends RefreshableState { } } - void _transferStockDialog() async { + void _transferStockDialog(BuildContext context) async { var locations = await InvenTreeStockLocation().list(); final _selectedController = TextEditingController(); - InvenTreeStockLocation? selectedLocation; + int? location_pk; _quantityController.text = "${item.quantityString}"; showFormDialog(L10().transferStock, key: _moveStockKey, callback: () { - var _loc = selectedLocation; + var _pk = location_pk; - if (_loc != null) { - _transferStock(_loc); + if (_pk != null) { + _transferStock(_pk); } }, fields: [ @@ -311,47 +312,57 @@ class _StockItemDisplayState extends RefreshableState { controller: _quantityController, max: item.quantity, ), - TypeAheadFormField( - textFieldConfiguration: TextFieldConfiguration( - controller: _selectedController, - autofocus: true, - decoration: InputDecoration( - hintText: L10().searchLocation, - border: OutlineInputBorder() - ) - ), - suggestionsCallback: (pattern) async { - List suggestions = []; + DropdownSearch( + mode: Mode.BOTTOM_SHEET, + showSelectedItem: false, + autoFocusSearchBox: true, + selectedItem: null, + errorBuilder: (context, entry, exception) { + print("entry: $entry"); + print(exception.toString()); - for (var loc in locations) { - if (loc.matchAgainstString(pattern)) { - suggestions.add(loc as InvenTreeStockLocation); - } + return Text( + exception.toString(), + style: TextStyle( + fontSize: 10, + ) + ); + }, + onFind: (String filter) async { + + Map _filters = { + "search": filter, + "offset": "0", + "limit": "25" + }; + + final List results = await InvenTreeStockLocation().list(filters: _filters); + + List items = []; + + for (InvenTreeModel loc in results) { + if (loc is InvenTreeStockLocation) { + items.add(loc.jsondata); } - - return suggestions; - }, - validator: (value) { - if (selectedLocation == null) { - return L10().selectLocation; - } - - return null; - }, - onSuggestionSelected: (suggestion) { - selectedLocation = suggestion as InvenTreeStockLocation; - _selectedController.text = selectedLocation!.pathstring; - }, - onSaved: (value) { - }, - itemBuilder: (context, suggestion) { - var location = suggestion as InvenTreeStockLocation; - - return ListTile( - title: Text("${location.pathstring}"), - subtitle: Text("${location.description}"), - ); } + + return items; + }, + label: L10().stockLocation, + hint: L10().searchLocation, + onChanged: null, + itemAsString: (dynamic location) { + return location['pathstring']; + }, + onSaved: (dynamic location) { + if (location == null) { + location_pk = null; + } else { + location_pk = location['pk']; + } + }, + isFilteredOnline: true, + showSearchBox: true, ), ], ); @@ -556,7 +567,7 @@ class _StockItemDisplayState extends RefreshableState { return tiles; } - List actionTiles() { + List actionTiles(BuildContext context) { List tiles = []; tiles.add(headerTile()); @@ -610,7 +621,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().transferStock), leading: FaIcon(FontAwesomeIcons.exchangeAlt), - onTap: _transferStockDialog, + onTap: () { _transferStockDialog(context); }, ) ); @@ -694,7 +705,7 @@ class _StockItemDisplayState extends RefreshableState { return ListView( children: ListTile.divideTiles( context: context, - tiles: actionTiles() + tiles: actionTiles(context) ).toList() ); default: diff --git a/pubspec.lock b/pubspec.lock index e7d8e070..e78def2d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -174,27 +174,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.2" - flutter_keyboard_visibility: - dependency: transitive - description: - name: flutter_keyboard_visibility - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.2" - flutter_keyboard_visibility_platform_interface: - dependency: transitive - description: - name: flutter_keyboard_visibility_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - flutter_keyboard_visibility_web: - dependency: transitive - description: - name: flutter_keyboard_visibility_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -233,13 +212,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_typeahead: - dependency: "direct main" - description: - name: flutter_typeahead - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.3" flutter_web_plugins: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index c35380db..17ccafaf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,7 +30,6 @@ dependencies: font_awesome_flutter: ^9.1.0 # FontAwesome icon set flutter_speed_dial: ^3.0.5 # FAB menu elements sentry_flutter: 5.0.0 # Error reporting - flutter_typeahead: ^3.1.0 # Auto-complete input field image_picker: ^0.8.0 # Select or take photos url_launcher: 6.0.0 # Open link in system browser flutter_markdown: ^0.6.2 # Rendering markdown