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> getDeviceInfo() async { "model": androidDeviceInfo.model, "device": androidDeviceInfo.device, "id": androidDeviceInfo.id, - "androidId": androidDeviceInfo.androidId, + "androidId": androidDeviceInfo.id, "brand": androidDeviceInfo.brand, "display": androidDeviceInfo.display, "hardware": androidDeviceInfo.hardware, @@ -202,6 +202,7 @@ Future sentryReportError(String source, dynamic error, dynamic stackTrace, Sentry.captureException(error, stackTrace: stackTrace).catchError((error) { print("Error uploading information to Sentry.io:"); print(error); + return SentryId.empty(); }).then((response) { print("Uploaded information to Sentry.io : ${response.toString()}"); }); diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 7ba8c5dc..5ac468b8 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -39,27 +39,36 @@ class InvenTreeAboutWidget extends StatelessWidget { Future _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)) { - await launch(docsUrl); + if (await canLaunchUrl(docsUrl)) { + await launchUrl(docsUrl); } } Future _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)) { - await launch(url); + if (await canLaunchUrl(url)) { + await launchUrl(url); } } Future _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)) { - await launch(url); + if (await canLaunchUrl(url)) { + await launchUrl(url); } } @@ -83,7 +92,7 @@ class InvenTreeAboutWidget extends StatelessWidget { title: Text(L10().address), subtitle: Text(InvenTreeAPI().baseUrl.isNotEmpty ? InvenTreeAPI().baseUrl : L10().notConnected), 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( title: Text(L10().version), 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, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.exclamationCircle) + leading: FaIcon(FontAwesomeIcons.circleExclamation) ) ); } @@ -148,7 +157,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().version), subtitle: Text("${info.version} - Build ${info.buildNumber}"), - leading: FaIcon(FontAwesomeIcons.infoCircle) + leading: FaIcon(FontAwesomeIcons.circleInfo) ) ); @@ -156,7 +165,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), - leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.fileLines, color: COLOR_CLICK), onTap: () { _releaseNotes(context); }, diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index a98bf9c8..ad7e58dc 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -81,7 +81,7 @@ class _InvenTreeAppSettingsState extends State { L10().languageSelect, "", fields, - icon: FontAwesomeIcons.checkCircle, + icon: FontAwesomeIcons.circleCheck, onSuccess: (Map data) async { String locale_name = (data["locale"] ?? "") as String; @@ -130,7 +130,7 @@ class _InvenTreeAppSettingsState extends State { L10().sounds, style: TextStyle(fontWeight: FontWeight.bold), ), - leading: FaIcon(FontAwesomeIcons.volumeUp), + leading: FaIcon(FontAwesomeIcons.volumeHigh), ), ListTile( title: Text(L10().serverError), diff --git a/lib/settings/home_settings.dart b/lib/settings/home_settings.dart index 071f96f1..926f31db 100644 --- a/lib/settings/home_settings.dart +++ b/lib/settings/home_settings.dart @@ -74,7 +74,7 @@ class _HomeScreenSettingsState extends State { ListTile( title: Text(L10().homeShowPo), subtitle: Text(L10().homeShowPoDescription), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: FaIcon(FontAwesomeIcons.cartShopping), trailing: Switch( value: homeShowPo, onChanged: (bool value) { diff --git a/lib/settings/login.dart b/lib/settings/login.dart index abccf9b0..e4606e6b 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -100,7 +100,7 @@ class _InvenTreeLoginSettingsState extends State { // Selected, but (for some reason) not the same as the API... if ((InvenTreeAPI().profile?.key ?? "") != profile.key) { return FaIcon( - FontAwesomeIcons.questionCircle, + FontAwesomeIcons.circleQuestion, color: COLOR_WARNING ); } @@ -108,7 +108,7 @@ class _InvenTreeLoginSettingsState extends State { // Reflect the connection status of the server if (InvenTreeAPI().isConnected()) { return FaIcon( - FontAwesomeIcons.checkCircle, + FontAwesomeIcons.circleCheck, color: COLOR_SUCCESS ); } else if (InvenTreeAPI().isConnecting()) { @@ -118,7 +118,7 @@ class _InvenTreeLoginSettingsState extends State { ); } else { return FaIcon( - FontAwesomeIcons.timesCircle, + FontAwesomeIcons.circleXmark, color: COLOR_DANGER, ); } @@ -167,7 +167,7 @@ class _InvenTreeLoginSettingsState extends State { }, child: ListTile( title: Text(L10().profileEdit), - leading: FaIcon(FontAwesomeIcons.edit) + leading: FaIcon(FontAwesomeIcons.penToSquare) ) ), SimpleDialogOption( @@ -184,7 +184,7 @@ class _InvenTreeLoginSettingsState extends State { }, child: ListTile( title: Text(L10().profileDelete), - leading: FaIcon(FontAwesomeIcons.trashAlt), + leading: FaIcon(FontAwesomeIcons.trashCan), ) ) ], @@ -209,7 +209,7 @@ class _InvenTreeLoginSettingsState extends State { title: Text(L10().profileSelect), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () { _editProfile(context, createNew: true); }, @@ -259,7 +259,7 @@ class _ProfileEditState extends State { title: Text(widget.profile == null ? L10().profileAdd : L10().profileEdit), actions: [ IconButton( - icon: FaIcon(FontAwesomeIcons.save), + icon: FaIcon(FontAwesomeIcons.floppyDisk), onPressed: () async { if (formKey.currentState!.validate()) { formKey.currentState!.save(); diff --git a/lib/settings/part_settings.dart b/lib/settings/part_settings.dart index 51282e5b..50d3f0df 100644 --- a/lib/settings/part_settings.dart +++ b/lib/settings/part_settings.dart @@ -47,7 +47,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().parameters), subtitle: Text(L10().parametersSettingDetail), - leading: FaIcon(FontAwesomeIcons.thList), + leading: FaIcon(FontAwesomeIcons.tableList), trailing: Switch( value: partShowParameters, onChanged: (bool value) { @@ -75,7 +75,7 @@ class _InvenTreePartSettingsState extends State { ListTile( title: Text(L10().stockItemHistory), subtitle: Text(L10().stockItemHistoryDetail), - leading: FaIcon(FontAwesomeIcons.history), + leading: FaIcon(FontAwesomeIcons.clockRotateLeft), trailing: Switch( value: stockShowHistory, onChanged: (bool value) { diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index e3f9b2d8..4e8bf038 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -45,7 +45,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().homeScreen), subtitle: Text(L10().homeScreenSettings), - leading: FaIcon(FontAwesomeIcons.home, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.house, color: COLOR_CLICK), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreenSettingsWidget())); } @@ -53,7 +53,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), - leading: FaIcon(FontAwesomeIcons.cogs, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.gears, color: COLOR_CLICK), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeAppSettingsWidget())); } diff --git a/lib/user_profile.dart b/lib/user_profile.dart index bee9a93a..53d7c0dc 100644 --- a/lib/user_profile.dart +++ b/lib/user_profile.dart @@ -103,7 +103,7 @@ class UserProfileDBManager { 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 profile.key = key; @@ -156,8 +156,8 @@ class UserProfileDBManager { if (profiles[idx].key is int && profiles[idx].key == selected) { return UserProfile.fromJson( - profiles[idx].key as int, - profiles[idx].value as Map, + profiles[idx].key! as int, + profiles[idx].value! as Map, profiles[idx].key == selected, ); } @@ -182,8 +182,8 @@ class UserProfileDBManager { if (profiles[idx].key is int) { profileList.add( UserProfile.fromJson( - profiles[idx].key as int, - profiles[idx].value as Map, + profiles[idx].key! as int, + profiles[idx].value! as Map, profiles[idx].key == selected, ) ); diff --git a/lib/widget/attachment_widget.dart b/lib/widget/attachment_widget.dart index 6d54bdd6..8320d1a2 100644 --- a/lib/widget/attachment_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -54,7 +54,7 @@ class _AttachmentWidgetState extends RefreshableState { // File upload actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () async { FilePickerDialog.pickFile( onPicked: (File file) async { @@ -117,7 +117,7 @@ class _AttachmentWidgetState extends RefreshableState { }, child: ListTile( title: Text(L10().delete), - leading: FaIcon(FontAwesomeIcons.trashAlt), + leading: FaIcon(FontAwesomeIcons.trashCan), ) ) ] @@ -187,8 +187,9 @@ class _AttachmentWidgetState extends RefreshableState { subtitle: Text(attachment.comment), leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), onTap: () async { - if (await canLaunch(attachment.link)) { - await launch(attachment.link); + var uri = Uri.tryParse(attachment.link.trimLeft()); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); } }, onLongPress: () { diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index a432e3a1..e72ec2a7 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -43,7 +43,7 @@ class _CategoryDisplayState extends RefreshableState { if ((widget.category != null) && InvenTreeAPI().checkPermission("part_category", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editCategoryDialog(context); @@ -121,7 +121,7 @@ class _CategoryDisplayState extends RefreshableState { title: Text(L10().parentCategory), subtitle: Text("${widget.category?.parentPathString}"), leading: FaIcon( - FontAwesomeIcons.levelUpAlt, + FontAwesomeIcons.turnUp, color: COLOR_CLICK, ), onTap: () async { @@ -338,7 +338,7 @@ class _CategoryDisplayState extends RefreshableState { subtitle: Text( L10().permissionAccountDenied, ), - leading: FaIcon(FontAwesomeIcons.userTimes), + leading: FaIcon(FontAwesomeIcons.userXmark), ) ); } diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index e5f05469..093ce07f 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -56,7 +56,7 @@ class _CompanyDetailState extends RefreshableState { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { editCompany(context); @@ -203,7 +203,7 @@ class _CompanyDetailState extends RefreshableState { tiles.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.shoppingCart, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.cartShopping, color: COLOR_CLICK), trailing: Text("${outstandingOrders.length}"), onTap: () { Navigator.push( @@ -246,7 +246,7 @@ class _CompanyDetailState extends RefreshableState { if (widget.company.notes.isNotEmpty) { tiles.add(ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote), + leading: FaIcon(FontAwesomeIcons.noteSticky), onTap: null, )); } diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 322e20c3..ba09b305 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -13,7 +13,7 @@ import "package:inventree/widget/snacks.dart"; /* * Display a "confirmation" dialog allowing the user to accept or reject an action */ -Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.questionCircle, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { +Future confirmationDialog(String title, String text, {IconData icon = FontAwesomeIcons.circleQuestion, String? acceptText, String? rejectText, Function? onAccept, Function? onReject}) async { String _accept = acceptText ?? L10().ok; String _reject = rejectText ?? L10().cancel; @@ -63,7 +63,7 @@ Future confirmationDialog(String title, String text, {IconData icon = Font * @description = Simple string description of error * @data = Error response (e.g from server) */ -Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.exclamationCircle, Function? onDismissed}) async { +Future showErrorDialog(String title, {String description = "", APIResponse? response, IconData icon = FontAwesomeIcons.circleExclamation, Function? onDismissed}) async { List children = []; diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 0aecc5f4..c760ce2e 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -96,7 +96,7 @@ class InvenTreeDrawer extends StatelessWidget { context: context, tiles: [ ListTile( - leading: FaIcon(FontAwesomeIcons.home), + leading: FaIcon(FontAwesomeIcons.house), title: Text( L10().appTitle, style: TextStyle(fontWeight: FontWeight.bold), @@ -110,7 +110,7 @@ class InvenTreeDrawer extends StatelessWidget { ), ListTile( title: Text(L10().search), - leading: FaIcon(FontAwesomeIcons.search), + leading: FaIcon(FontAwesomeIcons.magnifyingGlass), onTap: _search, ), ListTile( @@ -120,7 +120,7 @@ class InvenTreeDrawer extends StatelessWidget { ), ListTile( title: Text(L10().about), - leading: FaIcon(FontAwesomeIcons.infoCircle), + leading: FaIcon(FontAwesomeIcons.circleInfo), onTap: _about, ) ] diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index a5dac730..16f45e65 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -80,7 +80,7 @@ class FilePickerDialog { actions.add( SimpleDialogOption( child: ListTile( - leading: FaIcon(FontAwesomeIcons.fileUpload), + leading: FaIcon(FontAwesomeIcons.fileArrowUp), title: Text(allowFiles ? L10().selectFile : L10().selectImage), ), onPressed: () async { diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 0d15546f..8307f157 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -237,7 +237,7 @@ class _InvenTreeHomePageState extends State { if (!allowed) { showSnackIcon( L10().permissionRequired, - icon: FontAwesomeIcons.exclamationCircle, + icon: FontAwesomeIcons.circleExclamation, success: false, ); @@ -295,7 +295,7 @@ class _InvenTreeHomePageState extends State { tiles.add(_listTile( context, L10().stock, - FontAwesomeIcons.boxes, + FontAwesomeIcons.boxesStacked, callback: () { _showStock(context); } @@ -306,7 +306,7 @@ class _InvenTreeHomePageState extends State { tiles.add(_listTile( context, L10().purchaseOrders, - FontAwesomeIcons.shoppingCart, + FontAwesomeIcons.cartShopping, callback: () { _showPurchaseOrders(context); } @@ -358,7 +358,7 @@ class _InvenTreeHomePageState extends State { tiles.add(_listTile( context, L10().settings, - FontAwesomeIcons.cogs, + FontAwesomeIcons.gears, callback: () { _showSettings(context); } @@ -377,7 +377,7 @@ class _InvenTreeHomePageState extends State { bool validAddress = serverAddress != null; 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); String title = L10().serverNotConnected; String subtitle = L10().profileSelectOrCreate; @@ -443,11 +443,11 @@ class _InvenTreeHomePageState extends State { List items = [ BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.home), + icon: FaIcon(FontAwesomeIcons.house), label: L10().home, ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.search), + icon: FaIcon(FontAwesomeIcons.magnifyingGlass), label: L10().search, ), ]; diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 9f150c8e..95e45aee 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -54,7 +54,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeAPI().supportsMixin("locate")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.searchLocation), + icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), tooltip: L10().locateLocation, onPressed: () async { _locateStockLocation(context); @@ -67,7 +67,7 @@ class _LocationDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("stock_location", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editLocationDialog(context); }, ) @@ -202,7 +202,7 @@ class _LocationDisplayState extends RefreshableState { L10().stockTopLevel, style: TextStyle(fontStyle: FontStyle.italic) ), - leading: FaIcon(FontAwesomeIcons.boxes), + leading: FaIcon(FontAwesomeIcons.boxesStacked), ) ); } else { @@ -211,7 +211,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text("${location!.name}"), subtitle: Text("${location!.description}"), - leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxes), + leading: location!.customIcon ?? FaIcon(FontAwesomeIcons.boxesStacked), ), ]; @@ -220,7 +220,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().parentLocation), subtitle: Text("${location!.parentPathString}"), - leading: FaIcon(FontAwesomeIcons.levelUpAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.turnUp, color: COLOR_CLICK), onTap: () async { int parentId = location?.parentId ?? -1; @@ -261,7 +261,7 @@ class _LocationDisplayState extends RefreshableState { label: L10().details, ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxes), + icon: FaIcon(FontAwesomeIcons.boxesStacked), label: L10().stock, ), BottomNavigationBarItem( @@ -379,7 +379,7 @@ class _LocationDisplayState extends RefreshableState { title: Text(L10().locationCreate), subtitle: Text(L10().locationCreateDetail), leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - trailing: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), + trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), onTap: () async { _newLocation(context); }, @@ -390,8 +390,8 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().stockItemCreate), subtitle: Text(L10().stockItemCreateDetail), - leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - trailing: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK), + trailing: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), onTap: () async { _newStockItem(context); }, @@ -408,7 +408,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().barcodeScanItem), 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), onTap: () { @@ -434,7 +434,7 @@ class _LocationDisplayState extends RefreshableState { ListTile( title: Text(L10().transferStockLocation), 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), onTap: () { var _loc = location; diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index 71f64856..86b76c10 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -198,7 +198,7 @@ abstract class PaginatedSearchState extends Sta L10().filteringOptions, "", fields, - icon: FontAwesomeIcons.checkCircle, + icon: FontAwesomeIcons.circleCheck, onSuccess: (Map data) async { // Extract data from the processed form @@ -417,7 +417,7 @@ abstract class PaginatedSearchState extends Sta ), trailing: GestureDetector( child: FaIcon( - searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, + searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, color: searchController.text.isNotEmpty ? COLOR_DANGER : COLOR_CLICK, ), onTap: () { @@ -454,7 +454,7 @@ class NoResultsWidget extends StatelessWidget { description, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.exclamationCircle, color: COLOR_WARNING), + leading: FaIcon(FontAwesomeIcons.circleExclamation, color: COLOR_WARNING), ); } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index b347e497..3ebab6d5 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -85,7 +85,7 @@ class _PartDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("part", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editPartDialog(context); @@ -304,7 +304,7 @@ class _PartDisplayState extends RefreshableState { ) ), leading: FaIcon( - FontAwesomeIcons.exclamationCircle, + FontAwesomeIcons.circleExclamation, color: COLOR_DANGER ), ) @@ -395,7 +395,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), - leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.boxesStacked, color: COLOR_CLICK), trailing: Text( part.stockString(), style: TextStyle( @@ -418,7 +418,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().onOrder), subtitle: Text(L10().onOrderDetails), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: FaIcon(FontAwesomeIcons.cartShopping), trailing: Text("${part.onOrderString}"), onTap: () { // TODO - Order views @@ -435,7 +435,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().billOfMaterials), - leading: FaIcon(FontAwesomeIcons.thList, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.tableList, color: COLOR_CLICK), trailing: Text(bomCount.toString()), onTap: () { Navigator.push( @@ -453,7 +453,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().building), - leading: FaIcon(FontAwesomeIcons.tools), + leading: FaIcon(FontAwesomeIcons.screwdriverWrench), trailing: Text("${simpleNumberString(part.building)}"), onTap: () { // TODO @@ -548,7 +548,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( 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, onTap: () { Navigator.push( @@ -566,7 +566,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK), trailing: Text(""), onTap: () { Navigator.push( @@ -580,7 +580,7 @@ class _PartDisplayState extends RefreshableState { tiles.add( ListTile( 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, onTap: () { Navigator.push( @@ -749,11 +749,11 @@ class _PartDisplayState extends RefreshableState { onTap: onTabSelectionChanged, items: [ BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.infoCircle), + icon: FaIcon(FontAwesomeIcons.circleInfo), label: L10().details, ), BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.boxes), + icon: FaIcon(FontAwesomeIcons.boxesStacked), label: L10().stock ), BottomNavigationBarItem( diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part_image_widget.dart index a582dce2..fc4d0b93 100644 --- a/lib/widget/part_image_widget.dart +++ b/lib/widget/part_image_widget.dart @@ -47,7 +47,7 @@ class _PartImageState extends RefreshableState { // File upload actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.fileUpload), + icon: FaIcon(FontAwesomeIcons.fileArrowUp), onPressed: () async { FilePickerDialog.pickFile( diff --git a/lib/widget/part_notes.dart b/lib/widget/part_notes.dart index 6ceb23e6..32bffe93 100644 --- a/lib/widget/part_notes.dart +++ b/lib/widget/part_notes.dart @@ -40,7 +40,7 @@ class _PartNotesState extends RefreshableState { if (InvenTreeAPI().checkPermission("part", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { part.editForm( diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 3b9a1540..d81d1767 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -52,7 +52,7 @@ class _PurchaseOrderDetailState extends RefreshableState 0 ? Text(attachmentCount.toString()) : null, onTap: () { Navigator.push( @@ -250,7 +250,7 @@ class _PurchaseOrderDetailState extends RefreshableState extends State with @override void initState() { super.initState(); - WidgetsBinding.instance?.addPostFrameCallback((_) => onBuild(_context!)); + WidgetsBinding.instance.addPostFrameCallback((_) => onBuild(_context!)); } // Function called after the widget is first build diff --git a/lib/widget/search.dart b/lib/widget/search.dart index ccfb1802..59608c8d 100644 --- a/lib/widget/search.dart +++ b/lib/widget/search.dart @@ -263,7 +263,7 @@ class _SearchDisplayState extends RefreshableState { ), trailing: GestureDetector( child: FaIcon( - searchController.text.isEmpty ? FontAwesomeIcons.search : FontAwesomeIcons.backspace, + searchController.text.isEmpty ? FontAwesomeIcons.magnifyingGlass : FontAwesomeIcons.deleteLeft, color: searchController.text.isEmpty ? COLOR_CLICK : COLOR_DANGER, ), onTap: () { @@ -331,7 +331,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockItems), - leading: FaIcon(FontAwesomeIcons.boxes), + leading: FaIcon(FontAwesomeIcons.boxesStacked), trailing: Text("${nStockResults}"), onTap: () { Navigator.push( @@ -354,7 +354,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().stockLocations), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + leading: FaIcon(FontAwesomeIcons.locationDot), trailing: Text("${nLocationResults}"), onTap: () { Navigator.push( @@ -402,7 +402,7 @@ class _SearchDisplayState extends RefreshableState { results.add( ListTile( title: Text(L10().purchaseOrders), - leading: FaIcon(FontAwesomeIcons.shoppingCart), + leading: FaIcon(FontAwesomeIcons.cartShopping), trailing: Text("${nPurchaseOrderResults}"), onTap: () { Navigator.push( @@ -424,7 +424,7 @@ class _SearchDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().searching), - leading: FaIcon(FontAwesomeIcons.search), + leading: FaIcon(FontAwesomeIcons.magnifyingGlass), trailing: CircularProgressIndicator(), ) ); @@ -437,7 +437,7 @@ class _SearchDisplayState extends RefreshableState { L10().queryNoResults, style: TextStyle(fontStyle: FontStyle.italic), ), - leading: FaIcon(FontAwesomeIcons.searchMinus), + leading: FaIcon(FontAwesomeIcons.magnifyingGlassMinus), ) ); } else { diff --git a/lib/widget/snacks.dart b/lib/widget/snacks.dart index f9414435..b5341aff 100644 --- a/lib/widget/snacks.dart +++ b/lib/widget/snacks.dart @@ -32,14 +32,14 @@ void showSnackIcon(String text, {IconData? icon, Function()? onAction, bool? suc // Select an icon if we do not have an action if (icon == null && onAction == null) { - icon = FontAwesomeIcons.checkCircle; + icon = FontAwesomeIcons.circleCheck; } } else if (success != null && success == false) { backgroundColor = Colors.deepOrange; if (icon == null && onAction == null) { - icon = FontAwesomeIcons.exclamationCircle; + icon = FontAwesomeIcons.circleExclamation; } } diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index e29635bd..240a6d93 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -63,7 +63,7 @@ class _StockItemDisplayState extends RefreshableState { if (InvenTreeAPI().supportsMixin("locate")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.searchLocation), + icon: FaIcon(FontAwesomeIcons.magnifyingGlassLocation), tooltip: L10().locateItem, onPressed: () async { InvenTreeAPI().locateItemOrLocation(context, item: widget.item.pk); @@ -75,7 +75,7 @@ class _StockItemDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("stock", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { _editStockItem(context); }, ) @@ -189,7 +189,7 @@ class _StockItemDisplayState extends RefreshableState { confirmationDialog( L10().stockItemDelete, L10().stockItemDeleteConfirm, - icon: FontAwesomeIcons.trashAlt, + icon: FontAwesomeIcons.trashCan, onAccept: () async { final bool result = await widget.item.delete(); @@ -337,7 +337,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.addStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.plusCircle, + icon: FontAwesomeIcons.circlePlus, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -378,7 +378,7 @@ class _StockItemDisplayState extends RefreshableState { InvenTreeStockItem.removeStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.minusCircle, + icon: FontAwesomeIcons.circleMinus, onSuccess: (data) async { _stockUpdateMessage(true); refresh(context); @@ -527,7 +527,7 @@ class _StockItemDisplayState extends RefreshableState { title: Text(L10().stockLocation), subtitle: Text("${widget.item.locationPathString}"), leading: FaIcon( - FontAwesomeIcons.mapMarkerAlt, + FontAwesomeIcons.locationDot, color: COLOR_CLICK, ), onTap: () async { @@ -549,7 +549,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().stockLocation), - leading: FaIcon(FontAwesomeIcons.mapMarkerAlt), + leading: FaIcon(FontAwesomeIcons.locationDot), subtitle: Text(L10().locationNotSet), ) ); @@ -587,7 +587,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().inProduction), - leading: FaIcon(FontAwesomeIcons.tools), + leading: FaIcon(FontAwesomeIcons.screwdriverWrench), subtitle: Text(L10().inProductionDetail), onTap: () { // TODO: Click through to the "build order" @@ -623,7 +623,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastUpdated), subtitle: Text(widget.item.updatedDateString), - leading: FaIcon(FontAwesomeIcons.calendarAlt) + leading: FaIcon(FontAwesomeIcons.calendarDays) ) ); } @@ -634,7 +634,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().lastStocktake), subtitle: Text(widget.item.stocktakeDateString), - leading: FaIcon(FontAwesomeIcons.calendarAlt) + leading: FaIcon(FontAwesomeIcons.calendarDays) ) ); } @@ -655,7 +655,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().testResults), - leading: FaIcon(FontAwesomeIcons.tasks, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.listCheck, color: COLOR_CLICK), trailing: Text("${widget.item.testResultCount}"), onTap: () { Navigator.push( @@ -686,7 +686,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().history), - leading: FaIcon(FontAwesomeIcons.history, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.clockRotateLeft, color: COLOR_CLICK), trailing: Text("${widget.item.trackingItemCount}"), onTap: () { Navigator.push( @@ -705,7 +705,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.noteSticky, color: COLOR_CLICK), onTap: () { Navigator.push( context, @@ -718,7 +718,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( 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, onTap: () { Navigator.push( @@ -747,7 +747,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().permissionRequired), - leading: FaIcon(FontAwesomeIcons.userTimes) + leading: FaIcon(FontAwesomeIcons.userXmark) ) ); @@ -765,7 +765,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().countStock), - leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.circleCheck, color: COLOR_CLICK), onTap: _countStockDialog, trailing: Text(widget.item.quantityString(includeUnits: true)), ) @@ -774,7 +774,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().removeStock), - leading: FaIcon(FontAwesomeIcons.minusCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.circleMinus, color: COLOR_CLICK), onTap: _removeStockDialog, ) ); @@ -782,7 +782,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().addStock), - leading: FaIcon(FontAwesomeIcons.plusCircle, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_CLICK), onTap: _addStockDialog, ) ); @@ -792,7 +792,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().transferStock), subtitle: Text(L10().transferStockDetail), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), onTap: () { _transferStockDialog(context); }, ) ); @@ -802,7 +802,7 @@ class _StockItemDisplayState extends RefreshableState { ListTile( title: Text(L10().scanIntoLocation), subtitle: Text(L10().scanIntoLocationDetail), - leading: FaIcon(FontAwesomeIcons.exchangeAlt, color: COLOR_CLICK), + leading: FaIcon(FontAwesomeIcons.rightLeft, color: COLOR_CLICK), trailing: Icon(Icons.qr_code_scanner), onTap: () { Navigator.push( @@ -850,7 +850,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text("Delete Stock Item"), - leading: FaIcon(FontAwesomeIcons.trashAlt, color: COLOR_DANGER), + leading: FaIcon(FontAwesomeIcons.trashCan, color: COLOR_DANGER), onTap: () { _deleteItem(context); }, @@ -868,7 +868,7 @@ class _StockItemDisplayState extends RefreshableState { onTap: onTabSelectionChanged, items: [ BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.infoCircle), + icon: FaIcon(FontAwesomeIcons.circleInfo), label: L10().details, ), BottomNavigationBarItem( diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index 0410a9b8..3d602a9a 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -34,7 +34,7 @@ class _StockItemTestResultDisplayState extends RefreshableState getAppBarActions(BuildContext context) { return [ IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), + icon: FaIcon(FontAwesomeIcons.circlePlus), onPressed: () { addTestResult(context); } @@ -158,7 +158,7 @@ class _StockItemTestResultDisplayState extends RefreshableState { if (InvenTreeAPI().checkPermission("stock", "change")) { actions.add( IconButton( - icon: FaIcon(FontAwesomeIcons.edit), + icon: FaIcon(FontAwesomeIcons.penToSquare), tooltip: L10().edit, onPressed: () { item.editForm( diff --git a/lib/widget/supplier_part_detail.dart b/lib/widget/supplier_part_detail.dart index ee45e26e..fdccbf78 100644 --- a/lib/widget/supplier_part_detail.dart +++ b/lib/widget/supplier_part_detail.dart @@ -43,7 +43,7 @@ class _SupplierPartDisplayState extends RefreshableState=2.16.0 <3.0.0" - flutter: ">=2.10.0" + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index a12fa6dd..4d2f8acd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,44 +7,43 @@ environment: sdk: ">=2.16.0 <3.0.0" dependencies: - - audioplayers: ^0.20.1 # Play audio files + audioplayers: ^3.0.1 # Play audio files 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 datetime_picker_formfield: ^2.0.0 # Date / time picker - device_info_plus: ^3.2.2 # Information about the device - dropdown_search: ^0.6.3 # Dropdown autocomplete form fields - file_picker: ^4.5.1 # Select files from the device + device_info_plus: ^8.0.0 # Information about the device + dropdown_search: ^5.0.5 # Dropdown autocomplete form fields + file_picker: ^5.2.5 # Select files from the device flutter: sdk: flutter flutter_cache_manager: ^3.3.0 flutter_localizations: sdk: flutter - flutter_localized_locales: 2.0.3 - flutter_markdown: ^0.6.9 # Rendering markdown + flutter_localized_locales: ^2.0.4 + flutter_markdown: ^0.6.13+1 # Rendering markdown 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 - 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! intl: ^0.17.0 - one_context: ^1.1.1 # Dialogs without requiring context - open_file: ^3.2.1 # Open local files - package_info_plus: ^1.0.4 # App information introspection - path: ^1.8.0 - path_provider: ^2.0.2 # Local file storage - qr_code_scanner: ^0.7.0 # Barcode scanning - sembast: ^3.1.0+2 # NoSQL data storage - sentry_flutter: ^6.4.0 # Error reporting - url_launcher: ^6.0.9 # Open link in system browser + one_context: ^2.1.0 # Dialogs without requiring context + open_filex: ^4.3.2 # Open local files + package_info_plus: ^3.0.2 # App information introspection + path: ^1.8.2 + path_provider: ^2.0.12 # Local file storage + qr_code_scanner: ^1.0.1 # Barcode scanning + sembast: ^3.4.0+6 # NoSQL data storage + sentry_flutter: ^6.19.0 # Error reporting + url_launcher: ^6.1.9 # Open link in system browser dev_dependencies: - flutter_launcher_icons: ^0.9.0 + flutter_launcher_icons: ^0.11.0 flutter_test: sdk: flutter - lint: ^1.8.0 - test: ^1.19.0 + lint: ^2.0.1 + test: ^1.22.0 flutter_icons: android: true diff --git a/test/api_test.dart b/test/api_test.dart index 33f27604..5990d161 100644 --- a/test/api_test.dart +++ b/test/api_test.dart @@ -2,15 +2,18 @@ * 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/helpers.dart"; import "package:inventree/user_profile.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { diff --git a/test/barcode_test.dart b/test/barcode_test.dart index eaafa683..e7b3eee7 100644 --- a/test/barcode_test.dart +++ b/test/barcode_test.dart @@ -15,7 +15,11 @@ import "package:inventree/user_profile.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/stock.dart"; +import "setup.dart"; + + void main() { + setupTestEnv(); // Connect to the server setUpAll(() async { diff --git a/test/models_test.dart b/test/models_test.dart index 213ff56c..0fe5c74d 100644 --- a/test/models_test.dart +++ b/test/models_test.dart @@ -9,8 +9,11 @@ import "package:inventree/user_profile.dart"; import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/part.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { await UserProfileDBManager().addProfile(UserProfile( diff --git a/test/preferences_test.dart b/test/preferences_test.dart index 72941591..5d42a067 100644 --- a/test/preferences_test.dart +++ b/test/preferences_test.dart @@ -2,10 +2,13 @@ * Unit tests for the preferences manager */ -import "package:test/test.dart"; +import "package:flutter_test/flutter_test.dart"; import "package:inventree/preferences.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { }); diff --git a/test/setup.dart b/test/setup.dart new file mode 100644 index 00000000..c4b53879 --- /dev/null +++ b/test/setup.dart @@ -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 "."; + }); +} \ No newline at end of file diff --git a/test/user_profile_test.dart b/test/user_profile_test.dart index 9b672ad5..144a146b 100644 --- a/test/user_profile_test.dart +++ b/test/user_profile_test.dart @@ -5,7 +5,10 @@ import "package:test/test.dart"; import "package:inventree/user_profile.dart"; +import "setup.dart"; + void main() { + setupTestEnv(); setUp(() async { // Ensure we have a user profile available