From db6aae8a783720a71f29edfe63d067d3c3c93149 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 29 Jan 2021 00:08:17 +1100 Subject: [PATCH] Add "actions" panel to stock item view --- lib/widget/fields.dart | 1 - lib/widget/part_detail.dart | 14 +-- lib/widget/refreshable_state.dart | 10 ++ lib/widget/stock_detail.dart | 149 +++++++++++++++++++++++------- 4 files changed, 128 insertions(+), 46 deletions(-) diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index 80718bc5..c8cba169 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -141,7 +141,6 @@ class QuantityField extends TextFormField { labelText: label, hintText: hint, ), - initialValue: initial, controller: controller, keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), validator: (value) { diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index a06da60a..5d23eacf 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -51,8 +51,6 @@ class _PartDisplayState extends RefreshableState { InvenTreePart part; - int _tabIndex = 0; - @override Future onBuild(BuildContext context) async { refresh(); @@ -302,12 +300,6 @@ class _PartDisplayState extends RefreshableState { } - void _onTabSelectionChanged(int index) { - setState(() { - _tabIndex = index; - }); - } - Widget getSelectedWidget(int index) { switch (index) { case 0: @@ -335,8 +327,8 @@ class _PartDisplayState extends RefreshableState { @override Widget getBottomNavBar(BuildContext context) { return BottomNavigationBar( - currentIndex: _tabIndex, - onTap: _onTabSelectionChanged, + currentIndex: tabIndex, + onTap: onTabSelectionChanged, items: const [ BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.infoCircle), @@ -356,6 +348,6 @@ class _PartDisplayState extends RefreshableState { @override Widget getBody(BuildContext context) { - return getSelectedWidget(_tabIndex); + return getSelectedWidget(tabIndex); } } \ No newline at end of file diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 44e48553..84cf35ab 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -11,6 +11,16 @@ abstract class RefreshableState extends State { // Storage for context once "Build" is called BuildContext context; + // Current tab index (used for widgets which display bottom tabs) + int tabIndex = 0; + + // Update current tab selection + void onTabSelectionChanged(int index) { + setState(() { + tabIndex = index; + }); + } + List getAppBarActions(BuildContext context) { return []; } diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index d08b89cc..c769788b 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -119,6 +119,7 @@ class _StockItemDisplayState extends RefreshableState { void _addStockDialog() async { _quantityController.clear(); + _notesController.clear(); showFormDialog(context, "Add Stock", key: _addStockKey, @@ -165,6 +166,7 @@ class _StockItemDisplayState extends RefreshableState { void _removeStockDialog() { _quantityController.clear(); + _notesController.clear(); showFormDialog(context, "Remove Stock", key: _removeStockKey, @@ -212,6 +214,9 @@ class _StockItemDisplayState extends RefreshableState { void _countStockDialog() async { + _quantityController.text = item.quantity.toString(); + _notesController.clear(); + showFormDialog(context, "Count Stock", key: _countStockKey, actions: [ @@ -331,23 +336,25 @@ class _StockItemDisplayState extends RefreshableState { ); } + Widget headerTile() { + return Card( + child: ListTile( + title: Text("${item.partName}"), + subtitle: Text("${item.partDescription}"), + leading: InvenTreeAPI().getImage(item.partImage), + ) + ); + } + /* * Construct a list of detail elements about this StockItem. * The number of elements may vary depending on the StockItem details */ - List stockTiles() { + List detailTiles() { List tiles = []; // Image / name / description - tiles.add( - Card( - child: ListTile( - title: Text("${item.partName}"), - subtitle: Text("${item.partDescription}"), - leading: InvenTreeAPI().getImage(item.partImage), - ) - ) - ); + tiles.add(headerTile()); tiles.add( ListTile( @@ -412,20 +419,6 @@ class _StockItemDisplayState extends RefreshableState { ); } - tiles.add( - ListTile( - title: Text("Add Barcode"), - leading: FaIcon(FontAwesomeIcons.qrcode), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => InvenTreeQRView(StockItemBarcodeAssignmentHandler(item))) - ); - //Navigator.push(context, MaterialPageRoute(builder: (context) => AssignBarcodeToStockItemView(item))); - }, - ) - ); - // Supplier part? if (item.supplierPartId > 0) { tiles.add( @@ -486,11 +479,83 @@ class _StockItemDisplayState extends RefreshableState { return tiles; } + List actionTiles() { + List tiles = []; + + tiles.add(headerTile()); + + if (!item.isSerialized()) { + tiles.add( + ListTile( + title: Text("Count Stock"), + leading: FaIcon(FontAwesomeIcons.checkCircle), + onTap: _countStockDialog, + ) + ); + + tiles.add( + ListTile( + title: Text("Remove Stock"), + leading: FaIcon(FontAwesomeIcons.minusCircle), + onTap: _removeStockDialog, + ) + ); + + tiles.add( + ListTile( + title: Text("Add Stock"), + leading: FaIcon(FontAwesomeIcons.plusCircle), + onTap: _addStockDialog, + ) + ); + } + + tiles.add( + ListTile( + title: Text("Transfer Stock"), + leading: FaIcon(FontAwesomeIcons.exchangeAlt), + onTap: _transferStockDialog, + ) + ); + + // Scan item into a location + tiles.add( + ListTile( + title: Text("Scan Into Location"), + leading: FaIcon(FontAwesomeIcons.exchangeAlt), + trailing: FaIcon(FontAwesomeIcons.qrcode), + onTap: () { + }, + ) + ); + + // Add or remove custom barcode + if (item.uid.isEmpty) { + tiles.add( + ListTile( + title: Text("Assign Barcode"), + leading: FaIcon(FontAwesomeIcons.barcode), + trailing: FaIcon(FontAwesomeIcons.qrcode), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeQRView(StockItemBarcodeAssignmentHandler(item))) + ); + } + ) + ); + } + + return tiles; + } + /* * Return a list of context-sensitive action buttons. * Not all buttons will be avaialable for a given StockItem, * depending on the properties of that StockItem */ + + /* List actionButtons() { var buttons = List(); @@ -525,32 +590,47 @@ class _StockItemDisplayState extends RefreshableState { return buttons; } + */ @override Widget getBottomNavBar(BuildContext context) { return BottomNavigationBar( - currentIndex: 0, - onTap: null, + currentIndex: tabIndex, + onTap: onTabSelectionChanged, items: const [ BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.infoCircle), title: Text("Details"), ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.history), - title: Text("History"), - ) + icon: FaIcon(FontAwesomeIcons.wrench), + title: Text("Actions"), + ), ] ); } - @override - Widget getBody(BuildContext context) { - return ListView( - children: stockTiles() - ); + Widget getSelectedWidget(int index) { + switch (index) { + case 0: + return ListView( + children: detailTiles(), + ); + case 1: + return ListView( + children: actionTiles(), + ); + default: + return null; + } } + @override + Widget getBody(BuildContext context) { + return getSelectedWidget(tabIndex); + } + + /* @override Widget getFab(BuildContext context) { return SpeedDial( @@ -560,4 +640,5 @@ class _StockItemDisplayState extends RefreshableState { children: actionButtons(), ); } + */ } \ No newline at end of file