Skip to content

Commit

Permalink
feat(store): add DispatchItem and NotificationDispatchItem as con…
Browse files Browse the repository at this point in the history
…venience `ActionItem` subclasses to dispatch actions and events
  • Loading branch information
sassanh committed Sep 3, 2024
1 parent 87d2a36 commit 097a38f
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 35 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- test: fix an issue in tests which caused minor random store state changes, ruining snapshot assertions
- test: add vscode and rpi-connect services to `test_all_services` test
- refactor(housekeeping): improve store imports
- feat(store): add `DispatchItem` and `NotificationDispatchItem` as convenience `ActionItem` subclasses to dispatch actions and events

## Version 0.15.11

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@
"key": null,
"label": "Already up to date!",
"opacity": null,
"operation": {
"status": "checking"
},
"progress": null
}
],
Expand Down Expand Up @@ -246,6 +249,7 @@
"key": null,
"label": "Reboot",
"opacity": null,
"operation": {},
"progress": null
},
{
Expand All @@ -262,6 +266,7 @@
"key": null,
"label": "Power off",
"opacity": null,
"operation": {},
"progress": null
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@
"key": null,
"label": "Already up to date!",
"opacity": null,
"operation": {
"status": "checking"
},
"progress": null
}
],
Expand Down Expand Up @@ -246,6 +249,7 @@
"key": null,
"label": "Reboot",
"opacity": null,
"operation": {},
"progress": null
},
{
Expand All @@ -262,6 +266,7 @@
"key": null,
"label": "Power off",
"opacity": null,
"operation": {},
"progress": null
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,9 @@
"key": null,
"label": "Already up to date!",
"opacity": null,
"operation": {
"status": "checking"
},
"progress": null
}
],
Expand Down Expand Up @@ -699,6 +702,7 @@
"key": null,
"label": "Reboot",
"opacity": null,
"operation": {},
"progress": null
},
{
Expand All @@ -715,6 +719,7 @@
"key": null,
"label": "Power off",
"opacity": null,
"operation": {},
"progress": null
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,9 @@
"key": null,
"label": "Already up to date!",
"opacity": null,
"operation": {
"status": "checking"
},
"progress": null
}
],
Expand Down Expand Up @@ -699,6 +702,7 @@
"key": null,
"label": "Reboot",
"opacity": null,
"operation": {},
"progress": null
},
{
Expand All @@ -715,6 +719,7 @@
"key": null,
"label": "Power off",
"opacity": null,
"operation": {},
"progress": null
}
],
Expand Down
24 changes: 10 additions & 14 deletions ubo_app/store/core/_menus.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from __future__ import annotations

import functools
import socket
from datetime import UTC, datetime
from typing import TYPE_CHECKING

