2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-27 21:16:48 +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:
- 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

View File

@ -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

View File

@ -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

View File

@ -74,4 +74,6 @@ linter:
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 {
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"
}

View File

@ -31,10 +31,6 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
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 -->
<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 {
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()
}
}

View File

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

View File

@ -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

View File

@ -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<String, dynamic> data) async {
plugin_name = (data["plugin"] ?? "") as String;
}

View File

@ -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<dynamic>(
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<dynamic>(
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<String, String> _filters = {};
asyncItems: (String filter) async {
Map<String, String> 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<dynamic> 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<String, dynamic> data = item as Map<String, dynamic>;
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<void> launchApiForm(
String method = "PATCH",
Function(Map<String, dynamic>)? onSuccess,
Function? onCancel,
IconData icon = FontAwesomeIcons.save,
IconData icon = FontAwesomeIcons.floppyDisk,
}) async {
showLoadingOverlay(context);
@ -889,7 +895,7 @@ Future<void> 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<APIFormWidget> {
),
),
leading: FaIcon(
FontAwesomeIcons.exclamationCircle,
FontAwesomeIcons.circleExclamation,
color: COLOR_DANGER
),
)

View File

@ -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,
);
}

View File

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

View File

@ -223,8 +223,9 @@ class InvenTreeModel {
Future <void> 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 <void> 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;

View File

@ -37,7 +37,7 @@ Future<Map<String, dynamic>> 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<void> 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()}");
});

View File

@ -39,27 +39,36 @@ class InvenTreeAboutWidget extends StatelessWidget {
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)) {
await launch(docsUrl);
if (await canLaunchUrl(docsUrl)) {
await launchUrl(docsUrl);
}
}
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)) {
await launch(url);
if (await canLaunchUrl(url)) {
await launchUrl(url);
}
}
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)) {
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);
},

View File

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

View File

