mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 05:26:47 +00:00
Merge branch 'master' into api-forms
# Conflicts: # lib/api.dart # lib/widget/part_detail.dart
This commit is contained in:
commit
322b35ec1c
@ -1,6 +1,12 @@
|
||||
## InvenTree App Release Notes
|
||||
---
|
||||
|
||||
### 0.2.8 - July 2021
|
||||
---
|
||||
|
||||
- Bug fixes for API calls
|
||||
|
||||
|
||||
### 0.2.7 - July 2021
|
||||
---
|
||||
|
||||
|
@ -6,8 +6,8 @@ export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=lib\main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "SYMROOT=${SOURCE_ROOT}/../build\ios"
|
||||
export "FLUTTER_BUILD_NAME=0.2.7"
|
||||
export "FLUTTER_BUILD_NUMBER=15"
|
||||
export "FLUTTER_BUILD_NAME=0.2.8"
|
||||
export "FLUTTER_BUILD_NUMBER=16"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=false"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
|
548
lib/api.dart
548
lib/api.dart
@ -4,19 +4,40 @@ import 'dart:io';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:InvenTree/inventree/sentry.dart';
|
||||
import 'package:InvenTree/user_profile.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:inventree/inventree/sentry.dart';
|
||||
import 'package:inventree/user_profile.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
|
||||
/**
|
||||
* Class representing an API response from the server
|
||||
*/
|
||||
class APIResponse {
|
||||
|
||||
APIResponse({this.url = "", this.method = "", this.statusCode = -1, this.data});
|
||||
|
||||
int statusCode = -1;
|
||||
|
||||
String url = "";
|
||||
|
||||
String method = "";
|
||||
|
||||
dynamic data;
|
||||
|
||||
// Request is "valid" if a statusCode was returned
|
||||
bool isValid() => statusCode >= 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Custom FileService for caching network images
|
||||
* Requires a custom badCertificateCallback,
|
||||
@ -214,16 +235,12 @@ class InvenTreeAPI {
|
||||
|
||||
print("Connecting to ${apiUrl} -> username=${username}");
|
||||
|
||||
HttpClientResponse? response;
|
||||
APIResponse response;
|
||||
|
||||
dynamic data;
|
||||
response = await get("", expectedStatusCode: 200);
|
||||
|
||||
response = await getResponse("");
|
||||
|
||||
// Null response means something went horribly wrong!
|
||||
// Most likely, the server cannot be contacted
|
||||
if (response == null) {
|
||||
// An error message has already been displayed!
|
||||
// Response was invalid for some reason
|
||||
if (!response.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -232,10 +249,8 @@ class InvenTreeAPI {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = await responseToJson(response);
|
||||
|
||||
// We expect certain response from the server
|
||||
if (data == null || !data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) {
|
||||
if (response.data == null || !response.data.containsKey("server") || !response.data.containsKey("version") || !response.data.containsKey("instance")) {
|
||||
|
||||
showServerError(
|
||||
L10().missingData,
|
||||
@ -246,11 +261,11 @@ class InvenTreeAPI {
|
||||
}
|
||||
|
||||
// Record server information
|
||||
_version = data["version"];
|
||||
instance = data['instance'] ?? '';
|
||||
_version = response.data["version"];
|
||||
instance = response.data['instance'] ?? '';
|
||||
|
||||
// Default API version is 1 if not provided
|
||||
_apiVersion = (data['apiVersion'] ?? 1) as int;
|
||||
_apiVersion = (response.data['apiVersion'] ?? 1) as int;
|
||||
|
||||
if (_apiVersion < _minApiVersion) {
|
||||
|
||||
@ -280,10 +295,10 @@ class InvenTreeAPI {
|
||||
|
||||
print("Requesting token from server");
|
||||
|
||||
response = await getResponse(_URL_GET_TOKEN);
|
||||
response = await get(_URL_GET_TOKEN);
|
||||
|
||||
// A "null" response means that the request was unsuccessful
|
||||
if (response == null) {
|
||||
// Invalid response
|
||||
if (!response.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -305,9 +320,7 @@ class InvenTreeAPI {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = await responseToJson(response);
|
||||
|
||||
if (data == null || !data.containsKey("token")) {
|
||||
if (response.data == null || !response.data.containsKey("token")) {
|
||||
showServerError(
|
||||
L10().tokenMissing,
|
||||
L10().tokenMissingFromResponse,
|
||||
@ -317,7 +330,7 @@ class InvenTreeAPI {
|
||||
}
|
||||
|
||||
// Return the received token
|
||||
_token = data["token"];
|
||||
_token = response.data["token"];
|
||||
print("Received token - $_token");
|
||||
|
||||
// Request user role information
|
||||
@ -383,17 +396,15 @@ class InvenTreeAPI {
|
||||
// Any 'older' version of the server allows any API method for any logged in user!
|
||||
// We will return immediately, but request the user roles in the background
|
||||
|
||||
var response = await get(_URL_GET_ROLES);
|
||||
var response = await get(_URL_GET_ROLES, expectedStatusCode: 200);
|
||||
|
||||
// Null response from server
|
||||
if (response == null) {
|
||||
print("null response requesting user roles");
|
||||
if (!response.isValid() || response.statusCode != 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.containsKey('roles')) {
|
||||
if (response.data.containsKey('roles')) {
|
||||
// Save a local copy of the user roles
|
||||
roles = response['roles'];
|
||||
roles = response.data['roles'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,108 +431,27 @@ class InvenTreeAPI {
|
||||
|
||||
|
||||
// Perform a PATCH request
|
||||
Future<dynamic> patch(String url, {Map<String, String> body = const {}, int expectedStatusCode=200}) async {
|
||||
var _url = makeApiUrl(url);
|
||||
Future<APIResponse> patch(String url, {Map<String, String> body = const {}, int expectedStatusCode=200}) async {
|
||||
var _body = Map<String, String>();
|
||||
|
||||
// Copy across provided data
|
||||
body.forEach((K, V) => _body[K] = V);
|
||||
|
||||
print("PATCH: " + _url);
|
||||
HttpClientRequest? request = await apiRequest(url, "PATCH");
|
||||
|
||||
final uri = Uri.parse(_url);
|
||||
|
||||
// Check for invalid host
|
||||
if (uri.host.isEmpty) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
}
|
||||
|
||||
var client = createClient(true);
|
||||
|
||||
HttpClientRequest? request;
|
||||
|
||||
try {
|
||||
// Open a connection to the server
|
||||
request = await client.patchUrl(uri).timeout(Duration(seconds: 10));
|
||||
} on SocketException catch (error) {
|
||||
showServerError(L10().connectionRefused, error.toString());
|
||||
return null;
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
showServerError(
|
||||
L10().serverError,
|
||||
error.toString()
|
||||
if (request == null) {
|
||||
// Return an "invalid" APIResponse
|
||||
return new APIResponse(
|
||||
url: url,
|
||||
method: 'PATCH',
|
||||
);
|
||||
|
||||
sentryReportError(error, stackTrace);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = json.encode(_body);
|
||||
|
||||
// Set headers
|
||||
request.headers.set(HttpHeaders.acceptHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale());
|
||||
request.headers.set(HttpHeaders.contentLengthHeader, data.length.toString());
|
||||
request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader());
|
||||
|
||||
request.add(utf8.encode(data));
|
||||
|
||||
HttpClientResponse? response;
|
||||
|
||||
try {
|
||||
response = await request.close().timeout(Duration(seconds: 10));
|
||||
} on SocketException catch (error) {
|
||||
showServerError(
|
||||
L10().connectionRefused,
|
||||
error.toString()
|
||||
);
|
||||
return null;
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
showServerError(
|
||||
L10().serverError,
|
||||
error.toString()
|
||||
);
|
||||
|
||||
sentryReportError(error, stackTrace);
|
||||
return null;
|
||||
}
|
||||
|
||||
var responseData = await responseToJson(response);
|
||||
|
||||
if (response.statusCode != expectedStatusCode) {
|
||||
showStatusCodeError(response.statusCode);
|
||||
|
||||
print("PATCH to ${_url} returned status code ${response.statusCode}");
|
||||
print("Data:");
|
||||
print(responseData);
|
||||
|
||||
// Server error
|
||||
if (response.statusCode >= 500) {
|
||||
sentryReportMessage(
|
||||
"Server error on PATCH request",
|
||||
context: {
|
||||
"url": _url,
|
||||
"statusCode": "${response.statusCode}",
|
||||
"response": responseData.toString(),
|
||||
"request": body.toString(),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Include the statuscode in the response object
|
||||
responseData["statusCode"] = response.statusCode;
|
||||
|
||||
return responseData;
|
||||
return completeRequest(
|
||||
request,
|
||||
data: json.encode(_body),
|
||||
statusCode: expectedStatusCode
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -572,155 +502,42 @@ class InvenTreeAPI {
|
||||
* We send this with the currently selected "locale",
|
||||
* so that (hopefully) the field messages are correctly translated
|
||||
*/
|
||||
Future<dynamic> options(String url) async {
|
||||
Future<APIResponse> options(String url) async {
|
||||
|
||||
var _url = makeApiUrl(url);
|
||||
HttpClientRequest? request = await apiRequest(url, "OPTIONS");
|
||||
|
||||
var client = createClient(true);
|
||||
|
||||
final uri = Uri.parse(_url);
|
||||
|
||||
if (uri.host.isEmpty) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
if (request == null) {
|
||||
// Return an "invalid" APIResponse
|
||||
return new APIResponse(
|
||||
url: url,
|
||||
method: 'OPTIONS'
|
||||
);
|
||||
}
|
||||
|
||||
HttpClientRequest? request;
|
||||
HttpClientResponse? response;
|
||||
|
||||
try {
|
||||
request = await client.openUrl("OPTIONS", uri).timeout(Duration(seconds: 10));
|
||||
|
||||
request.headers.set(HttpHeaders.acceptHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale());
|
||||
request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader());
|
||||
|
||||
response = await request.close().timeout(Duration(seconds: 10));
|
||||
} on SocketException catch (error) {
|
||||
showServerError(L10().connectionRefused, error.toString());
|
||||
return null;
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
showServerError(L10().serverError, error.toString());
|
||||
sentryReportError(error, stackTrace);
|
||||
return null;
|
||||
}
|
||||
|
||||
var responseData = await responseToJson(response);
|
||||
|
||||
return responseData;
|
||||
return completeRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a HTTP POST request
|
||||
* Returns a json object (or null if unsuccessful)
|
||||
*/
|
||||
Future<dynamic> post(String url, {Map<String, dynamic> body = const {}, int expectedStatusCode=201}) async {
|
||||
Future<APIResponse> post(String url, {Map<String, dynamic> body = const {}, int expectedStatusCode=201}) async {
|
||||
|
||||
var _url = makeApiUrl(url);
|
||||
HttpClientRequest? request = await apiRequest(url, "POST");
|
||||
|
||||
print("POST: ${_url} -> ${body.toString()}");
|
||||
|
||||
var client = createClient(true);
|
||||
|
||||
final uri = Uri.parse(_url);
|
||||
|
||||
if (uri.host.isEmpty) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
if (request == null) {
|
||||
// Return an "invalid" APIResponse
|
||||
return new APIResponse(
|
||||
url: url,
|
||||
method: 'POST'
|
||||
);
|
||||
}
|
||||
|
||||
HttpClientRequest? request;
|
||||
|
||||
try {
|
||||
// Open a connection to the server
|
||||
request = await client.postUrl(uri).timeout(Duration(seconds: 10));
|
||||
} on SocketException catch (error) {
|
||||
showServerError(
|
||||
L10().connectionRefused,
|
||||
error.toString()
|
||||
);
|
||||
return null;
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
|
||||
showServerError(
|
||||
L10().serverError,
|
||||
error.toString()
|
||||
);
|
||||
|
||||
sentryReportError(error, stackTrace);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = json.encode(body);
|
||||
|
||||
// Set headers
|
||||
// Ref: https://stackoverflow.com/questions/59713003/body-not-sending-using-map-in-flutter
|
||||
request.headers.set(HttpHeaders.acceptHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale());
|
||||
request.headers.set(HttpHeaders.contentLengthHeader, data.length.toString());
|
||||
request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader());
|
||||
|
||||
// Add JSON data to the request
|
||||
request.add(utf8.encode(data));
|
||||
|
||||
HttpClientResponse? response;
|
||||
|
||||
try {
|
||||
response = await request.close().timeout(Duration(seconds: 10));
|
||||
} on SocketException catch (error) {
|
||||
showServerError(
|
||||
L10().connectionRefused,
|
||||
error.toString()
|
||||
);
|
||||
return null;
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
showServerError(
|
||||
L10().serverError,
|
||||
error.toString()
|
||||
);
|
||||
|
||||
sentryReportError(error, stackTrace);
|
||||
return null;
|
||||
}
|
||||
|
||||
var responseData = await responseToJson(response);
|
||||
|
||||
if (response.statusCode != expectedStatusCode) {
|
||||
showStatusCodeError(response.statusCode);
|
||||
|
||||
print("POST to ${_url} returned status code ${response.statusCode}");
|
||||
print("Data:");
|
||||
print(responseData);
|
||||
|
||||
// Server error
|
||||
if (response.statusCode >= 500) {
|
||||
sentryReportMessage(
|
||||
"Server error on POST request",
|
||||
context: {
|
||||
"url": _url,
|
||||
"statusCode": "${response.statusCode}",
|
||||
"response": responseData.toString(),
|
||||
"request": body.toString(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return responseData;
|
||||
return completeRequest(
|
||||
request,
|
||||
data: json.encode(body),
|
||||
statusCode: expectedStatusCode
|
||||
);
|
||||
}
|
||||
|
||||
HttpClient createClient(bool allowBadCert) {
|
||||
@ -750,20 +567,21 @@ class InvenTreeAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a HTTP GET request,
|
||||
* and return the Response object
|
||||
* (or null if the request fails)
|
||||
* Initiate a HTTP request to the server
|
||||
*
|
||||
* @param url is the API endpoint
|
||||
* @param method is the HTTP method e.g. 'POST' / 'PATCH' / 'GET' etc;
|
||||
* @param params is the request parameters
|
||||
*/
|
||||
Future<HttpClientResponse?> getResponse(String url, {Map<String, String> params = const {}}) async {
|
||||
Future<HttpClientRequest?> apiRequest(String url, String method, {Map<String, String> urlParams = const {}}) async {
|
||||
|
||||
var _url = makeApiUrl(url);
|
||||
|
||||
print("GET: ${_url}");
|
||||
// Add any required query parameters to the URL using ?key=value notation
|
||||
if (urlParams.isNotEmpty) {
|
||||
String query = "?";
|
||||
|
||||
// If query parameters are supplied, form a query string
|
||||
if (params.isNotEmpty) {
|
||||
String query = '?';
|
||||
|
||||
params.forEach((K, V) => query += K + '=' + V + '&');
|
||||
urlParams.forEach((k, v) => query += "${k}=${v}&");
|
||||
|
||||
_url += query;
|
||||
}
|
||||
@ -773,70 +591,106 @@ class InvenTreeAPI {
|
||||
_url = _url.substring(0, _url.length - 1);
|
||||
}
|
||||
|
||||
Uri? _uri = Uri.tryParse(_url);
|
||||
|
||||
print("apiRequest ${method} -> ${url}");
|
||||
|
||||
if (_uri == null) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_uri.host.isEmpty) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpClientRequest? _request;
|
||||
|
||||
var client = createClient(true);
|
||||
|
||||
Uri? uri = Uri.tryParse(_url);
|
||||
|
||||
if (uri == null) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for invalid host
|
||||
if (uri.host.isEmpty) {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpClientRequest? request;
|
||||
|
||||
// Attempt to open a connection to the server
|
||||
try {
|
||||
// Open a connection
|
||||
request = await client.getUrl(uri).timeout(Duration(seconds: 10));
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
_request = await client.openUrl(method, _uri).timeout(Duration(seconds: 10));
|
||||
|
||||
// Set headers
|
||||
_request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader());
|
||||
_request.headers.set(HttpHeaders.acceptHeader, 'application/json');
|
||||
_request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
|
||||
_request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale());
|
||||
|
||||
return _request;
|
||||
} on SocketException catch (error) {
|
||||
showServerError(L10().connectionRefused, error.toString());
|
||||
return null;
|
||||
} on FormatException {
|
||||
showServerError(L10().invalidHost, L10().invalidHostDetails);
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
sentryReportError(error, stackTrace);
|
||||
showServerError(L10().serverError, error.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set connection headers
|
||||
request.headers.set(HttpHeaders.acceptHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
|
||||
request.headers.set(HttpHeaders.acceptLanguageHeader, Intl.getCurrentLocale());
|
||||
request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader());
|
||||
|
||||
try {
|
||||
HttpClientResponse response = await request.close().timeout(Duration(seconds: 10));
|
||||
return response;
|
||||
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
return null;
|
||||
} on SocketException catch (error) {
|
||||
showServerError(L10().connectionRefused, error.toString());
|
||||
return null;
|
||||
} catch (error, stackTrace) {
|
||||
|
||||
showServerError(
|
||||
L10().serverError,
|
||||
error.toString()
|
||||
);
|
||||
|
||||
sentryReportError(error, stackTrace);
|
||||
|
||||
showServerError(L10().serverError, error.toString());
|
||||
sentryReportError(error, stackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Complete an API request, and return an APIResponse object
|
||||
*/
|
||||
Future<APIResponse> completeRequest(HttpClientRequest request, {String? data, int? statusCode}) async {
|
||||
|
||||
if (data != null && data.isNotEmpty) {
|
||||
request.headers.set(HttpHeaders.contentLengthHeader, data.length.toString());
|
||||
request.add(utf8.encode(data));
|
||||
}
|
||||
|
||||
APIResponse response = new APIResponse(
|
||||
method: request.method,
|
||||
url: request.uri.toString()
|
||||
);
|
||||
|
||||
try {
|
||||
HttpClientResponse? _response = await request.close().timeout(Duration(seconds: 10));
|
||||
|
||||
response.statusCode = _response.statusCode;
|
||||
response.data = await responseToJson(_response);
|
||||
|
||||
// Expected status code not returned
|
||||
if ((statusCode != null) && (statusCode != _response.statusCode)) {
|
||||
showStatusCodeError(_response.statusCode);
|
||||
}
|
||||
|
||||
// Report any server errors
|
||||
if (_response.statusCode >= 500) {
|
||||
sentryReportMessage(
|
||||
"Server error",
|
||||
context: {
|
||||
"url": request.uri.toString(),
|
||||
"method": request.method,
|
||||
"statusCode": _response.statusCode.toString(),
|
||||
"requestHeaders": request.headers.toString(),
|
||||
"responseHeaders": _response.headers.toString(),
|
||||
"responseData": response.data.toString(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} on SocketException catch (error) {
|
||||
showServerError(L10().connectionRefused, error.toString());
|
||||
} on TimeoutException {
|
||||
showTimeoutError();
|
||||
} catch (error, stackTrace) {
|
||||
showServerError(L10().serverError, error.toString());
|
||||
sentryReportError(error, stackTrace);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a HttpClientResponse response object to JSON
|
||||
*/
|
||||
dynamic responseToJson(HttpClientResponse response) async {
|
||||
|
||||
String body = await response.transform(utf8.decoder).join();
|
||||
@ -872,55 +726,37 @@ class InvenTreeAPI {
|
||||
* Perform a HTTP GET request
|
||||
* Returns a json object (or null if did not complete)
|
||||
*/
|
||||
Future<dynamic> get(String url, {Map<String, String> params = const {}, int expectedStatusCode=200}) async {
|
||||
Future<APIResponse> get(String url, {Map<String, String> params = const {}, int expectedStatusCode=200}) async {
|
||||
|
||||
var response = await getResponse(url, params: params);
|
||||
HttpClientRequest? request = await apiRequest(
|
||||
url,
|
||||
"GET",
|
||||
urlParams: params,
|
||||
);
|
||||
|
||||
// A null response means something has gone wrong...
|
||||
if (response == null) {
|
||||
print("null response from GET ${url}");
|
||||
return null;
|
||||
if (request == null) {
|
||||
// Return an "invalid" APIResponse
|
||||
return new APIResponse(
|
||||
url: url,
|
||||
method: 'GET',
|
||||
);
|
||||
}
|
||||
|
||||
var responseData = await responseToJson(response);
|
||||
|
||||
// Check the status code of the response
|
||||
if (response.statusCode != expectedStatusCode) {
|
||||
showStatusCodeError(response.statusCode);
|
||||
|
||||
// Server error
|
||||
if (response.statusCode >= 500) {
|
||||
sentryReportMessage(
|
||||
"Server error on GET request",
|
||||
context: {
|
||||
"url": url,
|
||||
"statusCode": "${response.statusCode}",
|
||||
"response": responseData.toString(),
|
||||
"params": params.toString(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return responseData;
|
||||
return completeRequest(request);
|
||||
}
|
||||
|
||||
// Return a list of request headers
|
||||
Map<String, String> defaultHeaders() {
|
||||
var headers = Map<String, String>();
|
||||
|
||||
headers[HttpHeaders.authorizationHeader] = _authorizationHeader();
|
||||
headers[HttpHeaders.acceptHeader] = 'application/json';
|
||||
headers[HttpHeaders.contentTypeHeader] = 'application/json';
|
||||
headers[HttpHeaders.acceptLanguageHeader] = Intl.getCurrentLocale();
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
Map<String, String> jsonHeaders() {
|
||||
var headers = defaultHeaders();
|
||||
headers['Content-Type'] = 'application/json';
|
||||
return headers;
|
||||
}
|
||||
|
||||
String _authorizationHeader() {
|
||||
if (_token.isNotEmpty) {
|
||||
return "Token $_token";
|
||||
@ -965,4 +801,4 @@ class InvenTreeAPI {
|
||||
cacheManager: manager,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import 'package:sembast/sembast.dart';
|
||||
import 'package:InvenTree/preferences.dart';
|
||||
import 'package:inventree/preferences.dart';
|
||||
|
||||
class InvenTreeSettingsManager {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:InvenTree/app_settings.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:inventree/app_settings.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -9,15 +9,15 @@ import 'package:one_context/one_context.dart';
|
||||
|
||||
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
||||
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
|
||||
import 'package:InvenTree/widget/location_display.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/stock_detail.dart';
|
||||
import 'package:inventree/widget/location_display.dart';
|
||||
import 'package:inventree/widget/part_detail.dart';
|
||||
import 'package:inventree/widget/stock_detail.dart';
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
@ -92,7 +92,7 @@ class BarcodeHandler {
|
||||
|
||||
print("Scanned barcode data: ${barcode}");
|
||||
|
||||
var data = await InvenTreeAPI().post(
|
||||
var response = await InvenTreeAPI().post(
|
||||
url,
|
||||
body: {
|
||||
"barcode": barcode,
|
||||
@ -100,19 +100,19 @@ class BarcodeHandler {
|
||||
expectedStatusCode: 200
|
||||
);
|
||||
|
||||
if (data == null) {
|
||||
if (!response.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.containsKey('error')) {
|
||||
if (response.data.containsKey('error')) {
|
||||
_controller?.resumeCamera();
|
||||
onBarcodeUnknown(data);
|
||||
} else if (data.containsKey('success')) {
|
||||
onBarcodeUnknown(response.data);
|
||||
} else if (response.data.containsKey('success')) {
|
||||
_controller?.resumeCamera();
|
||||
onBarcodeMatched(data);
|
||||
onBarcodeMatched(response.data);
|
||||
} else {
|
||||
_controller?.resumeCamera();
|
||||
onBarcodeUnhandled(data);
|
||||
onBarcodeUnhandled(response.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@ -149,13 +149,13 @@ class InvenTreeModel {
|
||||
*/
|
||||
Future<bool> reload() async {
|
||||
|
||||
var response = await api.get(url, params: defaultGetFilters());
|
||||
var response = await api.get(url, params: defaultGetFilters(), expectedStatusCode: 200);
|
||||
|
||||
if (response == null) {
|
||||
if (!response.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsondata = response;
|
||||
jsondata = response.data;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -163,19 +163,21 @@ class InvenTreeModel {
|
||||
// POST data to update the model
|
||||
Future<bool> update({Map<String, String> values = const {}}) async {
|
||||
|
||||
var addr = path.join(URL, pk.toString());
|
||||
var url = path.join(URL, pk.toString());
|
||||
|
||||
if (!addr.endsWith("/")) {
|
||||
addr += "/";
|
||||
if (!url.endsWith("/")) {
|
||||
url += "/";
|
||||
}
|
||||
|
||||
var response = await api.patch(
|
||||
addr,
|
||||
url,
|
||||
body: values,
|
||||
expectedStatusCode: 200
|
||||
);
|
||||
|
||||
if (response == null) return false;
|
||||
if (!response.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -199,15 +201,13 @@ class InvenTreeModel {
|
||||
params[key] = filters[key] ?? '';
|
||||
}
|
||||
|
||||
print("GET: $url ${params.toString()}");
|
||||
|
||||
var response = await api.get(url, params: params);
|
||||
|
||||
if (response == null) {
|
||||
if (!response.isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createFromJson(response);
|
||||
return createFromJson(response.data);
|
||||
}
|
||||
|
||||
Future<InvenTreeModel?> create(Map<String, dynamic> data) async {
|
||||
@ -224,11 +224,12 @@ class InvenTreeModel {
|
||||
|
||||
var response = await api.post(URL, body: data);
|
||||
|
||||
if (response == null) {
|
||||
// Invalid response returned from server
|
||||
if (!response.isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createFromJson(response);
|
||||
return createFromJson(response.data);
|
||||
}
|
||||
|
||||
Future<InvenTreePageResponse?> listPaginated(int limit, int offset, {Map<String, String> filters = const {}}) async {
|
||||
@ -243,19 +244,19 @@ class InvenTreeModel {
|
||||
|
||||
var response = await api.get(URL, params: params);
|
||||
|
||||
if (response == null) {
|
||||
if (!response.isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Construct the response
|
||||
InvenTreePageResponse page = new InvenTreePageResponse();
|
||||
|
||||
if (response.containsKey("count") && response.containsKey("results")) {
|
||||
page.count = response["count"] as int;
|
||||
if (response.data.containsKey("count") && response.data.containsKey("results")) {
|
||||
page.count = response.data["count"] as int;
|
||||
|
||||
page.results = [];
|
||||
|
||||
for (var result in response["results"]) {
|
||||
for (var result in response.data["results"]) {
|
||||
page.addResult(createFromJson(result));
|
||||
}
|
||||
|
||||
@ -282,7 +283,7 @@ class InvenTreeModel {
|
||||
// A list of "InvenTreeModel" items
|
||||
List<InvenTreeModel> results = [];
|
||||
|
||||
if (response == null) {
|
||||
if (!response.isValid()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -290,7 +291,7 @@ class InvenTreeModel {
|
||||
// - No data receieved
|
||||
// - Data is not a list of maps
|
||||
|
||||
for (var d in response) {
|
||||
for (var d in response.data) {
|
||||
|
||||
// Create a new object (of the current class type
|
||||
InvenTreeModel obj = createFromJson(d);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'model.dart';
|
||||
import 'dart:io';
|
||||
|
@ -4,7 +4,7 @@ import 'package:device_info/device_info.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
|
||||
Future<Map<String, dynamic>> getDeviceInfo() async {
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'model.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
|
||||
|
||||
class InvenTreeStockItemTestResult extends InvenTreeModel {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:InvenTree/inventree/sentry.dart';
|
||||
import 'package:inventree/inventree/sentry.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:InvenTree/widget/home.dart';
|
||||
import 'package:inventree/widget/home.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:one_context/one_context.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/settings/release.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/settings/release.dart';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
class InvenTreeAboutWidget extends StatelessWidget {
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
import 'package:InvenTree/app_settings.dart';
|
||||
import 'package:inventree/app_settings.dart';
|
||||
|
||||
class InvenTreeAppSettingsWidget extends StatefulWidget {
|
||||
@override
|
||||
|
@ -1,11 +1,11 @@
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/spinner.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/widget/spinner.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import '../api.dart';
|
||||
import '../user_profile.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
class ReleaseNotesWidget extends StatelessWidget {
|
||||
|
@ -1,13 +1,13 @@
|
||||
import 'package:InvenTree/inventree/sentry.dart';
|
||||
import 'package:InvenTree/settings/about.dart';
|
||||
import 'package:InvenTree/settings/app_settings.dart';
|
||||
import 'package:InvenTree/settings/login.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:inventree/inventree/sentry.dart';
|
||||
import 'package:inventree/settings/about.dart';
|
||||
import 'package:inventree/settings/app_settings.dart';
|
||||
import 'package:inventree/settings/login.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
|
@ -1,19 +1,19 @@
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/app_settings.dart';
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/inventree/sentry.dart';
|
||||
import 'package:InvenTree/widget/progress.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/app_settings.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/inventree/sentry.dart';
|
||||
import 'package:inventree/widget/progress.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/paginator.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:inventree/widget/part_detail.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/widget/paginator.dart';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/inventree/company.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/inventree/company.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
class CompanyDetailWidget extends StatefulWidget {
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
|
||||
import 'package:InvenTree/widget/company_detail.dart';
|
||||
import 'package:inventree/widget/company_detail.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/inventree/company.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/inventree/company.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
|
||||
abstract class CompanyListWidget extends StatefulWidget {
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
|
||||
import 'package:InvenTree/app_settings.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:inventree/app_settings.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
import 'package:one_context/one_context.dart';
|
||||
|
||||
Future<void> confirmationDialog(String title, String text, {String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async {
|
||||
|
@ -1,14 +1,14 @@
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/barcode.dart';
|
||||
import 'package:InvenTree/widget/company_list.dart';
|
||||
import 'package:InvenTree/widget/search.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/barcode.dart';
|
||||
import 'package:inventree/widget/company_list.dart';
|
||||
import 'package:inventree/widget/search.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:InvenTree/widget/category_display.dart';
|
||||
import 'package:InvenTree/widget/location_display.dart';
|
||||
import 'package:inventree/widget/category_display.dart';
|
||||
import 'package:inventree/widget/location_display.dart';
|
||||
|
||||
import 'package:InvenTree/settings/settings.dart';
|
||||
import 'package:inventree/settings/settings.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
class InvenTreeDrawer extends StatelessWidget {
|
||||
|
@ -2,7 +2,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:InvenTree/user_profile.dart';
|
||||
import 'package:inventree/user_profile.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -6,17 +6,17 @@ import 'file:///C:/inventree-app/lib/l10.dart';
|
||||
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
import 'package:InvenTree/barcode.dart';
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/barcode.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
|
||||
import 'package:InvenTree/settings/login.dart';
|
||||
import 'package:inventree/settings/login.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/spinner.dart';
|
||||
import 'package:InvenTree/widget/drawer.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/spinner.dart';
|
||||
import 'package:inventree/widget/drawer.dart';
|
||||
|
||||
class InvenTreeHomePage extends StatefulWidget {
|
||||
InvenTreeHomePage({Key? key}) : super(key: key);
|
||||
|
@ -1,17 +1,17 @@
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/app_settings.dart';
|
||||
import 'package:InvenTree/barcode.dart';
|
||||
import 'package:InvenTree/inventree/sentry.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/widget/progress.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/app_settings.dart';
|
||||
import 'package:inventree/barcode.dart';
|
||||
import 'package:inventree/inventree/sentry.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
import 'package:inventree/widget/progress.dart';
|
||||
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_detail.dart';
|
||||
import 'package:InvenTree/widget/paginator.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:inventree/widget/stock_detail.dart';
|
||||
import 'package:inventree/widget/paginator.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
class PaginatedSearchWidget extends StatelessWidget {
|
||||
|
@ -7,16 +7,16 @@ import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/widget/full_screen_image.dart';
|
||||
import 'package:InvenTree/widget/category_display.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/widget/full_screen_image.dart';
|
||||
import 'package:inventree/widget/category_display.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
|
||||
import 'location_display.dart';
|
||||
|
||||
@ -558,4 +558,4 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
Widget getBody(BuildContext context) {
|
||||
return getSelectedWidget(tabIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
class PartNotesWidget extends StatefulWidget {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:InvenTree/widget/drawer.dart';
|
||||
import 'package:inventree/widget/drawer.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
@ -1,15 +1,15 @@
|
||||
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/progress.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_detail.dart';
|
||||
import 'package:inventree/widget/part_detail.dart';
|
||||
import 'package:inventree/widget/progress.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:inventree/widget/stock_detail.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
|
||||
import '../api.dart';
|
||||
|
||||
|
@ -12,7 +12,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:one_context/one_context.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? success, String? actionText}) {
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/progress.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/widget/part_detail.dart';
|
||||
import 'package:inventree/widget/progress.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import '../api.dart';
|
||||
|
||||
@ -35,11 +35,9 @@ class _StarredPartState extends RefreshableState<StarredPartWidget> {
|
||||
|
||||
starredParts.clear();
|
||||
|
||||
if (parts != null) {
|
||||
for (int idx = 0; idx < parts.length; idx++) {
|
||||
if (parts[idx] is InvenTreePart) {
|
||||
starredParts.add(parts[idx] as InvenTreePart);
|
||||
}
|
||||
for (int idx = 0; idx < parts.length; idx++) {
|
||||
if (parts[idx] is InvenTreePart) {
|
||||
starredParts.add(parts[idx] as InvenTreePart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,21 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:InvenTree/barcode.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/location_display.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/progress.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_item_test_results.dart';
|
||||
import 'package:InvenTree/widget/stock_notes.dart';
|
||||
import 'package:inventree/barcode.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/widget/location_display.dart';
|
||||
import 'package:inventree/widget/part_detail.dart';
|
||||
import 'package:inventree/widget/progress.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
import 'package:inventree/widget/stock_item_test_results.dart';
|
||||
import 'package:inventree/widget/stock_notes.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
@ -1,19 +1,19 @@
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/inventree/model.dart';
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/progress.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:inventree/inventree/part.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
import 'package:inventree/inventree/model.dart';
|
||||
import 'package:inventree/api.dart';
|
||||
import 'package:inventree/widget/dialogs.dart';
|
||||
import 'package:inventree/widget/fields.dart';
|
||||
import 'package:inventree/widget/progress.dart';
|
||||
import 'package:inventree/widget/snacks.dart';
|
||||
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:inventree/inventree/stock.dart';
|
||||
import 'package:inventree/widget/refreshable_state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:InvenTree/l10.dart';
|
||||
import 'package:inventree/l10.dart';
|
||||
|
||||
|
||||
class StockNotesWidget extends StatefulWidget {
|
||||
|
@ -1,4 +1,4 @@
|
||||
name: InvenTree
|
||||
name: inventree
|
||||
description: InvenTree stock management
|
||||
|
||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
||||
@ -7,7 +7,7 @@ description: InvenTree stock management
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 0.2.7+15
|
||||
version: 0.2.8+16
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user