From 0ba72a59c61120b0a0fb33c4f3d316bc937ebe42 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@gmail.com>
Date: Mon, 1 Feb 2021 17:19:37 +1100
Subject: [PATCH] Separate main widget into separate file from app

---
 l10n.yaml               |   3 +-
 lib/generated/i18n.dart | 110 ++++--------
 lib/main.dart           | 359 +---------------------------------------
 lib/widget/home.dart    | 337 +++++++++++++++++++++++++++++++++++++
 pubspec.lock            |   2 +-
 5 files changed, 379 insertions(+), 432 deletions(-)
 create mode 100644 lib/widget/home.dart

diff --git a/l10n.yaml b/l10n.yaml
index b2fcf348..1baa7ccc 100644
--- a/l10n.yaml
+++ b/l10n.yaml
@@ -1,3 +1,4 @@
 arb-dir: lib/i18n
 template-arb-file: app_en.arb
-output-localization-file: app_localizations.dart
\ No newline at end of file
+output-localization-file: app_localizations.dart
+output-class: I18N
\ No newline at end of file
diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart
index 2dcf8369..db983ef0 100644
--- a/lib/generated/i18n.dart
+++ b/lib/generated/i18n.dart
@@ -1,122 +1,78 @@
+
 import 'dart:async';
 
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
-
 // ignore_for_file: non_constant_identifier_names
 // ignore_for_file: camel_case_types
 // ignore_for_file: prefer_single_quotes
 
-// This file is automatically generated. DO NOT EDIT, all your changes would be lost.
+//This file is automatically generated. DO NOT EDIT, all your changes would be lost.
+
 class S implements WidgetsLocalizations {
   const S();
 
   static const GeneratedLocalizationsDelegate delegate =
-    GeneratedLocalizationsDelegate();
+      const GeneratedLocalizationsDelegate();
 
-  static S of(BuildContext context) => Localizations.of<S>(context, S);
+  static S of(BuildContext context) =>
+      Localizations.of<S>(context, WidgetsLocalizations);
 
   @override
   TextDirection get textDirection => TextDirection.ltr;
 
 }
 
