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:
parent
298ee24a9c
commit
6d4973deb8
13
.github/workflows/android.yaml
vendored
13
.github/workflows/android.yaml
vendored
@ -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
|
||||
|
13
.github/workflows/ci.yaml
vendored
13
.github/workflows/ci.yaml
vendored
@ -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
|
||||
|
13
.github/workflows/ios.yaml
vendored
13
.github/workflows/ios.yaml
vendored
@ -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
|
||||
|
@ -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
|
@ -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"
|
||||
}
|
||||
|
@ -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
|
||||
|
9
android/app/src/main/res/values-v31/styles.xml
Normal file
9
android/app/src/main/res/values-v31/styles.xml
Normal 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>
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
android.enableD8=true
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
@ -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
|
12
lib/api.dart
12
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<String, dynamic> data) async {
|
||||
plugin_name = (data["plugin"] ?? "") as String;
|
||||
}
|
||||
|
@ -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
|
||||
),
|
||||
)
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -74,6 +74,6 @@ Future<void> playAudioFile(String path) async {
|
||||
return;
|
||||
}
|
||||
|
||||
final player = AudioCache();
|
||||
player.play(path);
|
||||
final player = AudioPlayer();
|
||||
player.play(AssetSource(path));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()}");
|
||||
});
|
||||
|
@ -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);
|
||||
},
|
||||
|
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
);
|
||||
|
@ -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: () {
|
||||
|
@ -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),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
));
|
||||
}
|
||||
|
@ -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 = [];
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
]
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
),
|
||||
];
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
)
|
||||
],
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
830
pubspec.lock
830
pubspec.lock
File diff suppressed because it is too large
Load Diff
43
pubspec.yaml
43
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
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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
22
test/setup.dart
Normal 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 ".";
|
||||
});
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user