cache products for item and product list and product view screen
BUG: when deleting a product the product list won't update
This commit is contained in:
parent
6cdfcdf85c
commit
9ff6d97c90
8 changed files with 466 additions and 177 deletions
|
@ -547,7 +547,7 @@ String colorIdFromColor(ColorSwatch<int> color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomProduct {
|
class RoomProduct {
|
||||||
int id;
|
final int id;
|
||||||
String name;
|
String name;
|
||||||
String description;
|
String description;
|
||||||
// category ID
|
// category ID
|
||||||
|
@ -563,9 +563,14 @@ class RoomProduct {
|
||||||
// parent product ID
|
// parent product ID
|
||||||
int? parent;
|
int? parent;
|
||||||
|
|
||||||
|
final String server;
|
||||||
|
final String room;
|
||||||
|
|
||||||
RoomProduct(
|
RoomProduct(
|
||||||
{required this.id,
|
{required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
required this.server,
|
||||||
|
required this.room,
|
||||||
this.description = '',
|
this.description = '',
|
||||||
this.category = -1,
|
this.category = -1,
|
||||||
this.defaultUnit = 0,
|
this.defaultUnit = 0,
|
||||||
|
@ -573,8 +578,10 @@ class RoomProduct {
|
||||||
this.ean,
|
this.ean,
|
||||||
this.parent});
|
this.parent});
|
||||||
|
|
||||||
factory RoomProduct.fromJSON(dynamic json) {
|
factory RoomProduct.fromJSON(String server, String room, dynamic json) {
|
||||||
return RoomProduct(
|
return RoomProduct(
|
||||||
|
server: server,
|
||||||
|
room: room,
|
||||||
id: json['listProdID'],
|
id: json['listProdID'],
|
||||||
name: json['title'],
|
name: json['title'],
|
||||||
description: json['description'],
|
description: json['description'],
|
||||||
|
@ -584,6 +591,78 @@ class RoomProduct {
|
||||||
ean: json['ean'],
|
ean: json['ean'],
|
||||||
parent: json['parent']);
|
parent: json['parent']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get list of all categories in a given room
|
||||||
|
static Future<List<RoomProduct>> list(String server, String room) async {
|
||||||
|
final db = Localstore.instance;
|
||||||
|
final rooms = (await db.collection('products:$room@$server').get()) ?? {};
|
||||||
|
List<RoomProduct> builder = [];
|
||||||
|
for (MapEntry entry in rooms.entries) {
|
||||||
|
try {
|
||||||
|
builder.add(RoomProduct.fromMap(entry.value));
|
||||||
|
} catch (e) {
|
||||||
|
// skip invalid entries
|
||||||
|
// NOTE: might want to autodelete them in the future
|
||||||
|
// although keeping them might be ok,
|
||||||
|
// in case we ever get a new dataset to fix the current state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen to room change
|
||||||
|
static listen(
|
||||||
|
String server, String room, Function(Map<String, dynamic>) cb) async {
|
||||||
|
final db = Localstore.instance;
|
||||||
|
final stream = db.collection('products:$room@$server').stream;
|
||||||
|
stream.listen(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory RoomProduct.fromMap(Map<String, dynamic> map) {
|
||||||
|
return RoomProduct(
|
||||||
|
server: map['server'],
|
||||||
|
room: map['room'],
|
||||||
|
id: map['id'],
|
||||||
|
name: map['name'],
|
||||||
|
description: map['description'],
|
||||||
|
category: map['category'],
|
||||||
|
defaultUnit: map['default_unit'],
|
||||||
|
defaultValue: map['default_value'],
|
||||||
|
ean: map['ean'],
|
||||||
|
parent: map['parent']);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
'server': server,
|
||||||
|
'room': room,
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'description': description,
|
||||||
|
'category': category,
|
||||||
|
'default_unit': defaultUnit,
|
||||||
|
'default_value': defaultValue,
|
||||||
|
'ean': ean,
|
||||||
|
'parent': parent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> toDisk() async {
|
||||||
|
final db = Localstore.instance;
|
||||||
|
await db.collection('products:$room@$server').doc('$id').set(toMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeDisk() async {
|
||||||
|
final db = Localstore.instance;
|
||||||
|
await db.collection('products:$room@$server').doc('$id').delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<RoomProduct> fromDisk(
|
||||||
|
{required int id, required String server, required String room}) async {
|
||||||
|
final db = Localstore.instance;
|
||||||
|
final raw = await db.collection('products:$room@$server').doc('$id').get();
|
||||||
|
return RoomProduct.fromMap(raw!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomItem {
|
class RoomItem {
|
||||||
|
|
|
@ -77,7 +77,8 @@ class _EditItemPageState extends State<EditItemPage> {
|
||||||
body: {'room': widget.room, 'server': widget.server}),
|
body: {'room': widget.room, 'server': widget.server}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final resp = body['data']
|
final resp = body['data']
|
||||||
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
.map<RoomProduct>((raw) =>
|
||||||
|
RoomProduct.fromJSON(widget.server, widget.room, raw))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
|
@ -66,7 +66,8 @@ class _NewItemPageState extends State<NewItemPage> {
|
||||||
body: {'room': widget.room, 'server': widget.server}),
|
body: {'room': widget.room, 'server': widget.server}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final resp = body['data']
|
final resp = body['data']
|
||||||
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
.map<RoomProduct>((raw) =>
|
||||||
|
RoomProduct.fromJSON(widget.server, widget.room, raw))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
|
@ -106,12 +106,25 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchCategories() {
|
void fetchCategories() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
// TODO: load cached categories first
|
// load cached categories
|
||||||
|
final cache = await RoomCategory.list(
|
||||||
|
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||||
|
if (mounted) {
|
||||||
|
Map<int?, RoomCategory> map = {};
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
for (RoomCategory cat in cache) {
|
||||||
|
map[cat.id] = cat;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
categories = map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -140,12 +153,20 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchProducts() {
|
void fetchProducts() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
// TODO: load cached products first
|
// load cached products first
|
||||||
|
final cache = await RoomProduct.list(
|
||||||
|
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
products = cache;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -153,7 +174,8 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
||||||
body: {'room': widget.room?.id, 'server': widget.room?.serverTag}),
|
body: {'room': widget.room?.id, 'server': widget.room?.serverTag}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final resp = body['data']
|
final resp = body['data']
|
||||||
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
.map<RoomProduct>((raw) => RoomProduct.fromJSON(
|
||||||
|
widget.room!.serverTag, widget.room!.id, raw))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
@ -168,6 +190,34 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
// wait for background room product changes
|
||||||
|
RoomProduct.listen(widget.room?.serverTag ?? "", widget.room?.id ?? "",
|
||||||
|
(_) async {
|
||||||
|
try {
|
||||||
|
final updated = await RoomProduct.list(
|
||||||
|
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||||
|
setState(() {
|
||||||
|
products = updated;
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
// wait for background room category changes
|
||||||
|
RoomCategory.listen(widget.room?.serverTag ?? "", widget.room?.id ?? "",
|
||||||
|
(_) async {
|
||||||
|
try {
|
||||||
|
final updated = await RoomCategory.list(
|
||||||
|
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||||
|
Map<int?, RoomCategory> map = {};
|
||||||
|
|
||||||
|
for (RoomCategory cat in updated) {
|
||||||
|
map[cat.id] = cat;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
categories = map;
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
fetchItems();
|
fetchItems();
|
||||||
fetchCategories();
|
fetchCategories();
|
||||||
|
|
|
@ -21,10 +21,20 @@ class RoomProductsPage extends StatefulWidget {
|
||||||
class _RoomProductsPageState extends State<RoomProductsPage> {
|
class _RoomProductsPageState extends State<RoomProductsPage> {
|
||||||
List<RoomProduct> products = [];
|
List<RoomProduct> products = [];
|
||||||
|
|
||||||
void fetchProducts() {
|
void fetchProducts() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
// load cached products first
|
||||||
|
final cache = await RoomProduct.list(
|
||||||
|
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
products = cache;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -32,10 +42,13 @@ class _RoomProductsPageState extends State<RoomProductsPage> {
|
||||||
body: {'room': widget.room?.id, 'server': widget.room?.serverTag}),
|
body: {'room': widget.room?.id, 'server': widget.room?.serverTag}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final resp = body['data']
|
final resp = body['data']
|
||||||
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
.map<RoomProduct>((raw) => RoomProduct.fromJSON(
|
||||||
|
widget.room!.serverTag, widget.room!.id, raw))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
// TODO: cache products
|
for (RoomProduct prod in resp) {
|
||||||
|
prod.toDisk();
|
||||||
|
}
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -49,6 +62,18 @@ class _RoomProductsPageState extends State<RoomProductsPage> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
// wait for background room product changes
|
||||||
|
RoomProduct.listen(widget.room?.serverTag ?? "", widget.room?.id ?? "",
|
||||||
|
(_) async {
|
||||||
|
try {
|
||||||
|
final updated = await RoomProduct.list(
|
||||||
|
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||||
|
setState(() {
|
||||||
|
products = updated;
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => fetchProducts());
|
WidgetsBinding.instance.addPostFrameCallback((_) => fetchProducts());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,19 @@ class _EditProductPageState extends State<EditProductPage> {
|
||||||
List<RoomCategory> categories = [];
|
List<RoomCategory> categories = [];
|
||||||
List<RoomProduct> products = [];
|
List<RoomProduct> products = [];
|
||||||
|
|
||||||
void fetchCategories() {
|
void fetchCategories() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
// TODO: load cached categories first
|
// load cached categories
|
||||||
|
final cache = await RoomCategory.list(widget.server, widget.room);
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
categories = cache;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -59,12 +66,19 @@ class _EditProductPageState extends State<EditProductPage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchProducts() {
|
void fetchProducts() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
// TODO: load cached products first
|
// load cached products first
|
||||||
|
final cache = await RoomProduct.list(widget.server, widget.room);
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
products = cache;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -72,7 +86,8 @@ class _EditProductPageState extends State<EditProductPage> {
|
||||||
body: {'room': widget.room, 'server': widget.server}),
|
body: {'room': widget.room, 'server': widget.server}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final resp = body['data']
|
final resp = body['data']
|
||||||
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
.map<RoomProduct>((raw) =>
|
||||||
|
RoomProduct.fromJSON(widget.server, widget.room, raw))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (widget.product != null) {
|
if (widget.product != null) {
|
||||||
|
@ -255,7 +270,22 @@ class _EditProductPageState extends State<EditProductPage> {
|
||||||
'ean': _ctrEAN.text,
|
'ean': _ctrEAN.text,
|
||||||
'parent': _ctrParent
|
'parent': _ctrParent
|
||||||
}),
|
}),
|
||||||
onOK: (_) async {
|
onOK: (body) async {
|
||||||
|
// cache product
|
||||||
|
final id = body["data"]["listProdID"];
|
||||||
|
final prod = RoomProduct(
|
||||||
|
id: id,
|
||||||
|
name: _ctrName.text,
|
||||||
|
server: widget.server,
|
||||||
|
room: widget.room,
|
||||||
|
description: _ctrDescription.text,
|
||||||
|
category: _ctrCategory,
|
||||||
|
defaultUnit: _ctrUnit,
|
||||||
|
defaultValue: _ctrValue,
|
||||||
|
ean: _ctrEAN.text,
|
||||||
|
parent: _ctrParent);
|
||||||
|
await prod.toDisk();
|
||||||
|
|
||||||
nav.pop();
|
nav.pop();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -277,6 +307,20 @@ class _EditProductPageState extends State<EditProductPage> {
|
||||||
'parent': _ctrParent
|
'parent': _ctrParent
|
||||||
}),
|
}),
|
||||||
onOK: (_) async {
|
onOK: (_) async {
|
||||||
|
// cache product
|
||||||
|
final prod = RoomProduct(
|
||||||
|
id: widget.product!,
|
||||||
|
name: _ctrName.text,
|
||||||
|
server: widget.server,
|
||||||
|
room: widget.room,
|
||||||
|
description: _ctrDescription.text,
|
||||||
|
category: _ctrCategory,
|
||||||
|
defaultUnit: _ctrUnit,
|
||||||
|
defaultValue: _ctrValue,
|
||||||
|
ean: _ctrEAN.text,
|
||||||
|
parent: _ctrParent);
|
||||||
|
await prod.toDisk();
|
||||||
|
|
||||||
nav.pop();
|
nav.pop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,12 +53,24 @@ class _ViewProductPageState extends State<ViewProductPage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchCategories() {
|
void fetchCategories() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
// TODO: load cached categories first
|
// load cached categories
|
||||||
|
final cache = await RoomCategory.list(widget.server, widget.room);
|
||||||
|
if (mounted) {
|
||||||
|
Map<int?, RoomCategory> map = {};
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
for (RoomCategory cat in cache) {
|
||||||
|
map[cat.id] = cat;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
categories = map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -81,12 +93,19 @@ class _ViewProductPageState extends State<ViewProductPage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchProducts() {
|
void fetchProducts() async {
|
||||||
final user = context.read<User>();
|
final user = context.read<User>();
|
||||||
|
final scaffmgr = ScaffoldMessenger.of(context);
|
||||||
|
|
||||||
// TODO: load cached products first
|
// load cached products first
|
||||||
|
final cache = await RoomProduct.list(widget.server, widget.room);
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
products = cache;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
doNetworkRequest(scaffmgr,
|
||||||
req: () => postWithCreadentials(
|
req: () => postWithCreadentials(
|
||||||
credentials: user,
|
credentials: user,
|
||||||
target: user.server,
|
target: user.server,
|
||||||
|
@ -94,7 +113,8 @@ class _ViewProductPageState extends State<ViewProductPage> {
|
||||||
body: {'room': widget.room, 'server': widget.server}),
|
body: {'room': widget.room, 'server': widget.server}),
|
||||||
onOK: (body) async {
|
onOK: (body) async {
|
||||||
final resp = body['data']
|
final resp = body['data']
|
||||||
.map<RoomProduct>((raw) => RoomProduct.fromJSON(raw))
|
.map<RoomProduct>((raw) =>
|
||||||
|
RoomProduct.fromJSON(widget.server, widget.room, raw))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (RoomProduct prod in resp) {
|
for (RoomProduct prod in resp) {
|
||||||
|
@ -116,6 +136,39 @@ class _ViewProductPageState extends State<ViewProductPage> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.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);
|
||||||
|
for (RoomProduct prod in updated) {
|
||||||
|
// load product info
|
||||||
|
// for current product
|
||||||
|
if (prod.id == widget.product) {
|
||||||
|
setState(() {
|
||||||
|
product = prod;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
Map<int?, RoomCategory> map = {};
|
||||||
|
|
||||||
|
for (RoomCategory cat in updated) {
|
||||||
|
map[cat.id] = cat;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
categories = map;
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
fetchCategories();
|
fetchCategories();
|
||||||
fetchProducts();
|
fetchProducts();
|
||||||
|
@ -132,156 +185,192 @@ class _ViewProductPageState extends State<ViewProductPage> {
|
||||||
title: Text(product?.name ?? ''),
|
title: Text(product?.name ?? ''),
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Column(children: [
|
child: Center(
|
||||||
// display product into
|
child: Padding(
|
||||||
Center(
|
padding: const EdgeInsets.all(14),
|
||||||
child: Padding(
|
child: ConstrainedBox(
|
||||||
padding: const EdgeInsets.all(14),
|
constraints: const BoxConstraints(maxWidth: 600),
|
||||||
child: Column(
|
child: Column(children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// display product into
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
Center(
|
||||||
children: [
|
child: Padding(
|
||||||
Text(product?.name ?? '', style: textTheme.headlineLarge),
|
padding: const EdgeInsets.all(14),
|
||||||
Text(product?.description ?? '',
|
child: Column(
|
||||||
style: textTheme.titleMedium),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
Text(product?.ean ?? ''),
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
CategoryChip(
|
children: [
|
||||||
server: widget.server,
|
Text(product?.name ?? '',
|
||||||
room: widget.room,
|
style: textTheme.headlineLarge),
|
||||||
category: categories[product?.category]),
|
Text(product?.description ?? '',
|
||||||
Text(product != null
|
style: textTheme.titleMedium),
|
||||||
? Unit.fromId(product!.defaultUnit)
|
Text(product?.ean ?? ''),
|
||||||
.display(context, product!.defaultValue)
|
CategoryChip(
|
||||||
: '')
|
server: widget.server,
|
||||||
],
|
room: widget.room,
|
||||||
))),
|
category:
|
||||||
|
categories[product?.category]),
|
||||||
|
Text(product != null
|
||||||
|
? Unit.fromId(product!.defaultUnit)
|
||||||
|
.display(
|
||||||
|
context, product!.defaultValue)
|
||||||
|
: '')
|
||||||
|
],
|
||||||
|
))),
|
||||||
|
|
||||||
// show actions (if allowed / available
|
// show actions (if allowed / available
|
||||||
// edit product button
|
// edit product button
|
||||||
...(info != null &&
|
...(info != null &&
|
||||||
(info!.isAdmin ||
|
(info!.isAdmin ||
|
||||||
info!.isOwner ||
|
info!.isOwner ||
|
||||||
(info!.permissions & RoomPermission.editRoomContent != 0)))
|
(info!.permissions &
|
||||||
? [
|
RoomPermission.editRoomContent !=
|
||||||
ListTile(
|
0)))
|
||||||
title: Text(AppLocalizations.of(context)!.editProductTitle),
|
? [
|
||||||
subtitle:
|
ListTile(
|
||||||
Text(AppLocalizations.of(context)!.editProductSubtitle),
|
title: Text(AppLocalizations.of(context)!
|
||||||
onTap: () {
|
.editProductTitle),
|
||||||
context.pushNamed('edit-product', params: {
|
subtitle: Text(AppLocalizations.of(context)!
|
||||||
'server': widget.server,
|
.editProductSubtitle),
|
||||||
'id': widget.room,
|
onTap: () {
|
||||||
'product': widget.product.toString()
|
context.pushNamed('edit-product', params: {
|
||||||
});
|
'server': widget.server,
|
||||||
},
|
'id': widget.room,
|
||||||
trailing: const Icon(Icons.chevron_right),
|
'product': widget.product.toString()
|
||||||
),
|
});
|
||||||
]
|
|
||||||
: [],
|
|
||||||
// show parent?
|
|
||||||
...(product?.parent != null)
|
|
||||||
? [
|
|
||||||
ListTile(
|
|
||||||
title: Text(
|
|
||||||
AppLocalizations.of(context)!.viewParentProductTitle),
|
|
||||||
subtitle: Text(
|
|
||||||
AppLocalizations.of(context)!.viewParentProductSubtitle),
|
|
||||||
onTap: () {
|
|
||||||
context.pushNamed('view-product', params: {
|
|
||||||
'server': widget.server,
|
|
||||||
'id': widget.room,
|
|
||||||
'product': product!.parent.toString()
|
|
||||||
});
|
|
||||||
},
|
|
||||||
trailing: const Icon(Icons.chevron_right),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
// show/manage children
|
|
||||||
ListTile(
|
|
||||||
title: Text(AppLocalizations.of(context)!.viewProductChildrenTitle),
|
|
||||||
subtitle:
|
|
||||||
Text(AppLocalizations.of(context)!.viewProductChildrenSubtitle),
|
|
||||||
onTap: () {
|
|
||||||
context.pushNamed('view-product-children', params: {
|
|
||||||
'server': widget.server,
|
|
||||||
'id': widget.room,
|
|
||||||
'product': widget.product.toString()
|
|
||||||
});
|
|
||||||
},
|
|
||||||
trailing: const Icon(Icons.chevron_right),
|
|
||||||
),
|
|
||||||
...(info != null &&
|
|
||||||
((info?.isAdmin ?? false) ||
|
|
||||||
(info?.isOwner ?? false) ||
|
|
||||||
((info?.permissions)! & RoomPermission.editRoomContent !=
|
|
||||||
0)))
|
|
||||||
? [
|
|
||||||
// delete product
|
|
||||||
ListTile(
|
|
||||||
title: Text(AppLocalizations.of(context)!.deleteProductTitle),
|
|
||||||
subtitle:
|
|
||||||
Text(AppLocalizations.of(context)!.deleteProductSubtitle),
|
|
||||||
onTap: () {
|
|
||||||
// show popup
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (ctx) => AlertDialog(
|
|
||||||
icon: const Icon(Icons.delete),
|
|
||||||
title: Text(
|
|
||||||
AppLocalizations.of(context)!.deleteProduct),
|
|
||||||
content: Text(AppLocalizations.of(context)!
|
|
||||||
.deleteProductConfirm(product?.name ?? "")),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
// close popup
|
|
||||||
Navigator.of(ctx).pop();
|
|
||||||
},
|
},
|
||||||
child: Text(
|
trailing: const Icon(Icons.chevron_right),
|
||||||
AppLocalizations.of(context)!.cancel),
|
|
||||||
),
|
),
|
||||||
FilledButton(
|
]
|
||||||
onPressed: () async {
|
: [],
|
||||||
// send request
|
// show parent?
|
||||||
final scaffMgr = ScaffoldMessenger.of(ctx);
|
...(product?.parent != null)
|
||||||
// popup context
|
? [
|
||||||
final navInner = Navigator.of(ctx);
|
ListTile(
|
||||||
// bottomsheet context
|
title: Text(AppLocalizations.of(context)!
|
||||||
final nav = Navigator.of(context);
|
.viewParentProductTitle),
|
||||||
final user = context.read<User>();
|
subtitle: Text(AppLocalizations.of(context)!
|
||||||
|
.viewParentProductSubtitle),
|
||||||
doNetworkRequest(scaffMgr,
|
onTap: () {
|
||||||
req: () => postWithCreadentials(
|
context.pushNamed('view-product', params: {
|
||||||
path: 'deleteProduct',
|
'server': widget.server,
|
||||||
target: user.server,
|
'id': widget.room,
|
||||||
body: {
|
'product': product!.parent.toString()
|
||||||
'room': widget.room,
|
});
|
||||||
'server': widget.server,
|
|
||||||
'listProdID': product?.id ?? ""
|
|
||||||
},
|
|
||||||
credentials: user),
|
|
||||||
onOK: (_) async {
|
|
||||||
// TODO: remove cached product
|
|
||||||
},
|
|
||||||
after: () {
|
|
||||||
// close popup
|
|
||||||
navInner.pop();
|
|
||||||
// close modal bottom sheet
|
|
||||||
nav.pop();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: Text(AppLocalizations.of(context)!
|
trailing: const Icon(Icons.chevron_right),
|
||||||
.deleteProduct),
|
),
|
||||||
)
|
]
|
||||||
],
|
: [],
|
||||||
));
|
// show/manage children
|
||||||
},
|
ListTile(
|
||||||
trailing: const Icon(Icons.chevron_right),
|
title: Text(AppLocalizations.of(context)!
|
||||||
),
|
.viewProductChildrenTitle),
|
||||||
]
|
subtitle: Text(AppLocalizations.of(context)!
|
||||||
: []
|
.viewProductChildrenSubtitle),
|
||||||
])),
|
onTap: () {
|
||||||
|
context.pushNamed('view-product-children', params: {
|
||||||
|
'server': widget.server,
|
||||||
|
'id': widget.room,
|
||||||
|
'product': widget.product.toString()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
trailing: const Icon(Icons.chevron_right),
|
||||||
|
),
|
||||||
|
...(info != null &&
|
||||||
|
((info?.isAdmin ?? false) ||
|
||||||
|
(info?.isOwner ?? false) ||
|
||||||
|
((info?.permissions)! &
|
||||||
|
RoomPermission.editRoomContent !=
|
||||||
|
0)))
|
||||||
|
? [
|
||||||
|
// delete product
|
||||||
|
ListTile(
|
||||||
|
title: Text(AppLocalizations.of(context)!
|
||||||
|
.deleteProductTitle),
|
||||||
|
subtitle: Text(AppLocalizations.of(context)!
|
||||||
|
.deleteProductSubtitle),
|
||||||
|
onTap: () {
|
||||||
|
// show popup
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!
|
||||||
|
.deleteProduct),
|
||||||
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!
|
||||||
|
.deleteProductConfirm(
|
||||||
|
product?.name ?? "")),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
// close popup
|
||||||
|
Navigator.of(ctx).pop();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(
|
||||||
|
context)!
|
||||||
|
.cancel),
|
||||||
|
),
|
||||||
|
FilledButton(
|
||||||
|
onPressed: () async {
|
||||||
|
// send request
|
||||||
|
final scaffMgr =
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
ctx);
|
||||||
|
// popup context
|
||||||
|
final navInner =
|
||||||
|
Navigator.of(ctx);
|
||||||
|
// bottomsheet context
|
||||||
|
final nav =
|
||||||
|
Navigator.of(context);
|
||||||
|
final user =
|
||||||
|
context.read<User>();
|
||||||
|
|
||||||
|
doNetworkRequest(scaffMgr,
|
||||||
|
req: () =>
|
||||||
|
postWithCreadentials(
|
||||||
|
path:
|
||||||
|
'deleteProduct',
|
||||||
|
target:
|
||||||
|
user.server,
|
||||||
|
body: {
|
||||||
|
'room': widget
|
||||||
|
.room,
|
||||||
|
'server': widget
|
||||||
|
.server,
|
||||||
|
'listProdID':
|
||||||
|
product?.id ??
|
||||||
|
""
|
||||||
|
},
|
||||||
|
credentials:
|
||||||
|
user),
|
||||||
|
onOK: (_) async {
|
||||||
|
// remove cached product
|
||||||
|
await product!
|
||||||
|
.removeDisk();
|
||||||
|
},
|
||||||
|
after: () {
|
||||||
|
// close popup
|
||||||
|
navInner.pop();
|
||||||
|
// close modal bottom sheet
|
||||||
|
nav.pop();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(
|
||||||
|
context)!
|
||||||
|
.deleteProduct),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
},
|
||||||
|
trailing: const Icon(Icons.chevron_right),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
]))))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,6 @@ Future<void> doNetworkRequest(ScaffoldMessengerState? sm,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (after != null) {
|
if (after != null) {
|
||||||
after();
|
await after();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue