286 lines
11 KiB
Dart
286 lines
11 KiB
Dart
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||
|
import 'package:go_router/go_router.dart';
|
||
|
import 'package:outbag_app/backend/request.dart';
|
||
|
import 'package:outbag_app/backend/room.dart';
|
||
|
import 'package:outbag_app/backend/user.dart';
|
||
|
import 'package:outbag_app/components/category_chip.dart';
|
||
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
||
|
import 'package:provider/provider.dart';
|
||
|
|
||
|
class NewItemPage extends StatefulWidget {
|
||
|
final String room;
|
||
|
final String server;
|
||
|
|
||
|
final int? item;
|
||
|
|
||
|
const NewItemPage(
|
||
|
{super.key, required this.room, required this.server, this.item});
|
||
|
|
||
|
@override
|
||
|
State<StatefulWidget> createState() => _NewItemPageState();
|
||
|
}
|
||
|
|
||
|
class _NewItemPageState extends State<NewItemPage> {
|
||
|
// input controllers
|
||
|
final _ctrInput = TextEditingController();
|
||
|
|
||
|
// data cache
|
||
|
List<RoomCategory> categories = [];
|
||
|
List<RoomProduct> products = [];
|
||
|
RoomItem? item;
|
||
|
|
||
|
void fetchCategories() {
|
||
|
final user = context.read<User>();
|
||
|
|
||
|
// TODO: load cached categories first
|
||
|
|
||
|
doNetworkRequest(ScaffoldMessenger.of(context),
|
||
|
req: () => postWithCreadentials(
|
||
|
credentials: user,
|
||
|
target: user.server,
|
||
|
path: 'getCategories',
|
||
|
body: {'room': widget.room, 'server': widget.server}),
|
||
|
onOK: (body) async {
|
||
|
final resp = body['data']
|
||
|
.map<RoomCategory>((raw) => RoomCategory.fromJSON(raw))
|
||
|
.toList();
|
||
|
|
||
|
setState(() {
|
||
|
categories = resp;
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void fetchProducts() {
|
||
|
final user = context.read<User>();
|
||
|
|
||
|
// TODO: load cached products first
|
||
|
|
||
|
doNetworkRequest(ScaffoldMessenger.of(context),
|
||
|
req: () => postWithCreadentials(
|
||
|
credentials: user,
|
||
|
target: user.server,
|
||
|
path: 'getProducts',
|
||
|
body: {'room': widget.room, 'server': widget.server}),
|
||
|
onOK: (body) async {
|
||
|
final resp = body['data']
|
||
|
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
||
|
.toList();
|
||
|
|
||
|
setState(() {
|
||
|
products = resp;
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void fetchItem() {
|
||
|
final user = context.read<User>();
|
||
|
|
||
|
// TODO: load cached item first
|
||
|
|
||
|
doNetworkRequest(ScaffoldMessenger.of(context),
|
||
|
req: () => postWithCreadentials(
|
||
|
credentials: user,
|
||
|
target: user.server,
|
||
|
path: 'getItem',
|
||
|
body: {
|
||
|
'room': widget.room,
|
||
|
'server': widget.server,
|
||
|
'listItemID': widget.item
|
||
|
}),
|
||
|
onOK: (body) async {
|
||
|
final resp = RoomItem.fromJSON(body['data']);
|
||
|
setState(() {
|
||
|
item = resp;
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
|
||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
|
fetchCategories();
|
||
|
fetchProducts();
|
||
|
|
||
|
if (widget.item != null) {
|
||
|
fetchItem();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
String _query = "";
|
||
|
|
||
|
void createItem(BuildContext ctx, String name, int? productID) {
|
||
|
final scaffMgr = ScaffoldMessenger.of(context);
|
||
|
final router = GoRouter.of(context);
|
||
|
final user = context.read<User>();
|
||
|
|
||
|
doNetworkRequest(scaffMgr,
|
||
|
req: () => postWithCreadentials(
|
||
|
target: user.server,
|
||
|
credentials: user,
|
||
|
path: 'addItem',
|
||
|
body: {
|
||
|
'room': widget.room,
|
||
|
'server': widget.server,
|
||
|
'state': 0,
|
||
|
'title': name,
|
||
|
'description': '',
|
||
|
'listCatID': null,
|
||
|
'unit': 0,
|
||
|
'value': '',
|
||
|
'listProdID': productID
|
||
|
}),
|
||
|
onOK: (body) async {
|
||
|
final id = body["data"]["listItemID"];
|
||
|
// TODO cache item
|
||
|
// launch edit item screen
|
||
|
router.pushReplacementNamed('edit-item', params: {
|
||
|
'server': widget.server,
|
||
|
'id': widget.room,
|
||
|
'item': id.toString()
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void createProduct(BuildContext ctx, String name, Function(int) cb) {
|
||
|
final scaffMgr = ScaffoldMessenger.of(context);
|
||
|
final user = context.read<User>();
|
||
|
|
||
|
doNetworkRequest(scaffMgr,
|
||
|
req: () => postWithCreadentials(
|
||
|
target: user.server,
|
||
|
credentials: user,
|
||
|
path: 'addProduct',
|
||
|
body: {
|
||
|
'room': widget.room,
|
||
|
'server': widget.server,
|
||
|
'title': name,
|
||
|
'description': '',
|
||
|
'listCatID': null,
|
||
|
'defUnit': 0,
|
||
|
'defValue': '',
|
||
|
'ean': '',
|
||
|
'parent': null
|
||
|
}),
|
||
|
onOK: (body) async {
|
||
|
final id = body["data"]["listProdID"];
|
||
|
// TODO: cache product
|
||
|
cb(id);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return Scaffold(
|
||
|
appBar: AppBar(
|
||
|
title: Text((widget.item == null)
|
||
|
? AppLocalizations.of(context)!.createItem
|
||
|
: AppLocalizations.of(context)!.editItem),
|
||
|
),
|
||
|
body: SingleChildScrollView(
|
||
|
child: Center(
|
||
|
child: Padding(
|
||
|
padding: const EdgeInsets.all(14),
|
||
|
child: ConstrainedBox(
|
||
|
constraints: const BoxConstraints(maxWidth: 400),
|
||
|
child: Column(
|
||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||
|
children: [
|
||
|
SearchBar(
|
||
|
controller: _ctrInput,
|
||
|
leading: const Icon(Icons.search),
|
||
|
hintText:
|
||
|
AppLocalizations.of(context)!.newItemQueryHint,
|
||
|
onChanged: (text) {
|
||
|
setState(() {
|
||
|
_query = text;
|
||
|
});
|
||
|
},
|
||
|
),
|
||
|
const Divider(),
|
||
|
// button bar
|
||
|
...((_query == "")
|
||
|
? ([
|
||
|
Text(AppLocalizations.of(context)!
|
||
|
.newItemQueryEmpty)
|
||
|
])
|
||
|
: ([
|
||
|
Wrap(
|
||
|
spacing: 20,
|
||
|
runSpacing: 10,
|
||
|
alignment: WrapAlignment.center,
|
||
|
crossAxisAlignment:
|
||
|
WrapCrossAlignment.center,
|
||
|
children: [
|
||
|
Text(AppLocalizations.of(context)!
|
||
|
.newItemQuickAccessPrefix),
|
||
|
// new item
|
||
|
FilledButton.icon(
|
||
|
onPressed: () {
|
||
|
// create new named item
|
||
|
// launch edit item screen once done
|
||
|
createItem(context, _query, null);
|
||
|
},
|
||
|
icon: const Icon(Icons.add),
|
||
|
label: Text(_query)),
|
||
|
// new product
|
||
|
FilledButton.icon(
|
||
|
onPressed: () {
|
||
|
// create new product with name,
|
||
|
// create new item with name
|
||
|
// and link to the created product
|
||
|
// launch edit item screen once done
|
||
|
createProduct(
|
||
|
context,
|
||
|
_query,
|
||
|
(p0) => createItem(
|
||
|
context, _query, p0));
|
||
|
},
|
||
|
icon: const Icon(Icons.add),
|
||
|
label: Text(AppLocalizations.of(
|
||
|
context)!
|
||
|
.newItemQuickProduct(_query))),
|
||
|
])
|
||
|
])),
|
||
|
const Divider(),
|
||
|
// link products search
|
||
|
...((products
|
||
|
// show all products if query is empty
|
||
|
// when query isn't empty show products
|
||
|
// that contain the query in the title
|
||
|
// or description
|
||
|
.where((element) =>
|
||
|
(_query == "") ||
|
||
|
element.name.contains(_query) ||
|
||
|
element.description.contains(_query))
|
||
|
.map((e) => ListTile(
|
||
|
title: Text(e.name),
|
||
|
subtitle: Text(e.description),
|
||
|
trailing: CategoryChip(
|
||
|
category: categories
|
||
|
.where((element) =>
|
||
|
element.id == e.category)
|
||
|
.firstOrNull ??
|
||
|
RoomCategory.other(context),
|
||
|
),
|
||
|
onTap: () {
|
||
|
// create new item and link it to the product
|
||
|
// launch edit item screen once done
|
||
|
createItem(
|
||
|
context,
|
||
|
// use productname as item name
|
||
|
e.name,
|
||
|
e.id);
|
||
|
},
|
||
|
))))
|
||
|
],
|
||
|
))))),
|
||
|
);
|
||
|
}
|
||
|
}
|