120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
"""A todo platform for OurGroceries."""
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
from homeassistant.components.todo import (
|
|
TodoItem,
|
|
TodoItemStatus,
|
|
TodoListEntity,
|
|
TodoListEntityFeature,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|
|
|
from .const import DOMAIN
|
|
from .coordinator import OurGroceriesDataUpdateCoordinator
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
|
) -> None:
|
|
"""Set up the OurGroceries todo platform config entry."""
|
|
coordinator: OurGroceriesDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
|
async_add_entities(
|
|
OurGroceriesTodoListEntity(coordinator, sl["id"], sl["name"])
|
|
for sl in coordinator.lists
|
|
)
|
|
|
|
|
|
def _completion_status(item: dict[str, Any]) -> TodoItemStatus:
|
|
if item.get("crossedOffAt", False):
|
|
return TodoItemStatus.COMPLETED
|
|
return TodoItemStatus.NEEDS_ACTION
|
|
|
|
|
|
class OurGroceriesTodoListEntity(
|
|
CoordinatorEntity[OurGroceriesDataUpdateCoordinator], TodoListEntity
|
|
):
|
|
"""An OurGroceries TodoListEntity."""
|
|
|
|
_attr_has_entity_name = True
|
|
_attr_supported_features = (
|
|
TodoListEntityFeature.CREATE_TODO_ITEM
|
|
| TodoListEntityFeature.UPDATE_TODO_ITEM
|
|
| TodoListEntityFeature.DELETE_TODO_ITEM
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: OurGroceriesDataUpdateCoordinator,
|
|
list_id: str,
|
|
list_name: str,
|
|
) -> None:
|
|
"""Initialize TodoistTodoListEntity."""
|
|
super().__init__(coordinator=coordinator)
|
|
self._list_id = list_id
|
|
self._attr_unique_id = list_id
|
|
self._attr_name = list_name
|
|
|
|
@callback
|
|
def _handle_coordinator_update(self) -> None:
|
|
"""Handle updated data from the coordinator."""
|
|
if self.coordinator.data is None:
|
|
self._attr_todo_items = None
|
|
else:
|
|
self._attr_todo_items = [
|
|
TodoItem(
|
|
summary=item["name"],
|
|
uid=item["id"],
|
|
status=_completion_status(item),
|
|
)
|
|
for item in self.coordinator.data[self._list_id]["list"]["items"]
|
|
]
|
|
super()._handle_coordinator_update()
|
|
|
|
async def async_create_todo_item(self, item: TodoItem) -> None:
|
|
"""Create a To-do item."""
|
|
if item.status != TodoItemStatus.NEEDS_ACTION:
|
|
raise ValueError("Only active tasks may be created.")
|
|
await self.coordinator.og.add_item_to_list(
|
|
self._list_id, item.summary, auto_category=True
|
|
)
|
|
await self.coordinator.async_refresh()
|
|
|
|
async def async_update_todo_item(self, item: TodoItem) -> None:
|
|
"""Update a To-do item."""
|
|
if item.summary:
|
|
api_items = self.coordinator.data[self._list_id]["list"]["items"]
|
|
category = next(
|
|
api_item.get("categoryId")
|
|
for api_item in api_items
|
|
if api_item["id"] == item.uid
|
|
)
|
|
await self.coordinator.og.change_item_on_list(
|
|
self._list_id, item.uid, category, item.summary
|
|
)
|
|
if item.status is not None:
|
|
cross_off = item.status == TodoItemStatus.COMPLETED
|
|
await self.coordinator.og.toggle_item_crossed_off(
|
|
self._list_id, item.uid, cross_off=cross_off
|
|
)
|
|
await self.coordinator.async_refresh()
|
|
|
|
async def async_delete_todo_items(self, uids: list[str]) -> None:
|
|
"""Delete a To-do item."""
|
|
await asyncio.gather(
|
|
*[
|
|
self.coordinator.og.remove_item_from_list(self._list_id, uid)
|
|
for uid in uids
|
|
]
|
|
)
|
|
await self.coordinator.async_refresh()
|
|
|
|
async def async_added_to_hass(self) -> None:
|
|
"""When entity is added to hass update state from existing coordinator data."""
|
|
await super().async_added_to_hass()
|
|
self._handle_coordinator_update()
|