mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-30 21:05:42 +00:00 
			
		
		
		
	* Remove unused lib/generated/i18n.dart * Use `fvm dart format .` * Add contributing guidelines * Enforce dart format * Add `dart format off` directive to generated files
		
			
				
	
	
		
			179 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import "package:flutter/material.dart";
 | |
| import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
 | |
| 
 | |
| import "package:inventree/api.dart";
 | |
| import "package:inventree/helpers.dart";
 | |
| import "package:inventree/l10.dart";
 | |
| 
 | |
| import "package:inventree/inventree/bom.dart";
 | |
| import "package:inventree/inventree/model.dart";
 | |
| import "package:inventree/inventree/part.dart";
 | |
| 
 | |
| import "package:inventree/widget/paginator.dart";
 | |
| import "package:inventree/widget/progress.dart";
 | |
| import "package:inventree/widget/refreshable_state.dart";
 | |
| 
 | |
| /*
 | |
|  * Widget for displaying a Bill of Materials for a specified Part instance
 | |
|  */
 | |
| class BillOfMaterialsWidget extends StatefulWidget {
 | |
|   const BillOfMaterialsWidget(
 | |
|     this.part, {
 | |
|     this.isParentComponent = true,
 | |
|     Key? key,
 | |
|   }) : super(key: key);
 | |
| 
 | |
|   final InvenTreePart part;
 | |
| 
 | |
|   final bool isParentComponent;
 | |
| 
 | |
|   @override
 | |
|   _BillOfMaterialsState createState() => _BillOfMaterialsState();
 | |
| }
 | |
| 
 | |
| class _BillOfMaterialsState extends RefreshableState<BillOfMaterialsWidget> {
 | |
|   _BillOfMaterialsState();
 | |
| 
 | |
|   bool showFilterOptions = false;
 | |
| 
 | |
|   @override
 | |
|   String getAppBarTitle() {
 | |
|     if (widget.isParentComponent) {
 | |
|       return L10().billOfMaterials;
 | |
|     } else {
 | |
|       return L10().usedIn;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   List<Widget> appBarActions(BuildContext context) => [
 | |
|     IconButton(
 | |
|       icon: Icon(TablerIcons.filter),
 | |
|       onPressed: () async {
 | |
|         setState(() {
 | |
|           showFilterOptions = !showFilterOptions;
 | |
|         });
 | |
|       },
 | |
|     ),
 | |
|   ];
 | |
| 
 | |
|   @override
 | |
|   Widget getBody(BuildContext context) {
 | |
|     Map<String, String> filters = {};
 | |
| 
 | |
|     if (widget.isParentComponent) {
 | |
|       filters["part"] = widget.part.pk.toString();
 | |
|     } else {
 | |
|       filters["uses"] = widget.part.pk.toString();
 | |
|     }
 | |
| 
 | |
|     return Column(
 | |
|       children: [
 | |
|         ListTile(
 | |
|           leading: InvenTreeAPI().getThumbnail(widget.part.thumbnail),
 | |
|           title: Text(widget.part.fullname),
 | |
|           subtitle: Text(
 | |
|             widget.isParentComponent
 | |
|                 ? L10().billOfMaterials
 | |
|                 : L10().usedInDetails,
 | |
|           ),
 | |
|           trailing: Text(L10().quantity),
 | |
|         ),
 | |
|         Divider(thickness: 1.25),
 | |
|         Expanded(
 | |
|           child: PaginatedBomList(
 | |
|             filters,
 | |
|             isParentPart: widget.isParentComponent,
 | |
|           ),
 | |
|         ),
 | |
|       ],
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Create a paginated widget displaying a list of BomItem objects
 | |
|  */
 | |
| class PaginatedBomList extends PaginatedSearchWidget {
 | |
|   const PaginatedBomList(
 | |
|     Map<String, String> filters, {
 | |
|     this.isParentPart = true,
 | |
|   }) : super(filters: filters);
 | |
| 
 | |
|   final bool isParentPart;
 | |
| 
 | |
|   @override
 | |
|   String get searchTitle => L10().parts;
 | |
| 
 | |
|   @override
 | |
|   _PaginatedBomListState createState() => _PaginatedBomListState();
 | |
| }
 | |
| 
 | |
| class _PaginatedBomListState extends PaginatedSearchState<PaginatedBomList> {
 | |
|   _PaginatedBomListState() : super();
 | |
| 
 | |
|   @override
 | |
|   String get prefix => "bom_";
 | |
| 
 | |
|   @override
 | |
|   Map<String, String> get orderingOptions => {
 | |
|     "quantity": L10().quantity,
 | |
|     "sub_part": L10().part,
 | |
|   };
 | |
| 
 | |
|   @override
 | |
|   Map<String, Map<String, dynamic>> get filterOptions => {
 | |
|     "sub_part_assembly": {
 | |
|       "label": L10().filterAssembly,
 | |
|       "help_text": L10().filterAssemblyDetail,
 | |
|     },
 | |
|   };
 | |
| 
 | |
|   @override
 | |
|   Future<InvenTreePageResponse?> requestPage(
 | |
|     int limit,
 | |
|     int offset,
 | |
|     Map<String, String> params,
 | |
|   ) async {
 | |
|     final page = await InvenTreeBomItem().listPaginated(
 | |
|       limit,
 | |
|       offset,
 | |
|       filters: params,
 | |
|     );
 | |
| 
 | |
|     return page;
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget buildItem(BuildContext context, InvenTreeModel model) {
 | |
|     InvenTreeBomItem bomItem = model as InvenTreeBomItem;
 | |
| 
 | |
|     InvenTreePart? subPart = widget.isParentPart
 | |
|         ? bomItem.subPart
 | |
|         : bomItem.part;
 | |
| 
 | |
|     String title = subPart?.fullname ?? "error - no name";
 | |
| 
 | |
|     return ListTile(
 | |
|       title: Text(title),
 | |
|       subtitle: Text(bomItem.reference),
 | |
|       trailing: Text(
 | |
|         simpleNumberString(bomItem.quantity),
 | |
|         style: TextStyle(fontWeight: FontWeight.bold),
 | |
|       ),
 | |
|       leading: InvenTreeAPI().getThumbnail(subPart?.thumbnail ?? ""),
 | |
|       onTap: subPart == null
 | |
|           ? null
 | |
|           : () async {
 | |
|               showLoadingOverlay();
 | |
|               var part = await InvenTreePart().get(subPart.pk);
 | |
|               hideLoadingOverlay();
 | |
| 
 | |
|               if (part is InvenTreePart) {
 | |
|                 part.goToDetailPage(context);
 | |
|               }
 | |
|             },
 | |
|     );
 | |
|   }
 | |
| }
 |