2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

API error messages now use snackIcon

- Press "details" for further error information
- Is nice
This commit is contained in:
Oliver Walters 2021-02-17 08:00:41 +11:00
parent 8ae4d2b584
commit 00943b7536
9 changed files with 108 additions and 109 deletions

View File

@ -1,3 +1,11 @@
## 0.1.1 - February 2021
---
- Fixes crash bug on top-level part category
- Fixed crash bug on top-level stock location
- Adds context overlay to barcode scanner view
- Notifcations are less obtrusive (uses snack bar)
## 0.1.0 - February 2021 ## 0.1.0 - February 2021
--- ---
This is the initial release of the InvenTree app. This is the initial release of the InvenTree app.

View File

@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:InvenTree/user_profile.dart'; import 'package:InvenTree/user_profile.dart';
import 'package:InvenTree/widget/snacks.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
@ -12,6 +13,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:InvenTree/widget/dialogs.dart'; import 'package:InvenTree/widget/dialogs.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:one_context/one_context.dart';
/** /**
@ -172,13 +174,11 @@ class InvenTreeAPI {
String password = profile.password.trim(); String password = profile.password.trim();
if (address.isEmpty || username.isEmpty || password.isEmpty) { if (address.isEmpty || username.isEmpty || password.isEmpty) {
await showErrorDialog( showSnackIcon(
context,
I18N.of(context).error,
"Incomplete server details", "Incomplete server details",
icon: FontAwesomeIcons.server icon: FontAwesomeIcons.exclamationCircle,
success: false
); );
return false; return false;
} }
@ -203,7 +203,6 @@ class InvenTreeAPI {
if (error is SocketException) { if (error is SocketException) {
showServerError( showServerError(
context,
I18N.of(context).connectionRefused, I18N.of(context).connectionRefused,
error.toString()); error.toString());
return null; return null;
@ -224,7 +223,7 @@ class InvenTreeAPI {
if (response.statusCode != 200) { if (response.statusCode != 200) {
// Any status code other than 200! // Any status code other than 200!
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
// TODO: Interpret the error codes and show custom message? // TODO: Interpret the error codes and show custom message?
return false; return false;
@ -238,7 +237,6 @@ class InvenTreeAPI {
if (!data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) { if (!data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) {
showServerError( showServerError(
context,
"Missing Data", "Missing Data",
"Server response missing required fields" "Server response missing required fields"
); );
@ -253,8 +251,7 @@ class InvenTreeAPI {
// Check that the remote server version is *new* enough // Check that the remote server version is *new* enough
if (!_checkServerVersion(_version)) { if (!_checkServerVersion(_version)) {
showServerError( showServerError(
context, I18N.of(OneContext().context).serverOld,
"Old Server Version",
"\n\nServer Version: ${_version}\n\nRequired version: ${_requiredVersionString}" "\n\nServer Version: ${_version}\n\nRequired version: ${_requiredVersionString}"
); );
@ -275,22 +272,22 @@ class InvenTreeAPI {
if (response == null) { if (response == null) {
showServerError( showServerError(
context, "Token Error", "Error requesting access token from server" I18N.of(OneContext().context).tokenError,
"Error requesting access token from server"
); );
return false; return false;
} }
if (response.statusCode != 200) { if (response.statusCode != 200) {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
return false; return false;
} else { } else {
var data = json.decode(response.body); var data = json.decode(response.body);
if (!data.containsKey("token")) { if (!data.containsKey("token")) {
showServerError( showServerError(
context, I18N.of(OneContext().context).tokenMissing,
"Missing Token",
"Access token missing from response" "Access token missing from response"
); );
@ -328,10 +325,10 @@ class InvenTreeAPI {
print("API Profile: ${profile.toString()}"); print("API Profile: ${profile.toString()}");
if (profile == null) { if (profile == null) {
await showErrorDialog( showSnackIcon(
context, I18N.of(OneContext().context).profileSelect,
"Select Profile", success: false,
"User profile not selected" icon: FontAwesomeIcons.exclamationCircle
); );
return false; return false;
} }
@ -344,6 +341,14 @@ class InvenTreeAPI {
_connecting = false; _connecting = false;
if (result) {
showSnackIcon(
I18N.of(OneContext().context).serverConnected,
icon: FontAwesomeIcons.server,
success: true,
);
}
return result; return result;
} }

View File

@ -46,7 +46,6 @@ class BarcodeHandler {
// Called when the server does not know about a barcode // Called when the server does not know about a barcode
// Override this function // Override this function
showErrorDialog( showErrorDialog(
_context,
"Invalid Barcode", "Invalid Barcode",
"Barcode does not match any known item", "Barcode does not match any known item",
error: "Barcode Error", error: "Barcode Error",
@ -60,7 +59,6 @@ class BarcodeHandler {
Future<void> onBarcodeUnhandled(Map<String, dynamic> data) { Future<void> onBarcodeUnhandled(Map<String, dynamic> data) {
// Called when the server returns an unhandled response // Called when the server returns an unhandled response
showErrorDialog( showErrorDialog(
_context,
"Response Data", "Response Data",
data.toString(), data.toString(),
error: "Unknown Response", error: "Unknown Response",
@ -85,19 +83,8 @@ class BarcodeHandler {
).then((var response) { ).then((var response) {
if (response.statusCode != 200) { if (response.statusCode != 200) {
showErrorDialog( showStatusCodeError(response.statusCode);
context,
"Status Code: ${response.statusCode}",
"${response.body
.toString()
.split('\n')
.first}",
onDismissed: () {
_controller.resumeCamera(); _controller.resumeCamera();
},
error: "Server Error",
icon: FontAwesomeIcons.server,
);
return; return;
} }
@ -117,8 +104,7 @@ class BarcodeHandler {
).catchError((error) { ).catchError((error) {
showErrorDialog( showErrorDialog(
context, I18N.of(OneContext().context).error,
"Error",
error.toString(), error.toString(),
onDismissed: () { onDismissed: () {
_controller.resumeCamera(); _controller.resumeCamera();
@ -145,8 +131,9 @@ class BarcodeScanHandler extends BarcodeHandler {
showSnackIcon( showSnackIcon(
"No barcode", "No barcode",
icon: FontAwesomeIcons.exclamationCircle, icon: FontAwesomeIcons.exclamationCircle,
onTap: () { actionText: "Details",
print("Tappity"); onAction: () {
print("Action!");
}, },
success: true, success: true,
); );
@ -249,7 +236,6 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
Future<void> onBarcodeMatched(Map<String, dynamic> data) { Future<void> onBarcodeMatched(Map<String, dynamic> data) {
// If the barcode is known, we can't asisgn it to the stock item! // If the barcode is known, we can't asisgn it to the stock item!
showErrorDialog( showErrorDialog(
_context,
"Barcode in Use", "Barcode in Use",
"Barcode is already known", "Barcode is already known",
onDismissed: () { onDismissed: () {
@ -264,7 +250,6 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
if (!data.containsKey("hash")) { if (!data.containsKey("hash")) {
showErrorDialog( showErrorDialog(
_context,
"Missing Data", "Missing Data",
"Missing hash data from server", "Missing hash data from server",
onDismissed: () { onDismissed: () {
@ -291,7 +276,6 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
); );
} else { } else {
showErrorDialog( showErrorDialog(
_context,
"Server Error", "Server Error",
"Could not assign barcode", "Could not assign barcode",
onDismissed: () { onDismissed: () {

View File

@ -148,7 +148,6 @@ class InvenTreeModel {
if (e is SocketException) { if (e is SocketException) {
showServerError( showServerError(
context,
I18N.of(context).connectionRefused, I18N.of(context).connectionRefused,
e.toString() e.toString()
); );
@ -168,7 +167,7 @@ class InvenTreeModel {
} }
if (response.statusCode != 200) { if (response.statusCode != 200) {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
print("Error retrieving data"); print("Error retrieving data");
return false; return false;
} }
@ -195,7 +194,6 @@ class InvenTreeModel {
if (e is SocketException) { if (e is SocketException) {
showServerError( showServerError(
context,
I18N.of(context).connectionRefused, I18N.of(context).connectionRefused,
e.toString() e.toString()
); );
@ -212,7 +210,7 @@ class InvenTreeModel {
if (response == null) return false; if (response == null) return false;
if (response.statusCode != 200) { if (response.statusCode != 200) {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
return false; return false;
} }
@ -248,7 +246,7 @@ class InvenTreeModel {
.catchError((e) { .catchError((e) {
if (e is SocketException) { if (e is SocketException) {
showServerError(context, I18N.of(context).connectionRefused, e.toString()); showServerError(I18N.of(context).connectionRefused, e.toString());
} }
else if (e is TimeoutException) { else if (e is TimeoutException) {
showTimeoutError(context); showTimeoutError(context);
@ -264,7 +262,7 @@ class InvenTreeModel {
} }
if (response.statusCode != 200) { if (response.statusCode != 200) {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
return null; return null;
} }
@ -293,7 +291,6 @@ class InvenTreeModel {
if (e is SocketException) { if (e is SocketException) {
showServerError( showServerError(
context,
I18N.of(context).connectionRefused, I18N.of(context).connectionRefused,
e.toString() e.toString()
); );
@ -313,7 +310,7 @@ class InvenTreeModel {
var decoded = json.decode(response.body); var decoded = json.decode(response.body);
_model = createFromJson(decoded); _model = createFromJson(decoded);
} else { } else {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
} }
}); });
@ -346,7 +343,6 @@ class InvenTreeModel {
if (e is SocketException) { if (e is SocketException) {
showServerError( showServerError(
context,
I18N.of(context).connectionRefused, I18N.of(context).connectionRefused,
e.toString() e.toString()
); );
@ -369,7 +365,7 @@ class InvenTreeModel {
List<InvenTreeModel> results = new List<InvenTreeModel>(); List<InvenTreeModel> results = new List<InvenTreeModel>();
if (response.statusCode != 200) { if (response.statusCode != 200) {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
// Return empty list // Return empty list
return results; return results;

View File

@ -442,7 +442,6 @@ class InvenTreeStockItem extends InvenTreeModel {
showTimeoutError(context); showTimeoutError(context);
} else if (error is SocketException) { } else if (error is SocketException) {
showServerError( showServerError(
context,
I18N.of(context).connectionRefused, I18N.of(context).connectionRefused,
error.toString() error.toString()
); );
@ -458,7 +457,7 @@ class InvenTreeStockItem extends InvenTreeModel {
if (response == null) return false; if (response == null) return false;
if (response.statusCode != 200) { if (response.statusCode != 200) {
showStatusCodeError(context, response.statusCode); showStatusCodeError(response.statusCode);
return false; return false;
} }

@ -1 +1 @@
Subproject commit dd7073d7434d5359ebbf9febff4e319ca0ec2ce0 Subproject commit f1e991199f3656bfc774f3793ad7ea1609857027

View File

@ -283,7 +283,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
// Navigator.of(context, rootNavigator: true).pop(); // Navigator.of(context, rootNavigator: true).pop();
confirmationDialog( confirmationDialog(
I18N.of(context).delete, I18N.of(context).delete,
"Delete this profile?", I18N.of(context).profileDelete + "?",
onAccept: () { onAccept: () {
_deleteProfile(profile); _deleteProfile(profile);
} }

View File

@ -1,4 +1,5 @@
import 'package:InvenTree/widget/snacks.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@ -86,61 +87,64 @@ Future<void> showInfoDialog(BuildContext context, String title, String descripti
}); });
} }
Future<void> showErrorDialog(BuildContext context, String title, String description, {IconData icon = FontAwesomeIcons.exclamationCircle, String error, Function onDismissed}) async { Future<void> showErrorDialog(String title, String description, {IconData icon = FontAwesomeIcons.exclamationCircle, String error, Function onDismissed}) async {
if (error == null || error.isEmpty) { if (error == null || error.isEmpty) {
error = I18N.of(context).error; error = I18N.of(OneContext().context).error;
} }
showDialog( OneContext().showDialog(
context: context, builder: (context) => SimpleDialog(
builder: (dialogContext) {
return SimpleDialog(
title: ListTile( title: ListTile(
title: Text(error), title: Text(error),
leading: FaIcon(icon), leading: FaIcon(icon),
), ),
children: <Widget>[ children: [
ListTile( ListTile(
title: Text(title), title: Text(title),
subtitle: Text(description) subtitle: Text(description),
) )
] ],
); )
}).then((value) { ).then((value) {
if (onDismissed != null) { if (onDismissed != null) {
onDismissed(); onDismissed();
} }
}); });
} }
Future<void> showServerError(BuildContext context, String title, String description) async { Future<void> showServerError(String title, String description) async {
if (title == null || title.isEmpty) { if (title == null || title.isEmpty) {
title = I18N.of(context).serverError; title = I18N.of(OneContext().context).serverError;
} }
await showErrorDialog( showSnackIcon(
context, title,
success: false,
actionText: I18N.of(OneContext().context).details,
onAction: () {
showErrorDialog(
title, title,
description, description,
error: I18N.of(context).serverError, error: I18N.of(OneContext().context).serverError,
icon: FontAwesomeIcons.server icon: FontAwesomeIcons.server
); );
}
);
} }
Future<void> showStatusCodeError(BuildContext context, int status, {int expected = 200}) async { Future<void> showStatusCodeError(int status, {int expected = 200}) async {
await showServerError( showServerError(
context, I18N.of(OneContext().context).responseInvalid,
"Invalid Response Code",
"Server responded with status code ${status}" "Server responded with status code ${status}"
); );
} }
Future<void> showTimeoutError(BuildContext context) async { Future<void> showTimeoutError(BuildContext context) async {
await showServerError(context, I18N.of(context).timeout, I18N.of(context).noResponse); await showServerError(I18N.of(context).timeout, I18N.of(context).noResponse);
} }
void showProgressDialog(BuildContext context, String title, String description) { void showProgressDialog(BuildContext context, String title, String description) {

View File

@ -13,7 +13,7 @@ import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:one_context/one_context.dart'; import 'package:one_context/one_context.dart';
void showSnackIcon(String text, {IconData icon, Function onTap, bool success}) { void showSnackIcon(String text, {IconData icon, Function onAction, bool success, String actionText}) {
OneContext().hideCurrentSnackBar(); OneContext().hideCurrentSnackBar();
@ -23,32 +23,35 @@ void showSnackIcon(String text, {IconData icon, Function onTap, bool success}) {
if (success == true) { if (success == true) {
backgroundColor = Colors.lightGreen; backgroundColor = Colors.lightGreen;
// Unspecified icon?
if (icon == null) {
icon = FontAwesomeIcons.checkCircle;
}
} else if (success == false) { } else if (success == false) {
backgroundColor = Colors.deepOrange; backgroundColor = Colors.deepOrange;
if (icon == null) {
icon = FontAwesomeIcons.timesCircle;
} }
SnackBarAction action;
if (onAction != null && actionText != null) {
action = SnackBarAction(
label: actionText,
onPressed: onAction,
);
}
List<Widget> childs = [
Text(text),
Spacer(),
];
if (icon != null) {
childs.add(FaIcon(icon));
} }
OneContext().showSnackBar(builder: (context) => SnackBar( OneContext().showSnackBar(builder: (context) => SnackBar(
content: GestureDetector( content: Row(
child: Row( children: childs
children: [
Text(text),
Spacer(),
FaIcon(icon)
],
),
onTap: onTap,
), ),
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
)); action: action
)
);
} }