diff --git a/lib/api.dart b/lib/api.dart index d66a7c56..8567965d 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -109,13 +109,11 @@ class InvenTreeAPI { String makeUrl(String endpoint) => _makeUrl(endpoint); - UserProfile _profile; + UserProfile profile; // Authentication token (initially empty, must be requested) String _token = ""; - bool isConnected() => _token.isNotEmpty; - /* * Check server connection and display messages if not connected. * Useful as a precursor check before performing operations. @@ -154,8 +152,14 @@ class InvenTreeAPI { // Connection status flag - set once connection has been validated bool _connected = false; - bool get connected { - return _connected && baseUrl.isNotEmpty && _token.isNotEmpty; + bool _connecting = true; + + bool isConnected() { + return profile != null && _connected && baseUrl.isNotEmpty && _token.isNotEmpty; + } + + bool isConnecting() { + return !isConnected() && _connecting; } // Ensure we only ever create a single instance of the API class @@ -167,35 +171,15 @@ class InvenTreeAPI { InvenTreeAPI._internal(); - Future connect(BuildContext context) async { - - _profile = await UserProfileDBManager().getSelectedProfile(); - - if (_profile == null) { - await showErrorDialog( - context, - "Select Profile", - "User profile not selected" - ); - return false; - } - - return connectToServer(context); - } - - Future connectToServer(BuildContext context) async { + Future _connect(BuildContext context) async { /* Address is the base address for the InvenTree server, * e.g. http://127.0.0.1:8000 */ - if (_profile == null) return false; - - String errorMessage = ""; - - String address = _profile.server.trim(); - String username = _profile.username.trim(); - String password = _profile.password.trim(); + String address = profile.server.trim(); + String username = profile.username.trim(); + String password = profile.password.trim(); if (address.isEmpty || username.isEmpty || password.isEmpty) { await showErrorDialog( @@ -220,19 +204,18 @@ class InvenTreeAPI { */ _BASE_URL = address; - _connected = false; - print("Connecting to " + apiUrl + " -> " + username + ":" + password); + print("Connecting to ${apiUrl} -> ${username}:${password}"); var response = await get("").timeout(Duration(seconds: 5)).catchError((error) { print("Error connecting to server: ${error.toString()}"); if (error is SocketException) { - errorMessage = "Could not connect to server"; + showServerError(context, "Connection Refused"); return null; } else if (error is TimeoutException) { - errorMessage = "Server timeout"; + showTimeoutDialog(context); return null; } else { // Unknown error type - re-throw the error and Sentry will catch it @@ -242,8 +225,6 @@ class InvenTreeAPI { if (response == null) { // Null (or error) response: Show dialog and exit - - await showServerError(context, errorMessage); return false; } @@ -322,6 +303,38 @@ class InvenTreeAPI { }; } + Future connectToServer(BuildContext context) async { + print("InvenTreeAPI().connectToServer()"); + + // Clear connection flag + _connected = false; + + // Clear token + _token = ''; + + // Load selected profile + profile = await UserProfileDBManager().getSelectedProfile(); + + if (profile == null) { + await showErrorDialog( + context, + "Select Profile", + "User profile not selected" + ); + return false; + } + + _connecting = true; + + _connect(context).then((result) { + + print("_connect() returned result: ${result}"); + _connecting = false; + + return result; + }); + } + // Perform a PATCH request Future patch(String url, {Map body}) async { var _url = makeApiUrl(url); @@ -405,7 +418,9 @@ class InvenTreeAPI { Map defaultHeaders() { var headers = Map(); - headers[HttpHeaders.authorizationHeader] = _authorizationHeader(_profile.username, _profile.password); + if (profile != null) { + headers[HttpHeaders.authorizationHeader] = _authorizationHeader(profile.username, profile.password); + } return headers; } diff --git a/lib/settings/login.dart b/lib/settings/login.dart index 53beff37..c20ad6de 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -180,7 +180,7 @@ class _InvenTreeLoginSettingsState extends State { _reload(); // Attempt server login (this will load the newly selected profile - InvenTreeAPI().connect(context); + InvenTreeAPI().connectToServer(context); } void _deleteProfile(UserProfile profile) async { @@ -220,7 +220,7 @@ class _InvenTreeLoginSettingsState extends State { List children = []; - if (profiles.length > 0) { + if (profiles != null && profiles.length > 0) { for (int idx = 0; idx < profiles.length; idx++) { UserProfile profile = profiles[idx]; diff --git a/lib/widget/home.dart b/lib/widget/home.dart index ae035516..31439b7e 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -44,109 +44,7 @@ class _InvenTreeHomePageState extends State { // Selected user profile UserProfile _profile; - void _loadProfile() async { - - final profile = await UserProfileDBManager().getSelectedProfile(); - - print("Loaded selected profile"); - - // If a different profile is selected, re-connect - if (_profile == null || (_profile.key != profile.key)) { - // TODO - } - - _profile = profile; - - setState(() { - - }); - } - - ListTile _serverTile() { - - // No profile selected - // Tap to select / create a profile - if (_profile == null) { - return ListTile( - title: Text("No Profile Selected"), - subtitle: Text("Tap to create or select a profile"), - leading: FaIcon(FontAwesomeIcons.user), - onTap: () { - _selectProfile(); - }, - ); - } - - // Profile is selected ... - if (InvenTreeAPI().isConnected()) { - return ListTile( - title: Text("Connected to ${_profile.server}"), - ); - } else { - return ListTile( - title: Text("Could not connect to server"), - subtitle: Text("Error connecting to ${_profile.server}"), - leading: FaIcon(FontAwesomeIcons.times), - onTap: () { - _selectProfile(); - }, - ); - } - } - - void onConnectSuccess(String msg) async { - - final profile = await UserProfileDBManager().getSelectedProfile(); - - String address = profile?.server ?? 'unknown server address'; - - _serverConnection = true; - _serverMessage = msg; - _serverStatus = "Connected to ${address}"; - _serverStatusColor = Color.fromARGB(255, 50, 250, 50); - _serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor); - - setState(() {}); - } - - void onConnectFailure(String msg) async { - - final profile = await UserProfileDBManager().getSelectedProfile(); - - _serverConnection = false; - _serverMessage = msg; - _serverStatus = "Could not connect to ${profile?.server}"; - _serverStatusColor = Color.fromARGB(255, 250, 50, 50); - _serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor); - - setState(() {}); - } - - /* - * Test the server connection - */ - void _checkServerConnection(BuildContext context) async { - - // 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(context).then((bool result) { - - if (result) { - onConnectSuccess(""); - } else { - onConnectFailure("Could not connect to server"); - } - - }); - - // Update widget state - setState(() {}); - } + BuildContext _context; void _search() { if (!InvenTreeAPI().checkConnection(context)) return; @@ -210,8 +108,130 @@ class _InvenTreeHomePageState extends State { ); } + + void _loadProfile() async { + + final profile = await UserProfileDBManager().getSelectedProfile(); + + // If a different profile is selected, re-connect + if (_profile == null || (_profile.key != profile.key)) { + + if (_context != null) { + print("Connecting Profile: ${profile.name} - ${profile.server}"); + + InvenTreeAPI().connectToServer(_context).then((result) { + setState(() { + + }); + }); + + setState(() { + }); + } + } + + _profile = profile; + + setState(() { + + }); + } + + ListTile _serverTile() { + + // No profile selected + // Tap to select / create a profile + if (_profile == null) { + return ListTile( + title: Text("No Profile Selected"), + subtitle: Text("Tap to create or select a profile"), + leading: FaIcon(FontAwesomeIcons.server), + trailing: FaIcon( + FontAwesomeIcons.user, + color: Color.fromRGBO(250, 50, 50, 1), + ), + onTap: () { + _selectProfile(); + }, + ); + } + + // Profile is selected ... + if (InvenTreeAPI().isConnecting()) { + return ListTile( + title: Text("Connecting to server..."), + subtitle: Text("${InvenTreeAPI().baseUrl}"), + leading: FaIcon(FontAwesomeIcons.server), + trailing: FaIcon( + FontAwesomeIcons.spinner, + color: Color.fromRGBO(50, 50, 250, 1), + ) + ); + } else if (InvenTreeAPI().isConnected()) { + return ListTile( + title: Text("Connected to server"), + subtitle: Text("${InvenTreeAPI().baseUrl}"), + leading: FaIcon(FontAwesomeIcons.server), + trailing: FaIcon( + FontAwesomeIcons.checkCircle, + color: Color.fromRGBO(50, 250, 50, 1) + ), + onTap: () { + _selectProfile(); + }, + ); + } else { + return ListTile( + title: Text("Could not connect to server"), + subtitle: Text("${_profile.server}"), + leading: FaIcon(FontAwesomeIcons.server), + trailing: FaIcon( + FontAwesomeIcons.timesCircle, + color: Color.fromRGBO(250, 50, 50, 1), + ), + onTap: () { + _selectProfile(); + }, + ); + } + } + + void onConnectSuccess(String msg) async { + + final profile = await UserProfileDBManager().getSelectedProfile(); + + String address = profile?.server ?? 'unknown server address'; + + _serverConnection = true; + _serverMessage = msg; + _serverStatus = "Connected to ${address}"; + _serverStatusColor = Color.fromARGB(255, 50, 250, 50); + _serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor); + + setState(() {}); + } + + void onConnectFailure(String msg) async { + + final profile = await UserProfileDBManager().getSelectedProfile(); + + _serverConnection = false; + _serverMessage = msg; + _serverStatus = "Could not connect to ${profile?.server}"; + _serverStatusColor = Color.fromARGB(255, 250, 50, 50); + _serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor); + + setState(() {}); + } + + @override Widget build(BuildContext context) { + + _context = context; + + _loadProfile(); + // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // @@ -369,6 +389,7 @@ class _InvenTreeHomePageState extends State { ), Spacer(), */ + Spacer(), Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,