mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-11-04 07:15:46 +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:
		@@ -22,8 +22,6 @@ import 'package:inventree/widget/snacks.dart';
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class APIFormField {
 | 
					class APIFormField {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final _controller = TextEditingController();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Constructor
 | 
					  // Constructor
 | 
				
			||||||
  APIFormField(this.name, this.data);
 | 
					  APIFormField(this.name, this.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,6 +45,8 @@ class APIFormField {
 | 
				
			|||||||
  // Is this field read only?
 | 
					  // Is this field read only?
 | 
				
			||||||
  bool get readOnly => (data['read_only'] ?? false) as bool;
 | 
					  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)
 | 
					  // Get the "value" as a string (look for "default" if not available)
 | 
				
			||||||
  dynamic get value => (data['value'] ?? data['default']);
 | 
					  dynamic get value => (data['value'] ?? data['default']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -341,6 +341,8 @@ class APIFormField {
 | 
				
			|||||||
        helperStyle: _helperStyle(),
 | 
					        helperStyle: _helperStyle(),
 | 
				
			||||||
        hintText: placeholderText,
 | 
					        hintText: placeholderText,
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
 | 
					      maxLines: multiline ? null : 1,
 | 
				
			||||||
 | 
					      expands: false,
 | 
				
			||||||
      initialValue: value ?? '',
 | 
					      initialValue: value ?? '',
 | 
				
			||||||
      onSaved: (val) {
 | 
					      onSaved: (val) {
 | 
				
			||||||
        data["value"] = val;
 | 
					        data["value"] = val;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import 'dart:ui';
 | 
				
			|||||||
const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1);
 | 
					const Color COLOR_GRAY = Color.fromRGBO(50, 50, 50, 1);
 | 
				
			||||||
const Color COLOR_GRAY_LIGHT = Color.fromRGBO(150, 150, 150, 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);
 | 
					const Color COLOR_BLUE = Color.fromRGBO(0, 0, 250, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import 'package:inventree/api.dart';
 | 
					import 'package:inventree/api.dart';
 | 
				
			||||||
 | 
					import 'package:inventree/app_colors.dart';
 | 
				
			||||||
import 'package:inventree/settings/release.dart';
 | 
					import 'package:inventree/settings/release.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
@@ -116,7 +117,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(L10().releaseNotes),
 | 
					        title: Text(L10().releaseNotes),
 | 
				
			||||||
        subtitle: Text(L10().appReleaseNotes),
 | 
					        subtitle: Text(L10().appReleaseNotes),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.fileAlt),
 | 
					        leading: FaIcon(FontAwesomeIcons.fileAlt, color: COLOR_CLICK),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
          _releaseNotes(context);
 | 
					          _releaseNotes(context);
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -127,7 +128,7 @@ class InvenTreeAboutWidget extends StatelessWidget {
 | 
				
			|||||||
      ListTile(
 | 
					      ListTile(
 | 
				
			||||||
        title: Text(L10().credits),
 | 
					        title: Text(L10().credits),
 | 
				
			||||||
        subtitle: Text(L10().appCredits),
 | 
					        subtitle: Text(L10().appCredits),
 | 
				
			||||||
        leading: FaIcon(FontAwesomeIcons.bullhorn),
 | 
					        leading: FaIcon(FontAwesomeIcons.bullhorn, color: COLOR_CLICK),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
          _credits(context);
 | 
					          _credits(context);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					import 'package:inventree/app_colors.dart';
 | 
				
			||||||
import 'package:inventree/inventree/sentry.dart';
 | 
					import 'package:inventree/inventree/sentry.dart';
 | 
				
			||||||
import 'package:inventree/settings/about.dart';
 | 
					import 'package:inventree/settings/about.dart';
 | 
				
			||||||
import 'package:inventree/settings/app_settings.dart';
 | 
					import 'package:inventree/settings/app_settings.dart';
 | 
				
			||||||
@@ -46,26 +47,26 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                  title: Text(L10().server),
 | 
					                  title: Text(L10().server),
 | 
				
			||||||
                  subtitle: Text(L10().configureServer),
 | 
					                  subtitle: Text(L10().configureServer),
 | 
				
			||||||
                  leading: FaIcon(FontAwesomeIcons.server),
 | 
					                  leading: FaIcon(FontAwesomeIcons.server, color: COLOR_CLICK),
 | 
				
			||||||
                  onTap: _editServerSettings,
 | 
					                  onTap: _editServerSettings,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.cogs),
 | 
					 | 
				
			||||||
                title: Text(L10().appSettings),
 | 
					                title: Text(L10().appSettings),
 | 
				
			||||||
                subtitle: Text(L10().appSettingsDetails),
 | 
					                subtitle: Text(L10().appSettingsDetails),
 | 
				
			||||||
 | 
					                leading: FaIcon(FontAwesomeIcons.cogs, color: COLOR_CLICK),
 | 
				
			||||||
                onTap: _editAppSettings,
 | 
					                onTap: _editAppSettings,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(L10().about),
 | 
					                title: Text(L10().about),
 | 
				
			||||||
                subtitle: Text(L10().appDetails),
 | 
					                subtitle: Text(L10().appDetails),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.infoCircle),
 | 
					                leading: FaIcon(FontAwesomeIcons.infoCircle, color: COLOR_CLICK),
 | 
				
			||||||
                onTap: _about,
 | 
					                onTap: _about,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(L10().documentation),
 | 
					                title: Text(L10().documentation),
 | 
				
			||||||
                subtitle: Text("https://inventree.readthedocs.io"),
 | 
					                subtitle: Text("https://inventree.readthedocs.io"),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.book),
 | 
					                leading: FaIcon(FontAwesomeIcons.book, color: COLOR_CLICK),
 | 
				
			||||||
                onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
                  _openDocs();
 | 
					                  _openDocs();
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -74,7 +75,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(L10().translate),
 | 
					                title: Text(L10().translate),
 | 
				
			||||||
                subtitle: Text(L10().translateHelp),
 | 
					                subtitle: Text(L10().translateHelp),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.language),
 | 
					                leading: FaIcon(FontAwesomeIcons.language, color: COLOR_CLICK),
 | 
				
			||||||
                onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
                  _translate();
 | 
					                  _translate();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -83,7 +84,7 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> {
 | 
				
			|||||||
              ListTile(
 | 
					              ListTile(
 | 
				
			||||||
                title: Text(L10().feedback),
 | 
					                title: Text(L10().feedback),
 | 
				
			||||||
                subtitle: Text(L10().submitFeedback),
 | 
					                subtitle: Text(L10().submitFeedback),
 | 
				
			||||||
                leading: FaIcon(FontAwesomeIcons.comments),
 | 
					                leading: FaIcon(FontAwesomeIcons.comments, color: COLOR_CLICK),
 | 
				
			||||||
                onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
                  _submitFeedback(context);
 | 
					                  _submitFeedback(context);
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,6 @@ import 'package:inventree/widget/progress.dart';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import 'package:inventree/l10.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/part_detail.dart';
 | 
				
			||||||
import 'package:inventree/widget/refreshable_state.dart';
 | 
					import 'package:inventree/widget/refreshable_state.dart';
 | 
				
			||||||
import 'package:inventree/widget/paginator.dart';
 | 
					import 'package:inventree/widget/paginator.dart';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,9 +8,6 @@ import 'package:inventree/inventree/stock.dart';
 | 
				
			|||||||
import 'package:inventree/widget/progress.dart';
 | 
					import 'package:inventree/widget/progress.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:inventree/widget/refreshable_state.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/stock_detail.dart';
 | 
				
			||||||
import 'package:inventree/widget/paginator.dart';
 | 
					import 'package:inventree/widget/paginator.dart';
 | 
				
			||||||
import 'package:inventree/l10.dart';
 | 
					import 'package:inventree/l10.dart';
 | 
				
			||||||
@@ -37,8 +34,6 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  final InvenTreeStockLocation? location;
 | 
					  final InvenTreeStockLocation? location;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final _editLocationKey = GlobalKey<FormState>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) { return L10().stockLocation; }
 | 
					  String getAppBarTitle(BuildContext context) { return L10().stockLocation; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -101,14 +96,6 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
 | 
				
			|||||||
      modelData: _loc.jsondata,
 | 
					      modelData: _loc.jsondata,
 | 
				
			||||||
      onSuccess: refresh
 | 
					      onSuccess: refresh
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Values which an be edited
 | 
					 | 
				
			||||||
    var _name;
 | 
					 | 
				
			||||||
    var _description;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (location == null) {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _LocationDisplayState(this.location);
 | 
					  _LocationDisplayState(this.location);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,6 @@ class PartDetailWidget extends StatefulWidget {
 | 
				
			|||||||
class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
					class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final _editImageKey = GlobalKey<FormState>();
 | 
					  final _editImageKey = GlobalKey<FormState>();
 | 
				
			||||||
  final _editPartKey = GlobalKey<FormState>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => L10().partDetails;
 | 
					  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.
 | 
					   * Upload image for this Part.
 | 
				
			||||||
   * Show a SnackBar with upload result.
 | 
					   * Show a SnackBar with upload result.
 | 
				
			||||||
@@ -411,22 +393,20 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Notes field?
 | 
					    // Notes field
 | 
				
			||||||
    if (part.notes.isNotEmpty) {
 | 
					    tiles.add(
 | 
				
			||||||
      tiles.add(
 | 
					      ListTile(
 | 
				
			||||||
          ListTile(
 | 
					        title: Text(L10().notes),
 | 
				
			||||||
            title: Text(L10().notes),
 | 
					        leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK),
 | 
				
			||||||
            leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK),
 | 
					        trailing: Text(""),
 | 
				
			||||||
            trailing: Text(""),
 | 
					        onTap: () {
 | 
				
			||||||
            onTap: () {
 | 
					          Navigator.push(
 | 
				
			||||||
              Navigator.push(
 | 
					            context,
 | 
				
			||||||
                context,
 | 
					            MaterialPageRoute(builder: (context) => PartNotesWidget(part))
 | 
				
			||||||
                MaterialPageRoute(builder: (context) => PartNotesWidget(part))
 | 
					          );
 | 
				
			||||||
              );
 | 
					        },
 | 
				
			||||||
            },
 | 
					      )
 | 
				
			||||||
          )
 | 
					    );
 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return tiles;
 | 
					    return tiles;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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/inventree/part.dart';
 | 
				
			||||||
import 'package:inventree/widget/refreshable_state.dart';
 | 
					import 'package:inventree/widget/refreshable_state.dart';
 | 
				
			||||||
import 'package:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
import 'package:flutter_markdown/flutter_markdown.dart';
 | 
					import 'package:flutter_markdown/flutter_markdown.dart';
 | 
				
			||||||
import 'package:inventree/l10.dart';
 | 
					import 'package:inventree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api_form.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PartNotesWidget extends StatefulWidget {
 | 
					class PartNotesWidget extends StatefulWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,9 +27,47 @@ class _PartNotesState extends RefreshableState<PartNotesWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  _PartNotesState(this.part);
 | 
					  _PartNotesState(this.part);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> request() async {
 | 
				
			||||||
 | 
					    await part.reload();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => L10().partNotes;
 | 
					  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
 | 
					  @override
 | 
				
			||||||
  Widget getBody(BuildContext context) {
 | 
					  Widget getBody(BuildContext context) {
 | 
				
			||||||
    return Markdown(
 | 
					    return Markdown(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,6 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
  final _removeStockKey = GlobalKey<FormState>();
 | 
					  final _removeStockKey = GlobalKey<FormState>();
 | 
				
			||||||
  final _countStockKey = GlobalKey<FormState>();
 | 
					  final _countStockKey = GlobalKey<FormState>();
 | 
				
			||||||
  final _moveStockKey = GlobalKey<FormState>();
 | 
					  final _moveStockKey = GlobalKey<FormState>();
 | 
				
			||||||
  final _editStockKey = GlobalKey<FormState>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _StockItemDisplayState(this.item);
 | 
					  _StockItemDisplayState(this.item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -291,9 +290,6 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void _transferStockDialog(BuildContext context) async {
 | 
					  void _transferStockDialog(BuildContext context) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var locations = await InvenTreeStockLocation().list();
 | 
					 | 
				
			||||||
    final _selectedController = TextEditingController();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int? location_pk;
 | 
					    int? location_pk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _quantityController.text = "${item.quantityString}";
 | 
					    _quantityController.text = "${item.quantityString}";
 | 
				
			||||||
@@ -563,22 +559,21 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (item.notes.isNotEmpty) {
 | 
					    // Notes field
 | 
				
			||||||
      tiles.add(
 | 
					    tiles.add(
 | 
				
			||||||
        ListTile(
 | 
					      ListTile(
 | 
				
			||||||
          title: Text(L10().notes),
 | 
					        title: Text(L10().notes),
 | 
				
			||||||
          leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK),
 | 
					        leading: FaIcon(FontAwesomeIcons.stickyNote, color: COLOR_CLICK),
 | 
				
			||||||
          onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
            Navigator.push(
 | 
					          Navigator.push(
 | 
				
			||||||
              context,
 | 
					            context,
 | 
				
			||||||
              MaterialPageRoute(builder: (context) => StockNotesWidget(item))
 | 
					            MaterialPageRoute(builder: (context) => StockNotesWidget(item))
 | 
				
			||||||
            );
 | 
					          );
 | 
				
			||||||
            // TODO: Load notes in markdown viewer widget
 | 
					          // TODO: Load notes in markdown viewer widget
 | 
				
			||||||
            // TODO: Make this widget editable?
 | 
					          // TODO: Make this widget editable?
 | 
				
			||||||
          }
 | 
					        }
 | 
				
			||||||
        )
 | 
					      )
 | 
				
			||||||
      );
 | 
					    );
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return tiles;
 | 
					    return tiles;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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/inventree/stock.dart';
 | 
				
			||||||
import 'package:inventree/widget/refreshable_state.dart';
 | 
					import 'package:inventree/widget/refreshable_state.dart';
 | 
				
			||||||
import 'package:flutter/cupertino.dart';
 | 
					import 'package:flutter/cupertino.dart';
 | 
				
			||||||
import 'package:flutter_markdown/flutter_markdown.dart';
 | 
					import 'package:flutter_markdown/flutter_markdown.dart';
 | 
				
			||||||
import 'package:inventree/l10.dart';
 | 
					import 'package:inventree/l10.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api.dart';
 | 
				
			||||||
 | 
					import '../api_form.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StockNotesWidget extends StatefulWidget {
 | 
					class StockNotesWidget extends StatefulWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,6 +31,43 @@ class _StockNotesState extends RefreshableState<StockNotesWidget> {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String getAppBarTitle(BuildContext context) => L10().stockItemNotes;
 | 
					  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
 | 
					  @override
 | 
				
			||||||
  Widget getBody(BuildContext context) {
 | 
					  Widget getBody(BuildContext context) {
 | 
				
			||||||
    return Markdown(
 | 
					    return Markdown(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user