mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-11-04 07:15:46 +00:00 
			
		
		
		
	Refactor of translation lookup!
This commit is contained in:
		
							
								
								
									
										63
									
								
								lib/api.dart
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								lib/api.dart
									
									
									
									
									
								
							@@ -2,16 +2,15 @@ import 'dart:async';
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
import 'dart:io';
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:InvenTree/app_settings.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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					 | 
				
			||||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
					import 'package:cached_network_image/cached_network_image.dart';
 | 
				
			||||||
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:http/http.dart' as http;
 | 
					import 'package:http/http.dart' as http;
 | 
				
			||||||
import 'package:one_context/one_context.dart';
 | 
					import 'package:one_context/one_context.dart';
 | 
				
			||||||
@@ -119,7 +118,7 @@ class InvenTreeAPI {
 | 
				
			|||||||
    if (!isConnected()) {
 | 
					    if (!isConnected()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(context).notConnected,
 | 
					        L10().notConnected,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
        icon: FontAwesomeIcons.server
 | 
					        icon: FontAwesomeIcons.server
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -227,8 +226,8 @@ class InvenTreeAPI {
 | 
				
			|||||||
    if (data == null || !data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) {
 | 
					    if (data == null || !data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showServerError(
 | 
					      showServerError(
 | 
				
			||||||
        I18N.of(ctx).missingData,
 | 
					        L10().missingData,
 | 
				
			||||||
        I18N.of(ctx).serverMissingData,
 | 
					        L10().serverMissingData,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
@@ -243,17 +242,17 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (_apiVersion < _minApiVersion) {
 | 
					    if (_apiVersion < _minApiVersion) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      String message = I18N.of(ctx).serverApiVersion + ": ${_apiVersion}";
 | 
					      String message = L10().serverApiVersion + ": ${_apiVersion}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      message += "\n";
 | 
					      message += "\n";
 | 
				
			||||||
      message += I18N.of(ctx).serverApiRequired + ": ${_minApiVersion}";
 | 
					      message += L10().serverApiRequired + ": ${_minApiVersion}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      message += "\n\n";
 | 
					      message += "\n\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      message += "Ensure your InvenTree server version is up to date!";
 | 
					      message += "Ensure your InvenTree server version is up to date!";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showServerError(
 | 
					      showServerError(
 | 
				
			||||||
        I18N.of(OneContext().context).serverOld,
 | 
					        L10().serverOld,
 | 
				
			||||||
        message
 | 
					        message
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -282,8 +281,8 @@ class InvenTreeAPI {
 | 
				
			|||||||
        case 401:
 | 
					        case 401:
 | 
				
			||||||
        case 403:
 | 
					        case 403:
 | 
				
			||||||
          showServerError(
 | 
					          showServerError(
 | 
				
			||||||
            I18N.of(ctx).serverAuthenticationError,
 | 
					            L10().serverAuthenticationError,
 | 
				
			||||||
            I18N.of(ctx).invalidUsernamePassword,
 | 
					            L10().invalidUsernamePassword,
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@@ -298,8 +297,8 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (data == null || !data.containsKey("token")) {
 | 
					    if (data == null || !data.containsKey("token")) {
 | 
				
			||||||
      showServerError(
 | 
					      showServerError(
 | 
				
			||||||
          I18N.of(OneContext().context).tokenMissing,
 | 
					          L10().tokenMissing,
 | 
				
			||||||
          I18N.of(OneContext().context).tokenMissingFromResponse,
 | 
					          L10().tokenMissingFromResponse,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
@@ -338,7 +337,7 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (profile == null) {
 | 
					    if (profile == null) {
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
          I18N.of(OneContext().context).profileSelect,
 | 
					          L10().profileSelect,
 | 
				
			||||||
          success: false,
 | 
					          success: false,
 | 
				
			||||||
          icon: FontAwesomeIcons.exclamationCircle
 | 
					          icon: FontAwesomeIcons.exclamationCircle
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -355,7 +354,7 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (_connected) {
 | 
					    if (_connected) {
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(OneContext().context).serverConnected,
 | 
					        L10().serverConnected,
 | 
				
			||||||
        icon: FontAwesomeIcons.server,
 | 
					        icon: FontAwesomeIcons.server,
 | 
				
			||||||
        success: true,
 | 
					        success: true,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -436,14 +435,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (error is SocketException) {
 | 
					      if (error is SocketException) {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
          I18N.of(ctx).connectionRefused,
 | 
					          L10().connectionRefused,
 | 
				
			||||||
          error.toString(),
 | 
					          error.toString(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (error is TimeoutException) {
 | 
					      } else if (error is TimeoutException) {
 | 
				
			||||||
        showTimeoutError(ctx);
 | 
					        showTimeoutError(ctx);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
          I18N.of(ctx).serverError,
 | 
					          L10().serverError,
 | 
				
			||||||
          error.toString()
 | 
					          error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -477,18 +476,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (error is SocketException) {
 | 
					      if (error is SocketException) {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
            I18N
 | 
					            L10().connectionRefused,
 | 
				
			||||||
                .of(ctx)
 | 
					 | 
				
			||||||
                .connectionRefused,
 | 
					 | 
				
			||||||
            error.toString()
 | 
					            error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (error is TimeoutException) {
 | 
					      } else if (error is TimeoutException) {
 | 
				
			||||||
        showTimeoutError(ctx);
 | 
					        showTimeoutError(ctx);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
            I18N
 | 
					            L10().serverError,
 | 
				
			||||||
                .of(ctx)
 | 
					 | 
				
			||||||
                .serverError,
 | 
					 | 
				
			||||||
            error.toString()
 | 
					            error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -558,14 +553,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (error is SocketException) {
 | 
					      if (error is SocketException) {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
          I18N.of(ctx).connectionRefused,
 | 
					          L10().connectionRefused,
 | 
				
			||||||
          error.toString()
 | 
					          error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (error is TimeoutException) {
 | 
					      } else if (error is TimeoutException) {
 | 
				
			||||||
        showTimeoutError(ctx);
 | 
					        showTimeoutError(ctx);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
        I18N.of(ctx).serverError,
 | 
					        L10().serverError,
 | 
				
			||||||
        error.toString()
 | 
					        error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -600,14 +595,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (error is SocketException) {
 | 
					      if (error is SocketException) {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
          I18N.of(ctx).connectionRefused,
 | 
					          L10().connectionRefused,
 | 
				
			||||||
          error.toString()
 | 
					          error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (error is TimeoutException) {
 | 
					      } else if (error is TimeoutException) {
 | 
				
			||||||
        showTimeoutError(ctx);
 | 
					        showTimeoutError(ctx);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
          I18N.of(ctx).serverError,
 | 
					          L10().serverError,
 | 
				
			||||||
          error.toString()
 | 
					          error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -643,8 +638,8 @@ class InvenTreeAPI {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
          I18N.of(OneContext().context).serverCertificateError,
 | 
					          L10().serverCertificateError,
 | 
				
			||||||
          I18N.of(OneContext().context).serverCertificateInvalid,
 | 
					          L10().serverCertificateInvalid,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -696,14 +691,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (error is SocketException) {
 | 
					      if (error is SocketException) {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
            I18N.of(ctx).connectionRefused,
 | 
					            L10().connectionRefused,
 | 
				
			||||||
            error.toString()
 | 
					            error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (error is TimeoutException) {
 | 
					      } else if (error is TimeoutException) {
 | 
				
			||||||
        showTimeoutError(ctx);
 | 
					        showTimeoutError(ctx);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
            I18N.of(ctx).serverError,
 | 
					            L10().serverError,
 | 
				
			||||||
            error.toString()
 | 
					            error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -730,14 +725,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (error is SocketException) {
 | 
					      if (error is SocketException) {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
            I18N.of(ctx).connectionRefused,
 | 
					            L10().connectionRefused,
 | 
				
			||||||
            error.toString()
 | 
					            error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (error is TimeoutException) {
 | 
					      } else if (error is TimeoutException) {
 | 
				
			||||||
        showTimeoutError(ctx);
 | 
					        showTimeoutError(ctx);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        showServerError(
 | 
					        showServerError(
 | 
				
			||||||
            I18N.of(ctx).serverError,
 | 
					            L10().serverError,
 | 
				
			||||||
            error.toString()
 | 
					            error.toString()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -766,8 +761,8 @@ class InvenTreeAPI {
 | 
				
			|||||||
      print("${body}");
 | 
					      print("${body}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showServerError(
 | 
					      showServerError(
 | 
				
			||||||
        I18N.of(OneContext().context).formatException,
 | 
					        L10().formatException,
 | 
				
			||||||
        I18N.of(OneContext().context).formatExceptionJson + ":\n${body}"
 | 
					        L10().formatExceptionJson + ":\n${body}"
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ 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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:InvenTree/api.dart';
 | 
					import 'package:InvenTree/api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,7 +70,7 @@ class BarcodeHandler {
 | 
				
			|||||||
      failureTone();
 | 
					      failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(OneContext().context).barcodeNoMatch,
 | 
					        L10().barcodeNoMatch,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
        icon: FontAwesomeIcons.qrcode
 | 
					        icon: FontAwesomeIcons.qrcode
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -81,7 +81,7 @@ class BarcodeHandler {
 | 
				
			|||||||
      failureTone();
 | 
					      failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Called when the server returns an unhandled response
 | 
					      // Called when the server returns an unhandled response
 | 
				
			||||||
      showServerError(I18N.of(OneContext().context).responseUnknown, data.toString());
 | 
					      showServerError(L10().responseUnknown, data.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      _controller.resumeCamera();
 | 
					      _controller.resumeCamera();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -125,7 +125,7 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanGeneral;
 | 
					  String getOverlayText(BuildContext context) => L10().barcodeScanGeneral;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> onBarcodeUnknown(Map<String, dynamic> data) {
 | 
					  Future<void> onBarcodeUnknown(Map<String, dynamic> data) {
 | 
				
			||||||
@@ -133,7 +133,7 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
				
			|||||||
    failureTone();
 | 
					    failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showSnackIcon(
 | 
					    showSnackIcon(
 | 
				
			||||||
        I18N.of(OneContext().context).barcodeNoMatch,
 | 
					        L10().barcodeNoMatch,
 | 
				
			||||||
        icon: FontAwesomeIcons.exclamationCircle,
 | 
					        icon: FontAwesomeIcons.exclamationCircle,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -166,7 +166,7 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
				
			|||||||
        failureTone();
 | 
					        failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
          I18N.of(OneContext().context).invalidStockLocation,
 | 
					          L10().invalidStockLocation,
 | 
				
			||||||
          success: false
 | 
					          success: false
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -188,7 +188,7 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
				
			|||||||
        failureTone();
 | 
					        failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
            I18N.of(OneContext().context).invalidStockItem,
 | 
					            L10().invalidStockItem,
 | 
				
			||||||
            success: false
 | 
					            success: false
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -209,7 +209,7 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
				
			|||||||
        failureTone();
 | 
					        failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
            I18N.of(OneContext().context).invalidPart,
 | 
					            L10().invalidPart,
 | 
				
			||||||
            success: false
 | 
					            success: false
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -218,16 +218,16 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
				
			|||||||
      failureTone();
 | 
					      failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(OneContext().context).barcodeUnknown,
 | 
					        L10().barcodeUnknown,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
        onAction: () {
 | 
					        onAction: () {
 | 
				
			||||||
          showDialog(
 | 
					          showDialog(
 | 
				
			||||||
              context: _context,
 | 
					              context: _context,
 | 
				
			||||||
              child: SimpleDialog(
 | 
					              child: SimpleDialog(
 | 
				
			||||||
                title: Text(I18N.of(_context).unknownResponse),
 | 
					                title: Text(L10().unknownResponse),
 | 
				
			||||||
                children: <Widget>[
 | 
					                children: <Widget>[
 | 
				
			||||||
                  ListTile(
 | 
					                  ListTile(
 | 
				
			||||||
                    title: Text(I18N.of(_context).responseData),
 | 
					                    title: Text(L10().responseData),
 | 
				
			||||||
                    subtitle: Text(data.toString()),
 | 
					                    subtitle: Text(data.toString()),
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
@@ -250,7 +250,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
 | 
				
			|||||||
  StockItemBarcodeAssignmentHandler(this.item);
 | 
					  StockItemBarcodeAssignmentHandler(this.item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanAssign;
 | 
					  String getOverlayText(BuildContext context) => L10().barcodeScanAssign;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> onBarcodeMatched(Map<String, dynamic> data) {
 | 
					  Future<void> onBarcodeMatched(Map<String, dynamic> data) {
 | 
				
			||||||
@@ -259,7 +259,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // If the barcode is known, we can't assign it to the stock item!
 | 
					    // If the barcode is known, we can't assign it to the stock item!
 | 
				
			||||||
    showSnackIcon(
 | 
					    showSnackIcon(
 | 
				
			||||||
      I18N.of(OneContext().context).barcodeInUse,
 | 
					      L10().barcodeInUse,
 | 
				
			||||||
      icon: FontAwesomeIcons.qrcode,
 | 
					      icon: FontAwesomeIcons.qrcode,
 | 
				
			||||||
      success: false
 | 
					      success: false
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -271,8 +271,8 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!data.containsKey("hash")) {
 | 
					    if (!data.containsKey("hash")) {
 | 
				
			||||||
      showServerError(
 | 
					      showServerError(
 | 
				
			||||||
          I18N.of(_context).missingData,
 | 
					          L10().missingData,
 | 
				
			||||||
          I18N.of(_context).barcodeMissingHash,
 | 
					          L10().barcodeMissingHash,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -292,7 +292,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
 | 
				
			|||||||
          Navigator.of(_context).pop();
 | 
					          Navigator.of(_context).pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          showSnackIcon(
 | 
					          showSnackIcon(
 | 
				
			||||||
            I18N.of(OneContext().context).barcodeAssigned,
 | 
					            L10().barcodeAssigned,
 | 
				
			||||||
            success: true,
 | 
					            success: true,
 | 
				
			||||||
            icon: FontAwesomeIcons.qrcode
 | 
					            icon: FontAwesomeIcons.qrcode
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
@@ -301,7 +301,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
 | 
				
			|||||||
          successTone();
 | 
					          successTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          showSnackIcon(
 | 
					          showSnackIcon(
 | 
				
			||||||
              I18N.of(OneContext().context).barcodeNotAssigned,
 | 
					              L10().barcodeNotAssigned,
 | 
				
			||||||
              success: false,
 | 
					              success: false,
 | 
				
			||||||
              icon: FontAwesomeIcons.qrcode
 | 
					              icon: FontAwesomeIcons.qrcode
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
@@ -325,7 +325,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler {
 | 
				
			|||||||
  StockItemScanIntoLocationHandler(this.item);
 | 
					  StockItemScanIntoLocationHandler(this.item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanLocation;
 | 
					  String getOverlayText(BuildContext context) => L10().barcodeScanLocation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> onBarcodeMatched(Map<String, dynamic> data) async {
 | 
					  Future<void> onBarcodeMatched(Map<String, dynamic> data) async {
 | 
				
			||||||
@@ -346,7 +346,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler {
 | 
				
			|||||||
        Navigator.of(_context).pop();
 | 
					        Navigator.of(_context).pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
          I18N.of(OneContext().context).barcodeScanIntoLocationSuccess,
 | 
					          L10().barcodeScanIntoLocationSuccess,
 | 
				
			||||||
          success: true,
 | 
					          success: true,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
@@ -354,7 +354,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler {
 | 
				
			|||||||
        failureTone();
 | 
					        failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
          I18N.of(OneContext().context).barcodeScanIntoLocationFailure,
 | 
					          L10().barcodeScanIntoLocationFailure,
 | 
				
			||||||
          success: false
 | 
					          success: false
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -363,7 +363,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler {
 | 
				
			|||||||
      failureTone();
 | 
					      failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(OneContext().context).invalidStockLocation,
 | 
					        L10().invalidStockLocation,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -381,7 +381,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
 | 
				
			|||||||
  StockLocationScanInItemsHandler(this.location);
 | 
					  StockLocationScanInItemsHandler(this.location);
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanItem;
 | 
					  String getOverlayText(BuildContext context) => L10().barcodeScanItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> onBarcodeMatched(Map<String, dynamic> data) async {
 | 
					  Future<void> onBarcodeMatched(Map<String, dynamic> data) async {
 | 
				
			||||||
@@ -398,16 +398,14 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
 | 
				
			|||||||
        failureTone();
 | 
					        failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
          I18N.of(OneContext().context).invalidStockItem,
 | 
					          L10().invalidStockItem,
 | 
				
			||||||
          success: false,
 | 
					          success: false,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (item.locationId == location.pk) {
 | 
					      } else if (item.locationId == location.pk) {
 | 
				
			||||||
        failureTone();
 | 
					        failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showSnackIcon(
 | 
					        showSnackIcon(
 | 
				
			||||||
            I18N
 | 
					            L10().itemInLocation,
 | 
				
			||||||
                .of(OneContext().context)
 | 
					 | 
				
			||||||
                .itemInLocation,
 | 
					 | 
				
			||||||
            success: true
 | 
					            success: true
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
@@ -418,7 +416,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
 | 
				
			|||||||
          successTone();
 | 
					          successTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          showSnackIcon(
 | 
					          showSnackIcon(
 | 
				
			||||||
            I18N.of(OneContext().context).barcodeScanIntoLocationSuccess,
 | 
					            L10().barcodeScanIntoLocationSuccess,
 | 
				
			||||||
            success: true
 | 
					            success: true
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@@ -426,7 +424,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
 | 
				
			|||||||
          failureTone();
 | 
					          failureTone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          showSnackIcon(
 | 
					          showSnackIcon(
 | 
				
			||||||
            I18N.of(OneContext().context).barcodeScanIntoLocationFailure,
 | 
					            L10().barcodeScanIntoLocationFailure,
 | 
				
			||||||
            success: false
 | 
					            success: false
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -437,7 +435,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // Does not match a valid stock item!
 | 
					      // Does not match a valid stock item!
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(OneContext().context).invalidStockItem,
 | 
					        L10().invalidStockItem,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,13 @@
 | 
				
			|||||||
import 'package:InvenTree/inventree/part.dart';
 | 
					import 'package:InvenTree/inventree/part.dart';
 | 
				
			||||||
import 'package:InvenTree/widget/dialogs.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 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
import 'dart:io';
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					 | 
				
			||||||
import 'package:InvenTree/api.dart';
 | 
					import 'package:InvenTree/api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,19 +62,19 @@ class InvenTreeStockItem extends InvenTreeModel {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    switch (status) {
 | 
					    switch (status) {
 | 
				
			||||||
      case OK:
 | 
					      case OK:
 | 
				
			||||||
        return I18N.of(context).ok;
 | 
					        return L10().ok;
 | 
				
			||||||
      case ATTENTION:
 | 
					      case ATTENTION:
 | 
				
			||||||
        return I18N.of(context).attention;
 | 
					        return L10().attention;
 | 
				
			||||||
      case DAMAGED:
 | 
					      case DAMAGED:
 | 
				
			||||||
        return I18N.of(context).damaged;
 | 
					        return L10().damaged;
 | 
				
			||||||
      case DESTROYED:
 | 
					      case DESTROYED:
 | 
				
			||||||
        return I18N.of(context).destroyed;
 | 
					        return L10().destroyed;
 | 
				
			||||||
      case REJECTED:
 | 
					      case REJECTED:
 | 
				
			||||||
        return I18N.of(context).rejected;
 | 
					        return L10().rejected;
 | 
				
			||||||
      case LOST:
 | 
					      case LOST:
 | 
				
			||||||
        return I18N.of(context).lost;
 | 
					        return L10().lost;
 | 
				
			||||||
      case RETURNED:
 | 
					      case RETURNED:
 | 
				
			||||||
        return I18N.of(context).returned;
 | 
					        return L10().returned;
 | 
				
			||||||
      default:
 | 
					      default:
 | 
				
			||||||
        return status.toString();
 | 
					        return status.toString();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								lib/l10.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/l10.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 | 
				
			||||||
 | 
					import 'package:one_context/one_context.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shortcut function to reduce boilerplate!
 | 
				
			||||||
 | 
					I18N L10()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return I18N.of(OneContext().context);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,6 +5,8 @@ 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 'file:///C:/inventree-app/lib/l10.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';
 | 
				
			||||||
@@ -57,7 +59,7 @@ class InvenTreeApp extends StatelessWidget {
 | 
				
			|||||||
    return MaterialApp(
 | 
					    return MaterialApp(
 | 
				
			||||||
      builder: OneContext().builder,
 | 
					      builder: OneContext().builder,
 | 
				
			||||||
      navigatorKey: OneContext().key,
 | 
					      navigatorKey: OneContext().key,
 | 
				
			||||||
      onGenerateTitle: (BuildContext context) => I18N.of(context).appTitle,
 | 
					      onGenerateTitle: (BuildContext context) => L10().appTitle,
 | 
				
			||||||
      theme: ThemeData(
 | 
					      theme: ThemeData(
 | 
				
			||||||
        primarySwatch: Colors.lightBlue,
 | 
					        primarySwatch: Colors.lightBlue,
 | 
				
			||||||
        secondaryHeaderColor: Colors.blueGrey,
 | 
					        secondaryHeaderColor: Colors.blueGrey,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,8 @@ import 'package:flutter/material.dart';
 | 
				
			|||||||
import 'package:flutter/services.dart';
 | 
					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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:package_info/package_info.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvenTreeAboutWidget extends StatelessWidget {
 | 
					class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,7 +44,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(
 | 
					        title: Text(
 | 
				
			||||||
          I18N.of(context).serverDetails,
 | 
					          L10().serverDetails,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold),
 | 
					          style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -54,33 +53,33 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
    if (InvenTreeAPI().isConnected()) {
 | 
					    if (InvenTreeAPI().isConnected()) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).address),
 | 
					            title: Text(L10().address),
 | 
				
			||||||
            subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : I18N.of(context).notConnected),
 | 
					            subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.globe),
 | 
					            leading: FaIcon(FontAwesomeIcons.globe),
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).version),
 | 
					          title: Text(L10().version),
 | 
				
			||||||
          subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : I18N.of(context).notConnected),
 | 
					          subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : L10().notConnected),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.infoCircle),
 | 
					          leading: FaIcon(FontAwesomeIcons.infoCircle),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).serverInstance),
 | 
					          title: Text(L10().serverInstance),
 | 
				
			||||||
          subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : I18N.of(context).notConnected),
 | 
					          subtitle: Text(InvenTreeAPI().instance.isNotEmpty ? InvenTreeAPI().instance : L10().notConnected),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.server),
 | 
					          leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).notConnected),
 | 
					          title: Text(L10().notConnected),
 | 
				
			||||||
          subtitle: Text(
 | 
					          subtitle: Text(
 | 
				
			||||||
            I18N.of(context).serverNotConnected,
 | 
					            L10().serverNotConnected,
 | 
				
			||||||
            style: TextStyle(fontStyle: FontStyle.italic),
 | 
					            style: TextStyle(fontStyle: FontStyle.italic),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.exclamationCircle)
 | 
					          leading: FaIcon(FontAwesomeIcons.exclamationCircle)
 | 
				
			||||||
@@ -91,7 +90,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(
 | 
					        title: Text(
 | 
				
			||||||
          I18N.of(context).appDetails,
 | 
					          L10().appDetails,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold),
 | 
					          style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -99,7 +98,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).packageName),
 | 
					        title: Text(L10().packageName),
 | 
				
			||||||
        subtitle: Text("${info.packageName}"),
 | 
					        subtitle: Text("${info.packageName}"),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.box)
 | 
					        leading: FaIcon(FontAwesomeIcons.box)
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -107,7 +106,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).version),
 | 
					        title: Text(L10().version),
 | 
				
			||||||
        subtitle: Text("${info.version}"),
 | 
					        subtitle: Text("${info.version}"),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.infoCircle)
 | 
					        leading: FaIcon(FontAwesomeIcons.infoCircle)
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -115,8 +114,8 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).releaseNotes),
 | 
					        title: Text(L10().releaseNotes),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).appReleaseNotes),
 | 
					        subtitle: Text(L10().appReleaseNotes),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.fileAlt),
 | 
					        leading: FaIcon(FontAwesomeIcons.fileAlt),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
          _releaseNotes(context);
 | 
					          _releaseNotes(context);
 | 
				
			||||||
@@ -126,8 +125,8 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).credits),
 | 
					        title: Text(L10().credits),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).appCredits),
 | 
					        subtitle: Text(L10().appCredits),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.bullhorn),
 | 
					        leading: FaIcon(FontAwesomeIcons.bullhorn),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
          _credits(context);
 | 
					          _credits(context);
 | 
				
			||||||
@@ -137,7 +136,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).appAbout),
 | 
					        title: Text(L10().appAbout),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: ListView(
 | 
					      body: ListView(
 | 
				
			||||||
        children: ListTile.divideTiles(
 | 
					        children: ListTile.divideTiles(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,8 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.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';
 | 
				
			||||||
@@ -82,21 +83,21 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
 | 
				
			|||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      key: _settingsKey,
 | 
					      key: _settingsKey,
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).appSettings),
 | 
					        title: Text(L10().appSettings),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Container(
 | 
					      body: Container(
 | 
				
			||||||
        child: ListView(
 | 
					        child: ListView(
 | 
				
			||||||
          children: [
 | 
					          children: [
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(
 | 
					              title: Text(
 | 
				
			||||||
                I18N.of(context).parts,
 | 
					                L10().parts,
 | 
				
			||||||
                style: TextStyle(fontWeight: FontWeight.bold),
 | 
					                style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.shapes),
 | 
					              leading: FaIcon(FontAwesomeIcons.shapes),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).includeSubcategories),
 | 
					              title: Text(L10().includeSubcategories),
 | 
				
			||||||
              subtitle: Text(I18N.of(context).includeSubcategoriesDetail),
 | 
					              subtitle: Text(L10().includeSubcategoriesDetail),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
					              leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
				
			||||||
              trailing: Switch(
 | 
					              trailing: Switch(
 | 
				
			||||||
                value: partSubcategory,
 | 
					                value: partSubcategory,
 | 
				
			||||||
@@ -105,14 +106,14 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
            Divider(height: 3),
 | 
					            Divider(height: 3),
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).stock,
 | 
					              title: Text(L10().stock,
 | 
				
			||||||
                style: TextStyle(fontWeight: FontWeight.bold),
 | 
					                style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.boxes),
 | 
					              leading: FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).includeSublocations),
 | 
					              title: Text(L10().includeSublocations),
 | 
				
			||||||
              subtitle: Text(I18N.of(context).includeSublocationsDetail),
 | 
					              subtitle: Text(L10().includeSublocationsDetail),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
					              leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
				
			||||||
              trailing: Switch(
 | 
					              trailing: Switch(
 | 
				
			||||||
                value: stockSublocation,
 | 
					                value: stockSublocation,
 | 
				
			||||||
@@ -122,14 +123,14 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
 | 
				
			|||||||
            Divider(height: 3),
 | 
					            Divider(height: 3),
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(
 | 
					              title: Text(
 | 
				
			||||||
                I18N.of(context).sounds,
 | 
					                L10().sounds,
 | 
				
			||||||
                style: TextStyle(fontWeight: FontWeight.bold),
 | 
					                style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.volumeUp),
 | 
					              leading: FaIcon(FontAwesomeIcons.volumeUp),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).serverError),
 | 
					              title: Text(L10().serverError),
 | 
				
			||||||
              subtitle: Text(I18N.of(context).soundOnServerError),
 | 
					              subtitle: Text(L10().soundOnServerError),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.server),
 | 
					              leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
              trailing: Switch(
 | 
					              trailing: Switch(
 | 
				
			||||||
                value: serverSounds,
 | 
					                value: serverSounds,
 | 
				
			||||||
@@ -137,8 +138,8 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
 | 
				
			|||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).barcodeTones),
 | 
					              title: Text(L10().barcodeTones),
 | 
				
			||||||
              subtitle: Text(I18N.of(context).soundOnBarcodeAction),
 | 
					              subtitle: Text(L10().soundOnBarcodeAction),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.qrcode),
 | 
					              leading: FaIcon(FontAwesomeIcons.qrcode),
 | 
				
			||||||
              trailing: Switch(
 | 
					              trailing: Switch(
 | 
				
			||||||
                value: barcodeSounds,
 | 
					                value: barcodeSounds,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,10 @@ 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:flutter_gen/gen_l10n/app_localizations.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 '../api.dart';
 | 
					import '../api.dart';
 | 
				
			||||||
import '../preferences.dart';
 | 
					import '../preferences.dart';
 | 
				
			||||||
import '../user_profile.dart';
 | 
					import '../user_profile.dart';
 | 
				
			||||||
@@ -53,7 +54,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(
 | 
					    showFormDialog(
 | 
				
			||||||
      createNew ? I18N.of(context).profileAdd : I18N.of(context).profileEdit,
 | 
					      createNew ? L10().profileAdd : L10().profileEdit,
 | 
				
			||||||
      key: _addProfileKey,
 | 
					      key: _addProfileKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
          if (createNew) {
 | 
					          if (createNew) {
 | 
				
			||||||
@@ -79,29 +80,29 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      fields: <Widget> [
 | 
					      fields: <Widget> [
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).name,
 | 
					          label: L10().name,
 | 
				
			||||||
          hint: "Enter profile name",
 | 
					          hint: "Enter profile name",
 | 
				
			||||||
          initial: createNew ? '' : profile.name,
 | 
					          initial: createNew ? '' : profile.name,
 | 
				
			||||||
          onSaved: (value) => _name = value,
 | 
					          onSaved: (value) => _name = value,
 | 
				
			||||||
          validator: _validateProfileName,
 | 
					          validator: _validateProfileName,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).server,
 | 
					          label: L10().server,
 | 
				
			||||||
          hint: "http[s]://<server>:<port>",
 | 
					          hint: "http[s]://<server>:<port>",
 | 
				
			||||||
          initial: createNew ? '' : profile.server,
 | 
					          initial: createNew ? '' : profile.server,
 | 
				
			||||||
          validator: _validateServer,
 | 
					          validator: _validateServer,
 | 
				
			||||||
          onSaved: (value) => _server = value,
 | 
					          onSaved: (value) => _server = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).username,
 | 
					          label: L10().username,
 | 
				
			||||||
          hint: I18N.of(context).enterPassword,
 | 
					          hint: L10().enterPassword,
 | 
				
			||||||
          initial: createNew ? '' : profile.username,
 | 
					          initial: createNew ? '' : profile.username,
 | 
				
			||||||
          onSaved: (value) => _username = value,
 | 
					          onSaved: (value) => _username = value,
 | 
				
			||||||
          validator: _validateUsername,
 | 
					          validator: _validateUsername,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).password,
 | 
					          label: L10().password,
 | 
				
			||||||
          hint: I18N.of(context).enterUsername,
 | 
					          hint: L10().enterUsername,
 | 
				
			||||||
          initial: createNew ? '' : profile.password,
 | 
					          initial: createNew ? '' : profile.password,
 | 
				
			||||||
          onSaved: (value) => _password = value,
 | 
					          onSaved: (value) => _password = value,
 | 
				
			||||||
          validator: _validatePassword,
 | 
					          validator: _validatePassword,
 | 
				
			||||||
@@ -266,28 +267,28 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
 | 
				
			|||||||
                          Navigator.of(context).pop();
 | 
					                          Navigator.of(context).pop();
 | 
				
			||||||
                          _selectProfile(context, profile);
 | 
					                          _selectProfile(context, profile);
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        child: Text(I18N.of(context).profileConnect),
 | 
					                        child: Text(L10().profileConnect),
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                      SimpleDialogOption(
 | 
					                      SimpleDialogOption(
 | 
				
			||||||
                        onPressed: () {
 | 
					                        onPressed: () {
 | 
				
			||||||
                          Navigator.of(context).pop();
 | 
					                          Navigator.of(context).pop();
 | 
				
			||||||
                          _editProfile(context, userProfile: profile);
 | 
					                          _editProfile(context, userProfile: profile);
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        child: Text(I18N.of(context).profileEdit),
 | 
					                        child: Text(L10().profileEdit),
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                      SimpleDialogOption(
 | 
					                      SimpleDialogOption(
 | 
				
			||||||
                        onPressed: () {
 | 
					                        onPressed: () {
 | 
				
			||||||
                          Navigator.of(context).pop();
 | 
					                          Navigator.of(context).pop();
 | 
				
			||||||
                          // Navigator.of(context, rootNavigator: true).pop();
 | 
					                          // Navigator.of(context, rootNavigator: true).pop();
 | 
				
			||||||
                          confirmationDialog(
 | 
					                          confirmationDialog(
 | 
				
			||||||
                              I18N.of(context).delete,
 | 
					                              L10().delete,
 | 
				
			||||||
                              I18N.of(context).profileDelete + "?",
 | 
					                              L10().profileDelete + "?",
 | 
				
			||||||
                              onAccept: () {
 | 
					                              onAccept: () {
 | 
				
			||||||
                                _deleteProfile(profile);
 | 
					                                _deleteProfile(profile);
 | 
				
			||||||
                              }
 | 
					                              }
 | 
				
			||||||
                          );
 | 
					                          );
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        child: Text(I18N.of(context).profileDelete),
 | 
					                        child: Text(L10().profileDelete),
 | 
				
			||||||
                      )
 | 
					                      )
 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                  );
 | 
					                  );
 | 
				
			||||||
@@ -300,7 +301,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
 | 
				
			|||||||
      // No profile available!
 | 
					      // No profile available!
 | 
				
			||||||
      children.add(
 | 
					      children.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).profileNone),
 | 
					          title: Text(L10().profileNone),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -308,7 +309,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
 | 
				
			|||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      key: _loginKey,
 | 
					      key: _loginKey,
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).profileSelect),
 | 
					        title: Text(L10().profileSelect),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Container(
 | 
					      body: Container(
 | 
				
			||||||
        child: ListView(
 | 
					        child: ListView(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,7 @@ 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:markdown/markdown.dart' as md;
 | 
					import 'package:markdown/markdown.dart' as md;
 | 
				
			||||||
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReleaseNotesWidget extends StatelessWidget {
 | 
					class ReleaseNotesWidget extends StatelessWidget {
 | 
				
			||||||
@@ -16,7 +15,7 @@ class ReleaseNotesWidget extends StatelessWidget {
 | 
				
			|||||||
  Widget build (BuildContext context) {
 | 
					  Widget build (BuildContext context) {
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).releaseNotes)
 | 
					        title: Text(L10().releaseNotes)
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Markdown(
 | 
					      body: Markdown(
 | 
				
			||||||
        selectable: false,
 | 
					        selectable: false,
 | 
				
			||||||
@@ -37,7 +36,7 @@ class CreditsWidget extends StatelessWidget {
 | 
				
			|||||||
  Widget build (BuildContext context) {
 | 
					  Widget build (BuildContext context) {
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).credits),
 | 
					        title: Text(L10().credits),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Markdown(
 | 
					      body: Markdown(
 | 
				
			||||||
        selectable: false,
 | 
					        selectable: false,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,8 @@ 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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:url_launcher/url_launcher.dart';
 | 
					import 'package:url_launcher/url_launcher.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'login.dart';
 | 
					import 'login.dart';
 | 
				
			||||||
@@ -35,7 +36,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      key: _scaffoldKey,
 | 
					      key: _scaffoldKey,
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).settings),
 | 
					        title: Text(L10().settings),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: ListView(
 | 
					        child: ListView(
 | 
				
			||||||
@@ -43,26 +44,26 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
            context: context,
 | 
					            context: context,
 | 
				
			||||||
            tiles: <Widget>[
 | 
					            tiles: <Widget>[
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                  title: Text(I18N.of(context).server),
 | 
					                  title: Text(L10().server),
 | 
				
			||||||
                  subtitle: Text(I18N.of(context).configureServer),
 | 
					                  subtitle: Text(L10().configureServer),
 | 
				
			||||||
                  leading: FaIcon(FontAwesomeIcons.server),
 | 
					                  leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
                  onTap: _editServerSettings,
 | 
					                  onTap: _editServerSettings,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.cogs),
 | 
					                leading: FaIcon(FontAwesomeIcons.cogs),
 | 
				
			||||||
                title: Text(I18N.of(context).appSettings),
 | 
					                title: Text(L10().appSettings),
 | 
				
			||||||
                subtitle: Text(I18N.of(context).appSettingsDetails),
 | 
					                subtitle: Text(L10().appSettingsDetails),
 | 
				
			||||||
                onTap: _editAppSettings,
 | 
					                onTap: _editAppSettings,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(I18N.of(context).about),
 | 
					                title: Text(L10().about),
 | 
				
			||||||
                subtitle: Text(I18N.of(context).appDetails),
 | 
					                subtitle: Text(L10().appDetails),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.infoCircle),
 | 
					                leading: FaIcon(FontAwesomeIcons.infoCircle),
 | 
				
			||||||
                onTap: _about,
 | 
					                onTap: _about,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(I18N.of(context).documentation),
 | 
					                title: Text(L10().documentation),
 | 
				
			||||||
                subtitle: Text("https://inventree.readthedocs.io"),
 | 
					                subtitle: Text("https://inventree.readthedocs.io"),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.book),
 | 
					                leading: FaIcon(FontAwesomeIcons.book),
 | 
				
			||||||
                onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
@@ -71,8 +72,8 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
              ),
 | 
					              ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(I18N.of(context).feedback),
 | 
					                title: Text(L10().feedback),
 | 
				
			||||||
                subtitle: Text(I18N.of(context).submitFeedback),
 | 
					                subtitle: Text(L10().submitFeedback),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.comments),
 | 
					                leading: FaIcon(FontAwesomeIcons.comments),
 | 
				
			||||||
                onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
                  _submitFeedback(context);
 | 
					                  _submitFeedback(context);
 | 
				
			||||||
@@ -115,12 +116,12 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (result) {
 | 
					    if (result) {
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(context).feedbackSuccess,
 | 
					        L10().feedbackSuccess,
 | 
				
			||||||
        success: true,
 | 
					        success: true,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(context).feedbackError,
 | 
					        L10().feedbackError,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -133,7 +134,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
    _controller.clear();
 | 
					    _controller.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(
 | 
					    showFormDialog(
 | 
				
			||||||
      I18N.of(context).submitFeedback,
 | 
					      L10().submitFeedback,
 | 
				
			||||||
      key: _feedbackKey,
 | 
					      key: _feedbackKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
        _sendReport(context, _controller.text);
 | 
					        _sendReport(context, _controller.text);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,15 @@
 | 
				
			|||||||
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/preferences.dart';
 | 
					 | 
				
			||||||
import 'package:InvenTree/widget/progress.dart';
 | 
					import 'package:InvenTree/widget/progress.dart';
 | 
				
			||||||
import 'package:InvenTree/widget/search.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.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/drawer.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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,7 +37,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
  final _editCategoryKey = GlobalKey<FormState>();
 | 
					  final _editCategoryKey = GlobalKey<FormState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).partCategory;
 | 
					  String getAppBarTitle(BuildContext context) => L10().partCategory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  List<Widget> getAppBarActions(BuildContext context) {
 | 
					  List<Widget> getAppBarActions(BuildContext context) {
 | 
				
			||||||
@@ -71,7 +69,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
      actions.add(
 | 
					      actions.add(
 | 
				
			||||||
        IconButton(
 | 
					        IconButton(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.edit),
 | 
					          icon: FaIcon(FontAwesomeIcons.edit),
 | 
				
			||||||
          tooltip: I18N.of(context).edit,
 | 
					          tooltip: L10().edit,
 | 
				
			||||||
          onPressed: _editCategoryDialog,
 | 
					          onPressed: _editCategoryDialog,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -99,7 +97,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
    var _description;
 | 
					    var _description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(
 | 
					    showFormDialog(
 | 
				
			||||||
      I18N.of(context).editCategory,
 | 
					      L10().editCategory,
 | 
				
			||||||
      key: _editCategoryKey,
 | 
					      key: _editCategoryKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
        _editCategory({
 | 
					        _editCategory({
 | 
				
			||||||
@@ -109,12 +107,12 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      fields: <Widget>[
 | 
					      fields: <Widget>[
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).name,
 | 
					          label: L10().name,
 | 
				
			||||||
          initial: category.name,
 | 
					          initial: category.name,
 | 
				
			||||||
          onSaved: (value) => _name = value
 | 
					          onSaved: (value) => _name = value
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).description,
 | 
					          label: L10().description,
 | 
				
			||||||
          initial: category.description,
 | 
					          initial: category.description,
 | 
				
			||||||
          onSaved: (value) => _description = value
 | 
					          onSaved: (value) => _description = value
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -163,7 +161,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
    if (category == null) {
 | 
					    if (category == null) {
 | 
				
			||||||
      return Card(
 | 
					      return Card(
 | 
				
			||||||
        child: ListTile(
 | 
					        child: ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).partCategoryTopLevel)
 | 
					          title: Text(L10().partCategoryTopLevel)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@@ -180,7 +178,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
      if (extra) {
 | 
					      if (extra) {
 | 
				
			||||||
        children.add(
 | 
					        children.add(
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).parentCategory),
 | 
					              title: Text(L10().parentCategory),
 | 
				
			||||||
              subtitle: Text("${category.parentpathstring}"),
 | 
					              subtitle: Text("${category.parentpathstring}"),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.levelUpAlt),
 | 
					              leading: FaIcon(FontAwesomeIcons.levelUpAlt),
 | 
				
			||||||
              onTap: () {
 | 
					              onTap: () {
 | 
				
			||||||
@@ -215,17 +213,17 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
      items: <BottomNavigationBarItem>[
 | 
					      items: <BottomNavigationBarItem>[
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.sitemap),
 | 
					          icon: FaIcon(FontAwesomeIcons.sitemap),
 | 
				
			||||||
          label: I18N.of(context).details,
 | 
					          label: L10().details,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.shapes),
 | 
					          icon: FaIcon(FontAwesomeIcons.shapes),
 | 
				
			||||||
          label: I18N.of(context).parts,
 | 
					          label: L10().parts,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        // TODO - Add the "actions" item back in
 | 
					        // TODO - Add the "actions" item back in
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.wrench),
 | 
					          icon: FaIcon(FontAwesomeIcons.wrench),
 | 
				
			||||||
          label: I18N.of(context).actions
 | 
					          label: L10().actions
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
@@ -237,7 +235,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
      getCategoryDescriptionCard(),
 | 
					      getCategoryDescriptionCard(),
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(
 | 
					        title: Text(
 | 
				
			||||||
          I18N.of(context).subcategories,
 | 
					          L10().subcategories,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold)
 | 
					          style: TextStyle(fontWeight: FontWeight.bold)
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        trailing: _subcategories.isNotEmpty ? Text("${_subcategories.length}") : null,
 | 
					        trailing: _subcategories.isNotEmpty ? Text("${_subcategories.length}") : null,
 | 
				
			||||||
@@ -248,8 +246,8 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
      tiles.add(progressIndicator());
 | 
					      tiles.add(progressIndicator());
 | 
				
			||||||
    } else if (_subcategories.length == 0) {
 | 
					    } else if (_subcategories.length == 0) {
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).noSubcategories),
 | 
					        title: Text(L10().noSubcategories),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).noSubcategoriesAvailable)
 | 
					        subtitle: Text(L10().noSubcategoriesAvailable)
 | 
				
			||||||
      ));
 | 
					      ));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(SubcategoryList(_subcategories));
 | 
					      tiles.add(SubcategoryList(_subcategories));
 | 
				
			||||||
@@ -263,7 +261,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
 | 
				
			|||||||
    List<Widget> tiles = [
 | 
					    List<Widget> tiles = [
 | 
				
			||||||
      getCategoryDescriptionCard(extra: false),
 | 
					      getCategoryDescriptionCard(extra: false),
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).actions,
 | 
					        title: Text(L10().actions,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold)
 | 
					          style: TextStyle(fontWeight: FontWeight.bold)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,13 +2,12 @@
 | 
				
			|||||||
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/drawer.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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CompanyDetailWidget extends StatefulWidget {
 | 
					class CompanyDetailWidget extends StatefulWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,7 +28,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
 | 
				
			|||||||
  final _editCompanyKey = GlobalKey<FormState>();
 | 
					  final _editCompanyKey = GlobalKey<FormState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).company;
 | 
					  String getAppBarTitle(BuildContext context) => L10().company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> request(BuildContext context) async {
 | 
					  Future<void> request(BuildContext context) async {
 | 
				
			||||||
@@ -55,17 +54,17 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
 | 
				
			|||||||
    var _description;
 | 
					    var _description;
 | 
				
			||||||
    var _website;
 | 
					    var _website;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(I18N.of(context).edit,
 | 
					    showFormDialog(L10().edit,
 | 
				
			||||||
        key: _editCompanyKey,
 | 
					        key: _editCompanyKey,
 | 
				
			||||||
        actions: <Widget>[
 | 
					        actions: <Widget>[
 | 
				
			||||||
          FlatButton(
 | 
					          FlatButton(
 | 
				
			||||||
            child: Text(I18N.of(context).cancel),
 | 
					            child: Text(L10().cancel),
 | 
				
			||||||
            onPressed: () {
 | 
					            onPressed: () {
 | 
				
			||||||
              Navigator.pop(context);
 | 
					              Navigator.pop(context);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          FlatButton(
 | 
					          FlatButton(
 | 
				
			||||||
            child: Text(I18N.of(context).save),
 | 
					            child: Text(L10().save),
 | 
				
			||||||
            onPressed: () {
 | 
					            onPressed: () {
 | 
				
			||||||
              if (_editCompanyKey.currentState.validate()) {
 | 
					              if (_editCompanyKey.currentState.validate()) {
 | 
				
			||||||
                _editCompanyKey.currentState.save();
 | 
					                _editCompanyKey.currentState.save();
 | 
				
			||||||
@@ -81,21 +80,21 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        fields: <Widget>[
 | 
					        fields: <Widget>[
 | 
				
			||||||
          StringField(
 | 
					          StringField(
 | 
				
			||||||
            label: I18N.of(context).name,
 | 
					            label: L10().name,
 | 
				
			||||||
            initial: company.name,
 | 
					            initial: company.name,
 | 
				
			||||||
            onSaved: (value) {
 | 
					            onSaved: (value) {
 | 
				
			||||||
              _name = value;
 | 
					              _name = value;
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          StringField(
 | 
					          StringField(
 | 
				
			||||||
            label: I18N.of(context).description,
 | 
					            label: L10().description,
 | 
				
			||||||
            initial: company.description,
 | 
					            initial: company.description,
 | 
				
			||||||
            onSaved: (value) {
 | 
					            onSaved: (value) {
 | 
				
			||||||
              _description = value;
 | 
					              _description = value;
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          StringField(
 | 
					          StringField(
 | 
				
			||||||
            label: I18N.of(context).website,
 | 
					            label: L10().website,
 | 
				
			||||||
            initial: company.website,
 | 
					            initial: company.website,
 | 
				
			||||||
            allowEmpty: true,
 | 
					            allowEmpty: true,
 | 
				
			||||||
            onSaved: (value) {
 | 
					            onSaved: (value) {
 | 
				
			||||||
@@ -193,7 +192,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (company.notes.isNotEmpty) {
 | 
					    if (company.notes.isNotEmpty) {
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).notes),
 | 
					        title: Text(L10().notes),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.stickyNote),
 | 
					        leading: FaIcon(FontAwesomeIcons.stickyNote),
 | 
				
			||||||
        onTap: null,
 | 
					        onTap: null,
 | 
				
			||||||
      ));
 | 
					      ));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,21 +2,20 @@
 | 
				
			|||||||
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/audio_cache.dart';
 | 
					import 'package:audioplayers/audio_cache.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:flutter_gen/gen_l10n/app_localizations.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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (acceptText == null || acceptText.isEmpty) {
 | 
					  if (acceptText == null || acceptText.isEmpty) {
 | 
				
			||||||
    acceptText = I18N.of(OneContext().context).ok;
 | 
					    acceptText = L10().ok;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rejectText == null || rejectText.isEmpty) {
 | 
					  if (rejectText == null || rejectText.isEmpty) {
 | 
				
			||||||
    rejectText = I18N.of(OneContext().context).cancel;
 | 
					    rejectText = L10().cancel;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  OneContext().showDialog(
 | 
					  OneContext().showDialog(
 | 
				
			||||||
@@ -60,7 +59,7 @@ Future<void> confirmationDialog(String title, String text, {String acceptText, S
 | 
				
			|||||||
Future<void> showInfoDialog(BuildContext context, String title, String description, {IconData icon = FontAwesomeIcons.info, String info, Function onDismissed}) async {
 | 
					Future<void> showInfoDialog(BuildContext context, String title, String description, {IconData icon = FontAwesomeIcons.info, String info, Function onDismissed}) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (info == null || info.isEmpty) {
 | 
					  if (info == null || info.isEmpty) {
 | 
				
			||||||
    info = I18N.of(context).info;
 | 
					    info = L10().info;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  showDialog(
 | 
					  showDialog(
 | 
				
			||||||
@@ -87,7 +86,7 @@ Future<void> showInfoDialog(BuildContext context, String title, String descripti
 | 
				
			|||||||
Future<void> showErrorDialog(String title, String description, {IconData icon = FontAwesomeIcons.exclamationCircle, String error, Function onDismissed}) async {
 | 
					Future<void> showErrorDialog(String title, String description, {IconData icon = FontAwesomeIcons.exclamationCircle, String error, Function onDismissed}) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (error == null || error.isEmpty) {
 | 
					  if (error == null || error.isEmpty) {
 | 
				
			||||||
    error = I18N.of(OneContext().context).error;
 | 
					    error = L10().error;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  OneContext().showDialog(
 | 
					  OneContext().showDialog(
 | 
				
			||||||
@@ -113,7 +112,7 @@ Future<void> showErrorDialog(String title, String description, {IconData icon =
 | 
				
			|||||||
Future<void> showServerError(String title, String description) async {
 | 
					Future<void> showServerError(String title, String description) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (title == null || title.isEmpty) {
 | 
					  if (title == null || title.isEmpty) {
 | 
				
			||||||
    title = I18N.of(OneContext().context).serverError;
 | 
					    title = L10().serverError;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Play a sound
 | 
					  // Play a sound
 | 
				
			||||||
@@ -127,12 +126,12 @@ Future<void> showServerError(String title, String description) async {
 | 
				
			|||||||
  showSnackIcon(
 | 
					  showSnackIcon(
 | 
				
			||||||
    title,
 | 
					    title,
 | 
				
			||||||
    success: false,
 | 
					    success: false,
 | 
				
			||||||
    actionText: I18N.of(OneContext().context).details,
 | 
					    actionText: L10().details,
 | 
				
			||||||
    onAction: () {
 | 
					    onAction: () {
 | 
				
			||||||
      showErrorDialog(
 | 
					      showErrorDialog(
 | 
				
			||||||
          title,
 | 
					          title,
 | 
				
			||||||
          description,
 | 
					          description,
 | 
				
			||||||
          error: I18N.of(OneContext().context).serverError,
 | 
					          error: L10().serverError,
 | 
				
			||||||
          icon: FontAwesomeIcons.server
 | 
					          icon: FontAwesomeIcons.server
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -143,27 +142,27 @@ Future<void> showStatusCodeError(int status, {int expected = 200}) async {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  BuildContext ctx = OneContext().context;
 | 
					  BuildContext ctx = OneContext().context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  String msg = I18N.of(ctx).responseInvalid;
 | 
					  String msg = L10().responseInvalid;
 | 
				
			||||||
  String extra = "Server responded with status code ${status}";
 | 
					  String extra = "Server responded with status code ${status}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (status) {
 | 
					  switch (status) {
 | 
				
			||||||
    case 400:
 | 
					    case 400:
 | 
				
			||||||
      msg = I18N.of(ctx).response400;
 | 
					      msg = L10().response400;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 401:
 | 
					    case 401:
 | 
				
			||||||
      msg = I18N.of(ctx).response401;
 | 
					      msg = L10().response401;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 403:
 | 
					    case 403:
 | 
				
			||||||
      msg = I18N.of(ctx).response403;
 | 
					      msg = L10().response403;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 404:
 | 
					    case 404:
 | 
				
			||||||
      msg = I18N.of(ctx).response404;
 | 
					      msg = L10().response404;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 405:
 | 
					    case 405:
 | 
				
			||||||
      msg = I18N.of(ctx).response405;
 | 
					      msg = L10().response405;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 429:
 | 
					    case 429:
 | 
				
			||||||
      msg = I18N.of(ctx).response429;
 | 
					      msg = L10().response429;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
@@ -180,7 +179,7 @@ Future<void> showTimeoutError(BuildContext context) async {
 | 
				
			|||||||
  // Use OneContext as "sometimes" context is null here?
 | 
					  // Use OneContext as "sometimes" context is null here?
 | 
				
			||||||
  var ctx = OneContext().context;
 | 
					  var ctx = OneContext().context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await showServerError(I18N.of(ctx).timeout, I18N.of(ctx).noResponse);
 | 
					  await showServerError(L10().timeout, L10().noResponse);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void showFormDialog(String title, {String acceptText, String cancelText, GlobalKey<FormState> key, List<Widget> fields, List<Widget> actions, Function callback}) {
 | 
					void showFormDialog(String title, {String acceptText, String cancelText, GlobalKey<FormState> key, List<Widget> fields, List<Widget> actions, Function callback}) {
 | 
				
			||||||
@@ -190,11 +189,11 @@ void showFormDialog(String title, {String acceptText, String cancelText, GlobalK
 | 
				
			|||||||
  var ctx = OneContext().context;
 | 
					  var ctx = OneContext().context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (acceptText == null) {
 | 
					  if (acceptText == null) {
 | 
				
			||||||
    acceptText = I18N.of(ctx).save;
 | 
					    acceptText = L10().save;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (cancelText == null) {
 | 
					  if (cancelText == null) {
 | 
				
			||||||
    cancelText = I18N.of(ctx).cancel;
 | 
					    cancelText = L10().cancel;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Undefined actions = OK + Cancel
 | 
					  // Undefined actions = OK + Cancel
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,7 @@ 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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					 | 
				
			||||||
import 'package:InvenTree/api.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';
 | 
				
			||||||
@@ -118,28 +116,28 @@ class InvenTreeDrawer extends StatelessWidget {
 | 
				
			|||||||
                    width: 30,
 | 
					                    width: 30,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                  title: Text(
 | 
					                  title: Text(
 | 
				
			||||||
                    I18N.of(context).appTitle,
 | 
					                    L10().appTitle,
 | 
				
			||||||
                    style: TextStyle(fontWeight: FontWeight.bold),
 | 
					                    style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                  onTap: _home,
 | 
					                  onTap: _home,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text(I18N.of(context).scanBarcode),
 | 
					                  title: Text(L10().scanBarcode),
 | 
				
			||||||
                  onTap: _scan,
 | 
					                  onTap: _scan,
 | 
				
			||||||
                  leading: FaIcon(FontAwesomeIcons.barcode),
 | 
					                  leading: FaIcon(FontAwesomeIcons.barcode),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text(I18N.of(context).search),
 | 
					                  title: Text(L10().search),
 | 
				
			||||||
                  leading: FaIcon(FontAwesomeIcons.search),
 | 
					                  leading: FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
                  onTap: _search,
 | 
					                  onTap: _search,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text(I18N.of(context).parts),
 | 
					                  title: Text(L10().parts),
 | 
				
			||||||
                  leading: Icon(Icons.category),
 | 
					                  leading: Icon(Icons.category),
 | 
				
			||||||
                  onTap: _showParts,
 | 
					                  onTap: _showParts,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text(I18N.of(context).stock),
 | 
					                  title: Text(L10().stock),
 | 
				
			||||||
                  leading: FaIcon(FontAwesomeIcons.boxes),
 | 
					                  leading: FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
                  onTap: _showStock,
 | 
					                  onTap: _showStock,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
@@ -161,7 +159,7 @@ class InvenTreeDrawer extends StatelessWidget {
 | 
				
			|||||||
                ),
 | 
					                ),
 | 
				
			||||||
                */
 | 
					                */
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text(I18N.of(context).settings),
 | 
					                  title: Text(L10().settings),
 | 
				
			||||||
                  leading: Icon(Icons.settings),
 | 
					                  leading: Icon(Icons.settings),
 | 
				
			||||||
                  onTap: _settings,
 | 
					                  onTap: _settings,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,8 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
				
			|||||||
import 'package:image_picker/image_picker.dart';
 | 
					import 'package:image_picker/image_picker.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:one_context/one_context.dart';
 | 
					import 'package:one_context/one_context.dart';
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					
 | 
				
			||||||
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
import 'dart:io';
 | 
					import 'dart:io';
 | 
				
			||||||
@@ -52,7 +53,7 @@ class ImagePickerField extends FormField<File> {
 | 
				
			|||||||
        onSaved: onSaved,
 | 
					        onSaved: onSaved,
 | 
				
			||||||
        validator: (File img) {
 | 
					        validator: (File img) {
 | 
				
			||||||
          if (required && (img == null)) {
 | 
					          if (required && (img == null)) {
 | 
				
			||||||
            return I18N.of(context).required;
 | 
					            return L10().required;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          return null;
 | 
					          return null;
 | 
				
			||||||
@@ -67,13 +68,13 @@ class ImagePickerField extends FormField<File> {
 | 
				
			|||||||
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
					              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
				
			||||||
              children: <Widget>[
 | 
					              children: <Widget>[
 | 
				
			||||||
                FlatButton(
 | 
					                FlatButton(
 | 
				
			||||||
                  child: Text(I18N.of(context).selectImage),
 | 
					                  child: Text(L10().selectImage),
 | 
				
			||||||
                  onPressed: () {
 | 
					                  onPressed: () {
 | 
				
			||||||
                    _selectFromGallery(state);
 | 
					                    _selectFromGallery(state);
 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                FlatButton(
 | 
					                FlatButton(
 | 
				
			||||||
                  child: Text(I18N.of(context).takePicture),
 | 
					                  child: Text(L10().takePicture),
 | 
				
			||||||
                  onPressed: () {
 | 
					                  onPressed: () {
 | 
				
			||||||
                    _selectFromCamera(state);
 | 
					                    _selectFromCamera(state);
 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
@@ -82,7 +83,7 @@ class ImagePickerField extends FormField<File> {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
          return ListTile(
 | 
					          return ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).selectImage),
 | 
					            title: Text(L10().selectImage),
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -120,7 +121,7 @@ class StringField extends TextFormField {
 | 
				
			|||||||
        enabled: isEnabled,
 | 
					        enabled: isEnabled,
 | 
				
			||||||
        validator: (value) {
 | 
					        validator: (value) {
 | 
				
			||||||
          if (!allowEmpty && value.isEmpty) {
 | 
					          if (!allowEmpty && value.isEmpty) {
 | 
				
			||||||
            return I18N.of(OneContext().context).valueCannotBeEmpty;
 | 
					            return L10().valueCannotBeEmpty;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (validator != null) {
 | 
					          if (validator != null) {
 | 
				
			||||||
@@ -148,14 +149,12 @@ class QuantityField extends TextFormField {
 | 
				
			|||||||
        keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
 | 
					        keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
 | 
				
			||||||
        validator: (value) {
 | 
					        validator: (value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          final ctx = OneContext().context;
 | 
					          if (value.isEmpty) return L10().quantityEmpty;
 | 
				
			||||||
 | 
					 | 
				
			||||||
          if (value.isEmpty) return I18N.of(ctx).quantityEmpty;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          double quantity = double.tryParse(value);
 | 
					          double quantity = double.tryParse(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (quantity == null) return I18N.of(ctx).quantityInvalid;
 | 
					          if (quantity == null) return L10().quantityInvalid;
 | 
				
			||||||
          if (quantity <= 0) return I18N.of(ctx).quantityPositive;
 | 
					          if (quantity <= 0) return L10().quantityPositive;
 | 
				
			||||||
          if ((max != null) && (quantity > max)) return "Quantity must not exceed ${max}";
 | 
					          if ((max != null) && (quantity > max)) return "Quantity must not exceed ${max}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          return null;
 | 
					          return null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import 'package:InvenTree/widget/starred_parts.dart';
 | 
				
			|||||||
import 'package:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -128,8 +128,8 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
    // Tap to select / create a profile
 | 
					    // Tap to select / create a profile
 | 
				
			||||||
    if (_profile == null) {
 | 
					    if (_profile == null) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).profileNotSelected),
 | 
					        title: Text(L10().profileNotSelected),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).profileTapToCreate),
 | 
					        subtitle: Text(L10().profileTapToCreate),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.server),
 | 
					        leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
        trailing: FaIcon(
 | 
					        trailing: FaIcon(
 | 
				
			||||||
          FontAwesomeIcons.user,
 | 
					          FontAwesomeIcons.user,
 | 
				
			||||||
@@ -144,7 +144,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
    // Profile is selected ...
 | 
					    // Profile is selected ...
 | 
				
			||||||
    if (InvenTreeAPI().isConnecting()) {
 | 
					    if (InvenTreeAPI().isConnecting()) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).serverConnecting),
 | 
					        title: Text(L10().serverConnecting),
 | 
				
			||||||
        subtitle: Text("${InvenTreeAPI().baseUrl}"),
 | 
					        subtitle: Text("${InvenTreeAPI().baseUrl}"),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.server),
 | 
					        leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
        trailing: Spinner(
 | 
					        trailing: Spinner(
 | 
				
			||||||
@@ -157,7 +157,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    } else if (InvenTreeAPI().isConnected()) {
 | 
					    } else if (InvenTreeAPI().isConnected()) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).serverConnected),
 | 
					        title: Text(L10().serverConnected),
 | 
				
			||||||
        subtitle: Text("${InvenTreeAPI().baseUrl}"),
 | 
					        subtitle: Text("${InvenTreeAPI().baseUrl}"),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.server),
 | 
					        leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
        trailing: FaIcon(
 | 
					        trailing: FaIcon(
 | 
				
			||||||
@@ -170,7 +170,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).serverCouldNotConnect),
 | 
					        title: Text(L10().serverCouldNotConnect),
 | 
				
			||||||
        subtitle: Text("${_profile.server}"),
 | 
					        subtitle: Text("${_profile.server}"),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.server),
 | 
					        leading: FaIcon(FontAwesomeIcons.server),
 | 
				
			||||||
        trailing: FaIcon(
 | 
					        trailing: FaIcon(
 | 
				
			||||||
@@ -198,12 +198,12 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      key: _homeKey,
 | 
					      key: _homeKey,
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Text(I18N.of(context).appTitle),
 | 
					        title: Text(L10().appTitle),
 | 
				
			||||||
        actions: <Widget>[
 | 
					        actions: <Widget>[
 | 
				
			||||||
          /*
 | 
					          /*
 | 
				
			||||||
          IconButton(
 | 
					          IconButton(
 | 
				
			||||||
            icon: FaIcon(FontAwesomeIcons.search),
 | 
					            icon: FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
            tooltip: I18N.of(context).search,
 | 
					            tooltip: L10().search,
 | 
				
			||||||
            onPressed: _searchParts,
 | 
					            onPressed: _searchParts,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          */
 | 
					          */
 | 
				
			||||||
@@ -224,10 +224,10 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
                  children: <Widget>[
 | 
					                  children: <Widget>[
 | 
				
			||||||
                    IconButton(
 | 
					                    IconButton(
 | 
				
			||||||
                      icon: new FaIcon(FontAwesomeIcons.barcode),
 | 
					                      icon: new FaIcon(FontAwesomeIcons.barcode),
 | 
				
			||||||
                      tooltip: I18N.of(context).scanBarcode,
 | 
					                      tooltip: L10().scanBarcode,
 | 
				
			||||||
                      onPressed: () { _scan(context); },
 | 
					                      onPressed: () { _scan(context); },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    Text(I18N.of(context).scanBarcode),
 | 
					                    Text(L10().scanBarcode),
 | 
				
			||||||
                  ],
 | 
					                  ],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
@@ -240,10 +240,10 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
                  children: <Widget>[
 | 
					                  children: <Widget>[
 | 
				
			||||||
                    IconButton(
 | 
					                    IconButton(
 | 
				
			||||||
                      icon: new FaIcon(FontAwesomeIcons.shapes),
 | 
					                      icon: new FaIcon(FontAwesomeIcons.shapes),
 | 
				
			||||||
                      tooltip: I18N.of(context).parts,
 | 
					                      tooltip: L10().parts,
 | 
				
			||||||
                      onPressed: () { _parts(context); },
 | 
					                      onPressed: () { _parts(context); },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    Text(I18N.of(context).parts),
 | 
					                    Text(L10().parts),
 | 
				
			||||||
                  ],
 | 
					                  ],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                Column(
 | 
					                Column(
 | 
				
			||||||
@@ -251,10 +251,10 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    IconButton(
 | 
					                    IconButton(
 | 
				
			||||||
                      icon: new FaIcon(FontAwesomeIcons.search),
 | 
					                      icon: new FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
                      tooltip: I18N.of(context).searchParts,
 | 
					                      tooltip: L10().searchParts,
 | 
				
			||||||
                      onPressed: _searchParts,
 | 
					                      onPressed: _searchParts,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    Text(I18N.of(context).searchParts),
 | 
					                    Text(L10().searchParts),
 | 
				
			||||||
                  ],
 | 
					                  ],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                // TODO - Re-add starred parts link
 | 
					                // TODO - Re-add starred parts link
 | 
				
			||||||
@@ -281,20 +281,20 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
 | 
				
			|||||||
                  children: <Widget>[
 | 
					                  children: <Widget>[
 | 
				
			||||||
                    IconButton(
 | 
					                    IconButton(
 | 
				
			||||||
                      icon: new FaIcon(FontAwesomeIcons.boxes),
 | 
					                      icon: new FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
                      tooltip: I18N.of(context).stock,
 | 
					                      tooltip: L10().stock,
 | 
				
			||||||
                      onPressed: () { _stock(context); },
 | 
					                      onPressed: () { _stock(context); },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    Text(I18N.of(context).stock),
 | 
					                    Text(L10().stock),
 | 
				
			||||||
                  ],
 | 
					                  ],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                Column(
 | 
					                Column(
 | 
				
			||||||
                  children: <Widget>[
 | 
					                  children: <Widget>[
 | 
				
			||||||
                    IconButton(
 | 
					                    IconButton(
 | 
				
			||||||
                      icon: new FaIcon(FontAwesomeIcons.search),
 | 
					                      icon: new FaIcon(FontAwesomeIcons.search),
 | 
				
			||||||
                      tooltip: I18N.of(context).searchStock,
 | 
					                      tooltip: L10().searchStock,
 | 
				
			||||||
                      onPressed: _searchStock,
 | 
					                      onPressed: _searchStock,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    Text(I18N.of(context).searchStock),
 | 
					                    Text(L10().searchStock),
 | 
				
			||||||
                  ],
 | 
					                  ],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ]
 | 
					              ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,22 +2,20 @@ 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/stock.dart';
 | 
					import 'package:InvenTree/inventree/stock.dart';
 | 
				
			||||||
import 'package:InvenTree/preferences.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/search.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:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/foundation.dart';
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
					import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
				
			||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					 | 
				
			||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 | 
					import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LocationDisplayWidget extends StatefulWidget {
 | 
					class LocationDisplayWidget extends StatefulWidget {
 | 
				
			||||||
@@ -71,7 +69,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
      actions.add(
 | 
					      actions.add(
 | 
				
			||||||
        IconButton(
 | 
					        IconButton(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.edit),
 | 
					          icon: FaIcon(FontAwesomeIcons.edit),
 | 
				
			||||||
          tooltip: I18N.of(context).edit,
 | 
					          tooltip: L10().edit,
 | 
				
			||||||
          onPressed: _editLocationDialog,
 | 
					          onPressed: _editLocationDialog,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -97,7 +95,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
    var _name;
 | 
					    var _name;
 | 
				
			||||||
    var _description;
 | 
					    var _description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(I18N.of(context).editLocation,
 | 
					    showFormDialog(L10().editLocation,
 | 
				
			||||||
      key: _editLocationKey,
 | 
					      key: _editLocationKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
        _editLocation({
 | 
					        _editLocation({
 | 
				
			||||||
@@ -107,12 +105,12 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      fields: <Widget> [
 | 
					      fields: <Widget> [
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).name,
 | 
					          label: L10().name,
 | 
				
			||||||
          initial: location.name,
 | 
					          initial: location.name,
 | 
				
			||||||
          onSaved: (value) => _name = value,
 | 
					          onSaved: (value) => _name = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).description,
 | 
					          label: L10().description,
 | 
				
			||||||
          initial: location.description,
 | 
					          initial: location.description,
 | 
				
			||||||
          onSaved: (value) => _description = value,
 | 
					          onSaved: (value) => _description = value,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -168,7 +166,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
    if (location == null) {
 | 
					    if (location == null) {
 | 
				
			||||||
      return Card(
 | 
					      return Card(
 | 
				
			||||||
        child: ListTile(
 | 
					        child: ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).stockTopLevel),
 | 
					          title: Text(L10().stockTopLevel),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@@ -183,7 +181,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
      if (includeActions) {
 | 
					      if (includeActions) {
 | 
				
			||||||
        children.add(
 | 
					        children.add(
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).parentCategory),
 | 
					              title: Text(L10().parentCategory),
 | 
				
			||||||
              subtitle: Text("${location.parentpathstring}"),
 | 
					              subtitle: Text("${location.parentpathstring}"),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.levelUpAlt),
 | 
					              leading: FaIcon(FontAwesomeIcons.levelUpAlt),
 | 
				
			||||||
              onTap: () {
 | 
					              onTap: () {
 | 
				
			||||||
@@ -217,16 +215,16 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
        items: <BottomNavigationBarItem> [
 | 
					        items: <BottomNavigationBarItem> [
 | 
				
			||||||
          BottomNavigationBarItem(
 | 
					          BottomNavigationBarItem(
 | 
				
			||||||
            icon: FaIcon(FontAwesomeIcons.sitemap),
 | 
					            icon: FaIcon(FontAwesomeIcons.sitemap),
 | 
				
			||||||
            label: I18N.of(context).details,
 | 
					            label: L10().details,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          BottomNavigationBarItem(
 | 
					          BottomNavigationBarItem(
 | 
				
			||||||
            icon: FaIcon(FontAwesomeIcons.boxes),
 | 
					            icon: FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
            label: I18N.of(context).stock,
 | 
					            label: L10().stock,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          // TODO - Add in actions when they are written...
 | 
					          // TODO - Add in actions when they are written...
 | 
				
			||||||
          BottomNavigationBarItem(
 | 
					          BottomNavigationBarItem(
 | 
				
			||||||
            icon: FaIcon(FontAwesomeIcons.wrench),
 | 
					            icon: FaIcon(FontAwesomeIcons.wrench),
 | 
				
			||||||
            label: I18N.of(context).actions,
 | 
					            label: L10().actions,
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -273,7 +271,7 @@ List<Widget> detailTiles() {
 | 
				
			|||||||
      locationDescriptionCard(),
 | 
					      locationDescriptionCard(),
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(
 | 
					        title: Text(
 | 
				
			||||||
          I18N.of(context).sublocations,
 | 
					          L10().sublocations,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold),
 | 
					          style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        trailing: sublocations.length > 0 ? Text("${sublocations.length}") : null,
 | 
					        trailing: sublocations.length > 0 ? Text("${sublocations.length}") : null,
 | 
				
			||||||
@@ -286,8 +284,8 @@ List<Widget> detailTiles() {
 | 
				
			|||||||
      tiles.add(SublocationList(_sublocations));
 | 
					      tiles.add(SublocationList(_sublocations));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).sublocationNone),
 | 
					        title: Text(L10().sublocationNone),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).sublocationNoneDetail)
 | 
					        subtitle: Text(L10().sublocationNoneDetail)
 | 
				
			||||||
      ));
 | 
					      ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -305,9 +303,7 @@ List<Widget> detailTiles() {
 | 
				
			|||||||
      // Scan items into location
 | 
					      // Scan items into location
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N
 | 
					            title: Text(L10().barcodeScanInItems),
 | 
				
			||||||
                .of(context)
 | 
					 | 
				
			||||||
                .barcodeScanInItems),
 | 
					 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.exchangeAlt),
 | 
					            leading: FaIcon(FontAwesomeIcons.exchangeAlt),
 | 
				
			||||||
            trailing: FaIcon(FontAwesomeIcons.qrcode),
 | 
					            trailing: FaIcon(FontAwesomeIcons.qrcode),
 | 
				
			||||||
            onTap: () {
 | 
					            onTap: () {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PaginatedSearchWidget extends StatelessWidget {
 | 
					class PaginatedSearchWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +36,7 @@ class PaginatedSearchWidget extends StatelessWidget {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        decoration: InputDecoration(
 | 
					        decoration: InputDecoration(
 | 
				
			||||||
          hintText: I18N.of(context).search,
 | 
					          hintText: L10().search,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      trailing: Text(
 | 
					      trailing: Text(
 | 
				
			||||||
@@ -57,7 +57,7 @@ class NoResultsWidget extends StatelessWidget {
 | 
				
			|||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ListTile(
 | 
					    return ListTile(
 | 
				
			||||||
      title: Text(I18N.of(context).noResults),
 | 
					      title: Text(L10().noResults),
 | 
				
			||||||
      subtitle: Text(description),
 | 
					      subtitle: Text(description),
 | 
				
			||||||
      leading: FaIcon(FontAwesomeIcons.exclamationCircle),
 | 
					      leading: FaIcon(FontAwesomeIcons.exclamationCircle),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,12 @@
 | 
				
			|||||||
import 'dart:io';
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:InvenTree/inventree/stock.dart';
 | 
					 | 
				
			||||||
import 'package:InvenTree/widget/part_notes.dart';
 | 
					import 'package:InvenTree/widget/part_notes.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: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:flutter_gen/gen_l10n/app_localizations.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';
 | 
				
			||||||
@@ -39,7 +37,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
  final _editPartKey = GlobalKey<FormState>();
 | 
					  final _editPartKey = GlobalKey<FormState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).partDetails;
 | 
					  String getAppBarTitle(BuildContext context) => L10().partDetails;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  List<Widget> getAppBarActions(BuildContext context) {
 | 
					  List<Widget> getAppBarActions(BuildContext context) {
 | 
				
			||||||
@@ -59,7 +57,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
      actions.add(
 | 
					      actions.add(
 | 
				
			||||||
        IconButton(
 | 
					        IconButton(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.edit),
 | 
					          icon: FaIcon(FontAwesomeIcons.edit),
 | 
				
			||||||
          tooltip: I18N.of(context).edit,
 | 
					          tooltip: L10().edit,
 | 
				
			||||||
          onPressed: _editPartDialog,
 | 
					          onPressed: _editPartDialog,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -127,7 +125,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    var _keywords;
 | 
					    var _keywords;
 | 
				
			||||||
    var _link;
 | 
					    var _link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(I18N.of(context).editPart,
 | 
					    showFormDialog(L10().editPart,
 | 
				
			||||||
      key: _editPartKey,
 | 
					      key: _editPartKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
        _savePart({
 | 
					        _savePart({
 | 
				
			||||||
@@ -140,29 +138,29 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      fields: <Widget>[
 | 
					      fields: <Widget>[
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).name,
 | 
					          label: L10().name,
 | 
				
			||||||
          initial: part.name,
 | 
					          initial: part.name,
 | 
				
			||||||
          onSaved: (value) => _name = value,
 | 
					          onSaved: (value) => _name = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).description,
 | 
					          label: L10().description,
 | 
				
			||||||
          initial: part.description,
 | 
					          initial: part.description,
 | 
				
			||||||
          onSaved: (value) => _description = value,
 | 
					          onSaved: (value) => _description = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).internalPartNumber,
 | 
					          label: L10().internalPartNumber,
 | 
				
			||||||
          initial: part.IPN,
 | 
					          initial: part.IPN,
 | 
				
			||||||
          allowEmpty: true,
 | 
					          allowEmpty: true,
 | 
				
			||||||
          onSaved: (value) => _ipn = value,
 | 
					          onSaved: (value) => _ipn = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).keywords,
 | 
					          label: L10().keywords,
 | 
				
			||||||
          initial: part.keywords,
 | 
					          initial: part.keywords,
 | 
				
			||||||
          allowEmpty: true,
 | 
					          allowEmpty: true,
 | 
				
			||||||
          onSaved: (value) => _keywords = value,
 | 
					          onSaved: (value) => _keywords = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).link,
 | 
					          label: L10().link,
 | 
				
			||||||
          initial: part.link,
 | 
					          initial: part.link,
 | 
				
			||||||
          allowEmpty: true,
 | 
					          allowEmpty: true,
 | 
				
			||||||
          onSaved: (value) => _link = value
 | 
					          onSaved: (value) => _link = value
 | 
				
			||||||
@@ -216,7 +214,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    if (part.categoryName != null && part.categoryName.isNotEmpty) {
 | 
					    if (part.categoryName != null && part.categoryName.isNotEmpty) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).partCategory),
 | 
					            title: Text(L10().partCategory),
 | 
				
			||||||
            subtitle: Text("${part.categoryName}"),
 | 
					            subtitle: Text("${part.categoryName}"),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
					            leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
				
			||||||
            onTap: () {
 | 
					            onTap: () {
 | 
				
			||||||
@@ -232,8 +230,8 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).partCategory),
 | 
					          title: Text(L10().partCategory),
 | 
				
			||||||
          subtitle: Text(I18N.of(context).partCategoryTopLevel),
 | 
					          subtitle: Text(L10().partCategoryTopLevel),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
					          leading: FaIcon(FontAwesomeIcons.sitemap),
 | 
				
			||||||
          onTap: () {
 | 
					          onTap: () {
 | 
				
			||||||
            Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)));
 | 
					            Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)));
 | 
				
			||||||
@@ -245,7 +243,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    // Stock information
 | 
					    // Stock information
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).stock),
 | 
					        title: Text(L10().stock),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.boxes),
 | 
					        leading: FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
        trailing: Text("${part.inStockString}"),
 | 
					        trailing: Text("${part.inStockString}"),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
@@ -261,7 +259,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
      if (part.supplier_count > 0) {
 | 
					      if (part.supplier_count > 0) {
 | 
				
			||||||
        tiles.add(
 | 
					        tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).suppliers),
 | 
					            title: Text(L10().suppliers),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.industry),
 | 
					            leading: FaIcon(FontAwesomeIcons.industry),
 | 
				
			||||||
            trailing: Text("${part.supplier_count}"),
 | 
					            trailing: Text("${part.supplier_count}"),
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
@@ -289,7 +287,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    if (false && part.isAssembly) {
 | 
					    if (false && part.isAssembly) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).billOfMaterials),
 | 
					        title: Text(L10().billOfMaterials),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.thList),
 | 
					        leading: FaIcon(FontAwesomeIcons.thList),
 | 
				
			||||||
        trailing: Text("${part.bomItemCount}"),
 | 
					        trailing: Text("${part.bomItemCount}"),
 | 
				
			||||||
        onTap: null,
 | 
					        onTap: null,
 | 
				
			||||||
@@ -298,7 +296,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).building),
 | 
					            title: Text(L10().building),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.tools),
 | 
					            leading: FaIcon(FontAwesomeIcons.tools),
 | 
				
			||||||
            trailing: Text("${part.building}"),
 | 
					            trailing: Text("${part.building}"),
 | 
				
			||||||
            onTap: null,
 | 
					            onTap: null,
 | 
				
			||||||
@@ -344,7 +342,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    // TODO - Add request tests?
 | 
					    // TODO - Add request tests?
 | 
				
			||||||
    if (false && part.isTrackable) {
 | 
					    if (false && part.isTrackable) {
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).testsRequired),
 | 
					          title: Text(L10().testsRequired),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.tasks),
 | 
					          leading: FaIcon(FontAwesomeIcons.tasks),
 | 
				
			||||||
          trailing: Text("${part.testTemplateCount}"),
 | 
					          trailing: Text("${part.testTemplateCount}"),
 | 
				
			||||||
          onTap: null,
 | 
					          onTap: null,
 | 
				
			||||||
@@ -356,7 +354,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    if (part.notes.isNotEmpty) {
 | 
					    if (part.notes.isNotEmpty) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).notes),
 | 
					            title: Text(L10().notes),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.stickyNote),
 | 
					            leading: FaIcon(FontAwesomeIcons.stickyNote),
 | 
				
			||||||
            trailing: Text(""),
 | 
					            trailing: Text(""),
 | 
				
			||||||
            onTap: () {
 | 
					            onTap: () {
 | 
				
			||||||
@@ -382,7 +380,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(
 | 
					        title: Text(
 | 
				
			||||||
          I18N.of(context).stockItems,
 | 
					          L10().stockItems,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold),
 | 
					          style: TextStyle(fontWeight: FontWeight.bold),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        subtitle: part.stockItems.isEmpty ? Text("No stock items available") : null,
 | 
					        subtitle: part.stockItems.isEmpty ? Text("No stock items available") : null,
 | 
				
			||||||
@@ -408,7 +406,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).stockItemCreate),
 | 
					        title: Text(L10().stockItemCreate),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.box),
 | 
					        leading: FaIcon(FontAwesomeIcons.box),
 | 
				
			||||||
        onTap: null,
 | 
					        onTap: null,
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -463,17 +461,17 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
      items: <BottomNavigationBarItem> [
 | 
					      items: <BottomNavigationBarItem> [
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.infoCircle),
 | 
					          icon: FaIcon(FontAwesomeIcons.infoCircle),
 | 
				
			||||||
          label: I18N.of(context).details,
 | 
					          label: L10().details,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.boxes),
 | 
					          icon: FaIcon(FontAwesomeIcons.boxes),
 | 
				
			||||||
          label: I18N.of(context).stock
 | 
					          label: L10().stock
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        // TODO - Add part actions
 | 
					        // TODO - Add part actions
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.wrench),
 | 
					          icon: FaIcon(FontAwesomeIcons.wrench),
 | 
				
			||||||
          label: I18N.of(context).actions,
 | 
					          label: L10().actions,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PartNotesWidget extends StatefulWidget {
 | 
					class PartNotesWidget extends StatefulWidget {
 | 
				
			||||||
@@ -26,7 +23,7 @@ class _PartNotesState extends RefreshableState<PartNotesWidget> {
 | 
				
			|||||||
  _PartNotesState(this.part);
 | 
					  _PartNotesState(this.part);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).partNotes;
 | 
					  String getAppBarTitle(BuildContext context) => L10().partNotes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget getBody(BuildContext context) {
 | 
					  Widget getBody(BuildContext context) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,10 @@ 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:flutter_gen/gen_l10n/app_localizations.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 'package:one_context/one_context.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../api.dart';
 | 
					import '../api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +36,7 @@ class PartSearchDelegate extends SearchDelegate<InvenTreePart> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String get searchFieldLabel => I18N.of(context).searchParts;
 | 
					  String get searchFieldLabel => L10().searchParts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // List of part results
 | 
					  // List of part results
 | 
				
			||||||
  List<InvenTreePart> partResults = [];
 | 
					  List<InvenTreePart> partResults = [];
 | 
				
			||||||
@@ -79,7 +79,7 @@ class PartSearchDelegate extends SearchDelegate<InvenTreePart> {
 | 
				
			|||||||
    _searching = false;
 | 
					    _searching = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showSnackIcon(
 | 
					    showSnackIcon(
 | 
				
			||||||
        "${partResults.length} ${I18N.of(OneContext().context).results}",
 | 
					        "${partResults.length} ${L10().results}",
 | 
				
			||||||
        success: partResults.length > 0,
 | 
					        success: partResults.length > 0,
 | 
				
			||||||
        icon: FontAwesomeIcons.pollH,
 | 
					        icon: FontAwesomeIcons.pollH,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -157,21 +157,21 @@ class PartSearchDelegate extends SearchDelegate<InvenTreePart> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (query.length == 0) {
 | 
					    if (query.length == 0) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).queryEnter)
 | 
					        title: Text(L10().queryEnter)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (query.length < 3) {
 | 
					    if (query.length < 3) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).queryShort),
 | 
					        title: Text(L10().queryShort),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).queryShortDetail)
 | 
					        subtitle: Text(L10().queryShortDetail)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (partResults.length == 0) {
 | 
					    if (partResults.length == 0) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).noResults),
 | 
					        title: Text(L10().noResults),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).queryNoResults + " '${query}'")
 | 
					        subtitle: Text(L10().queryNoResults + " '${query}'")
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,7 +221,7 @@ class StockSearchDelegate extends SearchDelegate<InvenTreeStockItem> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String get searchFieldLabel => I18N.of(context).searchStock;
 | 
					  String get searchFieldLabel => L10().searchStock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // List of StockItem results
 | 
					  // List of StockItem results
 | 
				
			||||||
  List<InvenTreeStockItem> itemResults = [];
 | 
					  List<InvenTreeStockItem> itemResults = [];
 | 
				
			||||||
@@ -263,7 +263,7 @@ class StockSearchDelegate extends SearchDelegate<InvenTreeStockItem> {
 | 
				
			|||||||
    _searching = false;
 | 
					    _searching = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showSnackIcon(
 | 
					    showSnackIcon(
 | 
				
			||||||
      "${itemResults.length} ${I18N.of(OneContext().context).results}",
 | 
					      "${itemResults.length} ${L10().results}",
 | 
				
			||||||
      success: itemResults.length > 0,
 | 
					      success: itemResults.length > 0,
 | 
				
			||||||
      icon: FontAwesomeIcons.pollH,
 | 
					      icon: FontAwesomeIcons.pollH,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -340,21 +340,21 @@ class StockSearchDelegate extends SearchDelegate<InvenTreeStockItem> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (query.length == 0) {
 | 
					    if (query.length == 0) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).queryEnter)
 | 
					          title: Text(L10().queryEnter)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (query.length < 3) {
 | 
					    if (query.length < 3) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).queryShort),
 | 
					          title: Text(L10().queryShort),
 | 
				
			||||||
          subtitle: Text(I18N.of(context).queryShortDetail)
 | 
					          subtitle: Text(L10().queryShortDetail)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (itemResults.length == 0) {
 | 
					    if (itemResults.length == 0) {
 | 
				
			||||||
      return ListTile(
 | 
					      return ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).noResults),
 | 
					          title: Text(L10().noResults),
 | 
				
			||||||
          subtitle: Text(I18N.of(context).queryNoResults + " '${query}'")
 | 
					          subtitle: Text(L10().queryNoResults + " '${query}'")
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@ 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:flutter_gen/gen_l10n/app_localizations.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}) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,7 +45,7 @@ void showSnackIcon(String text, {IconData icon, Function onAction, bool success,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (actionText == null) {
 | 
					    if (actionText == null) {
 | 
				
			||||||
      // Default action text
 | 
					      // Default action text
 | 
				
			||||||
      actionText = I18N.of(OneContext().context).details;
 | 
					      actionText = L10().details;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    action = SnackBarAction(
 | 
					    action = SnackBarAction(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ 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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../api.dart';
 | 
					import '../api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,7 +26,7 @@ class _StarredPartState extends RefreshableState<StarredPartWidget> {
 | 
				
			|||||||
  List<InvenTreePart> starredParts = [];
 | 
					  List<InvenTreePart> starredParts = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).partsStarred;
 | 
					  String getAppBarTitle(BuildContext context) => L10().partsStarred;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> request(BuildContext context) async {
 | 
					  Future<void> request(BuildContext context) async {
 | 
				
			||||||
@@ -77,8 +77,8 @@ class _StarredPartState extends RefreshableState<StarredPartWidget> {
 | 
				
			|||||||
      return ListView(
 | 
					      return ListView(
 | 
				
			||||||
        children: [
 | 
					        children: [
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).partsNone),
 | 
					            title: Text(L10().partsNone),
 | 
				
			||||||
            subtitle: Text(I18N.of(context).partsStarredNone)
 | 
					            subtitle: Text(L10().partsStarredNone)
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ 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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:InvenTree/api.dart';
 | 
					import 'package:InvenTree/api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,7 +37,7 @@ class StockDetailWidget extends StatefulWidget {
 | 
				
			|||||||
class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
					class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).stockItem;
 | 
					  String getAppBarTitle(BuildContext context) => L10().stockItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final TextEditingController _quantityController = TextEditingController();
 | 
					  final TextEditingController _quantityController = TextEditingController();
 | 
				
			||||||
  final TextEditingController _notesController = TextEditingController();
 | 
					  final TextEditingController _notesController = TextEditingController();
 | 
				
			||||||
@@ -62,7 +62,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
      /*
 | 
					      /*
 | 
				
			||||||
      IconButton(
 | 
					      IconButton(
 | 
				
			||||||
        icon: FaIcon(FontAwesomeIcons.edit),
 | 
					        icon: FaIcon(FontAwesomeIcons.edit),
 | 
				
			||||||
        tooltip: I18N.of(context).edit,
 | 
					        tooltip: L10().edit,
 | 
				
			||||||
        onPressed: _editPartDialog,
 | 
					        onPressed: _editPartDialog,
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
       */
 | 
					       */
 | 
				
			||||||
@@ -117,7 +117,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    _quantityController.clear();
 | 
					    _quantityController.clear();
 | 
				
			||||||
    _notesController.clear();
 | 
					    _notesController.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog( I18N.of(context).addStock,
 | 
					    showFormDialog( L10().addStock,
 | 
				
			||||||
      key: _addStockKey,
 | 
					      key: _addStockKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
        _addStock();
 | 
					        _addStock();
 | 
				
			||||||
@@ -125,12 +125,12 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
      fields: <Widget> [
 | 
					      fields: <Widget> [
 | 
				
			||||||
        Text("Current stock: ${item.quantity}"),
 | 
					        Text("Current stock: ${item.quantity}"),
 | 
				
			||||||
        QuantityField(
 | 
					        QuantityField(
 | 
				
			||||||
          label: I18N.of(context).addStock,
 | 
					          label: L10().addStock,
 | 
				
			||||||
          controller: _quantityController,
 | 
					          controller: _quantityController,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        TextFormField(
 | 
					        TextFormField(
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: I18N.of(context).notes,
 | 
					            labelText: L10().notes,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          controller: _notesController,
 | 
					          controller: _notesController,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -163,7 +163,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    _quantityController.clear();
 | 
					    _quantityController.clear();
 | 
				
			||||||
    _notesController.clear();
 | 
					    _notesController.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(I18N.of(context).removeStock,
 | 
					    showFormDialog(L10().removeStock,
 | 
				
			||||||
        key: _removeStockKey,
 | 
					        key: _removeStockKey,
 | 
				
			||||||
        callback: () {
 | 
					        callback: () {
 | 
				
			||||||
          _removeStock();
 | 
					          _removeStock();
 | 
				
			||||||
@@ -171,13 +171,13 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
        fields: <Widget>[
 | 
					        fields: <Widget>[
 | 
				
			||||||
          Text("Current stock: ${item.quantity}"),
 | 
					          Text("Current stock: ${item.quantity}"),
 | 
				
			||||||
          QuantityField(
 | 
					          QuantityField(
 | 
				
			||||||
            label: I18N.of(context).removeStock,
 | 
					            label: L10().removeStock,
 | 
				
			||||||
            controller: _quantityController,
 | 
					            controller: _quantityController,
 | 
				
			||||||
            max: item.quantity,
 | 
					            max: item.quantity,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          TextFormField(
 | 
					          TextFormField(
 | 
				
			||||||
            decoration: InputDecoration(
 | 
					            decoration: InputDecoration(
 | 
				
			||||||
              labelText: I18N.of(context).notes,
 | 
					              labelText: L10().notes,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            controller: _notesController,
 | 
					            controller: _notesController,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
@@ -202,21 +202,21 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    _quantityController.text = item.quantityString;
 | 
					    _quantityController.text = item.quantityString;
 | 
				
			||||||
    _notesController.clear();
 | 
					    _notesController.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(I18N.of(context).countStock,
 | 
					    showFormDialog(L10().countStock,
 | 
				
			||||||
      key: _countStockKey,
 | 
					      key: _countStockKey,
 | 
				
			||||||
      callback: () {
 | 
					      callback: () {
 | 
				
			||||||
        _countStock();
 | 
					        _countStock();
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      acceptText: I18N.of(context).count,
 | 
					      acceptText: L10().count,
 | 
				
			||||||
      fields: <Widget> [
 | 
					      fields: <Widget> [
 | 
				
			||||||
        QuantityField(
 | 
					        QuantityField(
 | 
				
			||||||
          label: I18N.of(context).countStock,
 | 
					          label: L10().countStock,
 | 
				
			||||||
          hint: "${item.quantityString}",
 | 
					          hint: "${item.quantityString}",
 | 
				
			||||||
          controller: _quantityController,
 | 
					          controller: _quantityController,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        TextFormField(
 | 
					        TextFormField(
 | 
				
			||||||
          decoration: InputDecoration(
 | 
					          decoration: InputDecoration(
 | 
				
			||||||
            labelText: I18N.of(context).notes,
 | 
					            labelText: L10().notes,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          controller: _notesController,
 | 
					          controller: _notesController,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -231,12 +231,12 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (result) {
 | 
					    if (result) {
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(context).stockItemUpdateSuccess,
 | 
					        L10().stockItemUpdateSuccess,
 | 
				
			||||||
        success: true
 | 
					        success: true
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      showSnackIcon(
 | 
					      showSnackIcon(
 | 
				
			||||||
        I18N.of(context).stockItemUpdateFailure,
 | 
					        L10().stockItemUpdateFailure,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -271,14 +271,14 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    _quantityController.text = "${item.quantityString}";
 | 
					    _quantityController.text = "${item.quantityString}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    showFormDialog(I18N.of(context).transferStock,
 | 
					    showFormDialog(L10().transferStock,
 | 
				
			||||||
        key: _moveStockKey,
 | 
					        key: _moveStockKey,
 | 
				
			||||||
        callback: () {
 | 
					        callback: () {
 | 
				
			||||||
          _transferStock(context, selectedLocation);
 | 
					          _transferStock(context, selectedLocation);
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        fields: <Widget>[
 | 
					        fields: <Widget>[
 | 
				
			||||||
          QuantityField(
 | 
					          QuantityField(
 | 
				
			||||||
            label: I18N.of(context).quantity,
 | 
					            label: L10().quantity,
 | 
				
			||||||
            controller: _quantityController,
 | 
					            controller: _quantityController,
 | 
				
			||||||
            max: item.quantity,
 | 
					            max: item.quantity,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
@@ -304,7 +304,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
              },
 | 
					              },
 | 
				
			||||||
              validator: (value) {
 | 
					              validator: (value) {
 | 
				
			||||||
                if (selectedLocation == null) {
 | 
					                if (selectedLocation == null) {
 | 
				
			||||||
                  return I18N.of(context).selectLocation;
 | 
					                  return L10().selectLocation;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
@@ -373,7 +373,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if (item.isSerialized()) {
 | 
					    if (item.isSerialized()) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).serialNumber),
 | 
					            title: Text(L10().serialNumber),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.hashtag),
 | 
					            leading: FaIcon(FontAwesomeIcons.hashtag),
 | 
				
			||||||
            trailing: Text("${item.serialNumber}"),
 | 
					            trailing: Text("${item.serialNumber}"),
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
@@ -381,7 +381,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).quantity),
 | 
					            title: Text(L10().quantity),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.cubes),
 | 
					            leading: FaIcon(FontAwesomeIcons.cubes),
 | 
				
			||||||
            trailing: Text("${item.quantityString}"),
 | 
					            trailing: Text("${item.quantityString}"),
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
@@ -392,7 +392,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if ((item.locationId > 0) && (item.locationName != null) && (item.locationName.isNotEmpty)) {
 | 
					    if ((item.locationId > 0) && (item.locationName != null) && (item.locationName.isNotEmpty)) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).stockLocation),
 | 
					            title: Text(L10().stockLocation),
 | 
				
			||||||
            subtitle: Text("${item.locationPathString}"),
 | 
					            subtitle: Text("${item.locationPathString}"),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.mapMarkerAlt),
 | 
					            leading: FaIcon(FontAwesomeIcons.mapMarkerAlt),
 | 
				
			||||||
            onTap: () {
 | 
					            onTap: () {
 | 
				
			||||||
@@ -408,9 +408,9 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: Text(I18N.of(context).stockLocation),
 | 
					            title: Text(L10().stockLocation),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.mapMarkerAlt),
 | 
					            leading: FaIcon(FontAwesomeIcons.mapMarkerAlt),
 | 
				
			||||||
            subtitle: Text(I18N.of(context).locationNotSet),
 | 
					            subtitle: Text(L10().locationNotSet),
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -445,7 +445,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if ((item.testResultCount > 0) || (part != null && part.isTrackable)) {
 | 
					    if ((item.testResultCount > 0) || (part != null && part.isTrackable)) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).testResults),
 | 
					              title: Text(L10().testResults),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.tasks),
 | 
					              leading: FaIcon(FontAwesomeIcons.tasks),
 | 
				
			||||||
              trailing: Text("${item.testResultCount}"),
 | 
					              trailing: Text("${item.testResultCount}"),
 | 
				
			||||||
              onTap: () {
 | 
					              onTap: () {
 | 
				
			||||||
@@ -465,7 +465,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if (false && item.trackingItemCount > 0) {
 | 
					    if (false && item.trackingItemCount > 0) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).history),
 | 
					          title: Text(L10().history),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.history),
 | 
					          leading: FaIcon(FontAwesomeIcons.history),
 | 
				
			||||||
          trailing: Text("${item.trackingItemCount}"),
 | 
					          trailing: Text("${item.trackingItemCount}"),
 | 
				
			||||||
          onTap: () {
 | 
					          onTap: () {
 | 
				
			||||||
@@ -481,7 +481,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if (item.notes.isNotEmpty) {
 | 
					    if (item.notes.isNotEmpty) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).notes),
 | 
					          title: Text(L10().notes),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.stickyNote),
 | 
					          leading: FaIcon(FontAwesomeIcons.stickyNote),
 | 
				
			||||||
          trailing: Text(""),
 | 
					          trailing: Text(""),
 | 
				
			||||||
          onTap: () {
 | 
					          onTap: () {
 | 
				
			||||||
@@ -508,14 +508,14 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if (!InvenTreeAPI().checkPermission('stock', 'change')) {
 | 
					    if (!InvenTreeAPI().checkPermission('stock', 'change')) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).permissionRequired),
 | 
					          title: Text(L10().permissionRequired),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.userTimes)
 | 
					          leading: FaIcon(FontAwesomeIcons.userTimes)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          subtitle: Text(I18N.of(context).permissionAccountDenied),
 | 
					          subtitle: Text(L10().permissionAccountDenied),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -525,7 +525,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if (!item.isSerialized()) {
 | 
					    if (!item.isSerialized()) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).countStock),
 | 
					              title: Text(L10().countStock),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.checkCircle),
 | 
					              leading: FaIcon(FontAwesomeIcons.checkCircle),
 | 
				
			||||||
              onTap: _countStockDialog,
 | 
					              onTap: _countStockDialog,
 | 
				
			||||||
              trailing: Text(item.quantityString),
 | 
					              trailing: Text(item.quantityString),
 | 
				
			||||||
@@ -534,7 +534,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).removeStock),
 | 
					              title: Text(L10().removeStock),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.minusCircle),
 | 
					              leading: FaIcon(FontAwesomeIcons.minusCircle),
 | 
				
			||||||
              onTap: _removeStockDialog,
 | 
					              onTap: _removeStockDialog,
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
@@ -542,7 +542,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
              title: Text(I18N.of(context).addStock),
 | 
					              title: Text(L10().addStock),
 | 
				
			||||||
              leading: FaIcon(FontAwesomeIcons.plusCircle),
 | 
					              leading: FaIcon(FontAwesomeIcons.plusCircle),
 | 
				
			||||||
              onTap: _addStockDialog,
 | 
					              onTap: _addStockDialog,
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
@@ -551,7 +551,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).transferStock),
 | 
					        title: Text(L10().transferStock),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.exchangeAlt),
 | 
					        leading: FaIcon(FontAwesomeIcons.exchangeAlt),
 | 
				
			||||||
        onTap: _transferStockDialog,
 | 
					        onTap: _transferStockDialog,
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -560,7 +560,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    // Scan item into a location
 | 
					    // Scan item into a location
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).scanIntoLocation),
 | 
					        title: Text(L10().scanIntoLocation),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.exchangeAlt),
 | 
					        leading: FaIcon(FontAwesomeIcons.exchangeAlt),
 | 
				
			||||||
        trailing: FaIcon(FontAwesomeIcons.qrcode),
 | 
					        trailing: FaIcon(FontAwesomeIcons.qrcode),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
@@ -578,7 +578,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    if (item.uid.isEmpty) {
 | 
					    if (item.uid.isEmpty) {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).barcodeAssign),
 | 
					          title: Text(L10().barcodeAssign),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.barcode),
 | 
					          leading: FaIcon(FontAwesomeIcons.barcode),
 | 
				
			||||||
          trailing: FaIcon(FontAwesomeIcons.qrcode),
 | 
					          trailing: FaIcon(FontAwesomeIcons.qrcode),
 | 
				
			||||||
          onTap: () {
 | 
					          onTap: () {
 | 
				
			||||||
@@ -594,7 +594,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      tiles.add(
 | 
					      tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					        ListTile(
 | 
				
			||||||
          title: Text(I18N.of(context).barcodeUnassign),
 | 
					          title: Text(L10().barcodeUnassign),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.barcode),
 | 
					          leading: FaIcon(FontAwesomeIcons.barcode),
 | 
				
			||||||
          onTap: () {
 | 
					          onTap: () {
 | 
				
			||||||
            _unassignBarcode(context);
 | 
					            _unassignBarcode(context);
 | 
				
			||||||
@@ -614,11 +614,11 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
      items: <BottomNavigationBarItem> [
 | 
					      items: <BottomNavigationBarItem> [
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.infoCircle),
 | 
					          icon: FaIcon(FontAwesomeIcons.infoCircle),
 | 
				
			||||||
          title: Text(I18N.of(context).details),
 | 
					          title: Text(L10().details),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        BottomNavigationBarItem(
 | 
					        BottomNavigationBarItem(
 | 
				
			||||||
          icon: FaIcon(FontAwesomeIcons.wrench),
 | 
					          icon: FaIcon(FontAwesomeIcons.wrench),
 | 
				
			||||||
          title: Text(I18N.of(context).actions),
 | 
					          title: Text(L10().actions),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,16 +7,15 @@ 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:flutter_gen/gen_l10n/app_localizations.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:flutter_speed_dial/flutter_speed_dial.dart';
 | 
					 | 
				
			||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
					import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
				
			||||||
import 'package:image_picker/image_picker.dart';
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StockItemTestResultsWidget extends StatefulWidget {
 | 
					class StockItemTestResultsWidget extends StatefulWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +33,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
 | 
				
			|||||||
  final _addResultKey = GlobalKey<FormState>();
 | 
					  final _addResultKey = GlobalKey<FormState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).testResults;
 | 
					  String getAppBarTitle(BuildContext context) => L10().testResults;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> request(BuildContext context) async {
 | 
					  Future<void> request(BuildContext context) async {
 | 
				
			||||||
@@ -78,38 +77,38 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      fields: <Widget>[
 | 
					      fields: <Widget>[
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).testName,
 | 
					          label: L10().testName,
 | 
				
			||||||
          initial: name,
 | 
					          initial: name,
 | 
				
			||||||
          isEnabled: nameIsEditable,
 | 
					          isEnabled: nameIsEditable,
 | 
				
			||||||
          onSaved: (value) => _name = value,
 | 
					          onSaved: (value) => _name = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        CheckBoxField(
 | 
					        CheckBoxField(
 | 
				
			||||||
          label: I18N.of(context).result,
 | 
					          label: L10().result,
 | 
				
			||||||
          hint: I18N.of(context).testPassedOrFailed,
 | 
					          hint: L10().testPassedOrFailed,
 | 
				
			||||||
          initial: true,
 | 
					          initial: true,
 | 
				
			||||||
          onSaved: (value) => _result = value,
 | 
					          onSaved: (value) => _result = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          label: I18N.of(context).value,
 | 
					          label: L10().value,
 | 
				
			||||||
          initial: value,
 | 
					          initial: value,
 | 
				
			||||||
          allowEmpty: true,
 | 
					          allowEmpty: true,
 | 
				
			||||||
          onSaved: (value) => _value = value,
 | 
					          onSaved: (value) => _value = value,
 | 
				
			||||||
          validator: (String value) {
 | 
					          validator: (String value) {
 | 
				
			||||||
            if (valueRequired && (value == null || value.isEmpty)) {
 | 
					            if (valueRequired && (value == null || value.isEmpty)) {
 | 
				
			||||||
              return I18N.of(context).valueRequired;
 | 
					              return L10().valueRequired;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        ImagePickerField(
 | 
					        ImagePickerField(
 | 
				
			||||||
          context,
 | 
					          context,
 | 
				
			||||||
          label: I18N.of(context).attachImage,
 | 
					          label: L10().attachImage,
 | 
				
			||||||
          required: attachmentRequired,
 | 
					          required: attachmentRequired,
 | 
				
			||||||
          onSaved: (attachment) => _attachment = attachment,
 | 
					          onSaved: (attachment) => _attachment = attachment,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        StringField(
 | 
					        StringField(
 | 
				
			||||||
          allowEmpty: true,
 | 
					          allowEmpty: true,
 | 
				
			||||||
          label: I18N.of(context).notes,
 | 
					          label: L10().notes,
 | 
				
			||||||
          onSaved: (value) => _notes = value,
 | 
					          onSaved: (value) => _notes = value,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
@@ -178,7 +177,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).testResults,
 | 
					        title: Text(L10().testResults,
 | 
				
			||||||
          style: TextStyle(fontWeight: FontWeight.bold)
 | 
					          style: TextStyle(fontWeight: FontWeight.bold)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -193,8 +192,8 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (results.length == 0) {
 | 
					    if (results.length == 0) {
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).testResultNone),
 | 
					        title: Text(L10().testResultNone),
 | 
				
			||||||
        subtitle: Text(I18N.of(context).testResultNoneDetail),
 | 
					        subtitle: Text(L10().testResultNoneDetail),
 | 
				
			||||||
      ));
 | 
					      ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return tiles;
 | 
					      return tiles;
 | 
				
			||||||
@@ -254,7 +253,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (tiles.isEmpty) {
 | 
					    if (tiles.isEmpty) {
 | 
				
			||||||
      tiles.add(ListTile(
 | 
					      tiles.add(ListTile(
 | 
				
			||||||
        title: Text(I18N.of(context).testResultNone),
 | 
					        title: Text(L10().testResultNone),
 | 
				
			||||||
      ));
 | 
					      ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -279,7 +278,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    buttons.add(SpeedDialChild(
 | 
					    buttons.add(SpeedDialChild(
 | 
				
			||||||
      child: Icon(FontAwesomeIcons.plusCircle),
 | 
					      child: Icon(FontAwesomeIcons.plusCircle),
 | 
				
			||||||
      label: I18N.of(context).testResultAdd,
 | 
					      label: L10().testResultAdd,
 | 
				
			||||||
      onTap: () {
 | 
					      onTap: () {
 | 
				
			||||||
        addTestResult();
 | 
					        addTestResult();
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +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:flutter_gen/gen_l10n/app_localizations.dart';
 | 
					import 'package:InvenTree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StockNotesWidget extends StatefulWidget {
 | 
					class StockNotesWidget extends StatefulWidget {
 | 
				
			||||||
@@ -26,7 +24,7 @@ class _StockNotesState extends RefreshableState<StockNotesWidget> {
 | 
				
			|||||||
  _StockNotesState(this.item);
 | 
					  _StockNotesState(this.item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => I18N.of(context).stockItemNotes;
 | 
					  String getAppBarTitle(BuildContext context) => L10().stockItemNotes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget getBody(BuildContext context) {
 | 
					  Widget getBody(BuildContext context) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user