Refactor calendars in Habitica (#131020)

* Refactor calendars

* changes
This commit is contained in:
Manu 2024-11-29 03:31:38 +01:00 committed by GitHub
parent 5c8fb5ec2c
commit 8e12fbff88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from abc import abstractmethod
from datetime import date, datetime, timedelta
from enum import StrEnum
@ -60,6 +61,43 @@ class HabiticaCalendarEntity(HabiticaBase, CalendarEntity):
"""Initialize calendar entity."""
super().__init__(coordinator, self.entity_description)
@abstractmethod
def get_events(
self, start_date: datetime, end_date: datetime | None = None
) -> list[CalendarEvent]:
"""Return events."""
@property
def event(self) -> CalendarEvent | None:
"""Return the current or next upcoming event."""
return next(iter(self.get_events(dt_util.now())), None)
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Return calendar events within a datetime range."""
return self.get_events(start_date, end_date)
@property
def start_of_today(self) -> datetime:
"""Habitica daystart."""
return dt_util.start_of_local_day(
datetime.fromisoformat(self.coordinator.data.user["lastCron"])
)
def get_recurrence_dates(
self, recurrences: rrule, start_date: datetime, end_date: datetime | None = None
) -> list[datetime]:
"""Calculate recurrence dates based on start_date and end_date."""
if end_date:
return recurrences.between(
start_date, end_date - timedelta(days=1), inc=True
)
# if no end_date is given, return only the next recurrence
return [recurrences.after(start_date, inc=True)]
class HabiticaTodosCalendarEntity(HabiticaCalendarEntity):
"""Habitica todos calendar entity."""
@ -69,7 +107,7 @@ class HabiticaTodosCalendarEntity(HabiticaCalendarEntity):
translation_key=HabiticaCalendar.TODOS,
)
def dated_todos(
def get_events(
self, start_date: datetime, end_date: datetime | None = None
) -> list[CalendarEvent]:
"""Get all dated todos."""
@ -112,18 +150,6 @@ class HabiticaTodosCalendarEntity(HabiticaCalendarEntity):
),
)
@property
def event(self) -> CalendarEvent | None:
"""Return the current or next upcoming event."""
return next(iter(self.dated_todos(dt_util.now())), None)
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Return calendar events within a datetime range."""
return self.dated_todos(start_date, end_date)
class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity):
"""Habitica dailies calendar entity."""
@ -133,13 +159,6 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity):
translation_key=HabiticaCalendar.DAILIES,
)
@property
def today(self) -> datetime:
"""Habitica daystart."""
return dt_util.start_of_local_day(
datetime.fromisoformat(self.coordinator.data.user["lastCron"])
)
def end_date(self, recurrence: datetime, end: datetime | None = None) -> date:
"""Calculate the end date for a yesterdaily.
@ -152,29 +171,20 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity):
if end:
return recurrence.date() + timedelta(days=1)
return (
dt_util.start_of_local_day() if recurrence == self.today else recurrence
dt_util.start_of_local_day()
if recurrence == self.start_of_today
else recurrence
).date() + timedelta(days=1)
def get_recurrence_dates(
self, recurrences: rrule, start_date: datetime, end_date: datetime | None = None
) -> list[datetime]:
"""Calculate recurrence dates based on start_date and end_date."""
if end_date:
return recurrences.between(
start_date, end_date - timedelta(days=1), inc=True
)
# if no end_date is given, return only the next recurrence
return [recurrences.after(self.today, inc=True)]
def due_dailies(
def get_events(
self, start_date: datetime, end_date: datetime | None = None
) -> list[CalendarEvent]:
"""Get dailies and recurrences for a given period or the next upcoming."""
# we only have dailies for today and future recurrences
if end_date and end_date < self.today:
if end_date and end_date < self.start_of_today:
return []
start_date = max(start_date, self.today)
start_date = max(start_date, self.start_of_today)
events = []
for task in self.coordinator.data.tasks:
@ -187,10 +197,12 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity):
recurrences, start_date, end_date
)
for recurrence in recurrence_dates:
is_future_event = recurrence > self.today
is_current_event = recurrence <= self.today and not task["completed"]
is_future_event = recurrence > self.start_of_today
is_current_event = (
recurrence <= self.start_of_today and not task["completed"]
)
if not (is_future_event or is_current_event):
if not is_future_event and not is_current_event:
continue
events.append(
@ -214,20 +226,15 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity):
@property
def event(self) -> CalendarEvent | None:
"""Return the next upcoming event."""
return next(iter(self.due_dailies(self.today)), None)
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Return calendar events within a datetime range."""
return self.due_dailies(start_date, end_date)
return next(iter(self.get_events(self.start_of_today)), None)
@property
def extra_state_attributes(self) -> dict[str, bool | None] | None:
"""Return entity specific state attributes."""
return {
"yesterdaily": self.event.start < self.today.date() if self.event else None
"yesterdaily": self.event.start < self.start_of_today.date()
if self.event
else None
}
@ -239,7 +246,7 @@ class HabiticaTodoRemindersCalendarEntity(HabiticaCalendarEntity):
translation_key=HabiticaCalendar.TODO_REMINDERS,
)
def reminders(
def get_events(
self, start_date: datetime, end_date: datetime | None = None
) -> list[CalendarEvent]:
"""Reminders for todos."""
@ -282,18 +289,6 @@ class HabiticaTodoRemindersCalendarEntity(HabiticaCalendarEntity):
key=lambda event: event.start,
)
@property
def event(self) -> CalendarEvent | None:
"""Return the next upcoming event."""
return next(iter(self.reminders(dt_util.now())), None)
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Return calendar events within a datetime range."""
return self.reminders(start_date, end_date)
class HabiticaDailyRemindersCalendarEntity(HabiticaCalendarEntity):
"""Habitica daily reminders calendar entity."""
@ -321,47 +316,31 @@ class HabiticaDailyRemindersCalendarEntity(HabiticaCalendarEntity):
tzinfo=dt_util.DEFAULT_TIME_ZONE,
)
@property
def today(self) -> datetime:
"""Habitica daystart."""
return dt_util.start_of_local_day(
datetime.fromisoformat(self.coordinator.data.user["lastCron"])
)
def get_recurrence_dates(
self, recurrences: rrule, start_date: datetime, end_date: datetime | None = None
) -> list[datetime]:
"""Calculate recurrence dates based on start_date and end_date."""
if end_date:
return recurrences.between(
start_date, end_date - timedelta(days=1), inc=True
)
# if no end_date is given, return only the next recurrence
return [recurrences.after(self.today, inc=True)]
def reminders(
def get_events(
self, start_date: datetime, end_date: datetime | None = None
) -> list[CalendarEvent]:
"""Reminders for dailies."""
events = []
if end_date and end_date < self.today:
if end_date and end_date < self.start_of_today:
return []
start_date = max(start_date, self.today)
start_date = max(start_date, self.start_of_today)
for task in self.coordinator.data.tasks:
if not (task["type"] == HabiticaTaskType.DAILY and task["everyX"]):
continue
recurrences = build_rrule(task)
recurrences_start = self.today
recurrences_start = self.start_of_today
recurrence_dates = self.get_recurrence_dates(
recurrences, recurrences_start, end_date
)
for recurrence in recurrence_dates:
is_future_event = recurrence > self.today
is_current_event = recurrence <= self.today and not task["completed"]
is_future_event = recurrence > self.start_of_today
is_current_event = (
recurrence <= self.start_of_today and not task["completed"]
)
if not is_future_event and not is_current_event:
continue
@ -388,15 +367,3 @@ class HabiticaDailyRemindersCalendarEntity(HabiticaCalendarEntity):
events,
key=lambda event: event.start,
)
@property
def event(self) -> CalendarEvent | None:
"""Return the next upcoming event."""
return next(iter(self.reminders(dt_util.now())), None)
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Return calendar events within a datetime range."""
return self.reminders(start_date, end_date)