From 4c8bbd46e7d2fc0a40ef82bde71cb2491c0898c6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 5 Apr 2020 23:10:36 +1000 Subject: [PATCH] StockLocation display now improved - Expandable list of sublocations - Expandable list of stockitems - Traverse upward (to higher locations) - Fix rendering of unknown part thumbnails --- lib/inventree/part.dart | 3 +- lib/inventree/stock.dart | 31 ++++++- lib/main.dart | 6 +- lib/widget/category_display.dart | 9 +- lib/widget/location_display.dart | 151 ++++++++++++++++++++++++------- 5 files changed, 154 insertions(+), 46 deletions(-) diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index c9d1fb59..6b09842e 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -15,6 +15,7 @@ class InvenTreePartCategory extends InvenTreeModel { String get pathstring => jsondata['pathstring'] ?? ''; String get parentpathstring { + // TODO - Drive the refactor tractor through this List psplit = pathstring.split("/"); if (psplit.length > 0) { @@ -24,7 +25,7 @@ class InvenTreePartCategory extends InvenTreeModel { String p = psplit.join("/"); if (p.isEmpty) { - p = "Top level parts category"; + p = "Top level part category"; } return p; diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 842f32b8..7bfe2bd2 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -16,7 +16,13 @@ class InvenTreeStockItem extends InvenTreeModel { String get partDescription => jsondata['part__description'] as String ?? ''; - String get partThumbnail => jsondata['part__thumbnail'] as String ?? InvenTreeAPI.staticThumb; + String get partThumbnail { + String thumb = jsondata['part__thumbnail'] as String ?? ''; + + if (thumb.isEmpty) thumb = InvenTreeAPI.staticThumb; + + return thumb; + } int get serialNumber => jsondata['serial'] as int ?? null; @@ -49,10 +55,31 @@ class InvenTreeStockLocation extends InvenTreeModel { @override String URL = "stock/location/"; + String get pathstring => jsondata['pathstring'] ?? ''; + + String get parentpathstring { + // TODO - Drive the refactor tractor through this + List psplit = pathstring.split('/'); + + if (psplit.length > 0) { + psplit.removeLast(); + } + + String p = psplit.join('/'); + + if (p.isEmpty) { + p = "Top level stock location"; + } + + return p; + } + + int get itemcount => jsondata['items'] ?? 0; + InvenTreeStockLocation() : super(); InvenTreeStockLocation.fromJson(Map json) : super.fromJson(json) { - + // TODO } @override diff --git a/lib/main.dart b/lib/main.dart index 1b5b59eb..121fa93a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -326,11 +326,11 @@ class _MyHomePageState extends State { Column( children: [ IconButton( - icon: new FaIcon(FontAwesomeIcons.shippingFast), - tooltip: "Sell", + icon: new FaIcon(FontAwesomeIcons.truck), + tooltip: "Ship", onPressed: _unsupported, ), - Text("Sell"), + Text("Ship"), ] ) ], diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index f22fd616..0f68703f 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -114,11 +114,9 @@ class _CategoryDisplayState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); } else { // TODO - Refactor this code into the InvenTreePart class - InvenTreePartCategory().get(category.parentId).then(( - var cat) { + InvenTreePartCategory().get(category.parentId).then((var cat) { if (cat is InvenTreePartCategory) { - Navigator.push(context, MaterialPageRoute(builder: ( - context) => CategoryDisplayWidget(cat))); + Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(cat))); } }); } @@ -138,13 +136,10 @@ class _CategoryDisplayState extends State { ), drawer: new InvenTreeDrawer(context), body: ListView( - //mainAxisAlignment: MainAxisAlignment.start, - //mainAxisSize: MainAxisSize.max, children: [ getCategoryDescriptionCard(), ExpansionPanelList( expansionCallback: (int index, bool isExpanded) { - print("callback!"); setState(() { switch (index) { diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 86d8a59c..49654ffb 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -5,6 +5,7 @@ import 'package:InvenTree/widget/stock_display.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class LocationDisplayWidget extends StatefulWidget { @@ -45,12 +46,19 @@ class _LocationDisplayState extends State { String get _title { if (location == null) { - return "Location:"; + return "Stock Locations"; } else { - return "Stock Location '${location.name}'"; + return "Stock Location - ${location.name}"; } } + /* + * Request data from the server. + * It will be displayed once loaded + * + * - List of sublocations under this one + * - List of stock items at this location + */ void _requestData() { int pk = location?.pk ?? -1; @@ -83,6 +91,50 @@ class _LocationDisplayState extends State { }); } + bool _locationListExpanded = false; + bool _stockListExpanded = true; + + Widget locationDescriptionCard() { + if (location == null) { + return Card( + child: ListTile( + title: Text("Stock Locations"), + subtitle: Text("Top level stock location") + ) + ); + } else { + return Card( + child: Column( + children: [ + ListTile( + title: Text("${location.name}"), + subtitle: Text("${location.description}"), + trailing: IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + onPressed: null, + ), + ), + ListTile( + title: Text("Parent Category"), + subtitle: Text("${location.parentpathstring}"), + onTap: () { + if (location.parentId < 0) { + Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); + } else { + InvenTreeStockLocation().get(location.parentId).then((var loc) { + if (loc is InvenTreeStockLocation) { + Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); + } + }); + } + }, + ) + ] + ) + ); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -90,36 +142,62 @@ class _LocationDisplayState extends State { title: Text(_title), ), drawer: new InvenTreeDrawer(context), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Sublocations - ${_sublocations.length}", - textAlign: TextAlign.left, - style: TextStyle(fontWeight: FontWeight.bold), - ), - TextField( - decoration: InputDecoration( - hintText: "Filter locations", + body: ListView( + children: [ + locationDescriptionCard(), + ExpansionPanelList( + expansionCallback: (int index, bool isExpanded) { + setState(() { + switch (index) { + case 0: + _locationListExpanded = !isExpanded; + break; + case 1: + _stockListExpanded = !isExpanded; + break; + default: + break; + } + }); + + }, + children: [ + ExpansionPanel( + headerBuilder: (BuildContext context, bool isExpanded) { + return ListTile( + title: Text("Sublocations"), + leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + trailing: Text("${_sublocations.length}"), + onTap: () { + setState(() { + _locationListExpanded = !_locationListExpanded; + }); + }, + ); + }, + body: SublocationList(_sublocations), + isExpanded: _locationListExpanded, ), - onChanged: (text) { - setState(() { - _locationFilter = text.trim().toLowerCase(); - }); - }, - ), - Expanded(child: SublocationList(sublocations)), - Divider(), - Text( - "Stock Items - ${_items.length}", - textAlign: TextAlign.left, - style: TextStyle(fontWeight: FontWeight.bold), - ), - Expanded(child: StockList(_items)), - ], - ) - ), + ExpansionPanel( + headerBuilder: (BuildContext context, bool isExpanded) { + return ListTile( + title: Text("Stock Items"), + leading: FaIcon(FontAwesomeIcons.boxes), + trailing: Text("${_items.length}"), + onTap: () { + setState(() { + _stockListExpanded = !_stockListExpanded; + }); + }, + ); + }, + body: StockList(_items), + isExpanded: _stockListExpanded, + ) + ] + ), + ] + ) ); } } @@ -146,6 +224,7 @@ class SublocationList extends StatelessWidget { return ListTile( title: Text('${loc.name}'), subtitle: Text("${loc.description}"), + trailing: Text("${loc.itemcount}"), onTap: () { _openLocation(context, loc.pk); }, @@ -154,7 +233,10 @@ class SublocationList extends StatelessWidget { @override Widget build(BuildContext context) { - return ListView.builder(itemBuilder: _build, itemCount: _locations.length); + return ListView.builder( + shrinkWrap: true, + physics: ClampingScrollPhysics(), + itemBuilder: _build, itemCount: _locations.length); } } @@ -192,6 +274,9 @@ class StockList extends StatelessWidget { @override Widget build(BuildContext context) { - return ListView.builder(itemBuilder: _build, itemCount: _items.length); + return ListView.builder( + shrinkWrap: true, + physics: ClampingScrollPhysics(), + itemBuilder: _build, itemCount: _items.length); } } \ No newline at end of file