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