cache itemss for items list and edit item screen
BUG: when deleting an item the item list won't update
This commit is contained in:
parent
9ff6d97c90
commit
7174a03cf2
5 changed files with 327 additions and 74 deletions
|
@ -666,7 +666,7 @@ class RoomProduct {
|
|||
}
|
||||
|
||||
class RoomItem {
|
||||
int id;
|
||||
final int id;
|
||||
int state;
|
||||
String name;
|
||||
String description;
|
||||
|
@ -679,9 +679,14 @@ class RoomItem {
|
|||
// may link to a product
|
||||
int? link;
|
||||
|
||||
final String server;
|
||||
final String room;
|
||||
|
||||
RoomItem(
|
||||
{required this.id,
|
||||
required this.name,
|
||||
required this.server,
|
||||
required this.room,
|
||||
this.description = '',
|
||||
this.state = 0,
|
||||
this.category = -1,
|
||||
|
@ -689,10 +694,12 @@ class RoomItem {
|
|||
this.value = '',
|
||||
this.link});
|
||||
|
||||
factory RoomItem.fromJSON(dynamic json) {
|
||||
factory RoomItem.fromJSON(String server, String room, dynamic json) {
|
||||
return RoomItem(
|
||||
id: json['listItemID'],
|
||||
name: json['title'],
|
||||
server: server,
|
||||
room: room,
|
||||
description: json['description'],
|
||||
category: json['listCatID'],
|
||||
state: json['state'],
|
||||
|
@ -705,10 +712,84 @@ class RoomItem {
|
|||
return RoomItem(
|
||||
id: id,
|
||||
name: name,
|
||||
server: server,
|
||||
room: room,
|
||||
description: description,
|
||||
category: category,
|
||||
unit: unit,
|
||||
value: value,
|
||||
link: link);
|
||||
}
|
||||
|
||||
// get list of all categories in a given room
|
||||
static Future<List<RoomItem>> list(String server, String room) async {
|
||||
final db = Localstore.instance;
|
||||
final rooms = (await db.collection('items:$room@$server').get()) ?? {};
|
||||
List<RoomItem> builder = [];
|
||||
for (MapEntry entry in rooms.entries) {
|
||||
try {
|
||||
builder.add(RoomItem.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('items:$room@$server').stream;
|
||||
stream.listen(cb);
|
||||
}
|
||||
|
||||
factory RoomItem.fromMap(Map<String, dynamic> map) {
|
||||
return RoomItem(
|
||||
server: map['server'],
|
||||
room: map['room'],
|
||||
id: map['id'],
|
||||
name: map['name'],
|
||||
description: map['description'],
|
||||
category: map['category'],
|
||||
state: map['state'],
|
||||
unit: map['unit'],
|
||||
value: map['value'],
|
||||
link: map['product']);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'server': server,
|
||||
'room': room,
|
||||
'id': id,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'category': category,
|
||||
'state': state,
|
||||
'unit': unit,
|
||||
'value': value,
|
||||
'product': link
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> toDisk() async {
|
||||
final db = Localstore.instance;
|
||||
await db.collection('items:$room@$server').doc('$id').set(toMap());
|
||||
}
|
||||
|
||||
Future<void> removeDisk() async {
|
||||
final db = Localstore.instance;
|
||||
await db.collection('items:$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('items:$room@$server').doc('$id').get();
|
||||
return RoomProduct.fromMap(raw!);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,12 +41,19 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
List<RoomProduct> products = [];
|
||||
RoomItem? item;
|
||||
|
||||
void fetchCategories() {
|
||||
void fetchCategories() async {
|
||||
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(
|
||||
credentials: user,
|
||||
target: user.server,
|
||||
|
@ -64,12 +71,19 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
});
|
||||
}
|
||||
|
||||
void fetchProducts() {
|
||||
void fetchProducts() async {
|
||||
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(
|
||||
credentials: user,
|
||||
target: user.server,
|
||||
|
@ -87,12 +101,19 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
});
|
||||
}
|
||||
|
||||
void fetchItem() {
|
||||
void fetchItem() async {
|
||||
final user = context.read<User>();
|
||||
final scaffmgr = ScaffoldMessenger.of(context);
|
||||
|
||||
// TODO: load cached item first
|
||||
// load cached item first
|
||||
try {
|
||||
await RoomItem.fromDisk(
|
||||
id: widget.item, server: widget.server, room: widget.room);
|
||||
} catch (_) {
|
||||
// cache miss
|
||||
}
|
||||
|
||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
||||
doNetworkRequest(scaffmgr,
|
||||
req: () => postWithCreadentials(
|
||||
credentials: user,
|
||||
target: user.server,
|
||||
|
@ -103,7 +124,8 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
'listItemID': widget.item
|
||||
}),
|
||||
onOK: (body) async {
|
||||
final resp = RoomItem.fromJSON(body['data']);
|
||||
final resp =
|
||||
RoomItem.fromJSON(widget.server, widget.room, body['data']);
|
||||
setState(() {
|
||||
item = resp;
|
||||
_ctrName.text = resp.name;
|
||||
|
@ -121,6 +143,26 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
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();
|
||||
|
@ -256,6 +298,20 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
'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();
|
||||
});
|
||||
},
|
||||
|
|
|
@ -28,14 +28,20 @@ class _NewItemPageState extends State<NewItemPage> {
|
|||
// data cache
|
||||
List<RoomCategory> categories = [];
|
||||
List<RoomProduct> products = [];
|
||||
RoomItem? item;
|
||||
|
||||
void fetchCategories() {
|
||||
void fetchCategories() async {
|
||||
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(
|
||||
credentials: user,
|
||||
target: user.server,
|
||||
|
@ -53,12 +59,19 @@ class _NewItemPageState extends State<NewItemPage> {
|
|||
});
|
||||
}
|
||||
|
||||
void fetchProducts() {
|
||||
void fetchProducts() async {
|
||||
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(
|
||||
credentials: user,
|
||||
target: user.server,
|
||||
|
@ -76,40 +89,33 @@ class _NewItemPageState extends State<NewItemPage> {
|
|||
});
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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();
|
||||
|
||||
if (widget.item != null) {
|
||||
fetchItem();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -138,7 +144,19 @@ class _NewItemPageState extends State<NewItemPage> {
|
|||
}),
|
||||
onOK: (body) async {
|
||||
final id = body["data"]["listItemID"];
|
||||
// TODO cache item
|
||||
// cache item
|
||||
final item = RoomItem(
|
||||
id: id,
|
||||
room: widget.room,
|
||||
server: widget.server,
|
||||
state: 0,
|
||||
name: name,
|
||||
description: '',
|
||||
category: null,
|
||||
unit: 0,
|
||||
value: '',
|
||||
link: productID);
|
||||
await item.toDisk();
|
||||
// launch edit item screen
|
||||
router.pushReplacementNamed('edit-item', params: {
|
||||
'server': widget.server,
|
||||
|
@ -170,7 +188,20 @@ class _NewItemPageState extends State<NewItemPage> {
|
|||
}),
|
||||
onOK: (body) async {
|
||||
final id = body["data"]["listProdID"];
|
||||
// TODO: cache product
|
||||
// cache product
|
||||
final prod = RoomProduct(
|
||||
id: id,
|
||||
name: name,
|
||||
server: widget.server,
|
||||
room: widget.room,
|
||||
description: '',
|
||||
category: null,
|
||||
defaultUnit: 0,
|
||||
defaultValue: '',
|
||||
ean: '',
|
||||
parent: null);
|
||||
await prod.toDisk();
|
||||
|
||||
cb(id);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,12 +28,37 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
Map<int?, RoomCategory> categories = {};
|
||||
List<RoomProduct> products = [];
|
||||
|
||||
void fetchItems() {
|
||||
void fetchItems() async {
|
||||
final user = context.read<User>();
|
||||
final scaffmgr = ScaffoldMessenger.of(context);
|
||||
|
||||
// TODO: load cached items first
|
||||
// load cached items first
|
||||
final cache = await RoomItem.list(
|
||||
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||
|
||||
doNetworkRequest(ScaffoldMessenger.of(context),
|
||||
final List<RoomItem> l = [];
|
||||
final List<RoomItem> c = [];
|
||||
|
||||
for (RoomItem item in cache) {
|
||||
if (item.state == 0) {
|
||||
l.add(item);
|
||||
} else {
|
||||
c.add(item);
|
||||
}
|
||||
// cache items
|
||||
await item.toDisk();
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
list = l;
|
||||
cart = c;
|
||||
|
||||
sortAll();
|
||||
});
|
||||
}
|
||||
|
||||
doNetworkRequest(scaffmgr,
|
||||
req: () => postWithCreadentials(
|
||||
credentials: user,
|
||||
target: user.server,
|
||||
|
@ -41,7 +66,8 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
body: {'room': widget.room?.id, 'server': widget.room?.serverTag}),
|
||||
onOK: (body) async {
|
||||
final resp = body['data']
|
||||
.map<RoomItem>((raw) => RoomItem.fromJSON(raw))
|
||||
.map<RoomItem>((raw) => RoomItem.fromJSON(
|
||||
widget.room?.serverTag ?? "", widget.room?.id ?? "", raw))
|
||||
.toList();
|
||||
|
||||
final List<RoomItem> l = [];
|
||||
|
@ -53,10 +79,10 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
} else {
|
||||
c.add(item);
|
||||
}
|
||||
// cache items
|
||||
await item.toDisk();
|
||||
}
|
||||
|
||||
// TODO: cache items
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
list = l;
|
||||
|
@ -111,17 +137,23 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
final scaffmgr = ScaffoldMessenger.of(context);
|
||||
|
||||
// load cached categories
|
||||
final cache = await RoomCategory.list(
|
||||
final resp = await RoomCategory.list(
|
||||
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||
if (mounted) {
|
||||
Map<int?, RoomCategory> map = {};
|
||||
|
||||
for (RoomCategory cat in cache) {
|
||||
map[cat.id] = cat;
|
||||
Map<int, int> map = {};
|
||||
Map<int?, RoomCategory> cat = {};
|
||||
for (int i = 0; i < resp.length; i++) {
|
||||
map[resp[i].id ?? 0] = i;
|
||||
cat[resp[i].id ?? 0] = resp[i];
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
weights = map;
|
||||
categories = cat;
|
||||
sortAll();
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
categories = map;
|
||||
});
|
||||
}
|
||||
|
||||
doNetworkRequest(scaffmgr,
|
||||
|
@ -190,6 +222,34 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// wait for background room item changes
|
||||
RoomItem.listen(widget.room?.serverTag ?? "", widget.room?.id ?? "",
|
||||
(_) async {
|
||||
try {
|
||||
final updated = await RoomItem.list(
|
||||
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||
|
||||
final List<RoomItem> l = [];
|
||||
final List<RoomItem> c = [];
|
||||
|
||||
for (RoomItem item in updated) {
|
||||
if (item.state == 0) {
|
||||
l.add(item);
|
||||
} else {
|
||||
c.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
list = l;
|
||||
cart = c;
|
||||
|
||||
sortAll();
|
||||
});
|
||||
}
|
||||
} catch (_) {}
|
||||
});
|
||||
// wait for background room product changes
|
||||
RoomProduct.listen(widget.room?.serverTag ?? "", widget.room?.id ?? "",
|
||||
(_) async {
|
||||
|
@ -205,16 +265,22 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
RoomCategory.listen(widget.room?.serverTag ?? "", widget.room?.id ?? "",
|
||||
(_) async {
|
||||
try {
|
||||
final updated = await RoomCategory.list(
|
||||
final resp = await RoomCategory.list(
|
||||
widget.room?.serverTag ?? "", widget.room?.id ?? "");
|
||||
Map<int?, RoomCategory> map = {};
|
||||
|
||||
for (RoomCategory cat in updated) {
|
||||
map[cat.id] = cat;
|
||||
Map<int, int> map = {};
|
||||
Map<int?, RoomCategory> cat = {};
|
||||
for (int i = 0; i < resp.length; i++) {
|
||||
map[resp[i].id ?? 0] = i;
|
||||
cat[resp[i].id ?? 0] = resp[i];
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
weights = map;
|
||||
categories = cat;
|
||||
sortAll();
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
categories = map;
|
||||
});
|
||||
} catch (_) {}
|
||||
});
|
||||
|
||||
|
@ -518,6 +584,9 @@ class ShoppingListItemInfo extends StatelessWidget {
|
|||
'id': room,
|
||||
'item': item.id.toString()
|
||||
});
|
||||
|
||||
final navInner = Navigator.of(context);
|
||||
navInner.pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
|
@ -567,7 +636,8 @@ class ShoppingListItemInfo extends StatelessWidget {
|
|||
},
|
||||
credentials: user),
|
||||
onOK: (_) async {
|
||||
// TODO: remove cached item
|
||||
// remove cached item
|
||||
await item.removeDisk();
|
||||
},
|
||||
after: () {
|
||||
// close popup
|
||||
|
@ -587,9 +657,9 @@ class ShoppingListItemInfo extends StatelessWidget {
|
|||
ListTile(
|
||||
title: Text(item.state == 0
|
||||
? AppLocalizations.of(context)!.moveItemToCartTitle
|
||||
: AppLocalizations.of(context)!.moveItemToCartSubtitle),
|
||||
: AppLocalizations.of(context)!.removeItemFromCartTitle),
|
||||
subtitle: Text(item.state == 0
|
||||
? AppLocalizations.of(context)!.removeItemFromCartTitle
|
||||
? AppLocalizations.of(context)!.moveItemToCartSubtitle
|
||||
: AppLocalizations.of(context)!.removeItemFromCartSubtitle),
|
||||
onTap: () {
|
||||
// flip state
|
||||
|
@ -605,7 +675,12 @@ class ShoppingListItemInfo extends StatelessWidget {
|
|||
'server': server,
|
||||
'listItemID': item.id,
|
||||
'state': item.state
|
||||
}));
|
||||
}),
|
||||
onOK: (_) async {
|
||||
final navInner = Navigator.of(context);
|
||||
await item.toDisk();
|
||||
navInner.pop();
|
||||
});
|
||||
})
|
||||
],
|
||||
),
|
||||
|
|
|
@ -118,6 +118,16 @@ class _EditProductPageState extends State<EditProductPage> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// 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();
|
||||
|
|
Loading…
Reference in a new issue