mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 05:26:47 +00:00
Add snackbar with icon
- stock adjust - part edit - location edit
This commit is contained in:
parent
ce2a866384
commit
c8c056f96d
@ -323,6 +323,15 @@ class InvenTreeStockItem extends InvenTreeModel {
|
||||
|
||||
double get quantity => double.tryParse(jsondata['quantity'].toString() ?? '0');
|
||||
|
||||
String get quantityString {
|
||||
|
||||
if (quantity.toInt() == quantity) {
|
||||
return quantity.toInt().toString();
|
||||
} else {
|
||||
return quantity.toString();
|
||||
}
|
||||
}
|
||||
|
||||
int get locationId => jsondata['location'] as int ?? -1;
|
||||
|
||||
bool isSerialized() => serialNumber != null && quantity.toInt() == 1;
|
||||
|
@ -161,7 +161,39 @@ void hideProgressDialog(BuildContext context) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
void showFormDialog(BuildContext context, String title, {GlobalKey<FormState> key, List<Widget> fields, List<Widget> actions}) {
|
||||
void showFormDialog(BuildContext context, String title, {GlobalKey<FormState> key, List<Widget> fields, List<Widget> actions, Function callback}) {
|
||||
|
||||
// Undefined actions = OK + Cancel
|
||||
if (actions == null) {
|
||||
actions = <Widget>[
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).cancel),
|
||||
onPressed: () {
|
||||
// Close the form
|
||||
Navigator.pop(context);
|
||||
}
|
||||
),
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).save),
|
||||
onPressed: () {
|
||||
if (key.currentState.validate()) {
|
||||
key.currentState.save();
|
||||
|
||||
// Close the dialog
|
||||
Navigator.pop(context);
|
||||
|
||||
// Callback
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
@ -1,13 +1,18 @@
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/preferences.dart';
|
||||
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_detail.dart';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
|
||||
class LocationDisplayWidget extends StatefulWidget {
|
||||
|
||||
@ -25,6 +30,8 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
|
||||
final InvenTreeStockLocation location;
|
||||
|
||||
final _editLocationKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
String getAppBarTitle(BuildContext context) { return "Stock Location"; }
|
||||
|
||||
@ -33,13 +40,53 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
return <Widget>[
|
||||
IconButton(
|
||||
icon: FaIcon(FontAwesomeIcons.edit),
|
||||
tooltip: "Edit",
|
||||
// TODO - Edit stock location
|
||||
onPressed: null,
|
||||
tooltip: I18N.of(context).edit,
|
||||
onPressed: _editLocationDialog,
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
void _editLocation(Map<String, String> values) async {
|
||||
|
||||
final bool result = await location.update(context, values: values);
|
||||
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
result ? "Location edited" : "Location editing failed",
|
||||
success: result
|
||||
);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void _editLocationDialog() {
|
||||
// Values which an be edited
|
||||
var _name;
|
||||
var _description;
|
||||
|
||||
showFormDialog(context, I18N.of(context).editLocation,
|
||||
key: _editLocationKey,
|
||||
callback: () {
|
||||
_editLocation({
|
||||
"name": _name,
|
||||
"description": _description
|
||||
});
|
||||
},
|
||||
fields: <Widget> [
|
||||
StringField(
|
||||
label: I18N.of(context).name,
|
||||
initial: location.name,
|
||||
onSaved: (value) => _name = value,
|
||||
),
|
||||
StringField(
|
||||
label: I18N.of(context).description,
|
||||
initial: location.description,
|
||||
onSaved: (value) => _description = value,
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
_LocationDisplayState(this.location) {}
|
||||
|
||||
List<InvenTreeStockLocation> _sublocations = List<InvenTreeStockLocation>();
|
||||
@ -67,6 +114,9 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
|
||||
int pk = location?.pk ?? -1;
|
||||
|
||||
// Reload location information
|
||||
await location.reload(context);
|
||||
|
||||
// Request a list of sub-locations under this one
|
||||
await InvenTreeStockLocation().list(context, filters: {"parent": "$pk"}).then((var locs) {
|
||||
_sublocations.clear();
|
||||
|
@ -1,4 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -74,9 +76,13 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
|
||||
void _savePart(Map<String, String> values) async {
|
||||
|
||||
Navigator.of(context).pop();
|
||||
final bool result = await part.update(context, values: values);
|
||||
|
||||
var response = await part.update(context, values: values);
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
result ? "Part edited" : "Part editing failed",
|
||||
success: result
|
||||
);
|
||||
|
||||
refresh();
|
||||
}
|
||||
@ -96,34 +102,18 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
var _name;
|
||||
var _description;
|
||||
var _ipn;
|
||||
var _revision;
|
||||
var _keywords;
|
||||
|
||||
showFormDialog(context, I18N.of(context).editPart,
|
||||
key: _editPartKey,
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).cancel),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).save),
|
||||
onPressed: () {
|
||||
if (_editPartKey.currentState.validate()) {
|
||||
_editPartKey.currentState.save();
|
||||
|
||||
_savePart({
|
||||
"name": _name,
|
||||
"description": _description,
|
||||
"IPN": _ipn,
|
||||
"keywords": _keywords,
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
callback: () {
|
||||
_savePart({
|
||||
"name": _name,
|
||||
"description": _description,
|
||||
"IPN": _ipn,
|
||||
"keywords": _keywords
|
||||
});
|
||||
},
|
||||
fields: <Widget>[
|
||||
StringField(
|
||||
label: I18N.of(context).name,
|
||||
@ -163,7 +153,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => FullScreenWidget(part.name, part.image))
|
||||
MaterialPageRoute(builder: (context) => FullScreenWidget(part.fullname, part.image))
|
||||
);
|
||||
}),
|
||||
)
|
||||
|
@ -8,6 +8,8 @@ import 'package:InvenTree/widget/drawer.dart';
|
||||
|
||||
abstract class RefreshableState<T extends StatefulWidget> extends State<T> {
|
||||
|
||||
final refreshableKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
// Storage for context once "Build" is called
|
||||
BuildContext context;
|
||||
|
||||
@ -80,6 +82,7 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> {
|
||||
this.context = context;
|
||||
|
||||
return Scaffold(
|
||||
key: refreshableKey,
|
||||
appBar: getAppBar(context),
|
||||
drawer: getDrawer(context),
|
||||
floatingActionButton: getFab(context),
|
||||
|
33
lib/widget/snacks.dart
Normal file
33
lib/widget/snacks.dart
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
/*
|
||||
* Display a snackbar with:
|
||||
*
|
||||
* a) Text on the left
|
||||
* b) Icon on the right
|
||||
*
|
||||
* | Text <icon> |
|
||||
*/
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
void showSnackIcon(GlobalKey<ScaffoldState> key, String text, {IconData icon, bool success}) {
|
||||
|
||||
// If icon not specified, use the success status
|
||||
if (icon == null) {
|
||||
icon = (success == true) ? FontAwesomeIcons.checkCircle : FontAwesomeIcons.timesCircle;
|
||||
}
|
||||
|
||||
key.currentState.showSnackBar(
|
||||
SnackBar(
|
||||
content: Row(
|
||||
children: [
|
||||
Text(text),
|
||||
Spacer(),
|
||||
FaIcon(icon)
|
||||
]
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:InvenTree/barcode.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
@ -8,6 +9,7 @@ import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/location_display.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_item_test_results.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -22,6 +24,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class StockDetailWidget extends StatefulWidget {
|
||||
|
||||
@ -71,10 +74,10 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
var response = await item.addStock(quantity, notes: _notesController.text);
|
||||
_notesController.clear();
|
||||
|
||||
_stockUpdateMessage(response);
|
||||
|
||||
// TODO - Handle error cases
|
||||
refresh();
|
||||
|
||||
// TODO - Display a snackbar here indicating the action was successful (or otherwise)
|
||||
}
|
||||
|
||||
void _addStockDialog() async {
|
||||
|
Loading…
x
Reference in New Issue
Block a user