diff --git a/lib/api.dart b/lib/api.dart index f22dd1f3..f947655f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -380,7 +380,7 @@ class InvenTreeAPI { * Load image from the InvenTree server, * or from local cache (if it has been cached!) */ - CachedNetworkImage getImage(String imageUrl) { + CachedNetworkImage getImage(String imageUrl, {double height, double width}) { if (imageUrl.isEmpty) { imageUrl = staticImage; } @@ -392,6 +392,8 @@ class InvenTreeAPI { placeholder: (context, url) => CircularProgressIndicator(), errorWidget: (context, url, error) => Icon(FontAwesomeIcons.exclamation), httpHeaders: defaultHeaders(), + height: height, + width: width, ); } } \ No newline at end of file diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index f9935227..0938be0c 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -47,13 +47,15 @@ class InvenTreeModel { String get description => jsondata['description'] ?? ''; - String get notes => jsondata['notes'] ?? ''; + String get notes => jsondata['notes'] as String ?? ''; - int get parentId => jsondata['parent'] ?? -1; + int get parentId => jsondata['parent'] as int ?? -1; // Legacy API provided external link as "URL", while newer API uses "link" String get link => jsondata['link'] ?? jsondata['URL'] ?? ''; + String get keywords => jsondata['keywords'] as String ?? ''; + // Create a new object from JSON data (not a constructor!) InvenTreeModel createFromJson(Map json) { diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 18f86349..73bb0d15 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -31,6 +31,17 @@ class _CategoryDisplayState extends RefreshableState { @override String getAppBarTitle(BuildContext context) { return "Part Category"; } + @override + List getAppBarActions(BuildContext context) { + return [ + IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + tooltip: 'Edit', + onPressed: null, + ) + ]; + } + _CategoryDisplayState(this.category) {} // The local InvenTreePartCategory object @@ -94,10 +105,6 @@ class _CategoryDisplayState extends RefreshableState { ListTile( title: Text("${category.name}"), subtitle: Text("${category.description}"), - trailing: IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - onPressed: null, - ), ), ListTile( title: Text("Parent Category"), @@ -260,7 +267,11 @@ class PartList extends StatelessWidget { return ListTile( title: Text("${part.name}"), subtitle: Text("${part.description}"), - leading: InvenTreeAPI().getImage(part.thumbnail), + leading: InvenTreeAPI().getImage( + part.thumbnail, + width: 40, + height: 40, + ), onTap: () { _openPart(context, part.pk); }, diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 359ee8f3..d61c8a70 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -28,6 +28,18 @@ class _LocationDisplayState extends RefreshableState { @override String getAppBarTitle(BuildContext context) { return "Stock Location"; } + @override + List getAppBarActions(BuildContext context) { + return [ + IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + tooltip: "Edit", + // TODO - Edit stock location + onPressed: null, + ) + ]; + } + _LocationDisplayState(this.location) {} List _sublocations = List(); @@ -98,10 +110,6 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text("${location.name}"), subtitle: Text("${location.description}"), - trailing: IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - onPressed: null, - ), ), ListTile( title: Text("Parent Category"), @@ -245,7 +253,11 @@ class StockList extends StatelessWidget { return ListTile( title: Text("${item.partName}"), subtitle: Text("${item.partDescription}"), - leading: InvenTreeAPI().getImage(item.partThumbnail), + leading: InvenTreeAPI().getImage( + item.partThumbnail, + width: 40, + height: 40, + ), trailing: Text("${item.displayQuantity}", style: TextStyle(fontWeight: FontWeight.bold), ), diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 6e72184d..ed366945 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -87,6 +87,7 @@ class _PartDisplayState extends RefreshableState { var _description; var _ipn; var _revision; + var _keywords; showFormDialog(context, "Edit Part", key: _editPartKey, @@ -107,6 +108,7 @@ class _PartDisplayState extends RefreshableState { "name": _name, "description": _description, "IPN": _ipn, + "keywords": _keywords, }); } }, @@ -128,6 +130,12 @@ class _PartDisplayState extends RefreshableState { initial: part.IPN, allowEmpty: true, onSaved: (value) => _ipn = value, + ), + StringField( + label: "Keywords", + initial: part.keywords, + allowEmpty: true, + onSaved: (value) => _keywords = value, ) ] @@ -183,37 +191,25 @@ class _PartDisplayState extends RefreshableState { ); } - // External link? - if (part.link.isNotEmpty) { - tiles.add( - ListTile( - title: Text("${part.link}"), - leading: FaIcon(FontAwesomeIcons.link), - trailing: Text(""), - onTap: null, - ) - ); - } - // Stock information tiles.add( - ListTile( - title: Text("Stock"), - leading: FaIcon(FontAwesomeIcons.boxes), - trailing: Text("${part.inStock}"), - onTap: () { - Navigator.push( + ListTile( + title: Text("Stock"), + leading: FaIcon(FontAwesomeIcons.boxes), + trailing: Text("${part.inStock}"), + onTap: () { + Navigator.push( context, MaterialPageRoute(builder: (context) => PartStockDetailWidget(part)) - ); - }, - ), + ); + }, + ), ); // Parts on order if (part.isPurchaseable) { tiles.add( - ListTile( + ListTile( title: Text("On Order"), leading: FaIcon(FontAwesomeIcons.shoppingCart), trailing: Text("${part.onOrder}"), @@ -227,11 +223,11 @@ class _PartDisplayState extends RefreshableState { if (false && part.isAssembly) { tiles.add(ListTile( - title: Text("Bill of Materials"), - leading: FaIcon(FontAwesomeIcons.thList), - trailing: Text("${part.bomItemCount}"), - onTap: null, - ) + title: Text("Bill of Materials"), + leading: FaIcon(FontAwesomeIcons.thList), + trailing: Text("${part.bomItemCount}"), + onTap: null, + ) ); tiles.add( @@ -247,9 +243,31 @@ class _PartDisplayState extends RefreshableState { // TODO - Do we want to use the app to display "used in"? if (false && part.isComponent) { tiles.add(ListTile( - title: Text("Used In"), - leading: FaIcon(FontAwesomeIcons.sitemap), - trailing: Text("${part.usedInCount}"), + title: Text("Used In"), + leading: FaIcon(FontAwesomeIcons.sitemap), + trailing: Text("${part.usedInCount}"), + onTap: null, + ) + ); + } + + // Keywords? + if (part.keywords.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${part.keywords}"), + leading: FaIcon(FontAwesomeIcons.key), + ) + ); + } + + // External link? + if (part.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${part.link}"), + leading: FaIcon(FontAwesomeIcons.link), + trailing: Text(""), onTap: null, ) );