from redux import AutorunOptions
from ubo_gui.menu.types import (
ActionItem,
HeadedMenu,
HeadlessMenu,
SubMenuItem,
Expand All @@ -19,6 +17,7 @@
RebootAction,
SettingsCategory,
)
from ubo_app.store.dispatch_action import DispatchItem
from ubo_app.store.main import store
from ubo_app.store.services.notifications import Notification, NotificationsDisplayEvent
from ubo_app.store.update_manager.utils import (
Expand Down Expand Up @@ -102,19 +101,16 @@ def notifications_title(unread_count: int) -> str:
def notifications_menu_items(notifications: Sequence[Notification]) -> list[Item]:
"""Return a list of menu items for the notification manager."""
return [
ActionItem(
DispatchItem(
key=str(notification.id),
label=notification.title,
icon=notification.icon,
color='black',
background_color=notification.color,
action=functools.partial(
store.dispatch,
NotificationsDisplayEvent(
notification=notification,
index=index,
count=len(notifications),
),
operation=NotificationsDisplayEvent(
notification=notification,
index=index,
count=len(notifications),
),
progress=notification.progress,
)
Expand Down Expand Up @@ -160,14 +156,14 @@ def notifications_color(unread_count: int) -> str:
sub_menu=HeadlessMenu(
title='󰐥Power',
items=[
ActionItem(
DispatchItem(
label='Reboot',
action=lambda: store.dispatch(RebootAction()),
operation=RebootAction(),
icon='󰜉',
),
ActionItem(
DispatchItem(
label='Power off',
action=lambda: store.dispatch(PowerOffAction()),
operation=PowerOffAction(),
icon='󰐥',
),
],
Expand Down
34 changes: 34 additions & 0 deletions ubo_app/store/dispatch_action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Implement a menu item that dispatches an action or an event."""

from __future__ import annotations

import sys
from dataclasses import field
from typing import TYPE_CHECKING

from ubo_gui.menu.types import ActionItem

if TYPE_CHECKING:
from collections.abc import Callable

from ubo_app.store.main import ActionType, EventType


def _default_action() -> Callable[[], None]:
# WARNING: Dirty hack ahead
# This is to set the default value of `icon` based on the provided/default value of
# `importance`
from ubo_app.store.main import store

parent_frame = sys._getframe().f_back # noqa: SLF001
if not parent_frame or not (operation := parent_frame.f_locals.get('operation')):
msg = 'No operation provided for `DispatchItem`'
raise ValueError(msg)
return lambda: store.dispatch(operation)


class DispatchItem(ActionItem):
"""Menu item that dispatches an action or an event."""

operation: ActionType | EventType
action: Callable[[], None] = field(default_factory=_default_action)
12 changes: 8 additions & 4 deletions ubo_app/store/services/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from ubo_gui.menu.types import ActionItem

from ubo_app.constants import NOTIFICATIONS_FLASH_TIME
from ubo_app.store.dispatch_action import DispatchItem

if TYPE_CHECKING:
from collections.abc import Callable, Sequence
Expand Down Expand Up @@ -50,7 +51,7 @@ class NotificationDisplayType(StrEnum):
STICKY = auto()


def default_icon() -> str:
def _default_icon() -> str:
# WARNING: Dirty hack ahead
# This is to set the default value of `icon` based on the provided/default value of
# `importance`
Expand All @@ -60,7 +61,7 @@ def default_icon() -> str:
return IMPORTANCE_ICONS[parent_frame.f_locals.get('importance', Importance.LOW)]


def default_color() -> str:
def _default_color() -> str:
# WARNING: Dirty hack ahead
# This is to set the default value of `color` based on the provided/default value of
# `importance`
Expand All @@ -82,6 +83,9 @@ class NotificationActionItem(ActionItem):
dismiss_notification: bool = False


class NotificationDispatchItem(DispatchItem, NotificationActionItem): ...


class NotificationExtraInformation(Immutable):
text: str
piper_text: str | None = None
Expand All @@ -99,8 +103,8 @@ class Notification(Immutable):
is_read: bool = False
sender: str | None = None
actions: list[NotificationActionItem] = field(default_factory=list)
icon: str = field(default_factory=default_icon)
color: str = field(default_factory=default_color)
icon: str = field(default_factory=_default_icon)
color: str = field(default_factory=_default_color)
expiry_date: datetime | None = None
display_type: NotificationDisplayType = NotificationDisplayType.NOT_SET
flash_time: float = NOTIFICATIONS_FLASH_TIME
Expand Down
31 changes: 14 additions & 17 deletions ubo_app/store/update_manager/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import aiohttp
import requests
from ubo_gui.constants import DANGER_COLOR, INFO_COLOR, SUCCESS_COLOR
from ubo_gui.menu.types import ActionItem, Item
from ubo_gui.menu.types import Item

from ubo_app.constants import (
INSTALLATION_PATH,
Expand All @@ -23,12 +23,13 @@
)
from ubo_app.logging import logger
from ubo_app.store.core import RebootEvent
from ubo_app.store.dispatch_action import DispatchItem
from ubo_app.store.main import store
from ubo_app.store.services.notifications import (
Chime,
Importance,
Notification,
NotificationActionItem,
NotificationDispatchItem,
NotificationDisplayType,
NotificationExtraInformation,
NotificationsAddAction,
Expand Down Expand Up @@ -96,7 +97,9 @@ async def check_version() -> None:
)
except Exception:
logger.exception('Failed to check for updates')
store.dispatch(UpdateManagerSetStatusAction(status=UpdateStatus.FAILED_TO_CHECK))
store.dispatch(
UpdateManagerSetStatusAction(status=UpdateStatus.FAILED_TO_CHECK),
)
return


Expand Down Expand Up @@ -247,9 +250,9 @@ async def download_files() -> None:
Then another reboot will be done to complete the update process.""",
),
actions=[
NotificationActionItem(
NotificationDispatchItem(
icon='󰜉',
action=lambda: store.dispatch(RebootEvent()),
operation=RebootEvent(),
),
],
display_type=NotificationDisplayType.STICKY,
Expand Down Expand Up @@ -296,34 +299,28 @@ def about_menu_items(state: UpdateManagerState) -> list[Item]:
]
if state.update_status is UpdateStatus.FAILED_TO_CHECK:
return [
ActionItem(
DispatchItem(
label='Failed to check for updates',
action=lambda: store.dispatch(
UpdateManagerSetStatusAction(status=UpdateStatus.CHECKING),
),
operation=UpdateManagerSetStatusAction(status=UpdateStatus.CHECKING),
icon='󰜺',
background_color=DANGER_COLOR,
),
]
if state.update_status is UpdateStatus.UP_TO_DATE:
return [
ActionItem(
DispatchItem(
label='Already up to date!',
icon='󰄬',
action=lambda: store.dispatch(
UpdateManagerSetStatusAction(status=UpdateStatus.CHECKING),
),
operation=UpdateManagerSetStatusAction(status=UpdateStatus.CHECKING),
background_color=SUCCESS_COLOR,
color='#000000',
),
]
if state.update_status is UpdateStatus.OUTDATED:
return [
ActionItem(
DispatchItem(
label=f'Update to v{state.latest_version}',
action=lambda: store.dispatch(
UpdateManagerSetStatusAction(status=UpdateStatus.UPDATING),
),
operation=UpdateManagerSetStatusAction(status=UpdateStatus.UPDATING),
icon='󰬬',
),
]
Expand Down

0 comments on commit 097a38f

Please sign in to comment.