diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c807cbd..4efa644a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - feat(store): add `DispatchItem` and `NotificationDispatchItem` as convenience `ActionItem` subclasses to dispatch actions and events - feat(users): add `users` service to create, list, delete and change password of system users - feat(ci): add `ubo-pod-pi5` to the list of github runners for `test`, also use it for `dependencies` and `type-check` jobs +- refactor(core): improve update-manager to be event driven ## Version 0.15.11 diff --git a/pyproject.toml b/pyproject.toml index 01fb95cf..2f3ca4fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,10 +93,21 @@ typecheck = "pyright -p pyproject.toml ." test = "pytest --cov=ubo_app" sanity = ["typecheck", "lint", "test"] build-docker-images = "sh -c 'docker buildx build . -f scripts/Dockerfile.dev -t ubo-app-dev && docker buildx build . -f scripts/Dockerfile.test -t ubo-app-test'" + +"device:deploy" = "poe deploy-to-device" +"device:deploy:deps" = "poe deploy-to-device --deps" +"device:deploy:kill" = "poe deploy-to-device --kill" +"device:deploy:restart" = "poe deploy-to-device --restart" +"device:deploy:bootstrap" = "poe deploy-to-device --bootstrap --restart" +"device:deploy:complete" = "poe deploy-to-device --deps --bootstrap --restart" +"device:deploy:env" = "poe deploy-to-device --env" + +"device:test" = "poe test-on-device --copy --run --results" "device:test:deps" = "poe test-on-device --deps" "device:test:copy" = "poe test-on-device --copy" "device:test:run" = "poe test-on-device --run" "device:test:results" = "poe test-on-device --results" +"device:test:complete" = "poe test-on-device --deps --copy --run --results" [tool.poe.tasks.test-on-device] args = [ diff --git a/ubo_app/menu_app/menu_notification_handler.py b/ubo_app/menu_app/menu_notification_handler.py index 2f09ee38..5652c07d 100644 --- a/ubo_app/menu_app/menu_notification_handler.py +++ b/ubo_app/menu_app/menu_notification_handler.py @@ -83,7 +83,7 @@ def close(_: object = None) -> None: notification.value.on_close() def clear_notification(event: NotificationsClearEvent) -> None: - if event.notification == notification: + if event.notification == notification.value: close() _self = weakref.ref(self) diff --git a/ubo_app/store/update_manager/utils.py b/ubo_app/store/update_manager/utils.py index c54674cb..900ad442 100644 --- a/ubo_app/store/update_manager/utils.py +++ b/ubo_app/store/update_manager/utils.py @@ -8,10 +8,11 @@ import subprocess import time from pathlib import Path -from typing import TypedDict import aiohttp import requests +from kivy.clock import Clock +from redux import FinishEvent from ubo_gui.constants import DANGER_COLOR, INFO_COLOR, SUCCESS_COLOR from ubo_gui.menu.types import Item @@ -335,46 +336,56 @@ def about_menu_items(state: UpdateManagerState) -> list[Item]: return [] -class _UpdateManagerServiceState(TypedDict): - is_running: bool - is_presented: bool - progress: int - - -@store.autorun( - lambda state: _UpdateManagerServiceState( - is_running=state.update_manager.is_update_service_active, - is_presented=any( - notification.id == UPDATE_MANAGER_NOTIFICATION_ID - for notification in state.notifications.notifications - ), - progress=int(time.time() / 2), +@store.view( + lambda state: any( + notification.id == UPDATE_MANAGER_NOTIFICATION_ID + for notification in state.notifications.notifications ), ) -def _(state: _UpdateManagerServiceState) -> None: - if state['is_running']: - store.dispatch( - NotificationsAddAction( - notification=Notification( - id=UPDATE_MANAGER_SECOND_PHASE_NOTIFICATION_ID, - title='Update in progress', - content="""\ +def dispatch_notification(is_presented: bool, _: float = 0) -> None: # noqa: FBT001 + """Dispatch the notification.""" + store.dispatch( + NotificationsAddAction( + notification=Notification( + id=UPDATE_MANAGER_SECOND_PHASE_NOTIFICATION_ID, + title='Update in progress', + content="""\ Please keep the device powered on. This may take around 20 minutes to complete.""", - importance=Importance.LOW, - icon='󰚰', - display_type=NotificationDisplayType.BACKGROUND - if state['is_presented'] - else NotificationDisplayType.STICKY, - dismissable=False, - dismiss_on_close=False, - color=INFO_COLOR, - progress=(state['progress'] % 4 + 1) / 4, - blink=not state['is_presented'], - ), + importance=Importance.LOW, + icon='󰚰', + display_type=NotificationDisplayType.BACKGROUND + if is_presented + else NotificationDisplayType.STICKY, + dismissable=False, + dismiss_on_close=False, + color=INFO_COLOR, + progress=(int(time.time() / 2) % 4 + 1) / 4, + blink=not is_presented, ), - ) + ), + ) + + +update_clock_event = Clock.create_trigger( + dispatch_notification, + timeout=2, + interval=True, +) + +store.subscribe_event(FinishEvent, update_clock_event.cancel) + + +@store.autorun( + lambda state: state.update_manager.is_update_service_active, +) +async def _(is_running: bool) -> None: # noqa: FBT001 + if is_running: + dispatch_notification() + update_clock_event() else: + update_clock_event.cancel() + await asyncio.sleep(0.2) store.dispatch( NotificationsClearByIdAction( id=UPDATE_MANAGER_SECOND_PHASE_NOTIFICATION_ID,