@ -74,7 +74,7 @@ class _HomeScreenSettingsState extends State<HomeScreenSettingsWidget> {
ListTile(
title: Text(L10().homeShowPo),
subtitle: Text(L10().homeShowPoDescription),
leading: FaIcon(FontAwesomeIcons.shoppingCart),
leading: FaIcon(FontAwesomeIcons.cartShopping),
trailing: Switch(
value: homeShowPo,
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...
if ((InvenTreeAPI().profile?.key ?? "") != profile.key) {
return FaIcon(
FontAwesomeIcons.questionCircle,
FontAwesomeIcons.circleQuestion,
color: COLOR_WARNING
);
}
@ -108,7 +108,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
// 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<InvenTreeLoginSettingsWidget> {
);
} else {
return FaIcon(
FontAwesomeIcons.timesCircle,
FontAwesomeIcons.circleXmark,
color: COLOR_DANGER,
);
}
@ -167,7 +167,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
},
child: ListTile(
title: Text(L10().profileEdit),
leading: FaIcon(FontAwesomeIcons.edit)
leading: FaIcon(FontAwesomeIcons.penToSquare)
)
),
SimpleDialogOption(
@ -184,7 +184,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
},
child: ListTile(
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),
actions: [
IconButton(
icon: FaIcon(FontAwesomeIcons.plusCircle),
icon: FaIcon(FontAwesomeIcons.circlePlus),
onPressed: () {
_editProfile(context, createNew: true);
},
@ -259,7 +259,7 @@ class _ProfileEditState extends State<ProfileEditWidget> {
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();

View File

@ -47,7 +47,7 @@ class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> {
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<InvenTreePartSettingsWidget> {
ListTile(
title: Text(L10().stockItemHistory),
subtitle: Text(L10().stockItemHistoryDetail),
leading: FaIcon(FontAwesomeIcons.history),
leading: FaIcon(FontAwesomeIcons.clockRotateLeft),
trailing: Switch(
value: stockShowHistory,
onChanged: (bool value) {

View File

@ -45,7 +45,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
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<InvenTreeSettingsWidget> {
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()));
}

View File

@ -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<String, dynamic>,
profiles[idx].key! as int,
profiles[idx].value! as Map<String, dynamic>,
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<String, dynamic>,
profiles[idx].key! as int,
profiles[idx].value! as Map<String, dynamic>,
profiles[idx].key == selected,
)
);

View File

@ -54,7 +54,7 @@ class _AttachmentWidgetState extends RefreshableState<AttachmentWidget> {
// 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<AttachmentWidget> {
},
child: ListTile(
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),
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: () {

View File

@ -43,7 +43,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
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<CategoryDisplayWidget> {
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<CategoryDisplayWidget> {
subtitle: Text(
L10().permissionAccountDenied,
),
leading: FaIcon(FontAwesomeIcons.userTimes),
leading: FaIcon(FontAwesomeIcons.userXmark),
)
);
}

View File

@ -56,7 +56,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
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<CompanyDetailWidget> {
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<CompanyDetailWidget> {
if (widget.company.notes.isNotEmpty) {
tiles.add(ListTile(
title: Text(L10().notes),
leading: FaIcon(FontAwesomeIcons.stickyNote),
leading: FaIcon(FontAwesomeIcons.noteSticky),
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
*/
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 _reject = rejectText ?? L10().cancel;
@ -63,7 +63,7 @@ Future<void> confirmationDialog(String title, String text, {IconData icon = Font
* @description = Simple string description of error
* @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 = [];

View File

@ -96,7 +96,7 @@ class InvenTreeDrawer extends StatelessWidget {
context: context,
tiles: <Widget>[
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,
)
]

View File

@ -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 {

View File

@ -237,7 +237,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
if (!allowed) {
showSnackIcon(
L10().permissionRequired,
icon: FontAwesomeIcons.exclamationCircle,
icon: FontAwesomeIcons.circleExclamation,
success: false,
);
@ -295,7 +295,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
tiles.add(_listTile(
context,
L10().stock,
FontAwesomeIcons.boxes,
FontAwesomeIcons.boxesStacked,
callback: () {
_showStock(context);
}
@ -306,7 +306,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
tiles.add(_listTile(
context,
L10().purchaseOrders,
FontAwesomeIcons.shoppingCart,
FontAwesomeIcons.cartShopping,
callback: () {
_showPurchaseOrders(context);
}
@ -358,7 +358,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
tiles.add(_listTile(
context,
L10().settings,
FontAwesomeIcons.cogs,
FontAwesomeIcons.gears,
callback: () {
_showSettings(context);
}
@ -377,7 +377,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
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<InvenTreeHomePage> {
List<BottomNavigationBarItem> items = <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.home),
icon: FaIcon(FontAwesomeIcons.house),
label: L10().home,
),
BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.search),
icon: FaIcon(FontAwesomeIcons.magnifyingGlass),
label: L10().search,
),
];

View File

@ -54,7 +54,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
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<LocationDisplayWidget> {
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<LocationDisplayWidget> {
L10().stockTopLevel,
style: TextStyle(fontStyle: FontStyle.italic)
),
leading: FaIcon(FontAwesomeIcons.boxes),
leading: FaIcon(FontAwesomeIcons.boxesStacked),
)
);
} else {
@ -211,7 +211,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
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<LocationDisplayWidget> {
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<LocationDisplayWidget> {
label: L10().details,
),
BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.boxes),
icon: FaIcon(FontAwesomeIcons.boxesStacked),
label: L10().stock,
),
BottomNavigationBarItem(
@ -379,7 +379,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
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<LocationDisplayWidget> {
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<LocationDisplayWidget> {
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<LocationDisplayWidget> {
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;

View File

@ -198,7 +198,7 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> extends Sta
L10().filteringOptions,
"",
fields,
icon: FontAwesomeIcons.checkCircle,
icon: FontAwesomeIcons.circleCheck,
onSuccess: (Map<String, dynamic> data) async {
// Extract data from the processed form
@ -417,7 +417,7 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget> 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),
);
}

View File

@ -85,7 +85,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
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<PartDetailWidget> {
)
),
leading: FaIcon(
FontAwesomeIcons.exclamationCircle,
FontAwesomeIcons.circleExclamation,
color: COLOR_DANGER
),
)
@ -395,7 +395,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
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<PartDetailWidget> {
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<PartDetailWidget> {
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<PartDetailWidget> {
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<PartDetailWidget> {
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<PartDetailWidget> {
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<PartDetailWidget> {
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<PartDetailWidget> {
onTap: onTabSelectionChanged,
items: <BottomNavigationBarItem> [
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(

View File

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

View File

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

View File

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

View File

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

View File

@ -263,7 +263,7 @@ class _SearchDisplayState extends RefreshableState<SearchWidget> {
),
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<SearchWidget> {
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<SearchWidget> {
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<SearchWidget> {
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<SearchWidget> {
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<SearchWidget> {
L10().queryNoResults,
style: TextStyle(fontStyle: FontStyle.italic),
),
leading: FaIcon(FontAwesomeIcons.searchMinus),
leading: FaIcon(FontAwesomeIcons.magnifyingGlassMinus),
)
);
} 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
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;
}
}

View File

@ -63,7 +63,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
tiles.add(
ListTile(
title: Text(L10().permissionRequired),
leading: FaIcon(FontAwesomeIcons.userTimes)
leading: FaIcon(FontAwesomeIcons.userXmark)
)
);
@ -765,7 +765,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
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<StockDetailWidget> {
onTap: onTabSelectionChanged,
items: <BottomNavigationBarItem> [
BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.infoCircle),
icon: FaIcon(FontAwesomeIcons.circleInfo),
label: L10().details,
),
BottomNavigationBarItem(

View File

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

View File

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

View File

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

View File

@ -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 {

View File

@ -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 {

View File

@ -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(

View File

@ -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 {
});

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:inventree/user_profile.dart";
import "setup.dart";
void main() {
setupTestEnv();
setUp(() async {
// Ensure we have a user profile available