mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-27 21:16:48 +00:00
Adds audio feedback
This commit is contained in:
parent
3761f4090f
commit
b293806fe3
@ -1,6 +1,6 @@
|
||||
buildscript {
|
||||
|
||||
ext.kotlin_version = '1.3.61'
|
||||
ext.kotlin_version = '1.4.21'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 0.1.3 - February 2021
|
||||
## 0.1.3 - March 2021
|
||||
---
|
||||
|
||||
- Adds ability to toggle "star" status for Part
|
||||
@ -6,6 +6,7 @@
|
||||
- User permissions are now queried from the InvenTree server
|
||||
- Any "unauthorized" actions are now not displayed
|
||||
- Uses server-side pagination, providing a significant increase in UI performance
|
||||
- Adds audio feedback for server errors and barcode scanning
|
||||
|
||||
## 0.1.2 - February 2021
|
||||
---
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:audioplayers/audio_cache.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
@ -38,6 +39,16 @@ class BarcodeHandler {
|
||||
QRViewController _controller;
|
||||
BuildContext _context;
|
||||
|
||||
void successTone() {
|
||||
AudioCache player = AudioCache();
|
||||
player.play("sounds/barcode_scan.mp3");
|
||||
}
|
||||
|
||||
void failureTone() {
|
||||
AudioCache player = AudioCache();
|
||||
player.play("sounds/barcode_error.mp3");
|
||||
}
|
||||
|
||||
Future<void> onBarcodeMatched(Map<String, dynamic> data) {
|
||||
// Called when the server "matches" a barcode
|
||||
// Override this function
|
||||
@ -46,6 +57,9 @@ class BarcodeHandler {
|
||||
Future<void> onBarcodeUnknown(Map<String, dynamic> data) {
|
||||
// Called when the server does not know about a barcode
|
||||
// Override this function
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeNoMatch,
|
||||
success: false,
|
||||
@ -54,6 +68,9 @@ class BarcodeHandler {
|
||||
}
|
||||
|
||||
Future<void> onBarcodeUnhandled(Map<String, dynamic> data) {
|
||||
|
||||
failureTone();
|
||||
|
||||
// Called when the server returns an unhandled response
|
||||
showServerError(I18N.of(OneContext().context).responseUnknown, data.toString());
|
||||
|
||||
@ -119,6 +136,8 @@ class BarcodeScanHandler extends BarcodeHandler {
|
||||
@override
|
||||
Future<void> onBarcodeUnknown(Map<String, dynamic> data) {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeNoMatch,
|
||||
icon: FontAwesomeIcons.exclamationCircle,
|
||||
@ -139,6 +158,9 @@ class BarcodeScanHandler extends BarcodeHandler {
|
||||
pk = data['stocklocation']['pk'] as int ?? null;
|
||||
|
||||
if (pk != null) {
|
||||
|
||||
successTone();
|
||||
|
||||
InvenTreeStockLocation().get(_context, pk).then((var loc) {
|
||||
if (loc is InvenTreeStockLocation) {
|
||||
Navigator.of(_context).pop();
|
||||
@ -146,6 +168,9 @@ class BarcodeScanHandler extends BarcodeHandler {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).invalidStockLocation,
|
||||
success: false
|
||||
@ -157,11 +182,17 @@ class BarcodeScanHandler extends BarcodeHandler {
|
||||
pk = data['stockitem']['pk'] as int ?? null;
|
||||
|
||||
if (pk != null) {
|
||||
|
||||
successTone();
|
||||
|
||||
InvenTreeStockItem().get(_context, pk).then((var item) {
|
||||
Navigator.of(_context).pop();
|
||||
Navigator.push(_context, MaterialPageRoute(builder: (context) => StockDetailWidget(item)));
|
||||
});
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).invalidStockItem,
|
||||
success: false
|
||||
@ -172,17 +203,26 @@ class BarcodeScanHandler extends BarcodeHandler {
|
||||
pk = data['part']['pk'] as int ?? null;
|
||||
|
||||
if (pk != null) {
|
||||
|
||||
successTone();
|
||||
|
||||
InvenTreePart().get(_context, pk).then((var part) {
|
||||
Navigator.of(_context).pop();
|
||||
Navigator.push(_context, MaterialPageRoute(builder: (context) => PartDetailWidget(part)));
|
||||
});
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).invalidPart,
|
||||
success: false
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeUnknown,
|
||||
success: false,
|
||||
@ -220,7 +260,10 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
|
||||
|
||||
@override
|
||||
Future<void> onBarcodeMatched(Map<String, dynamic> data) {
|
||||
// If the barcode is known, we can't asisgn it to the stock item!
|
||||
|
||||
failureTone();
|
||||
|
||||
// If the barcode is known, we can't assign it to the stock item!
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeInUse,
|
||||
icon: FontAwesomeIcons.qrcode,
|
||||
@ -245,6 +288,8 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
|
||||
).then((result) {
|
||||
if (result) {
|
||||
|
||||
failureTone();
|
||||
|
||||
// Close the barcode scanner
|
||||
_controller.dispose();
|
||||
Navigator.of(_context).pop();
|
||||
@ -256,6 +301,8 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler {
|
||||
);
|
||||
} else {
|
||||
|
||||
successTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeNotAssigned,
|
||||
success: false,
|
||||
@ -294,6 +341,9 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler {
|
||||
final result = await item.transferStock(location);
|
||||
|
||||
if (result) {
|
||||
|
||||
successTone();
|
||||
|
||||
// Close the scanner
|
||||
_controller.dispose();
|
||||
Navigator.of(_context).pop();
|
||||
@ -303,12 +353,18 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler {
|
||||
success: true,
|
||||
);
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeScanIntoLocationFailure,
|
||||
success: false
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).invalidStockLocation,
|
||||
success: false,
|
||||
@ -341,26 +397,37 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
|
||||
final InvenTreeStockItem item = await InvenTreeStockItem().get(_context, item_id);
|
||||
|
||||
if (item == null) {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).invalidStockItem,
|
||||
success: false,
|
||||
);
|
||||
} else if (item.locationId == location.pk) {
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).itemInLocation,
|
||||
success: true
|
||||
);
|
||||
}
|
||||
failureTone();
|
||||
|
||||
else {
|
||||
showSnackIcon(
|
||||
I18N
|
||||
.of(OneContext().context)
|
||||
.itemInLocation,
|
||||
success: true
|
||||
);
|
||||
} else {
|
||||
final result = await item.transferStock(location.pk);
|
||||
|
||||
if (result) {
|
||||
|
||||
successTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeScanIntoLocationSuccess,
|
||||
success: true
|
||||
);
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).barcodeScanIntoLocationFailure,
|
||||
success: false
|
||||
@ -368,6 +435,9 @@ class StockLocationScanInItemsHandler extends BarcodeHandler {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
failureTone();
|
||||
|
||||
// Does not match a valid stock item!
|
||||
showSnackIcon(
|
||||
I18N.of(OneContext().context).invalidStockItem,
|
||||
|
@ -1,5 +1,7 @@
|
||||
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:audioplayers/audio_cache.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
@ -113,7 +115,9 @@ Future<void> showServerError(String title, String description) async {
|
||||
title = I18N.of(OneContext().context).serverError;
|
||||
}
|
||||
|
||||
// TODO - Play audio notification
|
||||
// Play a sound
|
||||
AudioCache player = AudioCache();
|
||||
player.play("sounds/server_error.mp3");
|
||||
|
||||
showSnackIcon(
|
||||
title,
|
||||
|
@ -22,6 +22,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.5.0-nullsafety.1"
|
||||
audioplayers:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: audioplayers
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.17.4"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -39,6 +39,7 @@ dependencies:
|
||||
sembast: ^2.4.9 # NoSQL data storage
|
||||
one_context: ^0.5.0 # Dialogs without requiring context
|
||||
infinite_scroll_pagination: ^2.3.0 # Let the server do all the work!
|
||||
audioplayers:
|
||||
path:
|
||||
|
||||
dev_dependencies:
|
||||
|
Loading…
x
Reference in New Issue
Block a user