diff --git a/lib/l10n b/lib/l10n index 6e095a0d..cafa8e16 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit 6e095a0d6c7d044a60ccda07d03ae8594d8b4b27 +Subproject commit cafa8e1654abab53da273d73f505b4618bc3861a diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 9e47af4f..a3c94434 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -1,7 +1,9 @@ import 'dart:io'; +import 'package:InvenTree/inventree/stock.dart'; import 'package:InvenTree/widget/progress.dart'; import 'package:InvenTree/widget/snacks.dart'; +import 'package:InvenTree/widget/stock_detail.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -15,7 +17,6 @@ import 'package:InvenTree/widget/full_screen_image.dart'; import 'package:InvenTree/widget/category_display.dart'; import 'package:InvenTree/widget/dialogs.dart'; import 'package:InvenTree/widget/fields.dart'; -import 'package:InvenTree/widget/part_stock_detail.dart'; import 'package:InvenTree/api.dart'; import 'package:InvenTree/widget/refreshable_state.dart'; @@ -36,7 +37,7 @@ class _PartDisplayState extends RefreshableState { final _editPartKey = GlobalKey(); @override - String getAppBarTitle(BuildContext context) => I18N.of(context).part; + String getAppBarTitle(BuildContext context) => I18N.of(context).partDetails; @override List getAppBarActions(BuildContext context) { @@ -68,11 +69,8 @@ class _PartDisplayState extends RefreshableState { @override Future request(BuildContext context) async { await part.reload(context); + await part.getStockItems(context); await part.getTestTemplates(context); - - setState(() { - - }); } void _savePart(Map values) async { @@ -88,15 +86,6 @@ class _PartDisplayState extends RefreshableState { refresh(); } - void _showStock(BuildContext context) async { - await part.getStockItems(context); - - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartStockDetailWidget(part)) - ); - } - void _editPartDialog() { // Values which can be edited @@ -157,7 +146,7 @@ class _PartDisplayState extends RefreshableState { MaterialPageRoute(builder: (context) => FullScreenWidget(part.fullname, part.image)) ); }), - ) + ), ); } @@ -215,13 +204,16 @@ class _PartDisplayState extends RefreshableState { leading: FaIcon(FontAwesomeIcons.boxes), trailing: Text("${part.inStockString}"), onTap: () { - _showStock(context); + setState(() { + tabIndex = 1; + }); }, ), ); + // TODO - Add link to parts on order // Parts on order - if (part.isPurchaseable) { + if (false && part.isPurchaseable) { tiles.add( ListTile( title: Text("On Order"), @@ -318,6 +310,26 @@ class _PartDisplayState extends RefreshableState { } + // Return tiles for each stock item + List stockTiles() { + List tiles = []; + + tiles.add(headerTile()); + + if (loading) { + tiles.add(progressIndicator()); + } else if (part.stockItems.length > 0) { + tiles.add(PartStockList(part.stockItems)); + } else { + tiles.add(ListTile( + title: Text("No Stock"), + subtitle: Text("No stock items available") + )); + } + + return tiles; + } + List actionTiles() { List tiles = []; @@ -356,6 +368,15 @@ class _PartDisplayState extends RefreshableState { ), ); case 1: + return Center( + child: ListView( + children: ListTile.divideTiles( + context: context, + tiles: stockTiles() + ).toList() + ) + ); + case 2: return Center( child: ListView( children: ListTile.divideTiles( @@ -377,11 +398,15 @@ class _PartDisplayState extends RefreshableState { items: [ BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.infoCircle), - title: Text(I18N.of(context).details), + label: I18N.of(context).details, + ), + BottomNavigationBarItem( + icon: FaIcon(FontAwesomeIcons.boxes), + label: I18N.of(context).stock ), BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.wrench), - title: Text(I18N.of(context).actions), + label: I18N.of(context).actions, ), ] ); @@ -391,4 +416,45 @@ class _PartDisplayState extends RefreshableState { Widget getBody(BuildContext context) { return getSelectedWidget(tabIndex); } +} + +class PartStockList extends StatelessWidget { + final List _items; + + PartStockList(this._items); + + void _openItem(BuildContext context, int pk) { + // Load detail view for stock item + InvenTreeStockItem().get(context, pk).then((var item) { + if (item is InvenTreeStockItem) { + Navigator.push(context, MaterialPageRoute(builder: (context) => StockDetailWidget(item))); + } + }); + } + + Widget _build(BuildContext context, int index) { + + InvenTreeStockItem item = _items[index]; + + return ListTile( + title: Text("${item.locationName}"), + subtitle: Text("${item.locationPathString}"), + trailing: Text(item.serialOrQuantityDisplay()), + leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + onTap: () { + _openItem(context, item.pk); + }, + ); + } + + @override + Widget build(BuildContext context) { + return ListView.separated( + shrinkWrap: true, + physics: ClampingScrollPhysics(), + itemBuilder: _build, + separatorBuilder: (_, __) => const Divider(height: 3), + itemCount: _items.length + ); + } } \ No newline at end of file diff --git a/lib/widget/part_stock_detail.dart b/lib/widget/part_stock_detail.dart deleted file mode 100644 index 4d39f58a..00000000 --- a/lib/widget/part_stock_detail.dart +++ /dev/null @@ -1,110 +0,0 @@ -// Flutter packages -import 'package:InvenTree/inventree/stock.dart'; -import 'package:InvenTree/widget/refreshable_state.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -// InvenTree packages -import 'package:InvenTree/api.dart'; -import 'package:InvenTree/inventree/part.dart'; -import 'package:InvenTree/widget/stock_detail.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; - -class PartStockDetailWidget extends StatefulWidget { - /* - * The PartStockDetail widget displays all "in stock" instances for a given Part - */ - - PartStockDetailWidget(this.part, {Key key}) : super(key: key); - - final InvenTreePart part; - - @override - _PartStockDisplayState createState() => _PartStockDisplayState(part); -} - - -class _PartStockDisplayState extends RefreshableState { - - @override - String getAppBarTitle(BuildContext context) => I18N.of(context).partStock; - - _PartStockDisplayState(this.part) { - // TODO - } - - InvenTreePart part; - - @override - Future onBuild(BuildContext context) async { - refresh(); - } - - @override - Future request(BuildContext context) async { - await part.reload(context); - await part.getStockItems(context); - - setState(() { - }); - } - - @override - Widget getBody(BuildContext context) { - return ListView( - children: [ - Card( - child: ListTile( - title: Text(part.fullname), - subtitle: Text(part.description), - leading: InvenTreeAPI().getImage(part.thumbnail), - trailing: Text(part.inStockString), - ) - ), - PartStockList(part.stockItems), - ] - ); - } -} - - -class PartStockList extends StatelessWidget { - final List _items; - - PartStockList(this._items); - - void _openItem(BuildContext context, int pk) { - // Load detail view for stock item - InvenTreeStockItem().get(context, pk).then((var item) { - if (item is InvenTreeStockItem) { - Navigator.push(context, MaterialPageRoute(builder: (context) => StockDetailWidget(item))); - } - }); - } - - Widget _build(BuildContext context, int index) { - - InvenTreeStockItem item = _items[index]; - - return ListTile( - title: Text("${item.locationName}"), - subtitle: Text("${item.locationPathString}"), - trailing: Text(item.serialOrQuantityDisplay()), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), - onTap: () { - _openItem(context, item.pk); - }, - ); - } - - @override - Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - itemBuilder: _build, - separatorBuilder: (_, __) => const Divider(height: 3), - itemCount: _items.length - ); - } -} \ No newline at end of file