diff --git a/custom_components/custom_shopping_list/__init__.py b/custom_components/custom_shopping_list/__init__.py index b874763..657f058 100644 --- a/custom_components/custom_shopping_list/__init__.py +++ b/custom_components/custom_shopping_list/__init__.py @@ -180,10 +180,27 @@ class ShoppingItem: def __init__(self, item): self.name = item["name"] self.id = item["id"] + self.specification = item["specification"] self.complete = item["complete"] - def to_dict(self): - return vars(self) + def __str__(self): + return str(vars(self)) + + def __repr__(self) -> str: + return str(self) + + def to_ha(self): + specification = "" + if len(self.specification) > 0: + specification = f" [{self.specification}]" + return { + "name": self.name + specification, + "id": self.id, + "complete": self.complete, + } + + def to_bring(self): + return {"name": self.name, "specification": self.specification} class BringData: @@ -197,25 +214,30 @@ def __init__(self, userUUID, listUUID, language) -> None: } self.purchase_list = [] self.recent_list = [] - self.update_lists() @staticmethod - def bring_to_shopping(bitm, complete): - specification = bitm["specification"] - if specification == "": - specification = uuid.uuid4().hex + def bring_to_shopping(bitm, map, complete): + id = bitm["name"] + for key, itm in map.items(): + if bitm["name"] == itm.name and bitm["specification"] == itm.specification: + id = key + break return ShoppingItem( - {"name": bitm["name"], "id": specification, "complete": complete} + { + "name": bitm["name"], + "id": id, + "specification": bitm["specification"], + "complete": complete, + } ) - def update_lists(self): + def update_lists(self, map): + lists = self.api.get_items(self.language) self.purchase_list = [ - self.bring_to_shopping(itm, False) - for itm in self.api.get_items(self.language)["purchase"] + self.bring_to_shopping(itm, map, False) for itm in lists["purchase"] ] self.recent_list = [ - self.bring_to_shopping(itm, True) - for itm in self.api.get_items(self.language)["recently"] + self.bring_to_shopping(itm, map, True) for itm in lists["recently"] ] def convert_name(self, name): @@ -224,7 +246,7 @@ def convert_name(self, name): return name def purchase_item(self, item: ShoppingItem): - self.api.purchase_item(self.convert_name(item.name), item.id) + self.api.purchase_item(self.convert_name(item.name), item.specification) def recent_item(self, item: ShoppingItem): self.api.recent_item(self.convert_name(item.name)) @@ -240,67 +262,116 @@ def __init__(self, hass, username, password, language): """Initialize the shopping list.""" self.bring = BringData(username, password, language) self.hass = hass + self.map_items = {} self.items = [] + @staticmethod + def ha_to_shopping_item(item): + name = item["name"] + id = item["id"] + complete = item["complete"] + specification = "" + if " [" in name: + specification = name[name.index(" [") + 2 : len(name) - 1] + name = name[0 : name.index(" [")] + return ShoppingItem( + { + "name": name, + "id": id, + "specification": specification, + "complete": complete, + } + ) + + @staticmethod + def remove(list, item): + try: + list.remove(item) + except ValueError: + pass + + def find_item(self, id): + return next((i for i, item in enumerate(self.items) if item["id"] == id), None) + + def update_item(self, id, item): + i = self.find_item(id) + self.items[i] = item.to_ha() + self.items = [ + i for n, i in enumerate(self.items) if i not in self.items[n + 1 :] + ] + async def async_add(self, name): """Add a shopping list item.""" - item = ShoppingItem({"name": name, "id": uuid.uuid4().hex, "complete": False}) - self.items.append(item.to_dict()) + specification = "" + if " [" in name: + specification = name[name.index(" [") + 2 : len(name) - 1] + name = name[0 : name.index(" [")] + item = ShoppingItem( + { + "name": name, + "id": f"{name}", + "specification": specification, + "complete": False, + } + ) + self.items.append(item.to_ha()) self.bring.purchase_item(item) + self.map_items[item.id] = item await self.hass.async_add_executor_job(self.save) - return item.to_dict() + return item.to_ha() async def async_update(self, item_id, info): """Update a shopping list item.""" - temp = next((itm for itm in self.items if itm["id"] == item_id), None) - if temp is None: + item = self.map_items.get(item_id) + if item is None: raise KeyError info = ITEM_UPDATE_SCHEMA(info) - temp.update(info) - - item = ShoppingItem(temp) + key = list(info.keys())[0] + value = info[key] + + if key == "complete": + item.complete = value + elif key == "name": + name = value + specification = "" + if " [" in name: + specification = name[name.index(" [") + 2 : len(name) - 1] + name = name[0 : name.index(" [")] + self.bring.remove_item(item) + item.name = name + item.specification = specification + item.id = name + self.map_items.pop(item_id) + self.map_items[item.name] = item if item.complete: self.bring.recent_item(item) else: self.bring.purchase_item(item) + self.update_item(item_id, item) await self.hass.async_add_executor_job(self.save) - return item.to_dict() + return item.to_ha() async def async_clear_completed(self): """Clear completed items.""" - for itm in [itm for itm in self.items if itm["complete"]]: - self.bring.remove_item(ShoppingItem(itm)) - self.items = [itm for itm in self.items if not itm["complete"]] + to_remove = [] + for key, itm in self.map_items.items(): + if itm.complete: + self.bring.remove_item(itm) + self.remove(self.bring.recent_list, itm) + self.remove(self.items, itm.to_ha()) + to_remove.append(key) + for key in to_remove: + self.map_items.pop(key) await self.hass.async_add_executor_job(self.save) - def find_item(self, item): - """Find a Bring item in the shopping list""" - index = 0 - for itm in self.items: - if itm["name"] == item.name: - break - index = index + 1 - return index - def sync_bring(self): - self.bring.update_lists() + self.bring.update_lists(self.map_items) - for itm in self.bring.purchase_list: - if self.find_item(itm) == len(self.items): - self.items.append(itm.to_dict()) + for itm in self.bring.purchase_list + self.bring.recent_list: + self.map_items[itm.id] = itm - for itm in self.bring.recent_list: - if self.find_item(itm) < len(self.items): - self.items[self.find_item(itm)]["complete"] = True - - for itm in self.items: - if itm["complete"]: - if itm not in self.bring.recent_list: - self.bring.recent_item(ShoppingItem(itm)) - else: - if itm not in self.bring.purchase_list: - self.bring.purchase_item(ShoppingItem(itm)) + self.items = [itm.to_ha() for k, itm in self.map_items.items()] async def async_load(self): """Load items.""" @@ -310,6 +381,8 @@ def load(): return load_json(self.hass.config.path(PERSISTENCE), default=[]) self.items = await self.hass.async_add_executor_job(load) + for itm in self.items: + self.map_items[itm["id"]] = self.ha_to_shopping_item(itm) self.sync_bring() def save(self):