2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 05:26:47 +00:00

Updated dependencies (#255)

* Bump android compile and target version, also flutter dependencies and resolve issues

* Remove deprecated splashscreen and added support for new Android 12 version.

* Updated workflow action versions and flutter sdk

* Resolved linting issues

* Resolved test binding issues
This commit is contained in:
Gustaf Järgren 2023-02-10 14:24:06 +01:00 committed by GitHub
parent 298ee24a9c
commit 6d4973deb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 816 additions and 592 deletions

View File

@ -14,21 +14,22 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
java-version: '12.x' distribution: 'temurin'
java-version: '11'
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v2
with: with:
flutter-version: '2.10.3' flutter-version: '3.7.3'
- name: Setup Gradle - name: Setup Gradle
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
gradle-version: 6.1.1 gradle-version: 7.6
- name: Collect Translation Files - name: Collect Translation Files
run: | run: |
cd lib/l10n cd lib/l10n

View File

@ -28,17 +28,18 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
java-version: '12.x' distribution: 'temurin'
java-version: '11'
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v2
with: with:
flutter-version: '2.10.3' flutter-version: '3.7.3'
- name: Collect Translation Files - name: Collect Translation Files
run: | run: |
cd lib/l10n cd lib/l10n
@ -51,7 +52,7 @@ jobs:
flutter analyze flutter analyze
- name: Install Python - name: Install Python
uses: actions/setup-python@v2 uses: actions/setup-python@v4
with: with:
python-version: 3.9 python-version: 3.9
- name: Start InvenTree Server - name: Start InvenTree Server

View File

@ -14,17 +14,18 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
java-version: '12.x' distribution: 'temurin'
java-version: '11'
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v2
with: with:
flutter-version: '2.10.3' flutter-version: '3.7.3'
- name: Collect Translation Files - name: Collect Translation Files
run: | run: |
cd lib/l10n cd lib/l10n

View File

@ -75,3 +75,5 @@ linter:
avoid_dynamic_calls: false avoid_dynamic_calls: false
avoid_classes_with_only_static_members: false avoid_classes_with_only_static_members: false
no_leading_underscores_for_local_identifiers: false

View File

@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
} }
android { android {
compileSdkVersion 31 compileSdkVersion 33
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
@ -49,7 +49,7 @@ android {
defaultConfig { defaultConfig {
applicationId "inventree.inventree_app" applicationId "inventree.inventree_app"
minSdkVersion 25 minSdkVersion 25
targetSdkVersion 31 targetSdkVersion 33
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@ -83,7 +83,7 @@ dependencies {
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'com.android.support:multidex:2.0.1' androidTestImplementation 'com.android.support:multidex:2.0.1'
implementation "androidx.core:core:1.5.0-rc01" implementation "androidx.core:core:1.9.0"
implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'androidx.appcompat:appcompat:1.6.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
} }

View File

@ -31,10 +31,6 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- until Flutter renders its first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<!-- Theme to apply as soon as Flutter begins rendering frames --> <!-- Theme to apply as soon as Flutter begins rendering frames -->
<meta-data <meta-data

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowSplashScreenBackground">@color/splash_screen_background</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/launch_background</item>
</style>
</resources>

View File

@ -1,14 +1,14 @@
buildscript { buildscript {
ext.kotlin_version = '1.5.10' ext.kotlin_version = '1.8.10'
repositories { repositories {
google() google()
jcenter() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.android.tools.build:gradle:7.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@ -16,7 +16,7 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() google()
jcenter() mavenCentral()
} }
} }

View File

@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.enableR8=true android.enableD8=true
android.enableJetifier=true android.enableJetifier=true
android.useAndroidX=true android.useAndroidX=true

View File

@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

View File

@ -8,7 +8,7 @@ import "package:intl/intl.dart";
import "package:inventree/app_colors.dart"; import "package:inventree/app_colors.dart";
import "package:inventree/preferences.dart"; import "package:inventree/preferences.dart";
import "package:open_file/open_file.dart"; import "package:open_filex/open_filex.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";
@ -350,7 +350,7 @@ class InvenTreeAPI {
if (address.isEmpty || username.isEmpty || password.isEmpty) { if (address.isEmpty || username.isEmpty || password.isEmpty) {
showSnackIcon( showSnackIcon(
L10().incompleteDetails, L10().incompleteDetails,
icon: FontAwesomeIcons.exclamationCircle, icon: FontAwesomeIcons.circleExclamation,
success: false success: false
); );
return false; return false;
@ -507,7 +507,7 @@ class InvenTreeAPI {
showSnackIcon( showSnackIcon(
L10().profileSelect, L10().profileSelect,
success: false, success: false,
icon: FontAwesomeIcons.exclamationCircle icon: FontAwesomeIcons.circleExclamation
); );
return false; return false;
} }
@ -731,7 +731,7 @@ class InvenTreeAPI {
await localFile.writeAsBytes(bytes); await localFile.writeAsBytes(bytes);
if (openOnDownload) { if (openOnDownload) {
OpenFile.open(local_path); OpenFilex.open(local_path);
} }
} else { } else {
showStatusCodeError(url, response.statusCode); showStatusCodeError(url, response.statusCode);
@ -1272,7 +1272,7 @@ class InvenTreeAPI {
return CachedNetworkImage( return CachedNetworkImage(
imageUrl: url, imageUrl: url,
placeholder: (context, url) => CircularProgressIndicator(), placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => FaIcon(FontAwesomeIcons.timesCircle, color: COLOR_DANGER), errorWidget: (context, url, error) => FaIcon(FontAwesomeIcons.circleXmark, color: COLOR_DANGER),
httpHeaders: defaultHeaders(), httpHeaders: defaultHeaders(),
height: height, height: height,
width: width, width: width,
@ -1369,7 +1369,7 @@ class InvenTreeAPI {
L10().locateLocation, L10().locateLocation,
"", "",
fields, fields,
icon: FontAwesomeIcons.searchLocation, icon: FontAwesomeIcons.magnifyingGlassLocation,
onSuccess: (Map<String, dynamic> data) async { onSuccess: (Map<String, dynamic> data) async {
plugin_name = (data["plugin"] ?? "") as String; plugin_name = (data["plugin"] ?? "") as String;
} }

View File

@ -415,7 +415,7 @@ class APIFormField {
controller: controller, controller: controller,
), ),
trailing: IconButton( trailing: IconButton(
icon: FaIcon(FontAwesomeIcons.plusCircle), icon: FaIcon(FontAwesomeIcons.circlePlus),
onPressed: () async { onPressed: () async {
FilePickerDialog.pickFile( FilePickerDialog.pickFile(
message: L10().attachmentSelect, message: L10().attachmentSelect,
@ -436,26 +436,32 @@ class APIFormField {
// Field for selecting from multiple choice options // Field for selecting from multiple choice options
Widget _constructChoiceField() { Widget _constructChoiceField() {
dynamic _initial; dynamic initial;
// Check if the current value is within the allowed values // Check if the current value is within the allowed values
for (var opt in choices) { for (var opt in choices) {
if (opt["value"] == value) { if (opt["value"] == value) {
_initial = opt; initial = opt;
break; break;
} }
} }
return DropdownSearch<dynamic>( return DropdownSearch<dynamic>(
mode: Mode.BOTTOM_SHEET, popupProps: PopupProps.bottomSheet(
showSelectedItem: false, showSelectedItems: false,
selectedItem: _initial, searchFieldProps: TextFieldProps(
autofocus: true
)
),
selectedItem: initial,
items: choices, items: choices,
label: label, dropdownDecoratorProps: DropDownDecoratorProps(
hint: helpText, dropdownSearchDecoration: InputDecoration(
labelText: label,
hintText: helpText,
)),
onChanged: null, onChanged: null,
autoFocusSearchBox: true, clearButtonProps: ClearButtonProps(isVisible: !required),
showClearButton: !required,
itemAsString: (dynamic item) { itemAsString: (dynamic item) {
return (item["display_name"] ?? "") as String; return (item["display_name"] ?? "") as String;
}, },
@ -465,8 +471,7 @@ class APIFormField {
} else { } else {
data["value"] = item["value"]; data["value"] = item["value"];
} }
} });
);
} }
// Construct a floating point numerical input field // Construct a floating point numerical input field
@ -501,30 +506,37 @@ class APIFormField {
// Construct an input for a related field // Construct an input for a related field
Widget _constructRelatedField() { Widget _constructRelatedField() {
return DropdownSearch<dynamic>( return DropdownSearch<dynamic>(
mode: Mode.BOTTOM_SHEET, popupProps: PopupProps.bottomSheet(
showSelectedItem: true, showSelectedItems: true,
isFilterOnline: true,
showSearchBox: true,
itemBuilder: (context, item, isSelected) {
return _renderRelatedField(item, isSelected, true);
},
emptyBuilder: (context, item) {
return _renderEmptyResult();
},
searchFieldProps: TextFieldProps(
autofocus: true
)
),
selectedItem: initial_data, selectedItem: initial_data,
onFind: (String filter) async { asyncItems: (String filter) async {
Map<String, String> filters = {};
Map<String, String> _filters = {};
filters.forEach((key, value) { filters.forEach((key, value) {
_filters[key] = value; filters[key] = value;
}); });
_filters["search"] = filter; filters["search"] = filter;
_filters["offset"] = "0"; filters["offset"] = "0";
_filters["limit"] = "25"; filters["limit"] = "25";
final APIResponse response = await InvenTreeAPI().get( final APIResponse response =
api_url, await InvenTreeAPI().get(api_url, params: filters);
params: _filters
);
if (response.isValid()) { if (response.isValid()) {
List<dynamic> results = []; List<dynamic> results = [];
for (var result in response.data["results"] ?? []) { for (var result in response.data["results"] ?? []) {
@ -536,12 +548,16 @@ class APIFormField {
return []; return [];
} }
}, },
label: label, clearButtonProps: ClearButtonProps(
hint: helpText, isVisible: !required
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
labelText: label,
hintText: helpText,
)),
onChanged: null, onChanged: null,
showClearButton: !required,
itemAsString: (dynamic item) { itemAsString: (dynamic item) {
Map<String, dynamic> data = item as Map<String, dynamic>; Map<String, dynamic> data = item as Map<String, dynamic>;
switch (model) { switch (model) {
@ -555,15 +571,9 @@ class APIFormField {
return "itemAsString not implemented for '${model}'"; return "itemAsString not implemented for '${model}'";
} }
}, },
dropdownBuilder: (context, item, itemAsString) { dropdownBuilder: (context, item) {
return _renderRelatedField(item, true, false); return _renderRelatedField(item, true, false);
}, },
popupItemBuilder: (context, item, isSelected) {
return _renderRelatedField(item, isSelected, true);
},
emptyBuilder: (context, item) {
return _renderEmptyResult();
},
onSaved: (item) { onSaved: (item) {
if (item != null) { if (item != null) {
data["value"] = item["pk"]; data["value"] = item["pk"];
@ -571,9 +581,6 @@ class APIFormField {
data["value"] = null; data["value"] = null;
} }
}, },
isFilteredOnline: true,
showSearchBox: true,
autoFocusSearchBox: true,
compareFn: (dynamic item, dynamic selectedItem) { compareFn: (dynamic item, dynamic selectedItem) {
// Comparison is based on the PK value // Comparison is based on the PK value
@ -582,8 +589,7 @@ class APIFormField {
} }
return item["pk"] == selectedItem["pk"]; return item["pk"] == selectedItem["pk"];
} });
);
} }
Widget _renderRelatedField(dynamic item, bool selected, bool extended) { Widget _renderRelatedField(dynamic item, bool selected, bool extended) {
@ -672,7 +678,7 @@ class APIFormField {
// Construct a widget to instruct the user that no results were found // Construct a widget to instruct the user that no results were found
Widget _renderEmptyResult() { Widget _renderEmptyResult() {
return ListTile( return ListTile(
leading: FaIcon(FontAwesomeIcons.search), leading: FaIcon(FontAwesomeIcons.magnifyingGlass),
title: Text(L10().noResults), title: Text(L10().noResults),
subtitle: Text( subtitle: Text(
L10().queryNoResults, L10().queryNoResults,
@ -865,7 +871,7 @@ Future<void> launchApiForm(
String method = "PATCH", String method = "PATCH",
Function(Map<String, dynamic>)? onSuccess, Function(Map<String, dynamic>)? onSuccess,
Function? onCancel, Function? onCancel,
IconData icon = FontAwesomeIcons.save, IconData icon = FontAwesomeIcons.floppyDisk,
}) async { }) async {
showLoadingOverlay(context); showLoadingOverlay(context);
@ -889,7 +895,7 @@ Future<void> launchApiForm(
// User does not have permission to perform this action // User does not have permission to perform this action
showSnackIcon( showSnackIcon(
L10().response403, L10().response403,
icon: FontAwesomeIcons.userTimes, icon: FontAwesomeIcons.userXmark,
); );
hideLoadingOverlay(); hideLoadingOverlay();
@ -971,7 +977,7 @@ class APIFormWidget extends StatefulWidget {
Key? key, Key? key,
this.onSuccess, this.onSuccess,
this.fileField = "", this.fileField = "",
this.icon = FontAwesomeIcons.save, this.icon = FontAwesomeIcons.floppyDisk,
} }
) : super(key: key); ) : super(key: key);
@ -1025,7 +1031,7 @@ class _APIFormWidgetState extends State<APIFormWidget> {
), ),
), ),
leading: FaIcon( leading: FaIcon(
FontAwesomeIcons.exclamationCircle, FontAwesomeIcons.circleExclamation,
color: COLOR_DANGER color: COLOR_DANGER
), ),
) )

View File

@ -105,7 +105,7 @@ class BarcodeHandler {
showSnackIcon( showSnackIcon(
L10().barcodeError, L10().barcodeError,
icon: FontAwesomeIcons.exclamationCircle, icon: FontAwesomeIcons.circleExclamation,
success: false success: false
); );
@ -179,7 +179,7 @@ class BarcodeScanHandler extends BarcodeHandler {
showSnackIcon( showSnackIcon(
L10().barcodeNoMatch, L10().barcodeNoMatch,
icon: FontAwesomeIcons.exclamationCircle, icon: FontAwesomeIcons.circleExclamation,
success: false, success: false,
); );
} }

View File

@ -74,6 +74,6 @@ Future<void> playAudioFile(String path) async {
return; return;
} }
final player = AudioCache(); final player = AudioPlayer();
player.play(path); player.play(AssetSource(path));
} }

View File

@ -223,8 +223,9 @@ class InvenTreeModel {
Future <void> goToInvenTreePage() async { Future <void> goToInvenTreePage() async {
if (await canLaunch(webUrl)) { var uri = Uri.tryParse(webUrl);
await launch(webUrl); if (uri != null && await canLaunchUrl(uri)) {
await launchUrl(uri);
} else { } else {
// TODO // TODO
} }
@ -233,9 +234,9 @@ class InvenTreeModel {
Future <void> openLink() async { Future <void> openLink() async {
if (link.isNotEmpty) { if (link.isNotEmpty) {
var uri = Uri.tryParse(link);
if (await canLaunch(link)) { if (uri != null && await canLaunchUrl(uri)) {
await launch(link); await launchUrl(uri);
} }
} }
} }
@ -799,7 +800,7 @@ class InvenTreeAttachment extends InvenTreeModel {
} }
} }
return FontAwesomeIcons.fileAlt; return FontAwesomeIcons.fileLines;
} }
String get comment => (jsondata["comment"] ?? "") as String; String get comment => (jsondata["comment"] ?? "") as String;

View File

@ -37,7 +37,7 @@ Future<Map<String, dynamic>> getDeviceInfo() async {
"model": androidDeviceInfo.model, "model": androidDeviceInfo.model,
"device": androidDeviceInfo.device, "device": androidDeviceInfo.device,
"id": androidDeviceInfo.id, "id": androidDeviceInfo.id,
"androidId": androidDeviceInfo.androidId, "androidId": androidDeviceInfo.id,
"brand": androidDeviceInfo.brand, "brand": androidDeviceInfo.brand,
"display": androidDeviceInfo.display, "display": androidDeviceInfo.display,
"hardware": androidDeviceInfo.hardware, "hardware": androidDeviceInfo.hardware,
@ -202,6 +202,7 @@ Future<void> sentryReportError(String source, dynamic error, dynamic stackTrace,
Sentry.captureException(error, stackTrace: stackTrace).catchError((error) { Sentry.captureException(error, stackTrace: stackTrace).catchError((error) {
print("Error uploading information to Sentry.io:"); print("Error uploading information to Sentry.io:");
print(error); print(error);
return SentryId.empty();
}).then((response) { }).then((response) {
print("Uploaded information to Sentry.io : ${response.toString()}"); print("Uploaded information to Sentry.io : ${response.toString()}");
}); });

View File

@ -39,27 +39,36 @@ class InvenTreeAboutWidget extends StatelessWidget {
Future <void> _openDocs() async { Future <void> _openDocs() async {
const String docsUrl = "https://inventree.readthedocs.io/en/latest/app/app/"; var docsUrl = Uri(
scheme: "https",
host: "inventree.readthedocs.io",
path: "en/latest/app/app/");
if (await canLaunch(docsUrl)) { if (await canLaunchUrl(docsUrl)) {
await launch(docsUrl); await launchUrl(docsUrl);
} }
} }
Future <void> _reportBug(BuildContext context) async { Future <void> _reportBug(BuildContext context) async {
const String url = "https://github.com/inventree/inventree-app/issues/new?title=Enter+bug+description"; var url = Uri(
scheme: "https",
host: "github.com",
path: "inventree/inventree-app/issues/new?title=Enter+bug+description");
if (await canLaunch(url)) { if (await canLaunchUrl(url)) {
await launch(url); await launchUrl(url);
} }
} }
Future <void> _translate() async { Future <void> _translate() async {
const String url = "https://crowdin.com/project/inventree"; var url = Uri(
scheme: "https",
host: "crowdin.com",
path: "/project/inventree");
if (await canLaunch(url)) { if (await canLaunchUrl(url)) {
await launch(url); await launchUrl(url);
} }
} }
@ -83,7 +92,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
title: Text(L10().address), title: Text(L10().address),
subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected), subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected),
leading: FaIcon(FontAwesomeIcons.globe), leading: FaIcon(FontAwesomeIcons.globe),
trailing: InvenTreeAPI().isConnected() ? FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.timesCircle, color: COLOR_DANGER), trailing: InvenTreeAPI().isConnected() ? FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_SUCCESS) : FaIcon(FontAwesomeIcons.circleXmark, color: COLOR_DANGER),
) )
); );
@ -91,7 +100,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
ListTile( ListTile(
title: Text(L10().version), title: Text(L10().version),
subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : L10().notConnected), subtitle: Text(InvenTreeAPI().version.isNotEmpty ? InvenTreeAPI().version : L10().notConnected),
leading: FaIcon(FontAwesomeIcons.infoCircle), leading: FaIcon(FontAwesomeIcons.circleInfo),
) )
); );
@ -122,7 +131,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
L10().serverNotConnected, L10().serverNotConnected,
style: TextStyle(fontStyle: FontStyle.italic), style: TextStyle(fontStyle: FontStyle.italic),
), ),
leading: FaIcon(FontAwesomeIcons.exclamationCircle) leading: FaIcon(FontAwesomeIcons.circleExclamation)
) )
); );
} }
@ -148,7 +157,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
ListTile( ListTile(
title: Text(L10().version), title: Text(L10().version),
subtitle: Text("${info.version} - Build ${info.buildNumber}"), subtitle: Text("${info.version} - Build ${info.buildNumber}"),
leading: FaIcon(FontAwesomeIcons.infoCircle) leading: FaIcon(FontAwesomeIcons.circleInfo)
) )
); );
@ -156,7 +165,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
ListTile( ListTile(
title: Text(L10().releaseNotes), title: Text(L10().releaseNotes),
subtitle: Text(L10().appReleaseNotes), subtitle: Text(L10().appReleaseNotes),
leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK),
onTap: () { onTap: () {
_releaseNotes(context); _releaseNotes(context);
}, },

View File

@ -81,7 +81,7 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
L10().languageSelect, L10().languageSelect,
"", "",
fields, fields,
icon: FontAwesomeIcons.checkCircle, icon: FontAwesomeIcons.circleCheck,
onSuccess: (Map<String, dynamic> data) async { onSuccess: (Map<String, dynamic> data) async {
String locale_name = (data["locale"] ?? "") as String; String locale_name = (data["locale"] ?? "") as String;
@ -130,7 +130,7 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
L10().sounds, L10().sounds,
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
), ),
leading: FaIcon(FontAwesomeIcons.volumeUp), leading: FaIcon(FontAwesomeIcons.volumeHigh),
), ),
ListTile( ListTile(
title: Text(L10().serverError), title: Text(L10().serverError),

View File

@ -74,7 +74,7 @@ class _HomeScreenSettingsState extends State<HomeScreenSettingsWidget> {
ListTile( ListTile(
title: Text(L10().homeShowPo), title: Text(L10().homeShowPo),
subtitle: Text(L10().homeShowPoDescription), subtitle: Text(L10().homeShowPoDescription),
leading: FaIcon(FontAwesomeIcons.shoppingCart), leading: FaIcon(FontAwesomeIcons.cartShopping),
trailing: Switch( trailing: Switch(
value: homeShowPo, value: homeShowPo,
onChanged: (bool value) { onChanged: (bool value) {

View File

@ -100,7 +100,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
// Selected, but (for some reason) not the same as the API... // Selected, but (for some reason) not the same as the API...
if ((InvenTreeAPI().profile?.key ?? "") != profile.key) { if ((InvenTreeAPI().profile?.key ?? "") != profile.key) {
return FaIcon( return FaIcon(
FontAwesomeIcons.questionCircle, FontAwesomeIcons.circleQuestion,
color: COLOR_WARNING color: COLOR_WARNING
); );
} }
@ -108,7 +108,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
// Reflect the connection status of the server // Reflect the connection status of the server
if (InvenTreeAPI().isConnected()) { if (InvenTreeAPI().isConnected()) {
return FaIcon( return FaIcon(
FontAwesomeIcons.checkCircle, FontAwesomeIcons.circleCheck,
color: COLOR_SUCCESS color: COLOR_SUCCESS
); );
} else if (InvenTreeAPI().isConnecting()) { } else if (InvenTreeAPI().isConnecting()) {
@ -118,7 +118,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
); );
} else { } else {
return FaIcon( return FaIcon(
FontAwesomeIcons.timesCircle, FontAwesomeIcons.circleXmark,
color: COLOR_DANGER, color: COLOR_DANGER,
); );
} }
@ -167,7 +167,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
}, },
child: ListTile( child: ListTile(
title: Text(L10().profileEdit), title: Text(L10().profileEdit),
leading: FaIcon(FontAwesomeIcons.edit) leading: FaIcon(FontAwesomeIcons.penToSquare)
) )
), ),
SimpleDialogOption( SimpleDialogOption(
@ -184,7 +184,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
}, },
child: ListTile( child: ListTile(
title: Text(L10().profileDelete), title: Text(L10().profileDelete),
leading: FaIcon(FontAwesomeIcons.trashAlt), leading: FaIcon(FontAwesomeIcons.trashCan),
) )
) )
], ],
@ -209,7 +209,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
title: Text(L10().profileSelect), title: Text(L10().profileSelect),
actions: [ actions: [
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.plusCircle), icon: FaIcon(FontAwesomeIcons.circlePlus),
onPressed: () { onPressed: () {
_editProfile(context, createNew: true); _editProfile(context, createNew: true);
}, },
@ -259,7 +259,7 @@ class _ProfileEditState extends State<ProfileEditWidget> {
title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit),
actions: [ actions: [
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.save), icon: FaIcon(FontAwesomeIcons.floppyDisk),
onPressed: () async { onPressed: () async {
if (formKey.currentState!.validate()) { if (formKey.currentState!.validate()) {
formKey.currentState!.save(); formKey.currentState!.save();

View File

@ -47,7 +47,7 @@ class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> {
ListTile( ListTile(
title: Text(L10().parameters), title: Text(L10().parameters),
subtitle: Text(L10().parametersSettingDetail), subtitle: Text(L10().parametersSettingDetail),
leading: FaIcon(FontAwesomeIcons.thList), leading: FaIcon(FontAwesomeIcons.tableList),
trailing: Switch( trailing: Switch(
value: partShowParameters, value: partShowParameters,
onChanged: (bool value) { onChanged: (bool value) {
@ -75,7 +75,7 @@ class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> {
ListTile( ListTile(
title: Text(L10().stockItemHistory), title: Text(L10().stockItemHistory),
subtitle: Text(L10().stockItemHistoryDetail), subtitle: Text(L10().stockItemHistoryDetail),
leading: FaIcon(FontAwesomeIcons.history), leading: FaIcon(FontAwesomeIcons.clockRotateLeft),
trailing: Switch( trailing: Switch(
value: stockShowHistory, value: stockShowHistory,
onChanged: (bool value) { onChanged: (bool value) {

View File

@ -45,7 +45,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
ListTile( ListTile(
title: Text(L10().homeScreen), title: Text(L10().homeScreen),
subtitle: Text(L10().homeScreenSettings), subtitle: Text(L10().homeScreenSettings),
leading: FaIcon(FontAwesomeIcons.home, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.house, color: COLOR_CLICK),
onTap: () { onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget()));
} }
@ -53,7 +53,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
ListTile( ListTile(
title: Text(L10().appSettings), title: Text(L10().appSettings),
subtitle: Text(L10().appSettingsDetails), subtitle: Text(L10().appSettingsDetails),
leading: FaIcon(FontAwesomeIcons.cogs, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_CLICK),
onTap: () { onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget()));
} }

View File

@ -103,7 +103,7 @@ class UserProfileDBManager {
debug("Adding new profile: '${profile.name}'"); debug("Adding new profile: '${profile.name}'");
} }
int key = await store.add(await _db, profile.toJson()) as int; int? key = await store.add(await _db, profile.toJson()) as int?;
// Record the key // Record the key
profile.key = key; profile.key = key;
@ -156,8 +156,8 @@ class UserProfileDBManager {
if (profiles[idx].key is int && profiles[idx].key == selected) { if (profiles[idx].key is int && profiles[idx].key == selected) {
return UserProfile.fromJson( return UserProfile.fromJson(
profiles[idx].key as int, profiles[idx].key! as int,
profiles[idx].value as Map<String, dynamic>, profiles[idx].value! as Map<String, dynamic>,
profiles[idx].key == selected, profiles[idx].key == selected,
); );
} }
@ -182,8 +182,8 @@ class UserProfileDBManager {
if (profiles[idx].key is int) { if (profiles[idx].key is int) {
profileList.add( profileList.add(
UserProfile.fromJson( UserProfile.fromJson(
profiles[idx].key as int, profiles[idx].key! as int,
profiles[idx].value as Map<String, dynamic>, profiles[idx].value! as Map<String, dynamic>,
profiles[idx].key == selected, profiles[idx].key == selected,
) )
); );

View File

@ -54,7 +54,7 @@ class _AttachmentWidgetState extends RefreshableState<AttachmentWidget> {
// File upload // File upload
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.plusCircle), icon: FaIcon(FontAwesomeIcons.circlePlus),
onPressed: () async { onPressed: () async {
FilePickerDialog.pickFile( FilePickerDialog.pickFile(
onPicked: (File file) async { onPicked: (File file) async {
@ -117,7 +117,7 @@ class _AttachmentWidgetState extends RefreshableState<AttachmentWidget> {
}, },
child: ListTile( child: ListTile(
title: Text(L10().delete), title: Text(L10().delete),
leading: FaIcon(FontAwesomeIcons.trashAlt), leading: FaIcon(FontAwesomeIcons.trashCan),
) )
) )
] ]
@ -187,8 +187,9 @@ class _AttachmentWidgetState extends RefreshableState<AttachmentWidget> {
subtitle: Text(attachment.comment), subtitle: Text(attachment.comment),
leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK),
onTap: () async { onTap: () async {
if (await canLaunch(attachment.link)) { var uri = Uri.tryParse(attachment.link.trimLeft());
await launch(attachment.link); if (uri != null && await canLaunchUrl(uri)) {
await launchUrl(uri);
} }
}, },
onLongPress: () { onLongPress: () {

View File

@ -43,7 +43,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
if ((widget.category != null) && InvenTreeAPI().checkPermission("part_category", "change")) { if ((widget.category != null) && InvenTreeAPI().checkPermission("part_category", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
_editCategoryDialog(context); _editCategoryDialog(context);
@ -121,7 +121,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
title: Text(L10().parentCategory), title: Text(L10().parentCategory),
subtitle: Text("${widget.category?.parentPathString}"), subtitle: Text("${widget.category?.parentPathString}"),
leading: FaIcon( leading: FaIcon(
FontAwesomeIcons.levelUpAlt, FontAwesomeIcons.turnUp,
color: COLOR_CLICK, color: COLOR_CLICK,
), ),
onTap: () async { onTap: () async {
@ -338,7 +338,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
subtitle: Text( subtitle: Text(
L10().permissionAccountDenied, L10().permissionAccountDenied,
), ),
leading: FaIcon(FontAwesomeIcons.userTimes), leading: FaIcon(FontAwesomeIcons.userXmark),
) )
); );
} }

View File

@ -56,7 +56,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
editCompany(context); editCompany(context);
@ -203,7 +203,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().purchaseOrders), title: Text(L10().purchaseOrders),
leading: FaIcon(FontAwesomeIcons.shoppingCart, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_CLICK),
trailing: Text("${outstandingOrders.length}"), trailing: Text("${outstandingOrders.length}"),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -246,7 +246,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
if (widget.company.notes.isNotEmpty) { if (widget.company.notes.isNotEmpty) {
tiles.add(ListTile( tiles.add(ListTile(
title: Text(L10().notes), title: Text(L10().notes),
leading: FaIcon(FontAwesomeIcons.stickyNote), leading: FaIcon(FontAwesomeIcons.noteSticky),
onTap: null, onTap: null,
)); ));
} }

View File

@ -13,7 +13,7 @@ import "package:inventree/widget/snacks.dart";
/* /*
* Display a "confirmation" dialog allowing the user to accept or reject an action * Display a "confirmation" dialog allowing the user to accept or reject an action
*/ */
Future<void> confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { Future<void> confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.circleQuestion, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async {
String _accept = acceptText ?? L10().ok; String _accept = acceptText ?? L10().ok;
String _reject = rejectText ?? L10().cancel; String _reject = rejectText ?? L10().cancel;
@ -63,7 +63,7 @@ Future<void> confirmationDialog(String title, String text, {IconData icon = Font
* @description = Simple string description of error * @description = Simple string description of error
* @data = Error response (e.g from server) * @data = Error response (e.g from server)
*/ */
Future<void> showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.exclamationCircle, Function? onDismissed}) async { Future<void> showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.circleExclamation, Function? onDismissed}) async {
List<Widget> children = []; List<Widget> children = [];

View File

@ -96,7 +96,7 @@ class InvenTreeDrawer extends StatelessWidget {
context: context, context: context,
tiles: <Widget>[ tiles: <Widget>[
ListTile( ListTile(
leading: FaIcon(FontAwesomeIcons.home), leading: FaIcon(FontAwesomeIcons.house),
title: Text( title: Text(
L10().appTitle, L10().appTitle,
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
@ -110,7 +110,7 @@ class InvenTreeDrawer extends StatelessWidget {
), ),
ListTile( ListTile(
title: Text(L10().search), title: Text(L10().search),
leading: FaIcon(FontAwesomeIcons.search), leading: FaIcon(FontAwesomeIcons.magnifyingGlass),
onTap: _search, onTap: _search,
), ),
ListTile( ListTile(
@ -120,7 +120,7 @@ class InvenTreeDrawer extends StatelessWidget {
), ),
ListTile( ListTile(
title: Text(L10().about), title: Text(L10().about),
leading: FaIcon(FontAwesomeIcons.infoCircle), leading: FaIcon(FontAwesomeIcons.circleInfo),
onTap: _about, onTap: _about,
) )
] ]

View File

@ -80,7 +80,7 @@ class FilePickerDialog {
actions.add( actions.add(
SimpleDialogOption( SimpleDialogOption(
child: ListTile( child: ListTile(
leading: FaIcon(FontAwesomeIcons.fileUpload), leading: FaIcon(FontAwesomeIcons.fileArrowUp),
title: Text(allowFiles ? L10().selectFile : L10().selectImage), title: Text(allowFiles ? L10().selectFile : L10().selectImage),
), ),
onPressed: () async { onPressed: () async {

View File

@ -237,7 +237,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
if (!allowed) { if (!allowed) {
showSnackIcon( showSnackIcon(
L10().permissionRequired, L10().permissionRequired,
icon: FontAwesomeIcons.exclamationCircle, icon: FontAwesomeIcons.circleExclamation,
success: false, success: false,
); );
@ -295,7 +295,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
tiles.add(_listTile( tiles.add(_listTile(
context, context,
L10().stock, L10().stock,
FontAwesomeIcons.boxes, FontAwesomeIcons.boxesStacked,
callback: () { callback: () {
_showStock(context); _showStock(context);
} }
@ -306,7 +306,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
tiles.add(_listTile( tiles.add(_listTile(
context, context,
L10().purchaseOrders, L10().purchaseOrders,
FontAwesomeIcons.shoppingCart, FontAwesomeIcons.cartShopping,
callback: () { callback: () {
_showPurchaseOrders(context); _showPurchaseOrders(context);
} }
@ -358,7 +358,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
tiles.add(_listTile( tiles.add(_listTile(
context, context,
L10().settings, L10().settings,
FontAwesomeIcons.cogs, FontAwesomeIcons.gears,
callback: () { callback: () {
_showSettings(context); _showSettings(context);
} }
@ -377,7 +377,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
bool validAddress = serverAddress != null; bool validAddress = serverAddress != null;
bool connecting = !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting(); bool connecting = !InvenTreeAPI().isConnected() && InvenTreeAPI().isConnecting();
Widget leading = FaIcon(FontAwesomeIcons.exclamationCircle, color: COLOR_DANGER); Widget leading = FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_DANGER);
Widget trailing = FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK); Widget trailing = FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK);
String title = L10().serverNotConnected; String title = L10().serverNotConnected;
String subtitle = L10().profileSelectOrCreate; String subtitle = L10().profileSelectOrCreate;
@ -443,11 +443,11 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
List<BottomNavigationBarItem> items = <BottomNavigationBarItem>[ List<BottomNavigationBarItem> items = <BottomNavigationBarItem>[
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.home), icon: FaIcon(FontAwesomeIcons.house),
label: L10().home, label: L10().home,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.search), icon: FaIcon(FontAwesomeIcons.magnifyingGlass),
label: L10().search, label: L10().search,
), ),
]; ];

View File

@ -54,7 +54,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
if (InvenTreeAPI().supportsMixin("locate")) { if (InvenTreeAPI().supportsMixin("locate")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.searchLocation), icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation),
tooltip: L10().locateLocation, tooltip: L10().locateLocation,
onPressed: () async { onPressed: () async {
_locateStockLocation(context); _locateStockLocation(context);
@ -67,7 +67,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
if (InvenTreeAPI().checkPermission("stock_location", "change")) { if (InvenTreeAPI().checkPermission("stock_location", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { _editLocationDialog(context); }, onPressed: () { _editLocationDialog(context); },
) )
@ -202,7 +202,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
L10().stockTopLevel, L10().stockTopLevel,
style: TextStyle(fontStyle: FontStyle.italic) style: TextStyle(fontStyle: FontStyle.italic)
), ),
leading: FaIcon(FontAwesomeIcons.boxes), leading: FaIcon(FontAwesomeIcons.boxesStacked),
) )
); );
} else { } else {
@ -211,7 +211,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
ListTile( ListTile(
title: Text("${location!.name}"), title: Text("${location!.name}"),
subtitle: Text("${location!.description}"), subtitle: Text("${location!.description}"),
leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxes), leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxesStacked),
), ),
]; ];
@ -220,7 +220,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
ListTile( ListTile(
title: Text(L10().parentLocation), title: Text(L10().parentLocation),
subtitle: Text("${location!.parentPathString}"), subtitle: Text("${location!.parentPathString}"),
leading: FaIcon(FontAwesomeIcons.levelUpAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_CLICK),
onTap: () async { onTap: () async {
int parentId = location?.parentId ?? -1; int parentId = location?.parentId ?? -1;
@ -261,7 +261,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
label: L10().details, label: L10().details,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.boxes), icon: FaIcon(FontAwesomeIcons.boxesStacked),
label: L10().stock, label: L10().stock,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
@ -379,7 +379,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
title: Text(L10().locationCreate), title: Text(L10().locationCreate),
subtitle: Text(L10().locationCreateDetail), subtitle: Text(L10().locationCreateDetail),
leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK),
trailing: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK),
onTap: () async { onTap: () async {
_newLocation(context); _newLocation(context);
}, },
@ -390,8 +390,8 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
ListTile( ListTile(
title: Text(L10().stockItemCreate), title: Text(L10().stockItemCreate),
subtitle: Text(L10().stockItemCreateDetail), subtitle: Text(L10().stockItemCreateDetail),
leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK),
trailing: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK),
onTap: () async { onTap: () async {
_newStockItem(context); _newStockItem(context);
}, },
@ -408,7 +408,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
ListTile( ListTile(
title: Text(L10().barcodeScanItem), title: Text(L10().barcodeScanItem),
subtitle: Text(L10().barcodeScanInItems), subtitle: Text(L10().barcodeScanInItems),
leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK),
trailing: Icon(Icons.qr_code, color: COLOR_CLICK), trailing: Icon(Icons.qr_code, color: COLOR_CLICK),
onTap: () { onTap: () {
@ -434,7 +434,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
ListTile( ListTile(
title: Text(L10().transferStockLocation), title: Text(L10().transferStockLocation),
subtitle: Text(L10().transferStockLocationDetail), subtitle: Text(L10().transferStockLocationDetail),
leading: FaIcon(FontAwesomeIcons.signInAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.rightToBracket, color: COLOR_CLICK),
trailing: Icon(Icons.qr_code, color: COLOR_CLICK), trailing: Icon(Icons.qr_code, color: COLOR_CLICK),
onTap: () { onTap: () {
var _loc = location; var _loc = location;

View File

@ -198,7 +198,7 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta
L10().filteringOptions, L10().filteringOptions,
"", "",
fields, fields,
icon: FontAwesomeIcons.checkCircle, icon: FontAwesomeIcons.circleCheck,
onSuccess: (Map<String, dynamic> data) async { onSuccess: (Map<String, dynamic> data) async {
// Extract data from the processed form // Extract data from the processed form
@ -417,7 +417,7 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta
), ),
trailing: GestureDetector( trailing: GestureDetector(
child: FaIcon( child: FaIcon(
searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft,
color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_CLICK, color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_CLICK,
), ),
onTap: () { onTap: () {
@ -454,7 +454,7 @@ class NoResultsWidget extends StatelessWidget {
description, description,
style: TextStyle(fontStyle: FontStyle.italic), style: TextStyle(fontStyle: FontStyle.italic),
), ),
leading: FaIcon(FontAwesomeIcons.exclamationCircle, color: COLOR_WARNING), leading: FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_WARNING),
); );
} }

View File

@ -85,7 +85,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
if (InvenTreeAPI().checkPermission("part", "change")) { if (InvenTreeAPI().checkPermission("part", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
_editPartDialog(context); _editPartDialog(context);
@ -304,7 +304,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
) )
), ),
leading: FaIcon( leading: FaIcon(
FontAwesomeIcons.exclamationCircle, FontAwesomeIcons.circleExclamation,
color: COLOR_DANGER color: COLOR_DANGER
), ),
) )
@ -395,7 +395,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
ListTile( ListTile(
title: Text(L10().availableStock), title: Text(L10().availableStock),
subtitle: Text(L10().stockDetails), subtitle: Text(L10().stockDetails),
leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK),
trailing: Text( trailing: Text(
part.stockString(), part.stockString(),
style: TextStyle( style: TextStyle(
@ -418,7 +418,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
ListTile( ListTile(
title: Text(L10().onOrder), title: Text(L10().onOrder),
subtitle: Text(L10().onOrderDetails), subtitle: Text(L10().onOrderDetails),
leading: FaIcon(FontAwesomeIcons.shoppingCart), leading: FaIcon(FontAwesomeIcons.cartShopping),
trailing: Text("${part.onOrderString}"), trailing: Text("${part.onOrderString}"),
onTap: () { onTap: () {
// TODO - Order views // TODO - Order views
@ -435,7 +435,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().billOfMaterials), title: Text(L10().billOfMaterials),
leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK),
trailing: Text(bomCount.toString()), trailing: Text(bomCount.toString()),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -453,7 +453,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().building), title: Text(L10().building),
leading: FaIcon(FontAwesomeIcons.tools), leading: FaIcon(FontAwesomeIcons.screwdriverWrench),
trailing: Text("${simpleNumberString(part.building)}"), trailing: Text("${simpleNumberString(part.building)}"),
onTap: () { onTap: () {
// TODO // TODO
@ -548,7 +548,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().parameters), title: Text(L10().parameters),
leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK),
trailing: parameterCount > 0 ? Text(parameterCount.toString()) : null, trailing: parameterCount > 0 ? Text(parameterCount.toString()) : null,
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -566,7 +566,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().notes), title: Text(L10().notes),
leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK),
trailing: Text(""), trailing: Text(""),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -580,7 +580,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().attachments), title: Text(L10().attachments),
leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK),
trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null,
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -749,11 +749,11 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
onTap: onTabSelectionChanged, onTap: onTabSelectionChanged,
items: <BottomNavigationBarItem> [ items: <BottomNavigationBarItem> [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.infoCircle), icon: FaIcon(FontAwesomeIcons.circleInfo),
label: L10().details, label: L10().details,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.boxes), icon: FaIcon(FontAwesomeIcons.boxesStacked),
label: L10().stock label: L10().stock
), ),
BottomNavigationBarItem( BottomNavigationBarItem(

View File

@ -47,7 +47,7 @@ class _PartImageState extends RefreshableState<PartImageWidget> {
// File upload // File upload
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.fileUpload), icon: FaIcon(FontAwesomeIcons.fileArrowUp),
onPressed: () async { onPressed: () async {
FilePickerDialog.pickFile( FilePickerDialog.pickFile(

View File

@ -40,7 +40,7 @@ class _PartNotesState extends RefreshableState<PartNotesWidget> {
if (InvenTreeAPI().checkPermission("part", "change")) { if (InvenTreeAPI().checkPermission("part", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
part.editForm( part.editForm(

View File

@ -52,7 +52,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
if (InvenTreeAPI().checkPermission("purchase_order", "change")) { if (InvenTreeAPI().checkPermission("purchase_order", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
editOrder(context); editOrder(context);
@ -174,7 +174,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
tiles.add(ListTile( tiles.add(ListTile(
title: Text(L10().issueDate), title: Text(L10().issueDate),
subtitle: Text(order.issueDate), subtitle: Text(order.issueDate),
leading: FaIcon(FontAwesomeIcons.calendarAlt), leading: FaIcon(FontAwesomeIcons.calendarDays),
)); ));
} }
@ -182,7 +182,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
tiles.add(ListTile( tiles.add(ListTile(
title: Text(L10().targetDate), title: Text(L10().targetDate),
subtitle: Text(order.targetDate), subtitle: Text(order.targetDate),
leading: FaIcon(FontAwesomeIcons.calendarAlt), leading: FaIcon(FontAwesomeIcons.calendarDays),
)); ));
} }
@ -190,7 +190,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().attachments), title: Text(L10().attachments),
leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK),
trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null,
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -250,7 +250,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
order.receive_url, order.receive_url,
fields, fields,
method: "POST", method: "POST",
icon: FontAwesomeIcons.signInAlt, icon: FontAwesomeIcons.rightToBracket,
onSuccess: (data) async { onSuccess: (data) async {
showSnackIcon(L10().receivedItem, success: true); showSnackIcon(L10().receivedItem, success: true);
refresh(context); refresh(context);
@ -293,7 +293,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
}, },
child: ListTile( child: ListTile(
title: Text(L10().receiveItem), title: Text(L10().receiveItem),
leading: FaIcon(FontAwesomeIcons.signInAlt), leading: FaIcon(FontAwesomeIcons.rightToBracket),
) )
) )
); );
@ -411,11 +411,11 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
label: L10().details label: L10().details
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.thList), icon: FaIcon(FontAwesomeIcons.tableList),
label: L10().lineItems, label: L10().lineItems,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.boxes), icon: FaIcon(FontAwesomeIcons.boxesStacked),
label: L10().stockItems label: L10().stockItems
) )
], ],

View File

@ -75,7 +75,7 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> with
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance?.addPostFrameCallback((_) => onBuild(_context!)); WidgetsBinding.instance.addPostFrameCallback((_) => onBuild(_context!));
} }
// Function called after the widget is first build // Function called after the widget is first build

View File

@ -263,7 +263,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
), ),
trailing: GestureDetector( trailing: GestureDetector(
child: FaIcon( child: FaIcon(
searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft,
color: searchController.text.isEmpty ? COLOR_CLICK : COLOR_DANGER, color: searchController.text.isEmpty ? COLOR_CLICK : COLOR_DANGER,
), ),
onTap: () { onTap: () {
@ -331,7 +331,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
results.add( results.add(
ListTile( ListTile(
title: Text(L10().stockItems), title: Text(L10().stockItems),
leading: FaIcon(FontAwesomeIcons.boxes), leading: FaIcon(FontAwesomeIcons.boxesStacked),
trailing: Text("${nStockResults}"), trailing: Text("${nStockResults}"),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -354,7 +354,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
results.add( results.add(
ListTile( ListTile(
title: Text(L10().stockLocations), title: Text(L10().stockLocations),
leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), leading: FaIcon(FontAwesomeIcons.locationDot),
trailing: Text("${nLocationResults}"), trailing: Text("${nLocationResults}"),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -402,7 +402,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
results.add( results.add(
ListTile( ListTile(
title: Text(L10().purchaseOrders), title: Text(L10().purchaseOrders),
leading: FaIcon(FontAwesomeIcons.shoppingCart), leading: FaIcon(FontAwesomeIcons.cartShopping),
trailing: Text("${nPurchaseOrderResults}"), trailing: Text("${nPurchaseOrderResults}"),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -424,7 +424,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().searching), title: Text(L10().searching),
leading: FaIcon(FontAwesomeIcons.search), leading: FaIcon(FontAwesomeIcons.magnifyingGlass),
trailing: CircularProgressIndicator(), trailing: CircularProgressIndicator(),
) )
); );
@ -437,7 +437,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
L10().queryNoResults, L10().queryNoResults,
style: TextStyle(fontStyle: FontStyle.italic), style: TextStyle(fontStyle: FontStyle.italic),
), ),
leading: FaIcon(FontAwesomeIcons.searchMinus), leading: FaIcon(FontAwesomeIcons.magnifyingGlassMinus),
) )
); );
} else { } else {

View File

@ -32,14 +32,14 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc
// Select an icon if we do not have an action // Select an icon if we do not have an action
if (icon == null && onAction == null) { if (icon == null && onAction == null) {
icon = FontAwesomeIcons.checkCircle; icon = FontAwesomeIcons.circleCheck;
} }
} else if (success != null && success == false) { } else if (success != null && success == false) {
backgroundColor = Colors.deepOrange; backgroundColor = Colors.deepOrange;
if (icon == null && onAction == null) { if (icon == null && onAction == null) {
icon = FontAwesomeIcons.exclamationCircle; icon = FontAwesomeIcons.circleExclamation;
} }
} }

View File

@ -63,7 +63,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
if (InvenTreeAPI().supportsMixin("locate")) { if (InvenTreeAPI().supportsMixin("locate")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.searchLocation), icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation),
tooltip: L10().locateItem, tooltip: L10().locateItem,
onPressed: () async { onPressed: () async {
InvenTreeAPI().locateItemOrLocation(context, item: widget.item.pk); InvenTreeAPI().locateItemOrLocation(context, item: widget.item.pk);
@ -75,7 +75,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
if (InvenTreeAPI().checkPermission("stock", "change")) { if (InvenTreeAPI().checkPermission("stock", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { _editStockItem(context); }, onPressed: () { _editStockItem(context); },
) )
@ -189,7 +189,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
confirmationDialog( confirmationDialog(
L10().stockItemDelete, L10().stockItemDelete,
L10().stockItemDeleteConfirm, L10().stockItemDeleteConfirm,
icon: FontAwesomeIcons.trashAlt, icon: FontAwesomeIcons.trashCan,
onAccept: () async { onAccept: () async {
final bool result = await widget.item.delete(); final bool result = await widget.item.delete();
@ -337,7 +337,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
InvenTreeStockItem.addStockUrl(), InvenTreeStockItem.addStockUrl(),
fields, fields,
method: "POST", method: "POST",
icon: FontAwesomeIcons.plusCircle, icon: FontAwesomeIcons.circlePlus,
onSuccess: (data) async { onSuccess: (data) async {
_stockUpdateMessage(true); _stockUpdateMessage(true);
refresh(context); refresh(context);
@ -378,7 +378,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
InvenTreeStockItem.removeStockUrl(), InvenTreeStockItem.removeStockUrl(),
fields, fields,
method: "POST", method: "POST",
icon: FontAwesomeIcons.minusCircle, icon: FontAwesomeIcons.circleMinus,
onSuccess: (data) async { onSuccess: (data) async {
_stockUpdateMessage(true); _stockUpdateMessage(true);
refresh(context); refresh(context);
@ -527,7 +527,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
title: Text(L10().stockLocation), title: Text(L10().stockLocation),
subtitle: Text("${widget.item.locationPathString}"), subtitle: Text("${widget.item.locationPathString}"),
leading: FaIcon( leading: FaIcon(
FontAwesomeIcons.mapMarkerAlt, FontAwesomeIcons.locationDot,
color: COLOR_CLICK, color: COLOR_CLICK,
), ),
onTap: () async { onTap: () async {
@ -549,7 +549,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().stockLocation), title: Text(L10().stockLocation),
leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), leading: FaIcon(FontAwesomeIcons.locationDot),
subtitle: Text(L10().locationNotSet), subtitle: Text(L10().locationNotSet),
) )
); );
@ -587,7 +587,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().inProduction), title: Text(L10().inProduction),
leading: FaIcon(FontAwesomeIcons.tools), leading: FaIcon(FontAwesomeIcons.screwdriverWrench),
subtitle: Text(L10().inProductionDetail), subtitle: Text(L10().inProductionDetail),
onTap: () { onTap: () {
// TODO: Click through to the "build order" // TODO: Click through to the "build order"
@ -623,7 +623,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
ListTile( ListTile(
title: Text(L10().lastUpdated), title: Text(L10().lastUpdated),
subtitle: Text(widget.item.updatedDateString), subtitle: Text(widget.item.updatedDateString),
leading: FaIcon(FontAwesomeIcons.calendarAlt) leading: FaIcon(FontAwesomeIcons.calendarDays)
) )
); );
} }
@ -634,7 +634,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
ListTile( ListTile(
title: Text(L10().lastStocktake), title: Text(L10().lastStocktake),
subtitle: Text(widget.item.stocktakeDateString), subtitle: Text(widget.item.stocktakeDateString),
leading: FaIcon(FontAwesomeIcons.calendarAlt) leading: FaIcon(FontAwesomeIcons.calendarDays)
) )
); );
} }
@ -655,7 +655,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().testResults), title: Text(L10().testResults),
leading: FaIcon(FontAwesomeIcons.tasks, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.listCheck, color: COLOR_CLICK),
trailing: Text("${widget.item.testResultCount}"), trailing: Text("${widget.item.testResultCount}"),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -686,7 +686,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().history), title: Text(L10().history),
leading: FaIcon(FontAwesomeIcons.history, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.clockRotateLeft, color: COLOR_CLICK),
trailing: Text("${widget.item.trackingItemCount}"), trailing: Text("${widget.item.trackingItemCount}"),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -705,7 +705,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().notes), title: Text(L10().notes),
leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
@ -718,7 +718,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().attachments), title: Text(L10().attachments),
leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK),
trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null, trailing: attachmentCount > 0 ? Text(attachmentCount.toString()) : null,
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -747,7 +747,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().permissionRequired), title: Text(L10().permissionRequired),
leading: FaIcon(FontAwesomeIcons.userTimes) leading: FaIcon(FontAwesomeIcons.userXmark)
) )
); );
@ -765,7 +765,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().countStock), title: Text(L10().countStock),
leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_CLICK),
onTap: _countStockDialog, onTap: _countStockDialog,
trailing: Text(widget.item.quantityString(includeUnits: true)), trailing: Text(widget.item.quantityString(includeUnits: true)),
) )
@ -774,7 +774,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().removeStock), title: Text(L10().removeStock),
leading: FaIcon(FontAwesomeIcons.minusCircle, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.circleMinus, color: COLOR_CLICK),
onTap: _removeStockDialog, onTap: _removeStockDialog,
) )
); );
@ -782,7 +782,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().addStock), title: Text(L10().addStock),
leading: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK),
onTap: _addStockDialog, onTap: _addStockDialog,
) )
); );
@ -792,7 +792,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
ListTile( ListTile(
title: Text(L10().transferStock), title: Text(L10().transferStock),
subtitle: Text(L10().transferStockDetail), subtitle: Text(L10().transferStockDetail),
leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK),
onTap: () { _transferStockDialog(context); }, onTap: () { _transferStockDialog(context); },
) )
); );
@ -802,7 +802,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
ListTile( ListTile(
title: Text(L10().scanIntoLocation), title: Text(L10().scanIntoLocation),
subtitle: Text(L10().scanIntoLocationDetail), subtitle: Text(L10().scanIntoLocationDetail),
leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK),
trailing: Icon(Icons.qr_code_scanner), trailing: Icon(Icons.qr_code_scanner),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -850,7 +850,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text("Delete Stock Item"), title: Text("Delete Stock Item"),
leading: FaIcon(FontAwesomeIcons.trashAlt, color: COLOR_DANGER), leading: FaIcon(FontAwesomeIcons.trashCan, color: COLOR_DANGER),
onTap: () { onTap: () {
_deleteItem(context); _deleteItem(context);
}, },
@ -868,7 +868,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
onTap: onTabSelectionChanged, onTap: onTabSelectionChanged,
items: <BottomNavigationBarItem> [ items: <BottomNavigationBarItem> [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.infoCircle), icon: FaIcon(FontAwesomeIcons.circleInfo),
label: L10().details, label: L10().details,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(

View File

@ -34,7 +34,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
List<Widget> getAppBarActions(BuildContext context) { List<Widget> getAppBarActions(BuildContext context) {
return [ return [
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.plusCircle), icon: FaIcon(FontAwesomeIcons.circlePlus),
onPressed: () { onPressed: () {
addTestResult(context); addTestResult(context);
} }
@ -158,7 +158,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
String _value = ""; String _value = "";
String _notes = ""; String _notes = "";
FaIcon _icon = FaIcon(FontAwesomeIcons.questionCircle, color: COLOR_BLUE); FaIcon _icon = FaIcon(FontAwesomeIcons.circleQuestion, color: COLOR_BLUE);
bool _valueRequired = false; bool _valueRequired = false;
bool _attachmentRequired = false; bool _attachmentRequired = false;
@ -179,11 +179,11 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
} }
if (_result == true) { if (_result == true) {
_icon = FaIcon(FontAwesomeIcons.checkCircle, _icon = FaIcon(FontAwesomeIcons.circleCheck,
color: COLOR_SUCCESS, color: COLOR_SUCCESS,
); );
} else if (_result == false) { } else if (_result == false) {
_icon = FaIcon(FontAwesomeIcons.timesCircle, _icon = FaIcon(FontAwesomeIcons.circleXmark,
color: COLOR_DANGER, color: COLOR_DANGER,
); );
} }

View File

@ -43,7 +43,7 @@ class _StockNotesState extends RefreshableState<StockNotesWidget> {
if (InvenTreeAPI().checkPermission("stock", "change")) { if (InvenTreeAPI().checkPermission("stock", "change")) {
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
item.editForm( item.editForm(

View File

@ -43,7 +43,7 @@ class _SupplierPartDisplayState extends RefreshableState<SupplierPartDetailWidge
actions.add( actions.add(
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.edit), icon: FaIcon(FontAwesomeIcons.penToSquare),
tooltip: L10().edit, tooltip: L10().edit,
onPressed: () { onPressed: () {
editSupplierPart(context); editSupplierPart(context);
@ -158,8 +158,9 @@ class _SupplierPartDisplayState extends RefreshableState<SupplierPartDetailWidge
title: Text(widget.supplierPart.link), title: Text(widget.supplierPart.link),
leading: FaIcon(FontAwesomeIcons.link), leading: FaIcon(FontAwesomeIcons.link),
onTap: () async { onTap: () async {
if (await canLaunch(widget.supplierPart.link)) { var uri = Uri.tryParse(widget.supplierPart.link);
await launch(widget.supplierPart.link); if (uri != null && await canLaunchUrl(uri)) {
await launchUrl(uri);
} }
}, },
) )
@ -170,7 +171,7 @@ class _SupplierPartDisplayState extends RefreshableState<SupplierPartDetailWidge
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(widget.supplierPart.note), title: Text(widget.supplierPart.note),
leading: FaIcon(FontAwesomeIcons.pencilAlt), leading: FaIcon(FontAwesomeIcons.pencil),
) )
); );
} }
@ -224,7 +225,7 @@ class _SupplierPartDisplayState extends RefreshableState<SupplierPartDetailWidge
onTap: onTabSelectionChanged, onTap: onTabSelectionChanged,
items: [ items: [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.infoCircle), icon: FaIcon(FontAwesomeIcons.circle),
label: L10().details, label: L10().details,
), ),
BottomNavigationBarItem( BottomNavigationBarItem(

File diff suppressed because it is too large Load Diff

View File

@ -7,44 +7,43 @@ environment:
sdk: ">=2.16.0 <3.0.0" sdk: ">=2.16.0 <3.0.0"
dependencies: dependencies:
audioplayers: ^3.0.1 # Play audio files
audioplayers: ^0.20.1 # Play audio files
cached_network_image: ^3.2.0 # Download and cache remote images cached_network_image: ^3.2.0 # Download and cache remote images
camera: ^0.9.4 # Camera camera: ^0.10.3 # Camera
cupertino_icons: ^1.0.3 cupertino_icons: ^1.0.3
datetime_picker_formfield: ^2.0.0 # Date / time picker datetime_picker_formfield: ^2.0.0 # Date / time picker
device_info_plus: ^3.2.2 # Information about the device device_info_plus: ^8.0.0 # Information about the device
dropdown_search: ^0.6.3 # Dropdown autocomplete form fields dropdown_search: ^5.0.5 # Dropdown autocomplete form fields
file_picker: ^4.5.1 # Select files from the device file_picker: ^5.2.5 # Select files from the device
flutter: flutter:
sdk: flutter sdk: flutter
flutter_cache_manager: ^3.3.0 flutter_cache_manager: ^3.3.0
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
flutter_localized_locales: 2.0.3 flutter_localized_locales: ^2.0.4
flutter_markdown: ^0.6.9 # Rendering markdown flutter_markdown: ^0.6.13+1 # Rendering markdown
flutter_overlay_loader: ^2.0.0 # Overlay screen support flutter_overlay_loader: ^2.0.0 # Overlay screen support
font_awesome_flutter: ^9.1.0 # FontAwesome icon set font_awesome_flutter: ^10.3.0 # FontAwesome icon set
http: ^0.13.4 http: ^0.13.4
image_picker: ^0.8.3 # Select or take photos image_picker: ^0.8.6+1 # Select or take photos
infinite_scroll_pagination: ^3.1.0 # Let the server do all the work! infinite_scroll_pagination: ^3.1.0 # Let the server do all the work!
intl: ^0.17.0 intl: ^0.17.0
one_context: ^1.1.1 # Dialogs without requiring context one_context: ^2.1.0 # Dialogs without requiring context
open_file: ^3.2.1 # Open local files open_filex: ^4.3.2 # Open local files
package_info_plus: ^1.0.4 # App information introspection package_info_plus: ^3.0.2 # App information introspection
path: ^1.8.0 path: ^1.8.2
path_provider: ^2.0.2 # Local file storage path_provider: ^2.0.12 # Local file storage
qr_code_scanner: ^0.7.0 # Barcode scanning qr_code_scanner: ^1.0.1 # Barcode scanning
sembast: ^3.1.0+2 # NoSQL data storage sembast: ^3.4.0+6 # NoSQL data storage
sentry_flutter: ^6.4.0 # Error reporting sentry_flutter: ^6.19.0 # Error reporting
url_launcher: ^6.0.9 # Open link in system browser url_launcher: ^6.1.9 # Open link in system browser
dev_dependencies: dev_dependencies:
flutter_launcher_icons: ^0.9.0 flutter_launcher_icons: ^0.11.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
lint: ^1.8.0 lint: ^2.0.1
test: ^1.19.0 test: ^1.22.0
flutter_icons: flutter_icons:
android: true android: true

View File

@ -2,15 +2,18 @@
* Unit tests for the InvenTree API code * Unit tests for the InvenTree API code
*/ */
import "package:test/test.dart"; import "package:flutter_test/flutter_test.dart";
import "package:inventree/api.dart"; import "package:inventree/api.dart";
import "package:inventree/helpers.dart"; import "package:inventree/helpers.dart";
import "package:inventree/user_profile.dart"; import "package:inventree/user_profile.dart";
import "setup.dart";
void main() { void main() {
setupTestEnv();
setUp(() async { setUp(() async {

View File

@ -15,7 +15,11 @@ import "package:inventree/user_profile.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 "setup.dart";
void main() { void main() {
setupTestEnv();
// Connect to the server // Connect to the server
setUpAll(() async { setUpAll(() async {

View File

@ -9,8 +9,11 @@ import "package:inventree/user_profile.dart";
import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/model.dart";
import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/part.dart";
import "setup.dart";
void main() { void main() {
setupTestEnv();
setUp(() async { setUp(() async {
await UserProfileDBManager().addProfile(UserProfile( await UserProfileDBManager().addProfile(UserProfile(

View File

@ -2,10 +2,13 @@
* Unit tests for the preferences manager * Unit tests for the preferences manager
*/ */
import "package:test/test.dart"; import "package:flutter_test/flutter_test.dart";
import "package:inventree/preferences.dart"; import "package:inventree/preferences.dart";
import "setup.dart";
void main() { void main() {
setupTestEnv();
setUp(() async { setUp(() async {
}); });

22
test/setup.dart Normal file
View File

@ -0,0 +1,22 @@
import "package:flutter/services.dart";
import "package:flutter_test/flutter_test.dart";
// This is the same as the following issue except it keeps the http client
// TestWidgetsFlutterBinding.ensureInitialized();
class CustomBinding extends AutomatedTestWidgetsFlutterBinding {
@override
bool get overrideHttpClient => false;
}
void setupTestEnv() {
// Uses custom binding to not override the http client
CustomBinding();
// Mock the path provider
const MethodChannel channel = MethodChannel("plugins.flutter.io/path_provider");
TestDefaultBinaryMessengerBinding.instance?.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
return ".";
});
}

View File

@ -5,7 +5,10 @@
import "package:test/test.dart"; import "package:test/test.dart";
import "package:inventree/user_profile.dart"; import "package:inventree/user_profile.dart";
import "setup.dart";
void main() { void main() {
setupTestEnv();
setUp(() async { setUp(() async {
// Ensure we have a user profile available // Ensure we have a user profile available