diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 5d55e9f1..75d31a4d 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -636,6 +636,9 @@ class InvenTreeAttachment extends InvenTreeModel { InvenTreeAttachment.fromJson(Map json) : super.fromJson(json); + // Override this reference field for any subclasses + String get REFERENCE_FIELD => ""; + String get attachment => (jsondata["attachment"] ?? "") as String; // Return the filename of the attachment @@ -684,19 +687,27 @@ class InvenTreeAttachment extends InvenTreeModel { } } - Future uploadAttachment(File attachment, {String comment = "", Map fields = const {}}) async { + Future uploadAttachment(File attachment, int parentId, {String comment = "", Map fields = const {}}) async { + + // Ensure that the correct reference field is set + Map data = Map.from(fields); + + data[REFERENCE_FIELD] = parentId.toString(); final APIResponse response = await InvenTreeAPI().uploadFile( URL, attachment, method: "POST", name: "attachment", - fields: fields + fields: data ); return response.successful(); } + /* + * Download this attachment file + */ Future downloadAttachment() async { await InvenTreeAPI().downloadFile(attachment); diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 74670120..c528a583 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -422,6 +422,9 @@ class InvenTreePartAttachment extends InvenTreeAttachment { InvenTreePartAttachment.fromJson(Map json) : super.fromJson(json); + @override + String get REFERENCE_FIELD => "part"; + @override String get URL => "part/attachment/"; diff --git a/lib/widget/part_attachments_widget.dart b/lib/widget/attachment_widget.dart similarity index 50% rename from lib/widget/part_attachments_widget.dart rename to lib/widget/attachment_widget.dart index 5fada013..e5903258 100644 --- a/lib/widget/part_attachments_widget.dart +++ b/lib/widget/attachment_widget.dart @@ -1,33 +1,42 @@ +/* + * A generic widget for displaying a list of attachments. + * + * To allow use with different "types" of attachments, + * we pass a subclassed instance of the InvenTreeAttachment model. + */ + import "dart:io"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:inventree/inventree/part.dart"; +import "package:inventree/inventree/model.dart"; import "package:inventree/widget/fields.dart"; -import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; - -import "package:inventree/api.dart"; +import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/l10.dart"; -class PartAttachmentsWidget extends StatefulWidget { +class AttachmentWidget extends StatefulWidget { - const PartAttachmentsWidget(this.part, {Key? key}) : super(key: key); + const AttachmentWidget(this.attachment, this.referenceId, this.hasUploadPermission) : super(); - final InvenTreePart part; + final InvenTreeAttachment attachment; + final int referenceId; + final bool hasUploadPermission; @override - _PartAttachmentDisplayState createState() => _PartAttachmentDisplayState(part); + _AttachmentWidgetState createState() => _AttachmentWidgetState(attachment, referenceId, hasUploadPermission); } -class _PartAttachmentDisplayState extends RefreshableState { +class _AttachmentWidgetState extends RefreshableState { - _PartAttachmentDisplayState(this.part); + _AttachmentWidgetState(this.attachment, this.referenceId, this.hasUploadPermission); - final InvenTreePart part; + final InvenTreeAttachment attachment; + final int referenceId; + final bool hasUploadPermission; - List attachments = []; + List attachments = []; @override String getAppBarTitle(BuildContext context) => L10().attachments; @@ -37,20 +46,19 @@ class _PartAttachmentDisplayState extends RefreshableState actions = []; - if (InvenTreeAPI().checkPermission("part", "change")) { - + if (hasUploadPermission) { // File upload actions.add( - IconButton( - icon: FaIcon(FontAwesomeIcons.plusCircle), - onPressed: () async { - FilePickerDialog.pickFile( - onPicked: (File file) { - upload(file); - } - ); - }, - ) + IconButton( + icon: FaIcon(FontAwesomeIcons.plusCircle), + onPressed: () async { + FilePickerDialog.pickFile( + onPicked: (File file) { + upload(file); + } + ); + }, + ) ); } @@ -58,12 +66,8 @@ class _PartAttachmentDisplayState extends RefreshableState upload(File file) async { - final bool result = await InvenTreePartAttachment().uploadAttachment( - file, - fields: { - "part": "${part.pk}" - } - ); + + final bool result = await attachment.uploadAttachment(file, referenceId); if (result) { showSnackIcon(L10().uploadSuccess, success: true); @@ -77,32 +81,31 @@ class _PartAttachmentDisplayState extends RefreshableState request(BuildContext context) async { - await InvenTreePartAttachment().list( + await attachment.list( filters: { - "part": "${part.pk}" + attachment.REFERENCE_FIELD: referenceId.toString() } ).then((var results) { attachments.clear(); for (var result in results) { - if (result is InvenTreePartAttachment) { + if (result is InvenTreeAttachment) { attachments.add(result); } } }); - } @override Widget getBody(BuildContext context) { return Center( - child: ListView( - children: ListTile.divideTiles( - context: context, - tiles: attachmentTiles(context) - ).toList(), - ) + child: ListView( + children: ListTile.divideTiles( + context: context, + tiles: attachmentTiles(context) + ).toList(), + ) ); } @@ -126,14 +129,12 @@ class _PartAttachmentDisplayState extends RefreshableState { Navigator.push( context, MaterialPageRoute( - builder: (context) => PartAttachmentsWidget(part) + builder: (context) => AttachmentWidget( + InvenTreePartAttachment(), + part.pk, + InvenTreeAPI().checkPermission("part", "change")) ) ); },