diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml
index 4199cf28..abd2b882 100644
--- a/.github/workflows/android.yaml
+++ b/.github/workflows/android.yaml
@@ -14,21 +14,22 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Java
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v3
with:
- java-version: '12.x'
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup Flutter
- uses: subosito/flutter-action@v1
+ uses: subosito/flutter-action@v2
with:
- flutter-version: '2.10.3'
+ flutter-version: '3.7.3'
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
- gradle-version: 6.1.1
+ gradle-version: 7.6
- name: Collect Translation Files
run: |
cd lib/l10n
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index cf9e5a06..bc3be9c3 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -28,17 +28,18 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Java
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v3
with:
- java-version: '12.x'
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup Flutter
- uses: subosito/flutter-action@v1
+ uses: subosito/flutter-action@v2
with:
- flutter-version: '2.10.3'
+ flutter-version: '3.7.3'
- name: Collect Translation Files
run: |
cd lib/l10n
@@ -51,7 +52,7 @@ jobs:
flutter analyze
- name: Install Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Start InvenTree Server
diff --git a/.github/workflows/ios.yaml b/.github/workflows/ios.yaml
index abe8040a..b8afa474 100644
--- a/.github/workflows/ios.yaml
+++ b/.github/workflows/ios.yaml
@@ -14,17 +14,18 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Java
- uses: actions/setup-java@v1
- with:
- java-version: '12.x'
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup Flutter
- uses: subosito/flutter-action@v1
+ uses: subosito/flutter-action@v2
with:
- flutter-version: '2.10.3'
+ flutter-version: '3.7.3'
- name: Collect Translation Files
run: |
cd lib/l10n
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 29c06ebb..5e388c21 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -74,4 +74,6 @@ linter:
avoid_dynamic_calls: false
- avoid_classes_with_only_static_members: false
\ No newline at end of file
+ avoid_classes_with_only_static_members: false
+
+ no_leading_underscores_for_local_identifiers: false
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 6b6b83a7..b65c50a0 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
- compileSdkVersion 31
+ compileSdkVersion 33
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@@ -49,7 +49,7 @@ android {
defaultConfig {
applicationId "inventree.inventree_app"
minSdkVersion 25
- targetSdkVersion 31
+ targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
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.espresso:espresso-core:3.0.2'
androidTestImplementation 'com.android.support:multidex:2.0.1'
- implementation "androidx.core:core:1.5.0-rc01"
- implementation 'androidx.appcompat:appcompat:1.0.0'
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "androidx.core:core:1.9.0"
+ implementation 'androidx.appcompat:appcompat:1.6.0'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index cfb3762e..c852e9ec 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -31,10 +31,6 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
-
-
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
index af27b36c..a5b45642 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,14 +1,14 @@
buildscript {
- ext.kotlin_version = '1.5.10'
+ ext.kotlin_version = '1.8.10'
repositories {
google()
- jcenter()
+ mavenCentral()
}
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"
}
}
@@ -16,7 +16,7 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
}
}
diff --git a/android/gradle.properties b/android/gradle.properties
index 5f175379..615b166b 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
-android.enableR8=true
+android.enableD8=true
android.enableJetifier=true
android.useAndroidX=true
\ No newline at end of file
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 9b9d49f3..2b22d057 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
+networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
\ No newline at end of file
diff --git a/lib/api.dart b/lib/api.dart
index a0964416..6d06f7f9 100644
--- a/lib/api.dart
+++ b/lib/api.dart
@@ -8,7 +8,7 @@ import "package:intl/intl.dart";
import "package:inventree/app_colors.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:flutter/material.dart";
import "package:font_awesome_flutter/font_awesome_flutter.dart";
@@ -350,7 +350,7 @@ class InvenTreeAPI {
if (address.isEmpty || username.isEmpty || password.isEmpty) {
showSnackIcon(
L10().incompleteDetails,
- icon: FontAwesomeIcons.exclamationCircle,
+ icon: FontAwesomeIcons.circleExclamation,
success: false
);
return false;
@@ -507,7 +507,7 @@ class InvenTreeAPI {
showSnackIcon(
L10().profileSelect,
success: false,
- icon: FontAwesomeIcons.exclamationCircle
+ icon: FontAwesomeIcons.circleExclamation
);
return false;
}
@@ -731,7 +731,7 @@ class InvenTreeAPI {
await localFile.writeAsBytes(bytes);
if (openOnDownload) {
- OpenFile.open(local_path);
+ OpenFilex.open(local_path);
}
} else {
showStatusCodeError(url, response.statusCode);
@@ -1272,7 +1272,7 @@ class InvenTreeAPI {
return CachedNetworkImage(
imageUrl: url,
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(),
height: height,
width: width,
@@ -1369,7 +1369,7 @@ class InvenTreeAPI {
L10().locateLocation,
"",
fields,
- icon: FontAwesomeIcons.searchLocation,
+ icon: FontAwesomeIcons.magnifyingGlassLocation,
onSuccess: (Map data) async {
plugin_name = (data["plugin"] ?? "") as String;
}
diff --git a/lib/api_form.dart b/lib/api_form.dart
index e21eedbf..360617a4 100644
--- a/lib/api_form.dart
+++ b/lib/api_form.dart
@@ -415,7 +415,7 @@ class APIFormField {
controller: controller,
),
trailing: IconButton(
- icon: FaIcon(FontAwesomeIcons.plusCircle),
+ icon: FaIcon(FontAwesomeIcons.circlePlus),
onPressed: () async {
FilePickerDialog.pickFile(
message: L10().attachmentSelect,
@@ -436,26 +436,32 @@ class APIFormField {
// Field for selecting from multiple choice options
Widget _constructChoiceField() {
- dynamic _initial;
+ dynamic initial;
// Check if the current value is within the allowed values
for (var opt in choices) {
if (opt["value"] == value) {
- _initial = opt;
+ initial = opt;
break;
}
}
return DropdownSearch(
- mode: Mode.BOTTOM_SHEET,
- showSelectedItem: false,
- selectedItem: _initial,
+ popupProps: PopupProps.bottomSheet(
+ showSelectedItems: false,
+ searchFieldProps: TextFieldProps(
+ autofocus: true
+ )
+ ),
+ selectedItem: initial,
items: choices,
- label: label,
- hint: helpText,
+ dropdownDecoratorProps: DropDownDecoratorProps(
+ dropdownSearchDecoration: InputDecoration(
+ labelText: label,
+ hintText: helpText,
+ )),
onChanged: null,
- autoFocusSearchBox: true,
- showClearButton: !required,
+ clearButtonProps: ClearButtonProps(isVisible: !required),
itemAsString: (dynamic item) {
return (item["display_name"] ?? "") as String;
},
@@ -465,8 +471,7 @@ class APIFormField {
} else {
data["value"] = item["value"];
}
- }
- );
+ });
}
// Construct a floating point numerical input field
@@ -501,30 +506,37 @@ class APIFormField {
// Construct an input for a related field
Widget _constructRelatedField() {
-
return DropdownSearch(
- mode: Mode.BOTTOM_SHEET,
- showSelectedItem: true,
+ popupProps: PopupProps.bottomSheet(
+ 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,
- onFind: (String filter) async {
-
- Map _filters = {};
+ asyncItems: (String filter) async {
+ Map filters = {};
filters.forEach((key, value) {
- _filters[key] = value;
+ filters[key] = value;
});
- _filters["search"] = filter;
- _filters["offset"] = "0";
- _filters["limit"] = "25";
+ filters["search"] = filter;
+ filters["offset"] = "0";
+ filters["limit"] = "25";
- final APIResponse response = await InvenTreeAPI().get(
- api_url,
- params: _filters
- );
+ final APIResponse response =
+ await InvenTreeAPI().get(api_url, params: filters);
if (response.isValid()) {
-
List results = [];
for (var result in response.data["results"] ?? []) {
@@ -536,12 +548,16 @@ class APIFormField {
return [];
}
},
- label: label,
- hint: helpText,
+ clearButtonProps: ClearButtonProps(
+ isVisible: !required
+ ),
+ dropdownDecoratorProps: DropDownDecoratorProps(
+ dropdownSearchDecoration: InputDecoration(
+ labelText: label,
+ hintText: helpText,
+ )),
onChanged: null,
- showClearButton: !required,
itemAsString: (dynamic item) {
-
Map data = item as Map;
switch (model) {
@@ -555,15 +571,9 @@ class APIFormField {
return "itemAsString not implemented for '${model}'";
}
},
- dropdownBuilder: (context, item, itemAsString) {
+ dropdownBuilder: (context, item) {
return _renderRelatedField(item, true, false);
},
- popupItemBuilder: (context, item, isSelected) {
- return _renderRelatedField(item, isSelected, true);
- },
- emptyBuilder: (context, item) {
- return _renderEmptyResult();
- },
onSaved: (item) {
if (item != null) {
data["value"] = item["pk"];
@@ -571,9 +581,6 @@ class APIFormField {
data["value"] = null;
}
},
- isFilteredOnline: true,
- showSearchBox: true,
- autoFocusSearchBox: true,
compareFn: (dynamic item, dynamic selectedItem) {
// Comparison is based on the PK value
@@ -582,8 +589,7 @@ class APIFormField {
}
return item["pk"] == selectedItem["pk"];
- }
- );
+ });
}
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
Widget _renderEmptyResult() {
return ListTile(
- leading: FaIcon(FontAwesomeIcons.search),
+ leading: FaIcon(FontAwesomeIcons.magnifyingGlass),
title: Text(L10().noResults),
subtitle: Text(
L10().queryNoResults,
@@ -865,7 +871,7 @@ Future launchApiForm(
String method = "PATCH",
Function(Map)? onSuccess,
Function? onCancel,
- IconData icon = FontAwesomeIcons.save,
+ IconData icon = FontAwesomeIcons.floppyDisk,
}) async {
showLoadingOverlay(context);
@@ -889,7 +895,7 @@ Future launchApiForm(
// User does not have permission to perform this action
showSnackIcon(
L10().response403,
- icon: FontAwesomeIcons.userTimes,
+ icon: FontAwesomeIcons.userXmark,
);
hideLoadingOverlay();
@@ -971,7 +977,7 @@ class APIFormWidget extends StatefulWidget {
Key? key,
this.onSuccess,
this.fileField = "",
- this.icon = FontAwesomeIcons.save,
+ this.icon = FontAwesomeIcons.floppyDisk,
}
) : super(key: key);
@@ -1025,7 +1031,7 @@ class _APIFormWidgetState extends State {
),
),
leading: FaIcon(
- FontAwesomeIcons.exclamationCircle,
+ FontAwesomeIcons.circleExclamation,
color: COLOR_DANGER
),
)
diff --git a/lib/barcode.dart b/lib/barcode.dart
index e9d02624..77dbb40c 100644
--- a/lib/barcode.dart
+++ b/lib/barcode.dart
@@ -105,7 +105,7 @@ class BarcodeHandler {
showSnackIcon(
L10().barcodeError,
- icon: FontAwesomeIcons.exclamationCircle,
+ icon: FontAwesomeIcons.circleExclamation,
success: false
);
@@ -179,7 +179,7 @@ class BarcodeScanHandler extends BarcodeHandler {
showSnackIcon(
L10().barcodeNoMatch,
- icon: FontAwesomeIcons.exclamationCircle,
+ icon: FontAwesomeIcons.circleExclamation,
success: false,
);
}
diff --git a/lib/helpers.dart b/lib/helpers.dart
index b574c609..085a051e 100644
--- a/lib/helpers.dart
+++ b/lib/helpers.dart
@@ -74,6 +74,6 @@ Future playAudioFile(String path) async {
return;
}
- final player = AudioCache();
- player.play(path);
+ final player = AudioPlayer();
+ player.play(AssetSource(path));
}
diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart
index e2fe9808..33d5e477 100644
--- a/lib/inventree/model.dart
+++ b/lib/inventree/model.dart
@@ -223,8 +223,9 @@ class InvenTreeModel {
Future goToInvenTreePage() async {
- if (await canLaunch(webUrl)) {
- await launch(webUrl);
+ var uri = Uri.tryParse(webUrl);
+ if (uri != null && await canLaunchUrl(uri)) {
+ await launchUrl(uri);
} else {
// TODO
}
@@ -233,9 +234,9 @@ class InvenTreeModel {
Future openLink() async {
if (link.isNotEmpty) {
-
- if (await canLaunch(link)) {
- await launch(link);
+ var uri = Uri.tryParse(link);
+ if (uri != null && await canLaunchUrl(uri)) {
+ await launchUrl(uri);
}
}
}
@@ -799,7 +800,7 @@ class InvenTreeAttachment extends InvenTreeModel {
}
}
- return FontAwesomeIcons.fileAlt;
+ return FontAwesomeIcons.fileLines;
}
String get comment => (jsondata["comment"] ?? "") as String;
diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart
index 72964d61..de247338 100644
--- a/lib/inventree/sentry.dart
+++ b/lib/inventree/sentry.dart
@@ -37,7 +37,7 @@ Future