from __future__ import annotations from homeassistant.components.select import SelectEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity from .const import ( DOMAIN, FILL_COVER, FILL_CONTAIN, FILL_BLUR, MAX_RESOLUTION_OPTIONS, ORIENTATION_MISMATCH_PAIR, ORIENTATION_MISMATCH_SINGLE, ORIENTATION_MISMATCH_AVOID, ORDER_OPTIONS, ORDER_RANDOM, DATE_FILTER_OPTIONS, DATE_FILTER_OFF, MISSING_DATE_OPTIONS, MISSING_DATE_USE_UPLOADED, ) from .store import SlideshowStore ASPECT_RATIO_OPTIONS = ["16:9", "16:10", "4:3", "1:1", "3:4", "10:16", "9:16"] async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: store: SlideshowStore = hass.data[DOMAIN][entry.entry_id]["store"] async_add_entities( [ FillModeSelect(entry, store), PortraitModeSelect(entry, store), OrderModeSelect(entry, store), AspectRatioSelect(entry, store), MaxResolutionSelect(entry, store), DateFilterSelect(entry, store), MissingDateModeSelect(entry, store), ] ) class _BaseSelect(SelectEntity, RestoreEntity): _attr_has_entity_name = True _attr_should_poll = False _attr_entity_registry_enabled_default = True def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: self.entry = entry self.store = store async def async_added_to_hass(self) -> None: await super().async_added_to_hass() self.store.add_listener(self.async_write_ha_state) @property def device_info(self): return { "identifiers": {(DOMAIN, self.entry.entry_id)}, "name": f"Album Slideshow {self.entry.title}", "manufacturer": "Album Slideshow", } class FillModeSelect(_BaseSelect): _attr_icon = "mdi:aspect-ratio" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_fill_mode" self._attr_name = "Fill mode" self._attr_options = [FILL_BLUR, FILL_COVER, FILL_CONTAIN] @property def current_option(self): value = self.store.fill_mode return value if value in self.options else self.options[0] async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.fill_mode = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state in self.options: self.store.fill_mode = old.state self.store.notify() class PortraitModeSelect(_BaseSelect): _attr_icon = "mdi:account-box-outline" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_portrait_mode" self._attr_name = "Orientation mismatch mode" self._attr_options = [ ORIENTATION_MISMATCH_PAIR, ORIENTATION_MISMATCH_SINGLE, ORIENTATION_MISMATCH_AVOID, ] @property def current_option(self): value = self.store.portrait_mode return value if value in self.options else self.options[0] async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.portrait_mode = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old: restored = old.state if restored in ("blur", "crop"): restored = ORIENTATION_MISMATCH_SINGLE if restored in self.options: self.store.portrait_mode = restored self.store.notify() class OrderModeSelect(_BaseSelect): _attr_icon = "mdi:shuffle-variant" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_order_mode" self._attr_name = "Order mode" self._attr_options = list(ORDER_OPTIONS) @property def current_option(self): value = self.store.order_mode return value if value in self.options else ORDER_RANDOM async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.order_mode = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state in self.options: self.store.order_mode = old.state self.store.notify() class AspectRatioSelect(_BaseSelect): _attr_icon = "mdi:crop" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_aspect_ratio" self._attr_name = "Aspect ratio" self._attr_options = ASPECT_RATIO_OPTIONS @property def current_option(self): value = self.store.aspect_ratio return value if value in self.options else self.options[0] async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.aspect_ratio = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state in self.options: self.store.aspect_ratio = old.state self.store.notify() class MaxResolutionSelect(_BaseSelect): _attr_icon = "mdi:image-size-select-large" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_max_resolution" self._attr_name = "Max resolution" self._attr_options = MAX_RESOLUTION_OPTIONS @property def current_option(self): value = self.store.max_resolution return value if value in self.options else self.options[0] async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.max_resolution = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state in self.options: self.store.max_resolution = old.state self.store.notify() class DateFilterSelect(_BaseSelect): _attr_icon = "mdi:calendar-filter" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_date_filter" self._attr_name = "Date filter" self._attr_options = list(DATE_FILTER_OPTIONS) @property def current_option(self): value = self.store.date_filter return value if value in self.options else DATE_FILTER_OFF async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.date_filter = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state in self.options: self.store.date_filter = old.state self.store.notify() class MissingDateModeSelect(_BaseSelect): _attr_icon = "mdi:calendar-question" def __init__(self, entry: ConfigEntry, store: SlideshowStore) -> None: super().__init__(entry, store) self._attr_unique_id = f"{entry.entry_id}_missing_date_mode" self._attr_name = "Missing capture date" self._attr_options = list(MISSING_DATE_OPTIONS) @property def current_option(self): value = self.store.missing_date_mode return value if value in self.options else MISSING_DATE_USE_UPLOADED async def async_select_option(self, option: str) -> None: if option not in self.options: return self.store.missing_date_mode = option self.store.notify() async def async_added_to_hass(self) -> None: await super().async_added_to_hass() old = await self.async_get_last_state() if old and old.state in self.options: self.store.missing_date_mode = old.state self.store.notify()