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; final int item; const EditItemPage( {super.key, required this.room, required this.server, required this.item}); @override State createState() => _EditItemPageState(); } class _EditItemPageState extends State { // input controllers final _ctrName = TextEditingController(); final _ctrDescription = TextEditingController(); int? _ctrCategory; int _ctrUnit = 0; String _ctrValue = ''; int? _ctrLink; int _ctrState = 0; // data cache List categories = []; List products = []; RoomItem? item; void fetchCategories() async { final user = context.read(); final scaffmgr = ScaffoldMessenger.of(context); // load cached categories final cache = await RoomCategory.list(widget.server, widget.room); if (mounted) { setState(() { categories = cache; }); } doNetworkRequest(scaffmgr, req: () => postWithCreadentials( credentials: user, target: user.server, path: 'getCategories', body: {'room': widget.room, 'server': widget.server}), onOK: (body) async { final resp = body['data'] .map((raw) => RoomCategory.fromJSON(widget.server, widget.room, raw)) .toList(); setState(() { categories = resp; }); }); } void fetchProducts() async { final user = context.read(); final scaffmgr = ScaffoldMessenger.of(context); // load cached products first final cache = await RoomProduct.list(widget.server, widget.room); if (mounted) { setState(() { products = cache; }); } doNetworkRequest(scaffmgr, req: () => postWithCreadentials( credentials: user, target: user.server, path: 'getProducts', body: {'room': widget.room, 'server': widget.server}), onOK: (body) async { final resp = body['data'] .map((raw) => RoomProduct.fromJSON(widget.server, widget.room, raw)) .toList(); setState(() { products = resp; }); }); } void fetchItem() async { final user = context.read(); final scaffmgr = ScaffoldMessenger.of(context); // load cached item first try { await RoomItem.fromDisk( id: widget.item, server: widget.server, room: widget.room); } catch (_) { // cache miss } doNetworkRequest(scaffmgr, 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(widget.server, widget.room, body['data']); setState(() { item = resp; _ctrName.text = resp.name; _ctrDescription.text = resp.description; _ctrValue = resp.value; _ctrCategory = resp.category; _ctrLink = resp.link; _ctrUnit = resp.unit; _ctrState = resp.state; }); }); } @override void initState() { super.initState(); // 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 (_) {} }); WidgetsBinding.instance.addPostFrameCallback((_) { fetchCategories(); fetchProducts(); fetchItem(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.editItem), ), body: SingleChildScrollView( child: Center( child: Padding( padding: const EdgeInsets.all(14), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 600), 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( server: widget.server, room: widget.room, label: AppLocalizations.of(context)! .selectCategoryLabel, hint: AppLocalizations.of(context)! .selectCategoryHint, categories: categories, selected: _ctrCategory, onSelect: (cid) { setState(() { _ctrCategory = cid; }); }, ), ], ))))), floatingActionButton: FloatingActionButton.extended( onPressed: () async { final scaffMgr = ScaffoldMessenger.of(context); final trans = AppLocalizations.of(context); final nav = Navigator.of(context); if (_ctrName.text.isEmpty) { showSimpleSnackbar(scaffMgr, text: trans!.errorProductNameShouldNotBeEmpty, action: trans.ok); return; } final user = context.read(); 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 { // 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(); nav.pop(); }); }, label: Text(AppLocalizations.of(context)!.editItemShort), icon: const Icon(Icons.edit)), ); } }