2023-04-05 19:04:18 +02:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.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_picker.dart';
|
|
|
|
import 'package:outbag_app/components/product_picker.dart';
|
|
|
|
import 'package:outbag_app/components/value_unit_input.dart';
|
|
|
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
|
|
|
import 'package:outbag_app/tools/snackbar.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
class EditItemPage extends StatefulWidget {
|
|
|
|
final String room;
|
|
|
|
final String server;
|
|
|
|
|
2024-02-22 20:36:59 +01:00
|
|
|
final int item;
|
2023-04-05 19:04:18 +02:00
|
|
|
|
|
|
|
const EditItemPage(
|
2024-02-22 20:36:59 +01:00
|
|
|
{super.key,
|
|
|
|
required this.room,
|
|
|
|
required this.server,
|
|
|
|
required this.item});
|
2023-04-05 19:04:18 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
State<StatefulWidget> createState() => _EditItemPageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _EditItemPageState extends State<EditItemPage> {
|
|
|
|
// input controllers
|
|
|
|
final _ctrName = TextEditingController();
|
|
|
|
final _ctrDescription = TextEditingController();
|
|
|
|
int? _ctrCategory;
|
|
|
|
int _ctrUnit = 0;
|
|
|
|
String _ctrValue = '';
|
|
|
|
int? _ctrLink;
|
2024-02-22 20:36:59 +01:00
|
|
|
int _ctrState = 0;
|
2023-04-05 19:04:18 +02:00
|
|
|
|
|
|
|
// data cache
|
|
|
|
List<RoomCategory> categories = [];
|
|
|
|
List<RoomProduct> products = [];
|
|
|
|
RoomItem? item;
|
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
void fetchCategories() async {
|
2023-04-05 19:04:18 +02:00
|
|
|
final user = context.read<User>();
|
2024-02-23 20:44:42 +01:00
|
|
|
final scaffmgr = ScaffoldMessenger.of(context);
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
// load cached categories
|
|
|
|
final cache = await RoomCategory.list(widget.server, widget.room);
|
|
|
|
if (mounted) {
|
|
|
|
setState(() {
|
|
|
|
categories = cache;
|
|
|
|
});
|
|
|
|
}
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
doNetworkRequest(scaffmgr,
|
2023-12-22 20:14:36 +01:00
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
|
|
|
path: 'getCategories',
|
|
|
|
body: {'room': widget.room, 'server': widget.server}),
|
|
|
|
onOK: (body) async {
|
|
|
|
final resp = body['data']
|
2024-02-23 16:13:15 +01:00
|
|
|
.map<RoomCategory>((raw) =>
|
|
|
|
RoomCategory.fromJSON(widget.server, widget.room, raw))
|
2023-12-22 20:14:36 +01:00
|
|
|
.toList();
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2023-12-22 20:14:36 +01:00
|
|
|
setState(() {
|
2023-04-05 19:04:18 +02:00
|
|
|
categories = resp;
|
2023-12-22 20:14:36 +01:00
|
|
|
});
|
2023-04-05 19:04:18 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
void fetchProducts() async {
|
2023-04-05 19:04:18 +02:00
|
|
|
final user = context.read<User>();
|
2024-02-23 20:44:42 +01:00
|
|
|
final scaffmgr = ScaffoldMessenger.of(context);
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
// load cached products first
|
|
|
|
final cache = await RoomProduct.list(widget.server, widget.room);
|
|
|
|
if (mounted) {
|
|
|
|
setState(() {
|
|
|
|
products = cache;
|
|
|
|
});
|
|
|
|
}
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
doNetworkRequest(scaffmgr,
|
2023-12-22 20:14:36 +01:00
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
|
|
|
path: 'getProducts',
|
|
|
|
body: {'room': widget.room, 'server': widget.server}),
|
|
|
|
onOK: (body) async {
|
|
|
|
final resp = body['data']
|
2024-02-23 20:06:49 +01:00
|
|
|
.map<RoomProduct>((raw) =>
|
|
|
|
RoomProduct.fromJSON(widget.server, widget.room, raw))
|
2023-12-22 20:14:36 +01:00
|
|
|
.toList();
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2023-12-22 20:14:36 +01:00
|
|
|
setState(() {
|
2023-04-05 19:04:18 +02:00
|
|
|
products = resp;
|
2023-12-22 20:14:36 +01:00
|
|
|
});
|
2023-04-05 19:04:18 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
void fetchItem() async {
|
2023-04-05 19:04:18 +02:00
|
|
|
final user = context.read<User>();
|
2024-02-23 20:44:42 +01:00
|
|
|
final scaffmgr = ScaffoldMessenger.of(context);
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
// load cached item first
|
|
|
|
try {
|
|
|
|
await RoomItem.fromDisk(
|
|
|
|
id: widget.item, server: widget.server, room: widget.room);
|
|
|
|
} catch (_) {
|
|
|
|
// cache miss
|
|
|
|
}
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
doNetworkRequest(scaffmgr,
|
2023-12-22 20:14:36 +01:00
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
|
|
|
path: 'getItem',
|
|
|
|
body: {
|
|
|
|
'room': widget.room,
|
|
|
|
'server': widget.server,
|
|
|
|
'listItemID': widget.item
|
|
|
|
}),
|
|
|
|
onOK: (body) async {
|
2024-02-23 20:44:42 +01:00
|
|
|
final resp =
|
|
|
|
RoomItem.fromJSON(widget.server, widget.room, body['data']);
|
2023-12-22 20:14:36 +01:00
|
|
|
setState(() {
|
2023-04-05 19:04:18 +02:00
|
|
|
item = resp;
|
2024-02-22 20:36:59 +01:00
|
|
|
_ctrName.text = resp.name;
|
|
|
|
_ctrDescription.text = resp.description;
|
|
|
|
_ctrValue = resp.value;
|
|
|
|
_ctrCategory = resp.category;
|
|
|
|
_ctrLink = resp.link;
|
|
|
|
_ctrUnit = resp.unit;
|
|
|
|
_ctrState = resp.state;
|
2023-12-22 20:14:36 +01:00
|
|
|
});
|
2023-04-05 19:04:18 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
|
2024-02-23 20:44:42 +01:00
|
|
|
// wait for background room product changes
|
|
|
|
RoomProduct.listen(widget.server, widget.room, (_) async {
|
|
|
|
try {
|
|
|
|
final updated = await RoomProduct.list(widget.server, widget.room);
|
|
|
|
setState(() {
|
|
|
|
products = updated;
|
|
|
|
});
|
|
|
|
} catch (_) {}
|
|
|
|
});
|
|
|
|
|
|
|
|
// wait for background room category changes
|
|
|
|
RoomCategory.listen(widget.server, widget.room, (_) async {
|
|
|
|
try {
|
|
|
|
final updated = await RoomCategory.list(widget.server, widget.room);
|
|
|
|
setState(() {
|
|
|
|
categories = updated;
|
|
|
|
});
|
|
|
|
} catch (_) {}
|
|
|
|
});
|
|
|
|
|
2023-04-05 19:04:18 +02:00
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
2023-12-22 20:14:36 +01:00
|
|
|
fetchCategories();
|
|
|
|
fetchProducts();
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-22 20:36:59 +01:00
|
|
|
fetchItem();
|
2023-04-05 19:04:18 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
2024-02-22 20:36:59 +01:00
|
|
|
title: Text(AppLocalizations.of(context)!.editItem),
|
2023-04-05 19:04:18 +02:00
|
|
|
),
|
|
|
|
body: SingleChildScrollView(
|
2023-12-22 20:14:36 +01:00
|
|
|
child: Center(
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(14),
|
|
|
|
child: ConstrainedBox(
|
2024-02-23 10:16:57 +01:00
|
|
|
constraints: const BoxConstraints(maxWidth: 600),
|
2023-12-22 20:14:36 +01:00
|
|
|
child: Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
child: TextField(
|
|
|
|
controller: _ctrName,
|
|
|
|
keyboardType: TextInputType.name,
|
|
|
|
decoration: InputDecoration(
|
|
|
|
prefixIcon: const Icon(Icons.badge),
|
|
|
|
labelText: AppLocalizations.of(context)!
|
|
|
|
.inputItemNameLabel,
|
|
|
|
hintText: AppLocalizations.of(context)!
|
|
|
|
.inputItemNameHint,
|
|
|
|
helperText: AppLocalizations.of(context)!
|
|
|
|
.inputItemNameHelp,
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
ProductPicker(
|
|
|
|
label: AppLocalizations.of(context)!
|
|
|
|
.selectLinkedProductLabel,
|
|
|
|
hint: AppLocalizations.of(context)!
|
|
|
|
.selectLinkedProductHint,
|
|
|
|
products: products,
|
|
|
|
selected: _ctrLink,
|
|
|
|
onSelect: (pid) {
|
|
|
|
setState(() {
|
|
|
|
_ctrLink = pid;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
),
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
child: TextField(
|
|
|
|
controller: _ctrDescription,
|
|
|
|
keyboardType: TextInputType.text,
|
|
|
|
decoration: InputDecoration(
|
|
|
|
labelText: AppLocalizations.of(context)!
|
|
|
|
.inputItemDescriptionLabel,
|
|
|
|
hintText: AppLocalizations.of(context)!
|
|
|
|
.inputItemDescriptionHint,
|
|
|
|
helperText: AppLocalizations.of(context)!
|
|
|
|
.inputItemDescriptionHelp,
|
|
|
|
prefixIcon: const Icon(Icons.dns),
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
DynamicValueUnitInput(
|
|
|
|
initialUnit: _ctrUnit,
|
|
|
|
initialValue: _ctrValue,
|
|
|
|
onUnitChange: (unit) {
|
|
|
|
setState(() {
|
|
|
|
_ctrUnit = unit;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
onValueChange: (value) {
|
|
|
|
setState(() {
|
|
|
|
_ctrValue = value;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
),
|
|
|
|
CategoryPicker(
|
2024-02-23 16:13:15 +01:00
|
|
|
server: widget.server,
|
|
|
|
room: widget.room,
|
2023-12-22 20:14:36 +01:00
|
|
|
label: AppLocalizations.of(context)!
|
|
|
|
.selectCategoryLabel,
|
|
|
|
hint: AppLocalizations.of(context)!
|
|
|
|
.selectCategoryHint,
|
|
|
|
categories: categories,
|
|
|
|
selected: _ctrCategory,
|
|
|
|
onSelect: (cid) {
|
|
|
|
setState(() {
|
|
|
|
_ctrCategory = cid;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
))))),
|
2023-04-05 19:04:18 +02:00
|
|
|
floatingActionButton: FloatingActionButton.extended(
|
2023-12-22 20:14:36 +01:00
|
|
|
onPressed: () async {
|
|
|
|
final scaffMgr = ScaffoldMessenger.of(context);
|
|
|
|
final trans = AppLocalizations.of(context);
|
|
|
|
final nav = Navigator.of(context);
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2023-12-22 20:14:36 +01:00
|
|
|
if (_ctrName.text.isEmpty) {
|
|
|
|
showSimpleSnackbar(scaffMgr,
|
|
|
|
text: trans!.errorProductNameShouldNotBeEmpty,
|
|
|
|
action: trans.ok);
|
|
|
|
return;
|
|
|
|
}
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2023-12-22 20:14:36 +01:00
|
|
|
final user = context.read<User>();
|
2023-04-05 19:04:18 +02:00
|
|
|
|
2024-02-22 20:36:59 +01:00
|
|
|
doNetworkRequest(scaffMgr,
|
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
|
|
|
path: 'changeItem',
|
|
|
|
body: {
|
|
|
|
'listItemID': widget.item,
|
|
|
|
'room': widget.room,
|
|
|
|
'server': widget.server,
|
|
|
|
'title': _ctrName.text,
|
|
|
|
'state': _ctrState,
|
|
|
|
'description': _ctrDescription.text,
|
|
|
|
'listCatID': _ctrCategory,
|
|
|
|
'unit': _ctrUnit,
|
|
|
|
'value': _ctrValue,
|
|
|
|
'listProdID': _ctrLink
|
|
|
|
}),
|
|
|
|
onOK: (_) async {
|
2024-02-23 20:44:42 +01:00
|
|
|
// cache item
|
|
|
|
final item = RoomItem(
|
|
|
|
id: widget.item,
|
|
|
|
server: widget.server,
|
|
|
|
room: widget.room,
|
|
|
|
name: _ctrName.text,
|
|
|
|
state: _ctrState,
|
|
|
|
description: _ctrDescription.text,
|
|
|
|
category: _ctrCategory,
|
|
|
|
unit: _ctrUnit,
|
|
|
|
value: _ctrValue,
|
|
|
|
link: _ctrLink);
|
|
|
|
await item.toDisk();
|
|
|
|
|
2024-02-22 20:36:59 +01:00
|
|
|
nav.pop();
|
|
|
|
});
|
2023-12-22 20:14:36 +01:00
|
|
|
},
|
2024-02-22 20:36:59 +01:00
|
|
|
label: Text(AppLocalizations.of(context)!.editItemShort),
|
|
|
|
icon: const Icon(Icons.edit)),
|
2023-04-05 19:04:18 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|