mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 13:36:50 +00:00
Refactor company list views:
- Suppliers - Manufacturers - Customers
This commit is contained in:
parent
e5f09acf3f
commit
293750dce7
2
lib/l10n
2
lib/l10n
@ -1 +1 @@
|
|||||||
Subproject commit 15a67a8aa7ec5af876b0467152de13baff8f7806
|
Subproject commit 7cf4974a05bd78fa5efbea422e456ddb8a542441
|
@ -481,7 +481,7 @@ class _PaginatedPartListState extends State<PaginatedPartList> {
|
|||||||
return _buildPart(context, item);
|
return _buildPart(context, item);
|
||||||
},
|
},
|
||||||
noItemsFoundIndicatorBuilder: (context) {
|
noItemsFoundIndicatorBuilder: (context) {
|
||||||
return NoResultsWidget("No parts found");
|
return NoResultsWidget(L10().partNoResults);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
separatorBuilder: (context, index) => const Divider(height: 1),
|
separatorBuilder: (context, index) => const Divider(height: 1),
|
||||||
|
@ -1,128 +1,195 @@
|
|||||||
|
|
||||||
import 'package:inventree/widget/company_detail.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
|
|
||||||
import 'package:inventree/api.dart';
|
import 'package:inventree/api.dart';
|
||||||
import 'package:inventree/inventree/company.dart';
|
import 'package:inventree/inventree/company.dart';
|
||||||
|
import 'package:inventree/inventree/sentry.dart';
|
||||||
|
import 'package:inventree/widget/paginator.dart';
|
||||||
import 'package:inventree/widget/refreshable_state.dart';
|
import 'package:inventree/widget/refreshable_state.dart';
|
||||||
|
import 'package:inventree/widget/company_detail.dart';
|
||||||
|
|
||||||
abstract class CompanyListWidget extends StatefulWidget {
|
import '../l10.dart';
|
||||||
|
|
||||||
final String title = "";
|
|
||||||
Map<String, String> filters = {};
|
class CompanyListWidget extends StatefulWidget {
|
||||||
|
|
||||||
|
CompanyListWidget(this.title, this.filters, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
String title;
|
||||||
|
|
||||||
|
Map<String, String> filters;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CompanyListState createState() => _CompanyListState(title, filters);
|
_CompanyListWidgetState createState() => _CompanyListWidgetState(title, filters);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class SupplierListWidget extends CompanyListWidget {
|
|
||||||
@override
|
|
||||||
_CompanyListState createState() => _CompanyListState("Suppliers", {"is_supplier": "true"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerListWidget extends CompanyListWidget {
|
class _CompanyListWidgetState extends RefreshableState<CompanyListWidget> {
|
||||||
@override
|
|
||||||
_CompanyListState createState() => _CompanyListState("Manufacturers", {"is_manufacturer": "true"});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_CompanyListWidgetState(this.title, this.filters);
|
||||||
|
|
||||||
class CustomerListWidget extends CompanyListWidget {
|
final String title;
|
||||||
@override
|
|
||||||
_CompanyListState createState() => _CompanyListState("Customers", {"is_customer": "true"});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
final Map<String, String> filters;
|
||||||
class _CompanyListState extends RefreshableState<CompanyListWidget> {
|
|
||||||
|
|
||||||
List<InvenTreeCompany> _companies = [];
|
|
||||||
|
|
||||||
List<InvenTreeCompany> _filteredCompanies = [];
|
|
||||||
|
|
||||||
String _title = "Companies";
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getAppBarTitle(BuildContext context) { return _title; }
|
String getAppBarTitle(BuildContext context) => title;
|
||||||
|
|
||||||
Map<String, String> _filters = Map<String, String>();
|
|
||||||
|
|
||||||
_CompanyListState(this._title, this._filters);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onBuild(BuildContext context) async {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> request() async {
|
|
||||||
|
|
||||||
await InvenTreeCompany().list(filters: _filters).then((var companies) {
|
|
||||||
|
|
||||||
_companies.clear();
|
|
||||||
|
|
||||||
for (var c in companies) {
|
|
||||||
if (c is InvenTreeCompany) {
|
|
||||||
_companies.add(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_filterResults("");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _filterResults(String text) {
|
|
||||||
|
|
||||||
if (text.isEmpty) {
|
|
||||||
_filteredCompanies = _companies;
|
|
||||||
} else {
|
|
||||||
_filteredCompanies = _companies.where((c) => c.filter(text)).toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _showCompany(BuildContext context, int index) {
|
|
||||||
|
|
||||||
InvenTreeCompany company = _filteredCompanies[index];
|
|
||||||
|
|
||||||
return ListTile(
|
|
||||||
title: Text("${company.name}"),
|
|
||||||
subtitle: Text("${company.description}"),
|
|
||||||
leading: InvenTreeAPI().getImage(company.image),
|
|
||||||
onTap: () {
|
|
||||||
if (company.pk > 0) {
|
|
||||||
InvenTreeCompany().get(company.pk).then((var c) {
|
|
||||||
if (c != null && c is InvenTreeCompany) {
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyDetailWidget(c)));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getBody(BuildContext context) {
|
Widget getBody(BuildContext context) {
|
||||||
return ListView(
|
|
||||||
children: <Widget>[
|
return PaginatedCompanyList(filters);
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(
|
}
|
||||||
hintText: 'Filter results',
|
|
||||||
),
|
}
|
||||||
onChanged: (String text) {
|
|
||||||
setState(() {
|
|
||||||
_filterResults(text);
|
class PaginatedCompanyList extends StatefulWidget {
|
||||||
|
|
||||||
|
PaginatedCompanyList(this.filters, {this.onTotalChanged});
|
||||||
|
|
||||||
|
final Map<String, String> filters;
|
||||||
|
|
||||||
|
Function(int)? onTotalChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CompanyListState createState() => _CompanyListState(filters, onTotalChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CompanyListState extends State<PaginatedCompanyList> {
|
||||||
|
|
||||||
|
_CompanyListState(this.filters, this.onTotalChanged);
|
||||||
|
|
||||||
|
static const _pageSize = 25;
|
||||||
|
|
||||||
|
String _searchTerm = "";
|
||||||
|
|
||||||
|
Function(int)? onTotalChanged;
|
||||||
|
|
||||||
|
final Map<String, String> filters;
|
||||||
|
|
||||||
|
final PagingController<int, InvenTreeCompany> _pagingController = PagingController(firstPageKey: 0);
|
||||||
|
|
||||||
|
final TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_pagingController.addPageRequestListener((pageKey) {
|
||||||
|
_fetchPage(pageKey);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_pagingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
int resultCount = 0;
|
||||||
|
|
||||||
|
Future<void> _fetchPage(int pageKey) async {
|
||||||
|
try {
|
||||||
|
Map<String, String> params = filters;
|
||||||
|
|
||||||
|
params["search"] = _searchTerm;
|
||||||
|
|
||||||
|
final page = await InvenTreeCompany().listPaginated(
|
||||||
|
_pageSize, pageKey, filters: params);
|
||||||
|
|
||||||
|
int pageLength = page?.length ?? 0;
|
||||||
|
int pageCount = page?.count ?? 0;
|
||||||
|
|
||||||
|
final isLastPage = pageLength < _pageSize;
|
||||||
|
|
||||||
|
List<InvenTreeCompany> companies = [];
|
||||||
|
|
||||||
|
if (page != null) {
|
||||||
|
for (var result in page.results) {
|
||||||
|
if (result is InvenTreeCompany) {
|
||||||
|
companies.add(result);
|
||||||
|
} else {
|
||||||
|
print(result.jsondata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLastPage) {
|
||||||
|
_pagingController.appendLastPage(companies);
|
||||||
|
} else {
|
||||||
|
final int nextPageKey = pageKey + pageLength;
|
||||||
|
_pagingController.appendPage(companies, nextPageKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onTotalChanged != null) {
|
||||||
|
onTotalChanged!(pageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
resultCount = pageCount;
|
||||||
|
});
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
print("Error! - ${error.toString()}");
|
||||||
|
_pagingController.error = error;
|
||||||
|
|
||||||
|
sentryReportError(error, stackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSearchTerm() {
|
||||||
|
_searchTerm = searchController.text;
|
||||||
|
_pagingController.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCompany(BuildContext context, InvenTreeCompany company) {
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
title: Text(company.name),
|
||||||
|
subtitle: Text(company.description),
|
||||||
|
leading: InvenTreeAPI().getImage(
|
||||||
|
company.image,
|
||||||
|
width: 40,
|
||||||
|
height: 40
|
||||||
),
|
),
|
||||||
ListView.builder(
|
onTap: () async {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyDetailWidget(company)));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
PaginatedSearchWidget(searchController, updateSearchTerm, resultCount),
|
||||||
|
Expanded(
|
||||||
|
child: CustomScrollView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: ClampingScrollPhysics(),
|
physics: ClampingScrollPhysics(),
|
||||||
itemBuilder: _showCompany, itemCount: _filteredCompanies.length)
|
scrollDirection: Axis.vertical,
|
||||||
|
slivers: [
|
||||||
|
PagedSliverList.separated(
|
||||||
|
pagingController: _pagingController,
|
||||||
|
builderDelegate: PagedChildBuilderDelegate<InvenTreeCompany>(
|
||||||
|
itemBuilder: (context, item, index) {
|
||||||
|
return _buildCompany(context, item);
|
||||||
|
},
|
||||||
|
noItemsFoundIndicatorBuilder: (context) {
|
||||||
|
return NoResultsWidget(L10().companyNoResults);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
separatorBuilder: (context, index) => const Divider(height: 1),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -80,21 +80,21 @@ class InvenTreeDrawer extends StatelessWidget {
|
|||||||
if (!InvenTreeAPI().checkConnection(context)) return;
|
if (!InvenTreeAPI().checkConnection(context)) return;
|
||||||
_closeDrawer();
|
_closeDrawer();
|
||||||
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierListWidget()));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().suppliers, {"is_supplier": "true"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showManufacturers() {
|
void _showManufacturers() {
|
||||||
if (!InvenTreeAPI().checkConnection(context)) return;
|
if (!InvenTreeAPI().checkConnection(context)) return;
|
||||||
_closeDrawer();
|
_closeDrawer();
|
||||||
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => ManufacturerListWidget()));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().manufacturers, {"is_manufacturer": "true"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showCustomers() {
|
void _showCustomers() {
|
||||||
if (!InvenTreeAPI().checkConnection(context)) return;
|
if (!InvenTreeAPI().checkConnection(context)) return;
|
||||||
_closeDrawer();
|
_closeDrawer();
|
||||||
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => CustomerListWidget()));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -144,7 +144,7 @@ class InvenTreeDrawer extends StatelessWidget {
|
|||||||
leading: FaIcon(FontAwesomeIcons.boxes),
|
leading: FaIcon(FontAwesomeIcons.boxes),
|
||||||
onTap: _showStock,
|
onTap: _showStock,
|
||||||
),
|
),
|
||||||
/*
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text("Suppliers"),
|
title: Text("Suppliers"),
|
||||||
leading: FaIcon(FontAwesomeIcons.building),
|
leading: FaIcon(FontAwesomeIcons.building),
|
||||||
@ -160,7 +160,6 @@ class InvenTreeDrawer extends StatelessWidget {
|
|||||||
leading: FaIcon(FontAwesomeIcons.users),
|
leading: FaIcon(FontAwesomeIcons.users),
|
||||||
onTap: _showCustomers,
|
onTap: _showCustomers,
|
||||||
),
|
),
|
||||||
*/
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(L10().settings),
|
title: Text(L10().settings),
|
||||||
leading: Icon(Icons.settings),
|
leading: Icon(Icons.settings),
|
||||||
|
@ -79,19 +79,19 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
|
|||||||
void _suppliers() {
|
void _suppliers() {
|
||||||
if (!InvenTreeAPI().checkConnection(context)) return;
|
if (!InvenTreeAPI().checkConnection(context)) return;
|
||||||
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => SupplierListWidget()));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().suppliers, {"is_supplier": "true"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _manufacturers() {
|
void _manufacturers() {
|
||||||
if (!InvenTreeAPI().checkConnection(context)) return;
|
if (!InvenTreeAPI().checkConnection(context)) return;
|
||||||
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => ManufacturerListWidget()));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().manufacturers, {"is_manufacturer": "true"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _customers() {
|
void _customers() {
|
||||||
if (!InvenTreeAPI().checkConnection(context)) return;
|
if (!InvenTreeAPI().checkConnection(context)) return;
|
||||||
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => CustomerListWidget()));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CompanyListWidget(L10().customers, {"is_customer": "true"})));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectProfile() {
|
void _selectProfile() {
|
||||||
|
@ -8,6 +8,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:inventree/inventree/part.dart';
|
import 'package:inventree/inventree/part.dart';
|
||||||
import 'package:inventree/inventree/company.dart';
|
import 'package:inventree/inventree/company.dart';
|
||||||
|
import 'package:inventree/widget/company_detail.dart';
|
||||||
import 'package:inventree/widget/refreshable_state.dart';
|
import 'package:inventree/widget/refreshable_state.dart';
|
||||||
|
|
||||||
class PartSupplierWidget extends StatefulWidget {
|
class PartSupplierWidget extends StatefulWidget {
|
||||||
@ -57,7 +58,19 @@ class _PartSupplierState extends RefreshableState<PartSupplierWidget> {
|
|||||||
height: 40,
|
height: 40,
|
||||||
),
|
),
|
||||||
title: Text("${_part.SKU}"),
|
title: Text("${_part.SKU}"),
|
||||||
subtitle: Text("${_part.manufacturerName}: ${_part.MPN}")
|
subtitle: Text("${_part.manufacturerName}: ${_part.MPN}"),
|
||||||
|
onTap: () async {
|
||||||
|
var company = await InvenTreeCompany().get(_part.supplierId);
|
||||||
|
|
||||||
|
if (company != null && company is InvenTreeCompany) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => CompanyDetailWidget(company)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user