mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-11-04 07:15:46 +00:00 
			
		
		
		
	Adds search results
This commit is contained in:
		@@ -84,21 +84,15 @@ class InvenTreeModel {
 | 
				
			|||||||
  // Return the API detail endpoint for this Model object
 | 
					  // Return the API detail endpoint for this Model object
 | 
				
			||||||
  String get url => "${URL}/${pk}/";
 | 
					  String get url => "${URL}/${pk}/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					
 | 
				
			||||||
  // Search this Model type in the database
 | 
					  // Search this Model type in the database
 | 
				
			||||||
  Future<List<InvenTreeModel>> search(String searchTerm) async {
 | 
					  Future<List<InvenTreeModel>> search(BuildContext context, String searchTerm) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    String addr = url + "?search=" + search;
 | 
					    final results = list(context, filters: {"cascade": "true", "search": searchTerm});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print("Searching endpoint: $url");
 | 
					    return results;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO - Add "timeout"
 | 
					 | 
				
			||||||
    // TODO - Add error catching
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var response =
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, String> defaultListFilters() { return Map<String, String>(); }
 | 
					  Map<String, String> defaultListFilters() { return Map<String, String>(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,13 @@ class InvenTreeDrawer extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void _search() {
 | 
					  void _search() {
 | 
				
			||||||
    _closeDrawer();
 | 
					    _closeDrawer();
 | 
				
			||||||
    Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget()));
 | 
					
 | 
				
			||||||
 | 
					    showSearch(
 | 
				
			||||||
 | 
					      context: context,
 | 
				
			||||||
 | 
					      delegate: PartSearchDelegate()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget()));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					  /*
 | 
				
			||||||
@@ -101,62 +107,59 @@ class InvenTreeDrawer extends StatelessWidget {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return  Drawer(
 | 
					    return  Drawer(
 | 
				
			||||||
        child: new ListView(
 | 
					        child: ListView(
 | 
				
			||||||
            children: ListTile.divideTiles(
 | 
					            children: ListTile.divideTiles(
 | 
				
			||||||
              context: context,
 | 
					              context: context,
 | 
				
			||||||
              tiles: <Widget>[
 | 
					              tiles: <Widget>[
 | 
				
			||||||
                new ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  leading: new Image.asset(
 | 
					                  leading: Image.asset(
 | 
				
			||||||
                    "assets/image/icon.png",
 | 
					                    "assets/image/icon.png",
 | 
				
			||||||
                    fit: BoxFit.scaleDown,
 | 
					                    fit: BoxFit.scaleDown,
 | 
				
			||||||
                    width: 40,
 | 
					                    width: 40,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                  title: new Text(I18N.of(context).appTitle),
 | 
					                  title: Text(I18N.of(context).appTitle),
 | 
				
			||||||
                  onTap: _home,
 | 
					                  onTap: _home,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                /*
 | 
					                ListTile(
 | 
				
			||||||
                // TODO - Add search functionality!
 | 
					                  title: Text(I18N.of(context).scanBarcode),
 | 
				
			||||||
                new ListTile(
 | 
					                  onTap: _scan,
 | 
				
			||||||
                  title: new Text("Search"),
 | 
					                  leading: FaIcon(FontAwesomeIcons.barcode),
 | 
				
			||||||
                  leading: new FaIcon(FontAwesomeIcons.search),
 | 
					                ),
 | 
				
			||||||
 | 
					                ListTile(
 | 
				
			||||||
 | 
					                  title: Text(I18N.of(context).search),
 | 
				
			||||||
 | 
					                  leading: FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
                  onTap: _search,
 | 
					                  onTap: _search,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                */
 | 
					                ListTile(
 | 
				
			||||||
                new ListTile(
 | 
					                  title: Text(I18N.of(context).parts),
 | 
				
			||||||
                  title: new Text(I18N.of(context).scanBarcode),
 | 
					                  leading: Icon(Icons.category),
 | 
				
			||||||
                  onTap: _scan,
 | 
					 | 
				
			||||||
                  leading: new FaIcon(FontAwesomeIcons.barcode),
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                new ListTile(
 | 
					 | 
				
			||||||
                  title: new Text(I18N.of(context).parts),
 | 
					 | 
				
			||||||
                  leading: new Icon(Icons.category),
 | 
					 | 
				
			||||||
                  onTap: _showParts,
 | 
					                  onTap: _showParts,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                new ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: new Text(I18N.of(context).stock),
 | 
					                  title: Text(I18N.of(context).stock),
 | 
				
			||||||
                  leading: new FaIcon(FontAwesomeIcons.boxes),
 | 
					                  leading: FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
                  onTap: _showStock,
 | 
					                  onTap: _showStock,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                /*
 | 
					                /*
 | 
				
			||||||
                new ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: new Text("Suppliers"),
 | 
					                  title: Text("Suppliers"),
 | 
				
			||||||
                  leading: new FaIcon(FontAwesomeIcons.building),
 | 
					                  leading: FaIcon(FontAwesomeIcons.building),
 | 
				
			||||||
                  onTap: _showSuppliers,
 | 
					                  onTap: _showSuppliers,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                new ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text("Manufacturers"),
 | 
					                  title: Text("Manufacturers"),
 | 
				
			||||||
                  leading: new FaIcon(FontAwesomeIcons.industry),
 | 
					                  leading: FaIcon(FontAwesomeIcons.industry),
 | 
				
			||||||
                    onTap: _showManufacturers,
 | 
					                    onTap: _showManufacturers,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                new ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: new Text("Customers"),
 | 
					                  title: Text("Customers"),
 | 
				
			||||||
                  leading: new FaIcon(FontAwesomeIcons.users),
 | 
					                  leading: FaIcon(FontAwesomeIcons.users),
 | 
				
			||||||
                  onTap: _showCustomers,
 | 
					                  onTap: _showCustomers,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                */
 | 
					                */
 | 
				
			||||||
                new ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: new Text(I18N.of(context).settings),
 | 
					                  title: Text(I18N.of(context).settings),
 | 
				
			||||||
                  leading: new Icon(Icons.settings),
 | 
					                  leading: Icon(Icons.settings),
 | 
				
			||||||
                  onTap: _settings,
 | 
					                  onTap: _settings,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ]
 | 
					              ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,8 +43,10 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
  void _search() {
 | 
					  void _search() {
 | 
				
			||||||
    if (!InvenTreeAPI().checkConnection(context)) return;
 | 
					    if (!InvenTreeAPI().checkConnection(context)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget()));
 | 
					    showSearch(
 | 
				
			||||||
 | 
					        context: context,
 | 
				
			||||||
 | 
					        delegate: PartSearchDelegate()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void _scan(BuildContext context) {
 | 
					  void _scan(BuildContext context) {
 | 
				
			||||||
@@ -204,13 +206,11 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).appTitle),
 | 
					        title: Text(I18N.of(context).appTitle),
 | 
				
			||||||
        actions: <Widget>[
 | 
					        actions: <Widget>[
 | 
				
			||||||
          /*
 | 
					 | 
				
			||||||
          IconButton(
 | 
					          IconButton(
 | 
				
			||||||
            icon: FaIcon(FontAwesomeIcons.search),
 | 
					            icon: FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
            tooltip: 'Search',
 | 
					            tooltip: I18N.of(context).search,
 | 
				
			||||||
            onPressed: _search,
 | 
					            onPressed: _search,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
           */
 | 
					 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      drawer: new InvenTreeDrawer(context),
 | 
					      drawer: new InvenTreeDrawer(context),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:InvenTree/widget/part_detail.dart';
 | 
				
			||||||
 | 
					import 'package:InvenTree/widget/progress.dart';
 | 
				
			||||||
 | 
					import 'package:InvenTree/widget/snacks.dart';
 | 
				
			||||||
import 'package:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
					import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
				
			||||||
@@ -7,6 +10,156 @@ import 'package:InvenTree/widget/refreshable_state.dart';
 | 
				
			|||||||
import 'package:InvenTree/inventree/part.dart';
 | 
					import 'package:InvenTree/inventree/part.dart';
 | 
				
			||||||
import 'package:InvenTree/inventree/stock.dart';
 | 
					import 'package:InvenTree/inventree/stock.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PartSearchDelegate extends SearchDelegate<InvenTreePart> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final key = GlobalKey<ScaffoldState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool _searching = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // List of part results
 | 
				
			||||||
 | 
					  List<InvenTreePart> partResults = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> search(BuildContext context) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Search string too short!
 | 
				
			||||||
 | 
					    if (query.length < 3) {
 | 
				
			||||||
 | 
					      partResults.clear();
 | 
				
			||||||
 | 
					      showResults(context);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _searching = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Searching...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    showResults(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final results = await InvenTreePart().search(context, query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    partResults.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int idx = 0; idx < results.length; idx++) {
 | 
				
			||||||
 | 
					      if (results[idx] is InvenTreePart) {
 | 
				
			||||||
 | 
					        partResults.add(results[idx]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Searching complete! Results: ${partResults.length}");
 | 
				
			||||||
 | 
					    _searching = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Show a snackbar detailing number of results...
 | 
				
			||||||
 | 
					    //showSnackIcon("Found ${partResults.length} parts", context: context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // For some reason, need to toggle between suggestions and results here...
 | 
				
			||||||
 | 
					    showSuggestions(context);
 | 
				
			||||||
 | 
					    showResults(context);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  List<Widget> buildActions(BuildContext context) {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      IconButton(
 | 
				
			||||||
 | 
					          icon: FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
 | 
					          onPressed: () {
 | 
				
			||||||
 | 
					            search(context);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      IconButton(
 | 
				
			||||||
 | 
					        icon: FaIcon(FontAwesomeIcons.backspace),
 | 
				
			||||||
 | 
					        onPressed: () {
 | 
				
			||||||
 | 
					          query = '';
 | 
				
			||||||
 | 
					          search(context);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget buildLeading(BuildContext context) {
 | 
				
			||||||
 | 
					    return IconButton(
 | 
				
			||||||
 | 
					      icon: Icon(Icons.arrow_back),
 | 
				
			||||||
 | 
					      onPressed: () {
 | 
				
			||||||
 | 
					        this.close(context, null);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Widget _partResult(BuildContext context, int index) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    InvenTreePart part = partResults[index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ListTile(
 | 
				
			||||||
 | 
					      title: Text(part.fullname),
 | 
				
			||||||
 | 
					      subtitle: Text(part.description),
 | 
				
			||||||
 | 
					      leading: InvenTreeAPI().getImage(
 | 
				
			||||||
 | 
					        part.thumbnail,
 | 
				
			||||||
 | 
					        width: 40,
 | 
				
			||||||
 | 
					        height: 40
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      onTap: () {
 | 
				
			||||||
 | 
					        InvenTreePart().get(context, part.pk).then((var prt) {
 | 
				
			||||||
 | 
					          if (prt is InvenTreePart) {
 | 
				
			||||||
 | 
					            Navigator.push(
 | 
				
			||||||
 | 
					              context,
 | 
				
			||||||
 | 
					              MaterialPageRoute(builder: (context) => PartDetailWidget(prt))
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget buildResults(BuildContext context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("Build results called...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (_searching) {
 | 
				
			||||||
 | 
					      return progressIndicator();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (query.length < 3) {
 | 
				
			||||||
 | 
					      return ListTile(
 | 
				
			||||||
 | 
					        title: Text("Query too short"),
 | 
				
			||||||
 | 
					        subtitle: Text("Enter a query of at least three characters")
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (partResults.length == 0) {
 | 
				
			||||||
 | 
					      return ListTile(
 | 
				
			||||||
 | 
					        title: Text("No Results"),
 | 
				
			||||||
 | 
					        subtitle: Text("No results matching query")
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ListView.separated(
 | 
				
			||||||
 | 
					      shrinkWrap: true,
 | 
				
			||||||
 | 
					      physics: ClampingScrollPhysics(),
 | 
				
			||||||
 | 
					      separatorBuilder: (_, __) => const Divider(height: 3),
 | 
				
			||||||
 | 
					      itemBuilder: _partResult,
 | 
				
			||||||
 | 
					      itemCount: partResults.length,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget buildSuggestions(BuildContext context) {
 | 
				
			||||||
 | 
					    // TODO - Implement
 | 
				
			||||||
 | 
					    return Column();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Ensure the search theme matches the app theme
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  ThemeData appBarTheme(BuildContext context) {
 | 
				
			||||||
 | 
					    assert(context != null);
 | 
				
			||||||
 | 
					    final ThemeData theme = Theme.of(context);
 | 
				
			||||||
 | 
					    assert(theme != null);
 | 
				
			||||||
 | 
					    return theme;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SearchWidget extends StatefulWidget {
 | 
					class SearchWidget extends StatefulWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user