-class $en extends S {
-  const $en();
+class en extends S {
+  const en();
 }
 
-class GeneratedLocalizationsDelegate extends LocalizationsDelegate<S> {
+
+class GeneratedLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
   const GeneratedLocalizationsDelegate();
 
   List<Locale> get supportedLocales {
     return const <Locale>[
-      Locale("en", ""),
+
+      const Locale("en", ""),
+
     ];
   }
 
-  LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) {
-    return (List<Locale> locales, Iterable<Locale> supported) {
-      if (locales == null || locales.isEmpty) {
-        return fallback ?? supported.first;
-      } else {
-        return _resolve(locales.first, fallback, supported, withCountry);
-      }
-    };
-  }
-
-  LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) {
+  LocaleResolutionCallback resolution({Locale fallback}) {
     return (Locale locale, Iterable<Locale> supported) {
-      return _resolve(locale, fallback, supported, withCountry);
+      final Locale languageLocale = new Locale(locale.languageCode, "");
+      if (supported.contains(locale))
+        return locale;
+      else if (supported.contains(languageLocale))
+        return languageLocale;
+      else {
+        final Locale fallbackLocale = fallback ?? supported.first;
+        return fallbackLocale;
+      }
     };
   }
 
   @override
-  Future<S> load(Locale locale) {
+  Future<WidgetsLocalizations> load(Locale locale) {
     final String lang = getLang(locale);
-    if (lang != null) {
-      switch (lang) {
-        case "en":
-          return SynchronousFuture<S>(const $en());
-        default:
-          // NO-OP.
-      }
+    switch (lang) {
+
+      case "en":
+        return new SynchronousFuture<WidgetsLocalizations>(const en());
+
+      default:
+        return new SynchronousFuture<WidgetsLocalizations>(const S());
     }
-    return SynchronousFuture<S>(const S());
   }
 
   @override
-  bool isSupported(Locale locale) => _isSupported(locale, true);
+  bool isSupported(Locale locale) => supportedLocales.contains(locale);
 
   @override
   bool shouldReload(GeneratedLocalizationsDelegate old) => false;
-
-  ///
-  /// Internal method to resolve a locale from a list of locales.
-  ///
-  Locale _resolve(Locale locale, Locale fallback, Iterable<Locale> supported, bool withCountry) {
-    if (locale == null || !_isSupported(locale, withCountry)) {
-      return fallback ?? supported.first;
-    }
-
-    final Locale languageLocale = Locale(locale.languageCode, "");
-    if (supported.contains(locale)) {
-      return locale;
-    } else if (supported.contains(languageLocale)) {
-      return languageLocale;
-    } else {
-      final Locale fallbackLocale = fallback ?? supported.first;
-      return fallbackLocale;
-    }
-  }
-
-  ///
-  /// Returns true if the specified locale is supported, false otherwise.
-  ///
-  bool _isSupported(Locale locale, bool withCountry) {
-    if (locale != null) {
-      for (Locale supportedLocale in supportedLocales) {
-        // Language must always match both locales.
-        if (supportedLocale.languageCode != locale.languageCode) {
-          continue;
-        }
-
-        // If country code matches, return this locale.
-        if (supportedLocale.countryCode == locale.countryCode) {
-          return true;
-        }
-
-        // If no country requirement is requested, check if this locale has no country.
-        if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
 }
 
-String getLang(Locale l) => l == null
-  ? null
-  : l.countryCode != null && l.countryCode.isEmpty
+String getLang(Locale l) => l.countryCode != null && l.countryCode.isEmpty
     ? l.languageCode
     : l.toString();
diff --git a/lib/main.dart b/lib/main.dart
index ff94b80f..46b31b85 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,21 +1,12 @@
 import 'dart:async';
 
 import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 
-import 'package:InvenTree/widget/category_display.dart';
-import 'package:InvenTree/widget/company_list.dart';
-import 'package:InvenTree/widget/location_display.dart';
-import 'package:InvenTree/widget/search.dart';
-import 'package:InvenTree/widget/drawer.dart';
+import 'package:InvenTree/widget/home.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
-import 'package:shared_preferences/shared_preferences.dart';
 
-import 'package:font_awesome_flutter/font_awesome_flutter.dart';
-
-import 'barcode.dart';
-
-import 'api.dart';
 import 'dsn.dart';
 import 'preferences.dart';
 
@@ -73,16 +64,14 @@ class InvenTreeApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return MaterialApp(
-      title: 'InvenTree',
+      onGenerateTitle: (BuildContext context) => I18N.of(context).appTitle,
       theme: ThemeData(
         primarySwatch: Colors.lightBlue,
         secondaryHeaderColor: Colors.blueGrey,
       ),
-      home: MyHomePage(title: 'InvenTree'),
+      home: InvenTreeHomePage(),
       localizationsDelegates: [
-        // ... app-specific localization delegate[s] here
-        // TODO: uncomment the line below after codegen
-        // AppLocalizations.delegate,
+        I18N.delegate,
         GlobalMaterialLocalizations.delegate,
         GlobalWidgetsLocalizations.delegate,
         GlobalCupertinoLocalizations.delegate,
@@ -95,340 +84,4 @@ class InvenTreeApp extends StatelessWidget {
       ],
     );
   }
-}
-
-
-class MyHomePage extends StatefulWidget {
-  MyHomePage({Key key, this.title}) : super(key: key);
-
-
-  // This widget is the home page of your application. It is stateful, meaning
-  // that it has a State object (defined below) that contains fields that affect
-  // how it looks.
-
-  // This class is the configuration for the state. It holds the values (in this
-  // case the title) provided by the parent (in this case the App widget) and
-  // used by the build method of the State. Fields in a Widget subclass are
-  // always marked "final".
-
-  final String title;
-
-  @override
-  _MyHomePageState createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State<MyHomePage> {
-
-  _MyHomePageState() : super() {
-    _checkServerConnection();
-  }
-
-  String _serverAddress = "";
-
-  String _serverStatus = "Connecting to server";
-
-  String _serverMessage = "";
-
-  bool _serverConnection = false;
-
-  FaIcon _serverIcon = new FaIcon(FontAwesomeIcons.spinner);
-
-  Color _serverStatusColor = Color.fromARGB(255, 50, 50, 250);
-  
-  void onConnectSuccess(String msg) {
-    _serverConnection = true;
-    _serverMessage = msg;
-    _serverStatus = "Connected to $_serverAddress";
-    _serverStatusColor = Color.fromARGB(255, 50, 250, 50);
-    _serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor);
-
-    setState(() {});
-  }
-  
-  void onConnectFailure(String msg) {
-    _serverConnection = false;
-    _serverMessage = msg;
-    _serverStatus = "Could not connect to $_serverAddress";
-    _serverStatusColor = Color.fromARGB(255, 250, 50, 50);
-    _serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor);
-
-    setState(() {});
-  }
-
-  /*
-   * Test the server connection
-   */
-  void _checkServerConnection() async {
-
-    var prefs = await SharedPreferences.getInstance();
-
-    _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) {
-        onConnectSuccess("");
-      } else {
-        onConnectFailure("Could not connect to server");
-      }
-
-    });
-
-    // Update widget state
-    setState(() {});
-  }
-
-  void _search() {
-    if (!InvenTreeAPI().checkConnection(context)) return;
-
-    Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget()));
-
-  }
-
-  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)));
-  }
-
-  void _suppliers() {
-    if (!InvenTreeAPI().checkConnection(context)) return;
-
-    Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierListWidget()));
-  }
-
-  void _manufacturers() {
-    if (!InvenTreeAPI().checkConnection(context)) return;
-
-    Navigator.push(context, MaterialPageRoute(builder: (context) => ManufacturerListWidget()));
-  }
-
-  void _customers() {
-    if (!InvenTreeAPI().checkConnection(context)) return;
-
-    Navigator.push(context, MaterialPageRoute(builder: (context) => CustomerListWidget()));
-  }
-
-  void _unsupported() {
-    showDialog(
-      context:  context,
-      child: new SimpleDialog(
-        title: new Text("Unsupported"),
-        children: <Widget>[
-          ListTile(
-            title: Text("This feature is not yet supported"),
-            subtitle: Text("It will be supported in an upcoming release"),
-          )
-        ],
-      )
-    );
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    // This method is rerun every time setState is called, for instance as done
-    // by the _incrementCounter method above.
-    //
-    // The Flutter framework has been optimized to make rerunning build methods
-    // fast, so that you can just rebuild anything that needs updating rather
-    // than having to individually change instances of widgets.
-    return Scaffold(
-      appBar: AppBar(
-        // Here we take the value from the MyHomePage object that was created by
-        // the App.build method, and use it to set our appbar title.
-        title: Text(widget.title),
-        actions: <Widget>[
-          /*
-          IconButton(
-            icon: FaIcon(FontAwesomeIcons.search),
-            tooltip: 'Search',
-            onPressed: _search,
-          ),
-           */
-        ],
-      ),
-      drawer: new InvenTreeDrawer(context),
-      body: Center(
-        // Center is a layout widget. It takes a single child and positions it
-        // in the middle of the parent.
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: (<Widget>[
-            Spacer(),
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              children: <Widget>[
-                /*
-                Column(
-                  children: <Widget>[
-
-                   IconButton(
-                     icon: new FaIcon(FontAwesomeIcons.search),
-                     tooltip: 'Search',
-                     onPressed: _search,
-                   ),
-                   Text("Search"),
-                  ],
-                ),
-                */
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.barcode),
-                      tooltip: 'Scan Barcode',
-                      onPressed: _scan,
-                    ),
-                    Text("Scan Barcode"),
-                  ],
-                ),
-              ],
-            ),
-            Spacer(),
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              children: <Widget>[
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.shapes),
-                      tooltip: 'Parts',
-                      onPressed: _parts,
-                    ),
-                    Text("Parts"),
-                  ],
-                ),
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.boxes),
-                      tooltip: 'Stock',
-                      onPressed: _stock,
-                    ),
-                    Text('Stock'),
-                  ],
-                ),
-              ],
-            ),
-            Spacer(),
-            // TODO - Re-add these when the features actually do something..
-            /*
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              children: <Widget>[
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.building),
-                      tooltip: "Suppliers",
-                        onPressed: _suppliers,
-                    ),
-                    Text("Suppliers"),
-                  ],
-                ),
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: FaIcon(FontAwesomeIcons.industry),
-                      tooltip: "Manufacturers",
-                      onPressed: _manufacturers,
-                    ),
-                    Text("Manufacturers")
-                  ],
-                ),
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: FaIcon(FontAwesomeIcons.userTie),
-                      tooltip: "Customers",
-                      onPressed: _customers,
-                    ),
-                    Text("Customers"),
-                  ]
-                )
-              ],
-            ),
-            Spacer(),
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              children: <Widget>[
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.tools),
-                      tooltip: "Build",
-                      onPressed: _unsupported,
-                    ),
-                    Text("Build"),
-                  ],
-                ),
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.shoppingCart),
-                      tooltip: "Order",
-                      onPressed: _unsupported,
-                    ),
-                    Text("Order"),
-                  ]
-                ),
-                Column(
-                  children: <Widget>[
-                    IconButton(
-                      icon: new FaIcon(FontAwesomeIcons.truck),
-                      tooltip: "Ship",
-                      onPressed: _unsupported,
-                    ),
-                    Text("Ship"),
-                  ]
-                )
-              ],
-            ),
-            Spacer(),
-            */
-            Row(
-              mainAxisAlignment: MainAxisAlignment.center,
-              crossAxisAlignment: CrossAxisAlignment.center,
-              children: <Widget>[
-                Expanded(
-                  child: ListTile(
-                    title: Text("$_serverStatus",
-                      style: TextStyle(color: _serverStatusColor),
-                      ),
-                    subtitle: Text("$_serverMessage",
-                      style: TextStyle(color: _serverStatusColor),
-                    ),
-                    leading: _serverIcon,
-                    onTap: () {
-                      if (!_serverConnection) {
-                        _checkServerConnection();
-                      }
-                    },
-                  ),
-                ),
-              ],
-            ),
-          ]),
-        ),
-      ),
-    );
-  }
-}
+}
\ No newline at end of file
diff --git a/lib/widget/home.dart b/lib/widget/home.dart
new file mode 100644
index 00000000..b2d99479
--- /dev/null
+++ b/lib/widget/home.dart
@@ -0,0 +1,337 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+import 'package:font_awesome_flutter/font_awesome_flutter.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+import 'package:InvenTree/barcode.dart';
+import 'package:InvenTree/api.dart';
+
+import 'package:InvenTree/widget/category_display.dart';
+import 'package:InvenTree/widget/company_list.dart';
+import 'package:InvenTree/widget/location_display.dart';
+import 'package:InvenTree/widget/search.dart';
+import 'package:InvenTree/widget/drawer.dart';
+
+class InvenTreeHomePage extends StatefulWidget {
+  InvenTreeHomePage({Key key}) : super(key: key);
+
+  @override
+  _InvenTreeHomePageState createState() => _InvenTreeHomePageState();
+}
+
+class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
+
+  _InvenTreeHomePageState() : super() {
+    _checkServerConnection();
+  }
+
+  String _serverAddress = "";
+
+  String _serverStatus = "Connecting to server";
+
+  String _serverMessage = "";
+
+  bool _serverConnection = false;
+
+  FaIcon _serverIcon = new FaIcon(FontAwesomeIcons.spinner);
+
+  Color _serverStatusColor = Color.fromARGB(255, 50, 50, 250);
+
+  void onConnectSuccess(String msg) {
+    _serverConnection = true;
+    _serverMessage = msg;
+    _serverStatus = "Connected to $_serverAddress";
+    _serverStatusColor = Color.fromARGB(255, 50, 250, 50);
+    _serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor);
+
+    setState(() {});
+  }
+
+  void onConnectFailure(String msg) {
+    _serverConnection = false;
+    _serverMessage = msg;
+    _serverStatus = "Could not connect to $_serverAddress";
+    _serverStatusColor = Color.fromARGB(255, 250, 50, 50);
+    _serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor);
+
+    setState(() {});
+  }
+
+  /*
+   * Test the server connection
+   */
+  void _checkServerConnection() async {
+
+    var prefs = await SharedPreferences.getInstance();
+
+    _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) {
+        onConnectSuccess("");
+      } else {
+        onConnectFailure("Could not connect to server");
+      }
+
+    });
+
+    // Update widget state
+    setState(() {});
+  }
+
+  void _search() {
+    if (!InvenTreeAPI().checkConnection(context)) return;
+
+    Navigator.push(context, MaterialPageRoute(builder: (context) => SearchWidget()));
+
+  }
+
+  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)));
+  }
+
+  void _suppliers() {
+    if (!InvenTreeAPI().checkConnection(context)) return;
+
+    Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierListWidget()));
+  }
+
+  void _manufacturers() {
+    if (!InvenTreeAPI().checkConnection(context)) return;
+
+    Navigator.push(context, MaterialPageRoute(builder: (context) => ManufacturerListWidget()));
+  }
+
+  void _customers() {
+    if (!InvenTreeAPI().checkConnection(context)) return;
+
+    Navigator.push(context, MaterialPageRoute(builder: (context) => CustomerListWidget()));
+  }
+
+  void _unsupported() {
+    showDialog(
+        context:  context,
+        child: new SimpleDialog(
+          title: new Text("Unsupported"),
+          children: <Widget>[
+            ListTile(
+              title: Text("This feature is not yet supported"),
+              subtitle: Text("It will be supported in an upcoming release"),
+            )
+          ],
+        )
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    // This method is rerun every time setState is called, for instance as done
+    // by the _incrementCounter method above.
+    //
+    // The Flutter framework has been optimized to make rerunning build methods
+    // fast, so that you can just rebuild anything that needs updating rather
+    // than having to individually change instances of widgets.
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(I18N.of(context).appTitle),
+        actions: <Widget>[
+          /*
+          IconButton(
+            icon: FaIcon(FontAwesomeIcons.search),
+            tooltip: 'Search',
+            onPressed: _search,
+          ),
+           */
+        ],
+      ),
+      drawer: new InvenTreeDrawer(context),
+      body: Center(
+        // Center is a layout widget. It takes a single child and positions it
+        // in the middle of the parent.
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: (<Widget>[
+            Spacer(),
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+              children: <Widget>[
+                /*
+                Column(
+                  children: <Widget>[
+
+                   IconButton(
+                     icon: new FaIcon(FontAwesomeIcons.search),
+                     tooltip: 'Search',
+                     onPressed: _search,
+                   ),
+                   Text("Search"),
+                  ],
+                ),
+                */
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.barcode),
+                      tooltip: 'Scan Barcode',
+                      onPressed: _scan,
+                    ),
+                    Text("Scan Barcode"),
+                  ],
+                ),
+              ],
+            ),
+            Spacer(),
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+              children: <Widget>[
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.shapes),
+                      tooltip: 'Parts',
+                      onPressed: _parts,
+                    ),
+                    Text("Parts"),
+                  ],
+                ),
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.boxes),
+                      tooltip: 'Stock',
+                      onPressed: _stock,
+                    ),
+                    Text('Stock'),
+                  ],
+                ),
+              ],
+            ),
+            Spacer(),
+            // TODO - Re-add these when the features actually do something..
+            /*
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+              children: <Widget>[
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.building),
+                      tooltip: "Suppliers",
+                        onPressed: _suppliers,
+                    ),
+                    Text("Suppliers"),
+                  ],
+                ),
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: FaIcon(FontAwesomeIcons.industry),
+                      tooltip: "Manufacturers",
+                      onPressed: _manufacturers,
+                    ),
+                    Text("Manufacturers")
+                  ],
+                ),
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: FaIcon(FontAwesomeIcons.userTie),
+                      tooltip: "Customers",
+                      onPressed: _customers,
+                    ),
+                    Text("Customers"),
+                  ]
+                )
+              ],
+            ),
+            Spacer(),
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+              children: <Widget>[
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.tools),
+                      tooltip: "Build",
+                      onPressed: _unsupported,
+                    ),
+                    Text("Build"),
+                  ],
+                ),
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.shoppingCart),
+                      tooltip: "Order",
+                      onPressed: _unsupported,
+                    ),
+                    Text("Order"),
+                  ]
+                ),
+                Column(
+                  children: <Widget>[
+                    IconButton(
+                      icon: new FaIcon(FontAwesomeIcons.truck),
+                      tooltip: "Ship",
+                      onPressed: _unsupported,
+                    ),
+                    Text("Ship"),
+                  ]
+                )
+              ],
+            ),
+            Spacer(),
+            */
+            Row(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: <Widget>[
+                Expanded(
+                  child: ListTile(
+                    title: Text("$_serverStatus",
+                      style: TextStyle(color: _serverStatusColor),
+                    ),
+                    subtitle: Text("$_serverMessage",
+                      style: TextStyle(color: _serverStatusColor),
+                    ),
+                    leading: _serverIcon,
+                    onTap: () {
+                      if (!_serverConnection) {
+                        _checkServerConnection();
+                      }
+                    },
+                  ),
+                ),
+              ],
+            ),
+          ]),
+        ),
+      ),
+    );
+  }
+}
diff --git a/pubspec.lock b/pubspec.lock
index 389e467d..6569a05d 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -253,7 +253,7 @@ packages:
     source: hosted
     version: "1.1.1"
   intl:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: intl
       url: "https://pub.dartlang.org"