From 5652926a382939afd7fb5f7300c5606ff64236fe Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 5 Apr 2020 23:16:09 +1000 Subject: [PATCH 01/10] Close expander items if there are no children! --- lib/widget/category_display.dart | 4 ++-- lib/widget/location_display.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 0f68703f..f1f02823 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -169,7 +169,7 @@ class _CategoryDisplayState extends State { ); }, body: SubcategoryList(_subcategories), - isExpanded: _subcategoriesExpanded, + isExpanded: _subcategoriesExpanded && _subcategories.length > 0, ), ExpansionPanel( headerBuilder: (BuildContext context, bool isExpanded) { @@ -185,7 +185,7 @@ class _CategoryDisplayState extends State { ); }, body: PartList(_parts), - isExpanded: _partListExpanded, + isExpanded: _partListExpanded && _parts.length > 0, ) ], ), diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 49654ffb..8cfd141c 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -176,7 +176,7 @@ class _LocationDisplayState extends State { ); }, body: SublocationList(_sublocations), - isExpanded: _locationListExpanded, + isExpanded: _locationListExpanded && _sublocations.length > 0, ), ExpansionPanel( headerBuilder: (BuildContext context, bool isExpanded) { @@ -192,7 +192,7 @@ class _LocationDisplayState extends State { ); }, body: StockList(_items), - isExpanded: _stockListExpanded, + isExpanded: _stockListExpanded && _items.length > 0, ) ] ), From fb1fb799d2219948d8a16da9d9140826e2aa8185 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 12:09:27 +1000 Subject: [PATCH 02/10] Better layout mechanic for Part display - Now works well even if it overflows the available screen space --- lib/widget/part_display.dart | 88 +++++++++++------------------------- 1 file changed, 26 insertions(+), 62 deletions(-) diff --git a/lib/widget/part_display.dart b/lib/widget/part_display.dart index 712069e6..88e47b54 100644 --- a/lib/widget/part_display.dart +++ b/lib/widget/part_display.dart @@ -29,50 +29,35 @@ class _PartDisplayState extends State { InvenTreePart part; - /* - * Construct a list of detail elements about this part. - * Not all elements are set for each part, so only add the ones that are important. - */ - List partDetails() { - List widgets = [ - - // Image / name / description - ListTile( - title: Text("${part.fullname}"), - subtitle: Text("${part.description}"), - leading: Image( - image: InvenTreeAPI().getImage(part.image) - ), - trailing: IconButton( - icon: FaIcon(FontAwesomeIcons.edit), - onPressed: null, - ), - ) - ]; - - return widgets; - } - /* * Build a list of tiles to display under the part description */ List partTiles() { List tiles = [ - Card( - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: partDetails(), - ) - ), ]; + // Image / name / description + tiles.add( + Card( + child: ListTile( + title: Text("${part.fullname}"), + subtitle: Text("${part.description}"), + leading: Image( + image: InvenTreeAPI().getImage(part.image) + ), + trailing: IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + onPressed: null, + ), + ) + ) + ); + // Category information if (part.categoryName.isNotEmpty) { tiles.add( - Card( - child: ListTile( + ListTile( title: Text("Part Category"), subtitle: Text("${part.categoryName}"), leading: FaIcon(FontAwesomeIcons.stream), @@ -82,105 +67,86 @@ class _PartDisplayState extends State { }); }, ) - ) ); } // External link? if (part.link.isNotEmpty) { tiles.add( - Card( - child: ListTile( + ListTile( title: Text("${part.link}"), leading: FaIcon(FontAwesomeIcons.link), trailing: Text(""), onTap: null, ) - ) ); } // Stock information tiles.add( - Card( - child: ListTile( + ListTile( title: Text("Stock"), leading: FaIcon(FontAwesomeIcons.boxes), trailing: Text("${part.inStock}"), onTap: null, ), - ) ); // Parts on order if (part.isPurchaseable) { tiles.add( - Card( - child: ListTile( + ListTile( title: Text("On Order"), leading: FaIcon(FontAwesomeIcons.shoppingCart), trailing: Text("${part.onOrder}"), onTap: null, ) - ) ); } // Parts being built if (part.isAssembly) { - tiles.add( - Card( - child: ListTile( + tiles.add(ListTile( title: Text("Bill of Materials"), leading: FaIcon(FontAwesomeIcons.thList), trailing: Text("${part.bomItemCount}"), onTap: null, ) - ) ); tiles.add( - Card( - child: ListTile( + ListTile( title: Text("Building"), leading: FaIcon(FontAwesomeIcons.tools), trailing: Text("${part.building}"), onTap: null, ) - ) ); } if (part.isComponent) { - tiles.add( - Card( - child: ListTile( + tiles.add(ListTile( title: Text("Used In"), leading: FaIcon(FontAwesomeIcons.sitemap), trailing: Text("${part.usedInCount}"), onTap: null, ) - ) ); } // Notes field? if (part.notes.isNotEmpty) { tiles.add( - Card( - child: ListTile( + ListTile( title: Text("Notes"), leading: FaIcon(FontAwesomeIcons.stickyNote), trailing: Text(""), onTap: null, ) - ) ); } - tiles.add(Spacer()); - return tiles; } @@ -193,9 +159,7 @@ class _PartDisplayState extends State { ), drawer: new InvenTreeDrawer(context), body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, + child: ListView( children: partTiles(), ), ) From 59d2b9cf1a33adc1e89c0c83ff1c0de40ef08b30 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 12:35:59 +1000 Subject: [PATCH 03/10] Configurable GET and LIST filters per model type --- lib/inventree/model.dart | 32 ++++++++++++++++++++++++++++---- lib/inventree/part.dart | 9 +++++++++ lib/inventree/stock.dart | 11 +++++++++++ lib/widget/part_display.dart | 3 +-- lib/widget/stock_display.dart | 19 +++++++++++++++++++ 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 40ef716a..38680ba7 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -74,8 +74,13 @@ class InvenTreeModel { } */ + Map defaultListFilters() { return Map(); } + + // A map of "default" headers to use when performing a GET request + Map defaultGetFilters() { return Map(); } + // Return the detail view for the associated pk - Future get(int pk) async { + Future get(int pk, {Map filters}) async { // TODO - Add "timeout" // TODO - Add error catching @@ -86,7 +91,18 @@ class InvenTreeModel { addr += "/"; } - var response = await InvenTreeAPI().get(addr); + var params = defaultGetFilters(); + + if (filters != null) { + // Override any default values + for (String key in filters.keys) { + params[key] = filters[key]; + } + } + + print("GET: $addr ${params.toString()}"); + + var response = await InvenTreeAPI().get(addr, params: params); if (response.statusCode != 200) { print("Error retrieving data"); @@ -105,12 +121,20 @@ class InvenTreeModel { filters = {}; } - print("Listing endpoint: $URL"); + var params = defaultListFilters(); + + if (filters != null) { + for (String key in filters.keys) { + params[key] = filters[key]; + } + } + + print("LIST: $URL ${params.toString()}"); // TODO - Add "timeout" // TODO - Add error catching - var response = await InvenTreeAPI().get(URL, params:filters); + var response = await InvenTreeAPI().get(URL, params:params); // A list of "InvenTreeModel" items List results = new List(); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 6b09842e..3283a19c 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -12,6 +12,15 @@ class InvenTreePartCategory extends InvenTreeModel { @override String URL = "part/category/"; + @override + Map defaultListFilters() { + var filters = new Map(); + + filters["active"] = "true"; + + return filters; + } + String get pathstring => jsondata['pathstring'] ?? ''; String get parentpathstring { diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 7bfe2bd2..50ccadb5 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -6,6 +6,17 @@ class InvenTreeStockItem extends InvenTreeModel { @override String URL = "stock/"; + @override + Map defaultGetFilters() { + + var headers = new Map(); + + headers["part_detail"] = "true"; + headers["location_detail"] = "true"; + + return headers; + } + InvenTreeStockItem() : super(); InvenTreeStockItem.fromJson(Map json) : super.fromJson(json) { diff --git a/lib/widget/part_display.dart b/lib/widget/part_display.dart index 88e47b54..327040d7 100644 --- a/lib/widget/part_display.dart +++ b/lib/widget/part_display.dart @@ -34,8 +34,7 @@ class _PartDisplayState extends State { */ List partTiles() { - List tiles = [ - ]; + List tiles = []; // Image / name / description tiles.add( diff --git a/lib/widget/stock_display.dart b/lib/widget/stock_display.dart index 45c9e041..a4e04a97 100644 --- a/lib/widget/stock_display.dart +++ b/lib/widget/stock_display.dart @@ -33,6 +33,25 @@ class _StockItemDisplayState extends State { } } + /* + * Construct a list of detail elements about this StockItem. + * The number of elements may vary depending on the StockItem details + */ + List stockTiles() { + List tiles = []; + + // Image / name / description + tiles.add( + Card( + child: ListTile( + title: Text("${item.partName}"), + ) + ) + ); + + return tiles; + } + @override Widget build(BuildContext context) { return Scaffold( From 5e3793b3ba98157d2723475a0793f28332ac636a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 12:56:40 +1000 Subject: [PATCH 04/10] Moar features for "StockItem" class --- lib/inventree/stock.dart | 47 +++++++++++++++++++++++++++++++++-- lib/widget/stock_display.dart | 28 ++++++++++----------- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 50ccadb5..450a20cf 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'model.dart'; import 'package:InvenTree/api.dart'; @@ -23,9 +25,50 @@ class InvenTreeStockItem extends InvenTreeModel { // TODO } - String get partName => jsondata['part__name'] as String ?? ''; + String get partName { - String get partDescription => jsondata['part__description'] as String ?? ''; + String nm = ''; + + // Use the detailed part information as priority + if (jsondata.containsKey('part_detail')) { + nm = jsondata['part_detail']['full_name'] ?? ''; + } + + if (nm.isEmpty) { + nm = jsondata['part__name'] ?? ''; + } + + return nm; + } + + String get partDescription { + String desc = ''; + + // Use the detailed part description as priority + if (jsondata.containsKey('part_detail')) { + desc = jsondata['part_detail']['description'] ?? ''; + } + + if (desc.isEmpty) { + desc = jsondata['part__description'] ?? ''; + } + + return desc; + } + + String get partImage { + String img = ''; + + if (jsondata.containsKey('part_detail')) { + img = jsondata['part_detail']['thumbnail'] ?? ''; + } + + if (img.isEmpty) { + img = jsondata['part__thumbnail'] ?? ''; + } + + return img; + } String get partThumbnail { String thumb = jsondata['part__thumbnail'] as String ?? ''; diff --git a/lib/widget/stock_display.dart b/lib/widget/stock_display.dart index a4e04a97..5bce2bde 100644 --- a/lib/widget/stock_display.dart +++ b/lib/widget/stock_display.dart @@ -4,7 +4,10 @@ import 'package:InvenTree/inventree/stock.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:InvenTree/api.dart'; + import 'package:InvenTree/widget/drawer.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class StockItemDisplayWidget extends StatefulWidget { @@ -25,14 +28,6 @@ class _StockItemDisplayState extends State { final InvenTreeStockItem item; - String get _title { - if (item == null) { - return "Stock Item"; - } else { - return "Item: x ${item.partName}"; - } - } - /* * Construct a list of detail elements about this StockItem. * The number of elements may vary depending on the StockItem details @@ -45,6 +40,14 @@ class _StockItemDisplayState extends State { Card( child: ListTile( title: Text("${item.partName}"), + subtitle: Text("${item.partDescription}"), + leading: Image( + image: InvenTreeAPI().getImage(item.partImage), + ), + trailing: IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + onPressed: null, + ) ) ) ); @@ -56,15 +59,12 @@ class _StockItemDisplayState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(_title), + title: Text("Stock Item"), ), drawer: new InvenTreeDrawer(context), body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("Stock Item: hello"), - ], + child: ListView( + children: stockTiles(), ) ) ); From 948c9c1d23f2c84e8afe1f553c2fdd102439dde1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 22:13:57 +1000 Subject: [PATCH 05/10] Further improvements for stock view --- lib/inventree/stock.dart | 53 ++++++++++++++++++- lib/widget/part_display.dart | 9 ++-- lib/widget/stock_display.dart | 97 +++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 4 deletions(-) diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 450a20cf..60aaaecd 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -15,6 +15,7 @@ class InvenTreeStockItem extends InvenTreeModel { headers["part_detail"] = "true"; headers["location_detail"] = "true"; + headers["supplier_detail"] = "true"; return headers; } @@ -25,6 +26,10 @@ class InvenTreeStockItem extends InvenTreeModel { // TODO } + int get partId => jsondata['part'] ?? -1; + + int get trackingItemCount => jsondata['tracking_items'] as int ?? 0; + String get partName { String nm = ''; @@ -78,12 +83,58 @@ class InvenTreeStockItem extends InvenTreeModel { return thumb; } + int get supplierPartId => jsondata['supplier_part'] as int ?? -1; + + String get supplierImage { + String thumb = ''; + + if (jsondata.containsKey("supplier_detail")) { + thumb = jsondata['supplier_detail']['supplier_logo'] ?? ''; + } + + return thumb; + } + + String get supplierName { + String sname = ''; + + if (jsondata.containsKey("supplier_detail")) { + sname = jsondata["supplier_detail"]["supplier_name"] ?? ''; + } + + return sname; + } + + String get supplierSKU { + String sku = ''; + + if (jsondata.containsKey("supplier_detail")) { + sku = jsondata["supplier_detail"]["SKU"] ?? ''; + } + + return sku; + } + int get serialNumber => jsondata['serial'] as int ?? null; - double get quantity => jsondata['quantity'] as double ?? 0.0; + double get quantity => double.tryParse(jsondata['quantity'].toString() ?? '0'); int get locationId => jsondata['location'] as int ?? -1; + String get locationName { + String loc = ''; + + if (jsondata.containsKey('location_detail')) { + loc = jsondata['location_detail']['name'] ?? ''; + } + + if (loc.isEmpty) { + loc = jsondata['location__name'] ?? ''; + } + + return loc; + } + String get displayQuantity { // Display either quantity or serial number! diff --git a/lib/widget/part_display.dart b/lib/widget/part_display.dart index 327040d7..d987d91b 100644 --- a/lib/widget/part_display.dart +++ b/lib/widget/part_display.dart @@ -61,9 +61,12 @@ class _PartDisplayState extends State { subtitle: Text("${part.categoryName}"), leading: FaIcon(FontAwesomeIcons.stream), onTap: () { - InvenTreePartCategory().get(part.categoryId).then((var cat) { - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(cat))); - }); + if (part.categoryId > 0) { + InvenTreePartCategory().get(part.categoryId).then((var cat) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => CategoryDisplayWidget(cat))); + }); + } }, ) ); diff --git a/lib/widget/stock_display.dart b/lib/widget/stock_display.dart index 5bce2bde..6a4c5938 100644 --- a/lib/widget/stock_display.dart +++ b/lib/widget/stock_display.dart @@ -1,6 +1,9 @@ import 'package:InvenTree/inventree/stock.dart'; +import 'package:InvenTree/inventree/part.dart'; +import 'package:InvenTree/widget/location_display.dart'; +import 'package:InvenTree/widget/part_display.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -52,6 +55,100 @@ class _StockItemDisplayState extends State { ) ); + tiles.add( + ListTile( + title: Text("Part"), + subtitle: Text("${item.partName}"), + leading: FaIcon(FontAwesomeIcons.shapes), + onTap: () { + if (item.partId > 0) { + InvenTreePart().get(item.partId).then((var part) { + if (part is InvenTreePart) { + Navigator.push(context, MaterialPageRoute(builder: (context) => PartDisplayWidget(part))); + } + }); + } + }, + ) + ); + + // Quantity information + tiles.add( + ListTile( + title: Text("Quantity"), + leading: FaIcon(FontAwesomeIcons.cubes), + trailing: Text("${item.quantity}"), + ) + ); + + // Location information + if (item.locationName.isNotEmpty) { + tiles.add( + ListTile( + title: Text("Stock Location"), + subtitle: Text("${item.locationName}"), + leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + onTap: () { + if (item.locationId > 0) { + InvenTreeStockLocation().get(item.locationId).then((var loc) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => LocationDisplayWidget(loc))); + }); + } + }, + ) + ); + } + + // Supplier part? + if (item.supplierPartId > 0) { + tiles.add( + ListTile( + title: Text("${item.supplierName}"), + subtitle: Text("${item.supplierSKU}"), + leading: FaIcon(FontAwesomeIcons.industry), + trailing: Image( + image: InvenTreeAPI().getImage(item.supplierImage), + height: 32, + ), + onTap: null, + ) + ); + } + + if (item.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${item.link}"), + leading: FaIcon(FontAwesomeIcons.link), + trailing: Text(""), + onTap: null, + ) + ); + } + + if (item.trackingItemCount > 0) { + tiles.add( + ListTile( + title: Text("History"), + leading: FaIcon(FontAwesomeIcons.history), + trailing: Text("${item.trackingItemCount}"), + onTap: null, + ) + ); + } + + if (item.notes.isNotEmpty) { + tiles.add( + ListTile( + title: Text("Notes"), + leading: FaIcon(FontAwesomeIcons.stickyNote), + trailing: Text(""), + onTap: null, + ) + ); + } + return tiles; } From 0e35c370bad253985bade92a4fec6ff2cdafc454 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 22:19:43 +1000 Subject: [PATCH 06/10] Report server instance name --- lib/api.dart | 8 +++++++- lib/settings.dart | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/api.dart b/lib/api.dart index a02303f3..069a6fb2 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -72,8 +72,11 @@ class InvenTreeAPI { // Authentication token (initially empty, must be requested) String _token = ""; + // Server instance information + String instance = ''; + // Server version information - String _version; + String _version = ''; // Getter for server version information String get version => _version; @@ -174,6 +177,9 @@ class InvenTreeAPI { _version = data["version"]; + // Record the instance name of the server + instance = data['instance'] ?? ''; + // Request token from the server if we do not already have one if (_token.isNotEmpty) { print("Already have token - $_token"); diff --git a/lib/settings.dart b/lib/settings.dart index 48d8d363..9a640a9b 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -61,6 +61,10 @@ class _InvenTreeSettingsState extends State { title: Text("Server Version"), subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : "Not connected"), ), + ListTile( + title: Text("Server Instance"), + subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : "Not connected"), + ), Divider(), ListTile( title: Text("App Name"), From 37cdf23ae1631eb9514ac39c9aa22a4703089153 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 22:33:38 +1000 Subject: [PATCH 07/10] Add a connection checker --- lib/api.dart | 35 +++++++++++++++++++++++++++++++++++ lib/main.dart | 9 +++++++++ lib/widget/drawer.dart | 7 +++++++ 3 files changed, 51 insertions(+) diff --git a/lib/api.dart b/lib/api.dart index 069a6fb2..885fd145 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -72,6 +72,41 @@ class InvenTreeAPI { // Authentication token (initially empty, must be requested) String _token = ""; + bool isConnected() { + return _token.isNotEmpty; + } + + /* + * Check server connection and display messages if not connected. + * Useful as a precursor check before performing operations. + */ + bool checkConnection(BuildContext context) { + + // Firstly, is the server connected? + if (!isConnected()) { + showDialog( + context: context, + child: new SimpleDialog( + title: new Text("Not Connected"), + children: [ + ListTile( + title: Text("Server not connected"), + ) + ] + ) + ); + + return false; + } + + // Is the server version too old? + // TODO + + // Finally + return true; + + } + // Server instance information String instance = ''; diff --git a/lib/main.dart b/lib/main.dart index 121fa93a..ac1cc7a2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -179,18 +179,27 @@ class _MyHomePageState extends State { } void _search() { + if (!InvenTreeAPI().checkConnection(context)) return; + // TODO } void _scan() { + if (!InvenTreeAPI().checkConnection(context)) return; + scanQrCode(context); } void _parts() { + if (!InvenTreeAPI().checkConnection(context)) return; + Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); } void _stock() { + + if (!InvenTreeAPI().checkConnection(context)) return; + Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); } diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 03095ce1..ef031280 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -1,6 +1,9 @@ +import 'package:InvenTree/api.dart'; import 'package:InvenTree/barcode.dart'; import 'package:flutter/material.dart'; +import 'package:InvenTree/api.dart'; + import 'package:InvenTree/widget/category_display.dart'; import 'package:InvenTree/widget/location_display.dart'; @@ -33,6 +36,7 @@ class InvenTreeDrawer extends StatelessWidget { * Upon successful scan, data are passed off to be decoded. */ void _scan() async { + if (!InvenTreeAPI().checkConnection(context)) return; _closeDrawer(); scanQrCode(context); @@ -42,6 +46,7 @@ class InvenTreeDrawer extends StatelessWidget { * Display the top-level PartCategory list */ void _showParts() { + if (!InvenTreeAPI().checkConnection(context)) return; _closeDrawer(); Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); @@ -51,6 +56,7 @@ class InvenTreeDrawer extends StatelessWidget { * Display the top-level StockLocation list */ void _showStock() { + if (!InvenTreeAPI().checkConnection(context)) return; _closeDrawer(); Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(null))); } @@ -72,6 +78,7 @@ class InvenTreeDrawer extends StatelessWidget { leading: new Image.asset( "assets/image/icon.png", fit: BoxFit.scaleDown, + width: 40, ), title: new Text("InvenTree"), onTap: _home, From 31fc5cb80b2fe0eebd18fc7706c5f922cee61c98 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 22:37:40 +1000 Subject: [PATCH 08/10] Press to retry server connection --- lib/main.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index ac1cc7a2..555639b3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -151,6 +151,13 @@ class _MyHomePageState extends State { _serverAddress = prefs.getString("server"); + // Reset the connection status variables + _serverStatus = "Connecting to server"; + _serverMessage = ""; + _serverConnection = false; + _serverIcon = new FaIcon(FontAwesomeIcons.spinner); + _serverStatusColor = Color.fromARGB(255, 50, 50, 250); + InvenTreeAPI().connect().then((bool result) { if (result) { @@ -176,6 +183,9 @@ class _MyHomePageState extends State { onConnectFailure(fault); }); + + // Update widget state + setState(() {}); } void _search() { @@ -358,6 +368,11 @@ class _MyHomePageState extends State { style: TextStyle(color: _serverStatusColor), ), leading: _serverIcon, + onTap: () { + if (!_serverConnection) { + _checkServerConnection(); + } + }, ), ), ], From 4b33f9c65c8014b78280af927452f2f99cdf0a17 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 22:48:32 +1000 Subject: [PATCH 09/10] Cleanup settings page(s) - New separate directory - Separate view for About information --- lib/main.dart | 2 +- lib/settings.dart | 95 ------------------- lib/settings/about.dart | 64 +++++++++++++ .../login.dart} | 7 +- lib/settings/settings.dart | 62 ++++++++++++ lib/widget/drawer.dart | 2 +- 6 files changed, 131 insertions(+), 101 deletions(-) delete mode 100644 lib/settings.dart create mode 100644 lib/settings/about.dart rename lib/{login_settings.dart => settings/login.dart} (96%) create mode 100644 lib/settings/settings.dart diff --git a/lib/main.dart b/lib/main.dart index 555639b3..0c6775fc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,7 +14,7 @@ import 'barcode.dart'; import 'dart:convert'; -import 'settings.dart'; +import 'settings/settings.dart'; import 'api.dart'; import 'preferences.dart'; diff --git a/lib/settings.dart b/lib/settings.dart deleted file mode 100644 index 9a640a9b..00000000 --- a/lib/settings.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import 'package:InvenTree/api.dart'; -import 'login_settings.dart'; - -import 'package:package_info/package_info.dart'; - -class InvenTreeSettingsWidget extends StatefulWidget { - // InvenTree settings view - - @override - _InvenTreeSettingsState createState() => _InvenTreeSettingsState(); - -} - - -class _InvenTreeSettingsState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("InvenTree Settings"), - ), - body: Center( - child: ListView( - children: [ - ListTile( - title: Text("Server Settings"), - subtitle: Text("Configure server and login settings"), - onTap: _editServerSettings, - ), - Divider(), - ListTile( - title: Text("About"), - subtitle: Text("App details"), - onTap: _about, - ), - ], - ) - ) - ); - } - - void _editServerSettings() async { - - var prefs = await SharedPreferences.getInstance(); - - Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget(prefs))); - } - - void _about() async { - - PackageInfo.fromPlatform().then((PackageInfo info) { - showDialog( - context: context, - child: new SimpleDialog( - title: new Text("About InvenTree"), - children: [ - ListTile( - title: Text("Server Version"), - subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : "Not connected"), - ), - ListTile( - title: Text("Server Instance"), - subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : "Not connected"), - ), - Divider(), - ListTile( - title: Text("App Name"), - subtitle: Text("${info.appName}"), - ), - ListTile( - title: Text("Package Name"), - subtitle: Text("${info.packageName}"), - ), - ListTile( - title: Text("App Version"), - subtitle: Text("${info.version}"), - ), - ListTile( - title: Text("Build Number"), - subtitle: Text("${info.buildNumber}") - ), - Divider(), - ListTile( - title: Text("Submit Bug Report"), - subtitle: Text("Submit a bug report or feature request at:\n https://github.com/inventree/inventree-app/issues/"), - ) - ] - ), - ); - }); - } -} \ No newline at end of file diff --git a/lib/settings/about.dart b/lib/settings/about.dart new file mode 100644 index 00000000..ad812183 --- /dev/null +++ b/lib/settings/about.dart @@ -0,0 +1,64 @@ +import 'package:InvenTree/api.dart'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:package_info/package_info.dart'; + +class InvenTreeAboutWidget extends StatelessWidget { + + final PackageInfo info; + + InvenTreeAboutWidget(this.info) : super(); + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: AppBar( + title: Text("About InvenTree"), + ), + body: ListView( + children: [ + ListTile( + title: Text("Server Address"), + subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : "Not connected"), + ), + ListTile( + title: Text("Server Version"), + subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : "Not connected"), + ), + ListTile( + title: Text("Server Instance"), + subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : "Not connected"), + ), + Divider(), + ListTile( + title: Text("App Name"), + subtitle: Text("${info.appName}"), + ), + ListTile( + title: Text("Package Name"), + subtitle: Text("${info.packageName}"), + ), + ListTile( + title: Text("App Version"), + subtitle: Text("${info.version}"), + ), + ListTile( + title: Text("Build Number"), + subtitle: Text("${info.buildNumber}") + ), + Divider(), + ListTile( + title: Text("Submit Bug Report"), + subtitle: Text("https://github.com/inventree/inventree-app/issues/"), + onTap: () { + // TODO - Open the URL in an external webpage? + }, + ) + ], + ) + ); + } +} \ No newline at end of file diff --git a/lib/login_settings.dart b/lib/settings/login.dart similarity index 96% rename from lib/login_settings.dart rename to lib/settings/login.dart index aadbfffb..8415e2a4 100644 --- a/lib/login_settings.dart +++ b/lib/settings/login.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'api.dart'; -import 'preferences.dart'; +import '../api.dart'; +import '../preferences.dart'; class InvenTreeLoginSettingsWidget extends StatefulWidget { @@ -81,7 +81,6 @@ class _InvenTreeLoginSettingsState extends State { initialValue: _server, decoration: InputDecoration( hintText: "127.0.0.1:8000", - labelText: "Server:Port", ), validator: _validateServer, onSaved: (String value) { @@ -89,7 +88,7 @@ class _InvenTreeLoginSettingsState extends State { }, ), Divider(), - Text("Login Details"), + Text("Account Details"), TextFormField( initialValue: _username, decoration: InputDecoration( diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart new file mode 100644 index 00000000..119fdabb --- /dev/null +++ b/lib/settings/settings.dart @@ -0,0 +1,62 @@ +import 'package:InvenTree/settings/about.dart'; +import 'package:InvenTree/settings/login.dart'; + +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:InvenTree/api.dart'; +import 'login.dart'; + +import 'package:package_info/package_info.dart'; + +class InvenTreeSettingsWidget extends StatefulWidget { + // InvenTree settings view + + @override + _InvenTreeSettingsState createState() => _InvenTreeSettingsState(); + +} + + +class _InvenTreeSettingsState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("InvenTree Settings"), + ), + body: Center( + child: ListView( + children: [ + ListTile( + title: Text("Server Settings"), + subtitle: Text("Configure server and login settings"), + onTap: _editServerSettings, + ), + Divider(), + ListTile( + title: Text("About"), + subtitle: Text("App details"), + onTap: _about, + ), + ], + ) + ) + ); + } + + void _editServerSettings() async { + + var prefs = await SharedPreferences.getInstance(); + + Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget(prefs))); + } + + void _about() async { + + PackageInfo.fromPlatform().then((PackageInfo info) { + Navigator.push(context, + MaterialPageRoute(builder: (context) => InvenTreeAboutWidget(info))); + }); + } +} \ No newline at end of file diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index ef031280..f60b5497 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -7,7 +7,7 @@ import 'package:InvenTree/api.dart'; import 'package:InvenTree/widget/category_display.dart'; import 'package:InvenTree/widget/location_display.dart'; -import 'package:InvenTree/settings.dart'; +import 'package:InvenTree/settings/settings.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class InvenTreeDrawer extends StatelessWidget { From 99c7416755b3789ac0b30cd5f46c1dbde153699d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 6 Apr 2020 22:50:18 +1000 Subject: [PATCH 10/10] Some icons --- lib/settings/settings.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 119fdabb..a3651e88 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -2,6 +2,7 @@ import 'package:InvenTree/settings/about.dart'; import 'package:InvenTree/settings/login.dart'; import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:InvenTree/api.dart'; @@ -31,12 +32,14 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text("Server Settings"), subtitle: Text("Configure server and login settings"), + leading: FaIcon(FontAwesomeIcons.server), onTap: _editServerSettings, ), Divider(), ListTile( title: Text("About"), subtitle: Text("App details"), + leading: FaIcon(FontAwesomeIcons.infoCircle), onTap: _about, ), ],