actions-test/lib/screens/room/items/new.dart
Jakob Meier 384fbb0573
separate new item screen
The edit item screen might be overwhelming at first,
and if you only want to add simple items (by name) to the list,
it is way easier to simply type the name and click create to create a
simple item.
After creating the item the user will be redirected (history
replacement) to the edit screen, but clicking back will bring them back
to the list.
This screen also makes linking products easier and allows the user to
create new products if they notice they are using the same item multiple
times or can't be bothered to switch to the products tab
2024-02-22 20:36:59 +01:00

285 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);
},
))))
],
))))),
);
}
}