diff --git a/lib/widget/bom_list.dart b/lib/widget/bom_list.dart index 5e51feeb..e2b6f136 100644 --- a/lib/widget/bom_list.dart +++ b/lib/widget/bom_list.dart @@ -1,8 +1,9 @@ - import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/api.dart"; +import "package:inventree/api_form.dart"; import "package:inventree/helpers.dart"; import "package:inventree/inventree/bom.dart"; import "package:inventree/l10.dart"; @@ -15,6 +16,7 @@ import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/refreshable_state.dart"; + /* * Widget for displaying a list of BomItems for the specified 'parent' Part instance */ @@ -30,7 +32,7 @@ class BomList extends StatefulWidget { } -class _BomListState extends RefreshableState { +class _BomListState extends PaginatedState { _BomListState(this.parent); @@ -39,6 +41,15 @@ class _BomListState extends RefreshableState { @override String getAppBarTitle(BuildContext context) => L10().billOfMaterials; + @override + String get prefix => "bom_"; + + @override + Map get orderingOptions => { + "quantity": L10().quantity, + "part": L10().part, + }; + @override Widget getBody(BuildContext context) { return PaginatedBomList({ diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index aa62647d..26bae40a 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -3,9 +3,129 @@ import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:infinite_scroll_pagination/infinite_scroll_pagination.dart"; +import "package:inventree/api_form.dart"; +import "package:inventree/l10.dart"; + import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/sentry.dart"; -import "package:inventree/l10.dart"; +import "package:inventree/preferences.dart"; + +import "package:inventree/widget/refreshable_state.dart"; + + +/* + * Generic widget class for displaying a "paginated list". + * Provides some basic functionality for adjusting ordering and filtering options + */ +abstract class PaginatedState extends RefreshableState { + + // Prefix for storing and loading pagination options + String get prefix => "prefix_"; + + // Ordering options for this paginated state (override in implementing class) + Map get orderingOptions => {}; + + @override + List getAppBarActions(BuildContext context) { + List actions = []; + + // If ordering options have been provided + if (orderingOptions.isNotEmpty) { + actions.add(IconButton( + icon: FaIcon(FontAwesomeIcons.sort), + onPressed: () => _updateFilters(context), + )); + } + + return actions; + } + + // Return the selected ordering "field" for this list widget + Future orderingField() async { + dynamic field = await InvenTreeSettingsManager().getValue("${prefix}ordering_field", null); + + if (field != null) { + return field.toString(); + } else if (orderingOptions.isNotEmpty) { + // By default, return the first specified key + return orderingOptions.keys.first; + } else { + return ""; + } + } + + // Return the selected ordering "order" ("+" or "-") for this list widget + Future orderingOrder() async { + dynamic order = await InvenTreeSettingsManager().getValue("${prefix}ordering_order", "+"); + + return order == "+" ? "+" : "-"; + } + + // Update the (configurable) filters for this paginated list + Future _updateFilters(BuildContext context) async { + + // Retrieve stored setting + dynamic _field = await orderingField(); + dynamic _order = await orderingOrder(); + + // Construct the 'ordering' options + List> _opts = []; + + orderingOptions.forEach((k, v) => _opts.add({ + "value": k.toString(), + "display_name": v.toString() + })); + + if (_field == null && _opts.isNotEmpty) { + _field = _opts.first["value"]; + } + + Map fields = { + "ordering_field": { + "type": "choice", + "label": "Ordering Field", + "required": true, + "choices": _opts, + "value": _field, + }, + "ordering_order": { + "type": "choice", + "label": "Ordering Direction", + "required": true, + "value": _order, + "choices": [ + { + "value": "+", + "display_name": "Ascending", + }, + { + "value": "-", + "display_name": "Descending", + } + ] + } + }; + + launchApiForm( + context, + "...filtering...", + "", + fields, + icon: FontAwesomeIcons.checkCircle, + onSuccess: (Map data) async { + + // Extract data from the processed form + String f = (data["ordering_field"] ?? _field) as String; + String o = (data["ordering_order"] ?? _order) as String; + + // Save values to settings + await InvenTreeSettingsManager().setValue("${prefix}ordering_field", f); + await InvenTreeSettingsManager().setValue("${prefix}ordering_order", o); + } + ); + } + +} class PaginatedSearchState extends State { @@ -21,6 +141,10 @@ class PaginatedSearchState extends State { int resultCount = 0; + // List of variables by which the list can be "ordered". + // Override in any implementing sub-class + List orderingFilters = []; + // Text controller final TextEditingController searchController = TextEditingController(); diff --git a/pubspec.yaml b/pubspec.yaml index 16a35064..6528ab40 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,11 +10,11 @@ dependencies: audioplayers: ^0.20.1 # Play audio files cached_network_image: ^3.2.0 # Download and cache remote images - camera: ^0.9.4 # Camera + camera: ^0.9.4 # Camera cupertino_icons: ^1.0.3 datetime_picker_formfield: ^2.0.0 # Date / time picker device_info_plus: ^3.2.2 # Information about the device - dropdown_search: ^0.6.3 # Dropdown autocomplete form fields + dropdown_search: ^0.6.3 # Dropdown autocomplete form fields file_picker: ^4.5.1 # Select files from the device flutter: sdk: flutter @@ -28,14 +28,14 @@ dependencies: infinite_scroll_pagination: ^3.1.0 # Let the server do all the work! intl: ^0.17.0 one_context: ^1.1.0 # Dialogs without requiring context - open_file: ^3.2.1 # Open local files + open_file: ^3.2.1 # Open local files package_info_plus: ^1.0.4 # App information introspection path: ^1.8.0 - path_provider: ^2.0.2 # Local file storage + path_provider: ^2.0.2 # Local file storage qr_code_scanner: ^0.7.0 # Barcode scanning sembast: ^3.1.0+2 # NoSQL data storage - sentry_flutter: ^6.4.0 # Error reporting - url_launcher: ^6.0.9 # Open link in system browser + sentry_flutter: ^6.4.0 # Error reporting + url_launcher: ^6.0.9 # Open link in system browser dev_dependencies: flutter_launcher_icons: ^0.9.0