2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 05:26:47 +00:00

Enable multi-line text editing for API forms

- User can edit part notes
- User can edit stock item notes
This commit is contained in:
Oliver 2021-07-28 16:19:42 +10:00
parent b8379e05db
commit d6a2a41ab2
10 changed files with 129 additions and 82 deletions

View File

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

View File

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

View File

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

View File

@ -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<InvenTreeSettingsWidget> {
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<InvenTreeSettingsWidget> {
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<InvenTreeSettingsWidget> {
ListTile(
title: Text(L10().feedback),
subtitle: Text(L10().submitFeedback),
leading: FaIcon(FontAwesomeIcons.comments),
leading: FaIcon(FontAwesomeIcons.comments, color: COLOR_CLICK),
onTap: () {
_submitFeedback(context);
},

View File

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

View File

@ -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<LocationDisplayWidget> {
final InvenTreeStockLocation? location;
final _editLocationKey = GlobalKey<FormState>();
@override
String getAppBarTitle(BuildContext context) { return L10().stockLocation; }
@ -101,14 +96,6 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
modelData: _loc.jsondata,
onSuccess: refresh
);
// Values which an be edited
var _name;
var _description;
if (location == null) {
return;
}
}
_LocationDisplayState(this.location);

View File

@ -37,7 +37,6 @@ class PartDetailWidget extends StatefulWidget {
class _PartDisplayState extends RefreshableState<PartDetailWidget> {
final _editImageKey = GlobalKey<FormState>();
final _editPartKey = GlobalKey<FormState>();
@override
String getAppBarTitle(BuildContext context) => L10().partDetails;
@ -104,23 +103,6 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
}
}
void _savePart(Map<String, String> 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,8 +393,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
);
}
// Notes field?
if (part.notes.isNotEmpty) {
// Notes field
tiles.add(
ListTile(
title: Text(L10().notes),
@ -426,7 +407,6 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
},
)
);
}
return tiles;

View File

@ -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<PartNotesWidget> {
_PartNotesState(this.part);
@override
Future<void> request() async {
await part.reload();
}
@override
String getAppBarTitle(BuildContext context) => L10().partNotes;
@override
List<Widget> getAppBarActions(BuildContext context) {
List<Widget> 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(

View File

@ -47,7 +47,6 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
final _removeStockKey = GlobalKey<FormState>();
final _countStockKey = GlobalKey<FormState>();
final _moveStockKey = GlobalKey<FormState>();
final _editStockKey = GlobalKey<FormState>();
_StockItemDisplayState(this.item);
@ -291,9 +290,6 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
void _transferStockDialog(BuildContext context) async {
var locations = await InvenTreeStockLocation().list();
final _selectedController = TextEditingController();
int? location_pk;
_quantityController.text = "${item.quantityString}";
@ -563,7 +559,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
);
}
if (item.notes.isNotEmpty) {
// Notes field
tiles.add(
ListTile(
title: Text(L10().notes),
@ -578,7 +574,6 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
}
)
);
}
return tiles;
}

View File

@ -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<StockNotesWidget> {
@override
String getAppBarTitle(BuildContext context) => L10().stockItemNotes;
@override
Future<void> request() async {
await item.reload();
}
@override
List<Widget> getAppBarActions(BuildContext context) {
List<Widget> 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(