diff --git a/lib/api_form.dart b/lib/api_form.dart index 750aea6c..1b18b841 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -22,8 +22,6 @@ import 'package:inventree/widget/snacks.dart'; */ class APIFormField { - final _controller = TextEditingController(); - // Constructor APIFormField(this.name, this.data); @@ -47,6 +45,8 @@ class APIFormField { // Is this field read only? bool get readOnly => (data['read_only'] ?? false) as bool; + bool get multiline => (data['multiline'] ?? false) as bool; + // Get the "value" as a string (look for "default" if not available) dynamic get value => (data['value'] ?? data['default']); @@ -341,6 +341,8 @@ class APIFormField { helperStyle: _helperStyle(), hintText: placeholderText, ), + maxLines: multiline ? null : 1, + expands: false, initialValue: value ?? '', onSaved: (val) { data["value"] = val; diff --git a/lib/app_colors.dart b/lib/app_colors.dart index a4797c6a..36b7ee01 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -5,7 +5,7 @@ import 'dart:ui'; const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1); const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 1); -const Color COLOR_CLICK = Color.fromRGBO(175, 150, 100, 0.9); +const Color COLOR_CLICK = Color.fromRGBO(150, 120, 100, 0.9); const Color COLOR_BLUE = Color.fromRGBO(0, 0, 250, 1); diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 572eb1f5..22196ed2 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -1,4 +1,5 @@ import 'package:inventree/api.dart'; +import 'package:inventree/app_colors.dart'; import 'package:inventree/settings/release.dart'; import 'package:flutter/cupertino.dart'; @@ -116,7 +117,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().releaseNotes), subtitle: Text(L10().appReleaseNotes), - leading: FaIcon(FontAwesomeIcons.fileAlt), + leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK), onTap: () { _releaseNotes(context); }, @@ -127,7 +128,7 @@ class InvenTreeAboutWidget extends StatelessWidget { ListTile( title: Text(L10().credits), subtitle: Text(L10().appCredits), - leading: FaIcon(FontAwesomeIcons.bullhorn), + leading: FaIcon(FontAwesomeIcons.bullhorn, color: COLOR_CLICK), onTap: () { _credits(context); } diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index 90f769d1..d3a58113 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -1,3 +1,4 @@ +import 'package:inventree/app_colors.dart'; import 'package:inventree/inventree/sentry.dart'; import 'package:inventree/settings/about.dart'; import 'package:inventree/settings/app_settings.dart'; @@ -46,26 +47,26 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().server), subtitle: Text(L10().configureServer), - leading: FaIcon(FontAwesomeIcons.server), + leading: FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK), onTap: _editServerSettings, ), ListTile( - leading: FaIcon(FontAwesomeIcons.cogs), title: Text(L10().appSettings), subtitle: Text(L10().appSettingsDetails), + leading: FaIcon(FontAwesomeIcons.cogs, color: COLOR_CLICK), onTap: _editAppSettings, ), ListTile( title: Text(L10().about), subtitle: Text(L10().appDetails), - leading: FaIcon(FontAwesomeIcons.infoCircle), + leading: FaIcon(FontAwesomeIcons.infoCircle, color: COLOR_CLICK), onTap: _about, ), ListTile( title: Text(L10().documentation), subtitle: Text("https://inventree.readthedocs.io"), - leading: FaIcon(FontAwesomeIcons.book), + leading: FaIcon(FontAwesomeIcons.book, color: COLOR_CLICK), onTap: () { _openDocs(); }, @@ -74,7 +75,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().translate), subtitle: Text(L10().translateHelp), - leading: FaIcon(FontAwesomeIcons.language), + leading: FaIcon(FontAwesomeIcons.language, color: COLOR_CLICK), onTap: () { _translate(); } @@ -83,7 +84,7 @@ class _InvenTreeSettingsState extends State { ListTile( title: Text(L10().feedback), subtitle: Text(L10().submitFeedback), - leading: FaIcon(FontAwesomeIcons.comments), + leading: FaIcon(FontAwesomeIcons.comments, color: COLOR_CLICK), onTap: () { _submitFeedback(context); }, diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 87433f13..83fbaced 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -8,10 +8,6 @@ import 'package:inventree/widget/progress.dart'; import 'package:inventree/l10.dart'; - -import 'package:inventree/widget/fields.dart'; -import 'package:inventree/widget/dialogs.dart'; -import 'package:inventree/widget/snacks.dart'; import 'package:inventree/widget/part_detail.dart'; import 'package:inventree/widget/refreshable_state.dart'; import 'package:inventree/widget/paginator.dart'; diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 93bacd2e..9f91276f 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -8,9 +8,6 @@ import 'package:inventree/inventree/stock.dart'; import 'package:inventree/widget/progress.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:inventree/widget/paginator.dart'; import 'package:inventree/l10.dart'; @@ -37,8 +34,6 @@ class _LocationDisplayState extends RefreshableState { final InvenTreeStockLocation? location; - final _editLocationKey = GlobalKey(); - @override String getAppBarTitle(BuildContext context) { return L10().stockLocation; } @@ -101,14 +96,6 @@ class _LocationDisplayState extends RefreshableState { modelData: _loc.jsondata, onSuccess: refresh ); - - // Values which an be edited - var _name; - var _description; - - if (location == null) { - return; - } } _LocationDisplayState(this.location); diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 9fb5037a..bfef7222 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -37,7 +37,6 @@ class PartDetailWidget extends StatefulWidget { class _PartDisplayState extends RefreshableState { final _editImageKey = GlobalKey(); - final _editPartKey = GlobalKey(); @override String getAppBarTitle(BuildContext context) => L10().partDetails; @@ -104,23 +103,6 @@ class _PartDisplayState extends RefreshableState { } } - void _savePart(Map values) async { - - final bool result = await part.update(values: values); - - if (result) { - showSnackIcon(L10().partEdited, success: true); - } - /* - showSnackIcon( - result ? "Part edited" : "Part editing failed", - success: result - ); - */ - - refresh(); - } - /** * Upload image for this Part. * Show a SnackBar with upload result. @@ -411,22 +393,20 @@ class _PartDisplayState extends RefreshableState { ); } - // Notes field? - if (part.notes.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), - trailing: Text(""), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartNotesWidget(part)) - ); - }, - ) - ); - } + // Notes field + tiles.add( + ListTile( + title: Text(L10().notes), + leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), + trailing: Text(""), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => PartNotesWidget(part)) + ); + }, + ) + ); return tiles; diff --git a/lib/widget/part_notes.dart b/lib/widget/part_notes.dart index 31a5ae0a..1abea016 100644 --- a/lib/widget/part_notes.dart +++ b/lib/widget/part_notes.dart @@ -1,9 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:inventree/api.dart'; import 'package:inventree/inventree/part.dart'; import 'package:inventree/widget/refreshable_state.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:inventree/l10.dart'; +import '../api_form.dart'; + class PartNotesWidget extends StatefulWidget { @@ -22,9 +27,47 @@ class _PartNotesState extends RefreshableState { _PartNotesState(this.part); + @override + Future request() async { + await part.reload(); + } + @override String getAppBarTitle(BuildContext context) => L10().partNotes; + @override + List getAppBarActions(BuildContext context) { + + List actions = []; + + if (InvenTreeAPI().checkPermission('part', 'change')) { + actions.add( + IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + tooltip: L10().edit, + onPressed: () { + launchApiForm( + context, + L10().editNotes, + part.url, + { + "notes": { + "multiline": true, + } + }, + modelData: part.jsondata, + onSuccess: () async { + refresh(); + } + ); + } + ) + ); + } + + return actions; + } + @override Widget getBody(BuildContext context) { return Markdown( diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index c71335c4..aecfec18 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -47,7 +47,6 @@ class _StockItemDisplayState extends RefreshableState { final _removeStockKey = GlobalKey(); final _countStockKey = GlobalKey(); final _moveStockKey = GlobalKey(); - final _editStockKey = GlobalKey(); _StockItemDisplayState(this.item); @@ -291,9 +290,6 @@ class _StockItemDisplayState extends RefreshableState { void _transferStockDialog(BuildContext context) async { - var locations = await InvenTreeStockLocation().list(); - final _selectedController = TextEditingController(); - int? location_pk; _quantityController.text = "${item.quantityString}"; @@ -563,22 +559,21 @@ class _StockItemDisplayState extends RefreshableState { ); } - if (item.notes.isNotEmpty) { - tiles.add( - ListTile( - title: Text(L10().notes), - leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => StockNotesWidget(item)) - ); - // TODO: Load notes in markdown viewer widget - // TODO: Make this widget editable? - } - ) - ); - } + // Notes field + tiles.add( + ListTile( + title: Text(L10().notes), + leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => StockNotesWidget(item)) + ); + // TODO: Load notes in markdown viewer widget + // TODO: Make this widget editable? + } + ) + ); return tiles; } diff --git a/lib/widget/stock_notes.dart b/lib/widget/stock_notes.dart index 2fb5d3b7..1034605e 100644 --- a/lib/widget/stock_notes.dart +++ b/lib/widget/stock_notes.dart @@ -1,10 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:inventree/inventree/stock.dart'; import 'package:inventree/widget/refreshable_state.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:inventree/l10.dart'; +import '../api.dart'; +import '../api_form.dart'; + class StockNotesWidget extends StatefulWidget { @@ -26,6 +31,43 @@ class _StockNotesState extends RefreshableState { @override String getAppBarTitle(BuildContext context) => L10().stockItemNotes; + @override + Future request() async { + await item.reload(); + } + + @override + List getAppBarActions(BuildContext context) { + List actions = []; + + if (InvenTreeAPI().checkPermission('stock', 'change')) { + actions.add( + IconButton( + icon: FaIcon(FontAwesomeIcons.edit), + tooltip: L10().edit, + onPressed: () { + launchApiForm( + context, + L10().editNotes, + item.url, + { + "notes": { + "multiline": true, + } + }, + modelData: item.jsondata, + onSuccess: () { + refresh(); + } + ); + } + ) + ); + } + + return actions; + } + @override Widget getBody(BuildContext context) { return Markdown(