diff --git a/.github/workflows/integration_delivery.yml b/.github/workflows/integration_delivery.yml index 9024ba21..b51eced3 100644 --- a/.github/workflows/integration_delivery.yml +++ b/.github/workflows/integration_delivery.yml @@ -108,11 +108,6 @@ jobs: - uses: actions/checkout@v4 name: Checkout - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Install uv uses: astral-sh/setup-uv@v3 with: diff --git a/.gitignore b/.gitignore index bb20b834..f2c9451b 100644 --- a/.gitignore +++ b/.gitignore @@ -79,8 +79,8 @@ venv.bak/ *.log *.log.[0-9]* -# headless-kivy-pi -headless_kivy_pi_buffer.raw +# headless-kivy +headless_kivy*.raw # packer scripts/packer/packer_cache/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 54cccef2..47d9ab02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - fix(users): avoid setting user as sudoer when it performs a password reset - feat(ip): use pythonping to perform a real ping test instead to determine the internet connection status instead of opening a socket - feat(core): user can start/end recording actioning by hitting r, actions will be recorded in `recordings/` directory and the last recording can be replayed by hitting `ctrl+r` - closes #187 +- feat(core): use new `SpinnerWidget` of ubo-gui to show unknown progress in notifications, and add `General` sub menu to `System` settings menu to host ubo-pod/ubo-app related settings, currently it has `Debug` toggle to control a debug feature of `HeadlessWidget` - closes #190 ## Version 1.0.0 diff --git a/pyproject.toml b/pyproject.toml index 1d54e18c..4444a77f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,8 +8,8 @@ requires-python = ">=3.11" keywords = ['ubo', 'ubo-pod', 'raspberry pi', 'rpi', 'home assistance'] dependencies = [ "psutil >=6.0.0", - "ubo-gui >=0.13.3", - "headless-kivy >=0.9.8", + "ubo-gui >=0.13.7", + "headless-kivy >=0.12.1", "pyzbar >=0.1.9", "sdbus-networkmanager >=2.0.0 ; platform_machine=='aarch64'", "rpi_ws281x >=5.0.0 ; platform_machine=='aarch64'", @@ -65,7 +65,7 @@ packages = ["ubo_app"] [tool.uv] dev-dependencies = [ - "headless-kivy [test] >=0.9.8", + "headless-kivy [test] >=0.12.1", "poethepoet >=0.24.4", "pyright >=1.1.377", "pytest >=8.0.0", diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 7b54b605..a91835a3 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -48,9 +48,9 @@ function run_on_pod_as_root() { scp dist/$LATEST_VERSION ubo-development-pod:/tmp/ -run_on_pod "$(if [ "$deps" == "True" ]; then echo "pip install --upgrade /tmp/$LATEST_VERSION[default] &&"; fi) +run_on_pod "$(if [ "$deps" == "True" ]; then echo "pip install --upgrade /tmp/$LATEST_VERSION &&"; fi) mv /opt/ubo/env/lib/python3.*/site-packages/ubo_app/services/*-voice/models /tmp/ -pip install --no-index --upgrade --force-reinstal --no-deps /tmp/$LATEST_VERSION[default] +pip install --no-index --upgrade --force-reinstal --no-deps /tmp/$LATEST_VERSION mv /tmp/models /opt/ubo/env/lib/python3.*/site-packages/ubo_app/services/*-voice/ true" diff --git a/tests/conftest.py b/tests/conftest.py index a2778540..746178c2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -67,8 +67,6 @@ def pytest_addoption(parser: pytest.Parser) -> None: """Add options to the pytest command line.""" - parser.addoption('--override-window-snapshots', action='store_true') - parser.addoption('--make-screenshots', action='store_true') parser.addoption('--use-fakefs', action='store_true') diff --git a/tests/fixtures/app.py b/tests/fixtures/app.py index dcff6f48..7e3d7d2a 100644 --- a/tests/fixtures/app.py +++ b/tests/fixtures/app.py @@ -241,6 +241,10 @@ def patched_config_set(category: str, key: str, value: str) -> None: from kivy.config import Config Config.set('graphics', 'window_state', 'hidden') + Config.set('graphics', 'fbo', 'force-hardware') + Config.set('graphics', 'fullscreen', '0') + Config.set('graphics', 'multisamples', '1') + Config.set('graphics', 'vsync', '0') import headless_kivy.config @@ -249,7 +253,6 @@ def patched_config_set(category: str, key: str, value: str) -> None: headless_kivy.config.setup_headless_kivy( { 'callback': render_on_display, - 'automatic_fps': True, 'flip_vertical': True, 'width': WIDTH, 'height': HEIGHT, diff --git a/tests/fixtures/stability.py b/tests/fixtures/stability.py index f1617c26..b7a7a189 100644 --- a/tests/fixtures/stability.py +++ b/tests/fixtures/stability.py @@ -122,13 +122,7 @@ def check() -> None: assert is_window_stable, 'The content of the screen is not stable yet' assert is_store_stable, 'The content of the store is not stable yet' - from headless_kivy import HeadlessWidget, config - - headless_widget_instance = HeadlessWidget.get_instance(app_context.app.root) - if headless_widget_instance: - assert ( - headless_widget_instance.fps == config.min_fps() - ), 'Not in low fps mode' + from headless_kivy import HeadlessWidget await _run( initial_wait=initial_wait, diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-000.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-000.hash index fdc8a783..e3b093eb 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-000.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-000.hash @@ -1,2 +1,2 @@ // window-rpi-000 -1065fa10934619a40701fb78803e9aabb2a0b798b7f2ac50b1c6150a283dccdf +b3db0573bb0c73f16d0a5e5be0a017c8660a53c687d8559e76814a441db075bd diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-001.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-001.hash index 2836abc5..96e4f6da 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-001.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-001.hash @@ -1,2 +1,2 @@ // window-rpi-001 -92b0e1d02d380eb831bcafb57b27c2f2afa023a52a95af44765c17754ca3de38 +c680100b9cf09561e1adb62abfa8eb985a00c0468b392a6a1e772921807b5878 diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-002.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-002.hash index ce58dfb7..caa8faa1 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-002.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-002.hash @@ -1,2 +1,2 @@ // window-rpi-002 -92b0e1d02d380eb831bcafb57b27c2f2afa023a52a95af44765c17754ca3de38 +c680100b9cf09561e1adb62abfa8eb985a00c0468b392a6a1e772921807b5878 diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-003.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-003.hash index 8cd7ab53..42f72b97 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-003.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-003.hash @@ -1,2 +1,2 @@ // window-rpi-003 -f166f0f580b7f33e71abca3d05740a35231e891fa48e8d5c8e1236d92c500340 +0f13319443f4340c4fc4b753226ba6e1605e569189dc8d58e403b4bc21c4c32a diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-004.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-004.hash index d28739a5..0237597c 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-004.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-004.hash @@ -1,2 +1,2 @@ // window-rpi-004 -6aa0aa68a5e7047343d85d3099ac0efbbd9ca72399be7959659a4f39fa2009d5 +c26e7c4aaeb369597c6cb9426df8f0a5bb6e4fb899dfec04634ff7c2e4b747b1 diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-005.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-005.hash index f2729627..d8d89756 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-005.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-005.hash @@ -1,2 +1,2 @@ // window-rpi-005 -1501dd2e4901ed86258b63fa459fa9a63dbc88a76e2e7ad26b0f2dee647facda +f2a748ff52bd9c34a298ab624ff9a474ecae5883842941aca8ee9559cd92a6d7 diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-006.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-006.hash index 0293b00c..85c47545 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-006.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-006.hash @@ -1,2 +1,2 @@ // window-rpi-006 -6aa0aa68a5e7047343d85d3099ac0efbbd9ca72399be7959659a4f39fa2009d5 +c26e7c4aaeb369597c6cb9426df8f0a5bb6e4fb899dfec04634ff7c2e4b747b1 diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-007.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-007.hash index 33c2895f..8e6b96ea 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-007.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-007.hash @@ -1,2 +1,2 @@ // window-rpi-007 -65789d796f04d6ca6d3aa84469b18e0907e9938fab1209d6e633974147bce2de +12e31e10eadf55d4b824e563c2c18f2705d7261c6d401b6001d2b2e5ba92c808 diff --git a/tests/flows/results/test_wireless/wireless_flow/window-rpi-008.hash b/tests/flows/results/test_wireless/wireless_flow/window-rpi-008.hash index 392f8349..aae3bb0d 100644 --- a/tests/flows/results/test_wireless/wireless_flow/window-rpi-008.hash +++ b/tests/flows/results/test_wireless/wireless_flow/window-rpi-008.hash @@ -1,2 +1,2 @@ // window-rpi-008 -184a835de154aa889f3568f461d4b566e30d304bb808b8065f9a1edbdfb873ca +a47eeb0c63e483413e618f7c05dbcf97e832c945a0282876a4ee8c4b70767227 diff --git a/tests/flows/test_wireless.py b/tests/flows/test_wireless.py index 210e8f60..a60e320f 100644 --- a/tests/flows/test_wireless.py +++ b/tests/flows/test_wireless.py @@ -52,7 +52,7 @@ async def strength() -> int: ) from ubo_app.menu_app.menu import MenuApp - from ubo_app.store.core import ( + from ubo_app.store.core.types import ( MenuChooseByIconAction, MenuChooseByLabelAction, MenuGoBackAction, diff --git a/tests/integration/results/test_core/app_runs_and_exits/store-desktop-000.jsonc b/tests/integration/results/test_core/app_runs_and_exits/store-desktop-000.jsonc index 07310321..6f72dec7 100644 --- a/tests/integration/results/test_core/app_runs_and_exits/store-desktop-000.jsonc +++ b/tests/integration/results/test_core/app_runs_and_exits/store-desktop-000.jsonc @@ -6,6 +6,8 @@ "main": { "_type": "MainState", "depth": 1, + "is_footer_visible": true, + "is_header_visible": true, "is_recording": false, "menu": { "_type": "HeadlessMenu", @@ -121,17 +123,61 @@ 1, 1 ], - "icon": "󰕈", + "icon": "󰒔", "is_short": false, - "key": "OS", - "label": "OS", + "key": "System", + "label": "System", "opacity": null, "progress": null, "sub_menu": { "_type": "HeadlessMenu", - "items": [], + "items": [ + { + "_type": "SubMenuItem", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰒓", + "is_short": false, + "key": "general", + "label": "General", + "opacity": null, + "progress": null, + "sub_menu": { + "_type": "HeadlessMenu", + "items": [ + { + "_type": "DispatchItem", + "action": ">", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰄱", + "is_short": false, + "key": null, + "label": "Debug", + "opacity": null, + "progress": null, + "store_action": { + "_type": "SettingsToggleDebugModeAction" + } + } + ], + "placeholder": null, + "title": "󰒓General" + } + } + ], "placeholder": "No settings in this category", - "title": "󰕈OS" + "title": "󰒔System" } }, { @@ -317,6 +363,10 @@ "recorded_sequence": [], "settings_items_priorities": {} }, + "settings": { + "_type": "SettingsState", + "is_debug_enabled": false + }, "status_icons": { "_type": "StatusIconsState", "icons": [] diff --git a/tests/integration/results/test_core/app_runs_and_exits/store-rpi-000.jsonc b/tests/integration/results/test_core/app_runs_and_exits/store-rpi-000.jsonc index 316867f8..a6dfcb7b 100644 --- a/tests/integration/results/test_core/app_runs_and_exits/store-rpi-000.jsonc +++ b/tests/integration/results/test_core/app_runs_and_exits/store-rpi-000.jsonc @@ -6,6 +6,8 @@ "main": { "_type": "MainState", "depth": 1, + "is_footer_visible": true, + "is_header_visible": true, "is_recording": false, "menu": { "_type": "HeadlessMenu", @@ -121,17 +123,61 @@ 1, 1 ], - "icon": "󰕈", + "icon": "󰒔", "is_short": false, - "key": "OS", - "label": "OS", + "key": "System", + "label": "System", "opacity": null, "progress": null, "sub_menu": { "_type": "HeadlessMenu", - "items": [], + "items": [ + { + "_type": "SubMenuItem", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰒓", + "is_short": false, + "key": "general", + "label": "General", + "opacity": null, + "progress": null, + "sub_menu": { + "_type": "HeadlessMenu", + "items": [ + { + "_type": "DispatchItem", + "action": ">", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰄱", + "is_short": false, + "key": null, + "label": "Debug", + "opacity": null, + "progress": null, + "store_action": { + "_type": "SettingsToggleDebugModeAction" + } + } + ], + "placeholder": null, + "title": "󰒓General" + } + } + ], "placeholder": "No settings in this category", - "title": "󰕈OS" + "title": "󰒔System" } }, { @@ -317,6 +363,10 @@ "recorded_sequence": [], "settings_items_priorities": {} }, + "settings": { + "_type": "SettingsState", + "is_debug_enabled": false + }, "status_icons": { "_type": "StatusIconsState", "icons": [] diff --git a/tests/integration/results/test_core/app_runs_and_exits/window-desktop-000.hash b/tests/integration/results/test_core/app_runs_and_exits/window-desktop-000.hash index 35a72bce..596833c5 100644 --- a/tests/integration/results/test_core/app_runs_and_exits/window-desktop-000.hash +++ b/tests/integration/results/test_core/app_runs_and_exits/window-desktop-000.hash @@ -1,2 +1,2 @@ // window-desktop-000 -f01c8c31e23986fc788412f94a90c811765b446290ad9754217d02a67f08dc31 +3b1d881ec84387d968591db2f48196cd9eeaeeff69e4a1630cf8ace1afb42038 diff --git a/tests/integration/results/test_core/app_runs_and_exits/window-rpi-000.hash b/tests/integration/results/test_core/app_runs_and_exits/window-rpi-000.hash index 8a4c1250..064adb14 100644 --- a/tests/integration/results/test_core/app_runs_and_exits/window-rpi-000.hash +++ b/tests/integration/results/test_core/app_runs_and_exits/window-rpi-000.hash @@ -1,2 +1,2 @@ // window-rpi-000 -541be70b6889a2116a6e4bb0d731b41ff14d9512af8786ceb4fb32b4adf594a4 +dff1a2e925b4140a892f85e9c7db0895d8128920f7f4ff68efeec064765f6559 diff --git a/tests/integration/results/test_services/all_services_register/store-desktop-000.jsonc b/tests/integration/results/test_services/all_services_register/store-desktop-000.jsonc index cf89616f..32602394 100644 --- a/tests/integration/results/test_services/all_services_register/store-desktop-000.jsonc +++ b/tests/integration/results/test_services/all_services_register/store-desktop-000.jsonc @@ -108,6 +108,8 @@ "main": { "_type": "MainState", "depth": 1, + "is_footer_visible": true, + "is_header_visible": true, "is_recording": false, "menu": { "_type": "HeadlessMenu", @@ -515,10 +517,10 @@ 1, 1 ], - "icon": "󰕈", + "icon": "󰒔", "is_short": false, - "key": "OS", - "label": "OS", + "key": "System", + "label": "System", "opacity": null, "progress": null, "sub_menu": { @@ -648,10 +650,53 @@ "label": "Desktop", "opacity": null, "progress": null + }, + { + "_type": "SubMenuItem", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰒓", + "is_short": false, + "key": "general", + "label": "General", + "opacity": null, + "progress": null, + "sub_menu": { + "_type": "HeadlessMenu", + "items": [ + { + "_type": "DispatchItem", + "action": ">", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰄱", + "is_short": false, + "key": null, + "label": "Debug", + "opacity": null, + "progress": null, + "store_action": { + "_type": "SettingsToggleDebugModeAction" + } + } + ], + "placeholder": null, + "title": "󰒓General" + } } ], "placeholder": "No settings in this category", - "title": "󰕈OS" + "title": "󰒔System" } }, { @@ -1039,6 +1084,10 @@ "value": 0.0 } }, + "settings": { + "_type": "SettingsState", + "is_debug_enabled": false + }, "ssh": { "_type": "SSHState", "is_active": true, diff --git a/tests/integration/results/test_services/all_services_register/store-rpi-000.jsonc b/tests/integration/results/test_services/all_services_register/store-rpi-000.jsonc index 3403262c..94750e28 100644 --- a/tests/integration/results/test_services/all_services_register/store-rpi-000.jsonc +++ b/tests/integration/results/test_services/all_services_register/store-rpi-000.jsonc @@ -108,6 +108,8 @@ "main": { "_type": "MainState", "depth": 1, + "is_footer_visible": true, + "is_header_visible": true, "is_recording": false, "menu": { "_type": "HeadlessMenu", @@ -515,10 +517,10 @@ 1, 1 ], - "icon": "󰕈", + "icon": "󰒔", "is_short": false, - "key": "OS", - "label": "OS", + "key": "System", + "label": "System", "opacity": null, "progress": null, "sub_menu": { @@ -713,10 +715,53 @@ "label": "Desktop", "opacity": null, "progress": null + }, + { + "_type": "SubMenuItem", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰒓", + "is_short": false, + "key": "general", + "label": "General", + "opacity": null, + "progress": null, + "sub_menu": { + "_type": "HeadlessMenu", + "items": [ + { + "_type": "DispatchItem", + "action": ">", + "background_color": "#68B7FF", + "color": [ + 1, + 1, + 1, + 1 + ], + "icon": "󰄱", + "is_short": false, + "key": null, + "label": "Debug", + "opacity": null, + "progress": null, + "store_action": { + "_type": "SettingsToggleDebugModeAction" + } + } + ], + "placeholder": null, + "title": "󰒓General" + } } ], "placeholder": "No settings in this category", - "title": "󰕈OS" + "title": "󰒔System" } }, { @@ -1104,6 +1149,10 @@ "value": 0.0 } }, + "settings": { + "_type": "SettingsState", + "is_debug_enabled": false + }, "ssh": { "_type": "SSHState", "is_active": true, diff --git a/tests/integration/results/test_services/all_services_register/window-desktop-000.hash b/tests/integration/results/test_services/all_services_register/window-desktop-000.hash index 7e1cdb91..f30b715c 100644 --- a/tests/integration/results/test_services/all_services_register/window-desktop-000.hash +++ b/tests/integration/results/test_services/all_services_register/window-desktop-000.hash @@ -1,2 +1,2 @@ // window-desktop-000 -3620d71f464832b8c78da353873df66e3f2daf54a324150709b4e8190b6dbafb +aad52836c8f7d0c66cbb3adfa398a98c0b7360111c44001ff9cb0f99ec3be972 diff --git a/tests/integration/results/test_services/all_services_register/window-rpi-000.hash b/tests/integration/results/test_services/all_services_register/window-rpi-000.hash index 6fa41853..c0305d4a 100644 --- a/tests/integration/results/test_services/all_services_register/window-rpi-000.hash +++ b/tests/integration/results/test_services/all_services_register/window-rpi-000.hash @@ -1,2 +1,2 @@ // window-rpi-000 -006d4f47428eb62a54e3111ed4ffae84fbf14a4baff55a93a213475f7457a13b +4f9ae77e900d1730ea38afb3e188da604ff12d861b393ff896c67cbc46a1cb6c diff --git a/tests/integration/test_core.py b/tests/integration/test_core.py index 7e249c4f..8f6519ab 100644 --- a/tests/integration/test_core.py +++ b/tests/integration/test_core.py @@ -11,6 +11,7 @@ from redux_pytest.fixtures import StoreSnapshot, WaitFor from tests.fixtures import AppContext + from tests.fixtures.stability import Stability async def test_app_runs_and_exits( @@ -19,6 +20,7 @@ async def test_app_runs_and_exits( store_snapshot: StoreSnapshot, wait_for: WaitFor, needs_finish: None, + stability: Stability, ) -> None: """Test the application starts, runs and quits.""" _ = needs_finish @@ -34,17 +36,7 @@ def stack_is_loaded() -> None: await stack_is_loaded() - from headless_kivy import HeadlessWidget, config - - @wait_for(run_async=True, stop=stop_after_attempt(5)) - def check() -> None: - headless_widget_instance = HeadlessWidget.get_instance(app.root) - if headless_widget_instance: - assert ( - headless_widget_instance.fps == config.min_fps() - ), 'Not in low fps mode' - - await check() + await stability() window_snapshot.take() store_snapshot.take() diff --git a/ubo_app/display.py b/ubo_app/display.py index f66328ef..4c58235e 100644 --- a/ubo_app/display.py +++ b/ubo_app/display.py @@ -1,7 +1,8 @@ -"""Provides the adafruit display tools.""" +"""Provides the adRegion display tools.""" from __future__ import annotations +import time import zlib from typing import TYPE_CHECKING, cast @@ -17,17 +18,15 @@ from ubo_app.utils import IS_RPI if TYPE_CHECKING: - from threading import Thread + from headless_kivy.config import Region - from numpy._typing import NDArray +from ubo_app.constants import HEIGHT, WIDTH if IS_RPI: import board import digitalio - from ubo_app.constants import HEIGHT, WIDTH - cs_pin = digitalio.DigitalInOut(board.CE0) dc_pin = digitalio.DigitalInOut(board.D25) reset_pin = digitalio.DigitalInOut(board.D24) @@ -41,7 +40,7 @@ cs=cs_pin, dc=dc_pin, rst=reset_pin, - baudrate=60000000, + baudrate=70000000, ) else: display = cast(ST7789, Fake()) @@ -49,43 +48,51 @@ def render_on_display( *, - rectangle: tuple[int, int, int, int], - data: NDArray[np.uint8], - data_hash: int, - last_render_thread: Thread, + regions: list[Region], ) -> None: """Transfer data to the display via SPI controller.""" - data_ = data.astype(np.uint16) - color = ( - ((data_[:, :, 0] & 0xF8) << 8) - | ((data_[:, :, 1] & 0xFC) << 3) - | (data_[:, :, 2] >> 3) - ) - data_bytes = bytes( - np.dstack(((color >> 8) & 0xFF, color & 0xFF)).flatten().tolist(), - ) - if last_render_thread: - last_render_thread.join() - render_block(rectangle, data_bytes) - compressor = zlib.compressobj(wbits=-zlib.MAX_WBITS) - store._dispatch( # noqa: SLF001 - [ - DisplayRenderEvent( - data=data.tobytes(), - data_hash=data_hash, - rectangle=rectangle, + for region in regions: + rectangle = region['rectangle'] + data = region['data'].astype(np.uint16) + color = ( + ((data[:, :, 0] & 0xF8) << 8) + | ((data[:, :, 1] & 0xFC) << 3) + | (data[:, :, 2] >> 3) + ).copy() + data_bytes = ( + color.astype(np.uint16).view(np.uint8).reshape(-1, 2)[:, ::-1].tobytes() + ) + render_block( + ( + rectangle[1], + rectangle[0], + rectangle[3] - 1, + rectangle[2] - 1, ), - DisplayCompressedRenderEvent( - compressed_data=compressor.compress(data.tobytes()) - + compressor.flush(), - data_hash=data_hash, - rectangle=rectangle, - ), - ], - ) - - -@store.view(lambda state: state.display.is_paused) + data_bytes, + ) + compressor = zlib.compressobj(wbits=-zlib.MAX_WBITS) + store._dispatch( # noqa: SLF001 + [ + DisplayRenderEvent( + data=data.tobytes(), + rectangle=rectangle, + ), + DisplayCompressedRenderEvent( + compressed_data=compressor.compress(data.tobytes()) + + compressor.flush(), + rectangle=rectangle, + ), + ], + ) + + +original_block = display._block # noqa: SLF001 + + +@store.view( + lambda state: state.display.is_paused if hasattr(state, 'display') else False, +) def render_block( is_paused: bool, # noqa: FBT001 rectangle: tuple[int, int, int, int], @@ -106,4 +113,14 @@ def turn_off() -> None: def render_blank() -> None: """Render a blank screen.""" - display.fill(0) + if IS_RPI: + original_block(0, 0, WIDTH - 1, HEIGHT - 1, b'\x00\x00' * WIDTH * HEIGHT) + time.sleep(0.2) + original_block(0, 0, WIDTH - 1, HEIGHT - 1, b'\x00\x00' * WIDTH * HEIGHT) + + +splash_screen = None +if splash_screen: + render_block((0, 0, WIDTH - 1, HEIGHT - 1), splash_screen) +else: + render_blank() diff --git a/ubo_app/main.py b/ubo_app/main.py index 3c45b77c..8224dbf4 100644 --- a/ubo_app/main.py +++ b/ubo_app/main.py @@ -22,7 +22,14 @@ def main() -> None: os.environ['KIVY_NO_CONFIG'] = '1' os.environ['KIVY_NO_FILELOG'] = '1' os.environ['KIVY_NO_CONSOLELOG'] = '1' + # We want to have full control over the exit behavior os.environ['KCFG_KIVY_EXIT_ON_ESCAPE'] = '0' + # Hardware FBO is needed to make sure the in memory buffer uses the GPU + os.environ['KCFG_GRAPHICS_FBO'] = 'force-hardware' + # Anti-aliasing is not needed since Kivy is not directly rendering on a display + os.environ['KCFG_GRAPHICS_MULTISAMPLES'] = '0' + # V-SYNC is not needed since Kivy is not directly rendering on a display + os.environ['KCFG_GRAPHICS_VSYNC'] = '0' # `setup_logging` needs to be called before anything else to initialize the rotating # log files @@ -47,13 +54,16 @@ def main() -> None: from ubo_app.display import render_on_display headless_kivy.config.setup_headless_kivy( - { - 'callback': render_on_display, - 'automatic_fps': True, - 'flip_vertical': True, - 'width': WIDTH, - 'height': HEIGHT, - }, + headless_kivy.config.SetupHeadlessConfig( + bandwidth_limit=70 * 1000 * 1000 // 8 // 2, + bandwidth_limit_window=0.03, + bandwidth_limit_overhead=10000, + region_size=60, + callback=render_on_display, + flip_vertical=True, + width=WIDTH, + height=HEIGHT, + ), ) from ubo_app.logging import logger diff --git a/ubo_app/menu_app/menu.py b/ubo_app/menu_app/menu.py index e3b8efee..6b1a187c 100644 --- a/ubo_app/menu_app/menu.py +++ b/ubo_app/menu_app/menu.py @@ -8,14 +8,26 @@ from ubo_app.menu_app.menu_central import MenuAppCentral from ubo_app.menu_app.menu_footer import MenuAppFooter from ubo_app.menu_app.menu_header import MenuAppHeader +from ubo_app.store.main import store +from ubo_app.store.settings.types import SettingsSetDebugModeEvent class MenuApp(MenuAppCentral, MenuAppFooter, MenuAppHeader, UboApp): """Menu application.""" + def set_debug_mode(self: MenuApp, event: SettingsSetDebugModeEvent) -> None: + """Set the debug mode.""" + self.root.show_update_regions = event.is_enabled + @override def on_start(self: MenuApp) -> None: """Start the application.""" from ubo_app.side_effects import setup_side_effects setup_side_effects() + + store.subscribe_event( + SettingsSetDebugModeEvent, + self.set_debug_mode, + keep_ref=False, + ) diff --git a/ubo_app/menu_app/menu_central.py b/ubo_app/menu_app/menu_central.py index 50eb12fe..d1100f7b 100644 --- a/ubo_app/menu_app/menu_central.py +++ b/ubo_app/menu_app/menu_central.py @@ -14,7 +14,7 @@ from ubo_app.constants import DEBUG_MODE_MENU from ubo_app.logging import logger from ubo_app.menu_app.menu_notification_handler import MenuNotificationHandler -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( CloseApplicationEvent, MenuChooseByIconEvent, MenuChooseByIndexEvent, @@ -24,11 +24,12 @@ MenuScrollDirection, MenuScrollEvent, OpenApplicationEvent, + SetAreEnclosuresVisibleAction, SetMenuPathAction, ) from ubo_app.store.main import store from ubo_app.store.services.notifications import NotificationsDisplayEvent -from ubo_app.store.update_manager import UpdateManagerSetUpdateServiceStatusAction +from ubo_app.store.update_manager.types import UpdateManagerSetUpdateServiceStatusAction from ubo_app.utils.async_ import create_task from .home_page import HomePage @@ -56,19 +57,6 @@ def _render_menu(self: MenuWidgetWithHomePage, menu: Menu) -> PageWidget | None: return super()._render_menu(menu) -def set_path(_: MenuWidget, stack: list[StackItem]) -> None: - store.dispatch( - SetMenuPathAction( - path=[ - stack_item.selection.key - for stack_item in stack - if isinstance(stack_item, StackMenuItem) and stack_item.selection - ], - depth=len(stack), - ), - ) - - class MenuAppCentral(MenuNotificationHandler, UboApp): def __init__(self: MenuAppCentral, **kwargs: object) -> None: super().__init__(**kwargs) @@ -76,6 +64,12 @@ def __init__(self: MenuAppCentral, **kwargs: object) -> None: self.menu_widget.bind(page_index=self.handle_page_index_change) self.menu_widget.bind(current_menu=self.handle_page_index_change) + self.menu_widget.bind(title=self.handle_title_change) + self.menu_widget.bind(stack=self.handle_stack_change) + + if DEBUG_MODE_MENU: + menu_representation = 'Menu:\n' + repr(self.menu_widget) + self.menu_widget.bind(stack=lambda *_: logger.info(menu_representation)) _self = weakref.ref(self) @@ -110,27 +104,38 @@ def handle_page_index_change( self: MenuAppCentral, *_: object, ) -> None: - self.root.ids.header_layout.opacity = ( - 1 if self.menu_widget.page_index == 0 else 0 - ) - self.root.ids.footer_layout.opacity = ( - 1 if self.menu_widget.page_index >= self.menu_widget.pages - 1 else 0 + store.dispatch( + SetAreEnclosuresVisibleAction( + is_header_visible=self.menu_widget.page_index == 0, + is_footer_visible=self.menu_widget.page_index + >= self.menu_widget.pages - 1, + ), ) def handle_title_change(self: MenuAppCentral, _: MenuWidget, title: str) -> None: self.root.title = title + def handle_stack_change( + self: MenuAppCentral, + _: MenuWidget, + stack: list[StackItem], + ) -> None: + store.dispatch( + SetMenuPathAction( + path=[ + stack_item.selection.key + for stack_item in stack + if isinstance(stack_item, StackMenuItem) and stack_item.selection + ], + depth=len(stack), + ), + ) + @cached_property def central(self: MenuAppCentral) -> Widget | None: """Build the main menu and initiate it.""" self.root.is_fullscreen = True self.root.title = self.menu_widget.title - self.menu_widget.bind(title=self.handle_title_change) - self.menu_widget.bind(stack=set_path) - - if DEBUG_MODE_MENU: - menu_representation = 'Menu:\n' + repr(self.menu_widget) - self.menu_widget.bind(stack=lambda *_: logger.info(menu_representation)) store.subscribe_event( NotificationsDisplayEvent, diff --git a/ubo_app/menu_app/menu_footer.py b/ubo_app/menu_app/menu_footer.py index 8f996b48..8d883112 100644 --- a/ubo_app/menu_app/menu_footer.py +++ b/ubo_app/menu_app/menu_footer.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: from collections.abc import Sequence - from ubo_app.store.status_icons import IconState + from ubo_app.store.status_icons.types import IconState class MenuAppFooter(UboApp): @@ -148,15 +148,15 @@ def render_icons( self.icons_layout.add_widget(Widget(size_hint=(None, 1), width=dp(2))) self.icons_layout.bind(minimum_width=self.icons_layout.setter('width')) - def handle_depth_change(self: MenuAppFooter, _: Sequence[str]) -> None: - is_fullscreen = False - if not is_fullscreen: - if self.normal_footer_layout in self.footer_layout.children: - self.footer_layout.remove_widget(self.normal_footer_layout) + def handle_is_footer_visible_change( + self: MenuAppFooter, + is_footer_visible: bool, # noqa: FBT001 + ) -> None: + if is_footer_visible: + if self.home_footer_layout not in self.footer_layout.children: self.footer_layout.add_widget(self.home_footer_layout) elif self.home_footer_layout in self.footer_layout.children: self.footer_layout.remove_widget(self.home_footer_layout) - self.footer_layout.add_widget(self.normal_footer_layout) def set_icons_layout_x(self: MenuAppFooter, *_: list[Any]) -> None: self.icons_layout.x = ( @@ -165,22 +165,6 @@ def set_icons_layout_x(self: MenuAppFooter, *_: list[Any]) -> None: @cached_property def footer(self: MenuAppFooter) -> Widget | None: - self.footer_layout = BoxLayout() - - self.normal_footer_layout = BoxLayout( - orientation='horizontal', - spacing=0, - padding=0, - ) - self.normal_footer_layout.add_widget( - Label( - text='', - font_size=dp(20), - size_hint=(None, 1), - ), - ) - self.normal_footer_layout.add_widget(Widget(size_hint=(1, 1))) - self.home_footer_layout = BoxLayout( orientation='horizontal', spacing=0, @@ -216,16 +200,17 @@ def footer(self: MenuAppFooter) -> Widget | None: x=self.set_icons_layout_x, ) + self.footer_layout = BoxLayout() + self.footer_layout.add_widget(self.home_footer_layout) + store.autorun( lambda state: state.status_icons.icons, options=AutorunOptions(keep_ref=False), )(self.render_icons) store.autorun( - lambda state: state.main.path, + lambda state: state.main.is_footer_visible, options=AutorunOptions(keep_ref=False), - )(self.handle_depth_change) - - self.footer_layout.add_widget(self.home_footer_layout) + )(self.handle_is_footer_visible_change) return self.footer_layout diff --git a/ubo_app/menu_app/menu_header.py b/ubo_app/menu_app/menu_header.py index 661fb37a..0e5ac345 100644 --- a/ubo_app/menu_app/menu_header.py +++ b/ubo_app/menu_app/menu_header.py @@ -1,14 +1,17 @@ # ruff: noqa: D100, D101, D102, D103, D104, D107 from __future__ import annotations +import math from functools import cached_property from typing import TYPE_CHECKING from kivy.metrics import dp from kivy.uix.boxlayout import BoxLayout from kivy.uix.relativelayout import RelativeLayout +from redux import AutorunOptions from ubo_gui.app import UboApp from ubo_gui.progress_ring import ProgressRingWidget +from ubo_gui.spinner import SpinnerWidget from ubo_app.store.main import store @@ -19,51 +22,116 @@ class MenuAppHeader(UboApp): + notification_widgets: dict[str, tuple[Notification, Widget]] + progress_layout: BoxLayout + + def set_notification_widgets( + self: MenuAppHeader, + notifications: list[Notification], + ) -> None: + for notification in notifications: + if notification.progress is None: + if notification.id in self.notification_widgets: + self.progress_layout.remove_widget( + self.notification_widgets[notification.id][1], + ) + del self.notification_widgets[notification.id] + elif math.isnan(notification.progress): + if notification.id not in self.notification_widgets or not isinstance( + self.notification_widgets[notification.id][1], + SpinnerWidget, + ): + self.notification_widgets[notification.id] = ( + notification, + SpinnerWidget( + font_size=dp(16), + size_hint=(None, None), + pos_hint={'center_y': 0.5}, + height=dp(16), + width=dp(16), + ), + ) + self.notification_widgets[notification.id][1].color = notification.color + else: + if notification.id not in self.notification_widgets or not isinstance( + self.notification_widgets[notification.id][1], + ProgressRingWidget, + ): + self.notification_widgets[notification.id] = ( + notification, + ProgressRingWidget( + background_color=(0.3, 0.3, 0.3, 1), + height=dp(16), + band_width=dp(7), + size_hint=(None, None), + pos_hint={'center_y': 0.5}, + ), + ) + self.notification_widgets[notification.id][ + 1 + ].progress = notification.progress + self.notification_widgets[notification.id][1].color = notification.color + + for id in set(self.notification_widgets) - { + notification.id for notification in notifications + }: + del self.notification_widgets[id] + + self.progress_layout.clear_widgets() + + for item in sorted( + self.notification_widgets.values(), + key=lambda item: item[0].timestamp, + ): + self.progress_layout.add_widget(item[1]) + + self.progress_layout.width = self.progress_layout.minimum_width + + def handle_is_header_visible_change( + self: MenuAppHeader, + is_header_visible: bool, # noqa: FBT001 + ) -> None: + if is_header_visible: + if self.header_content not in self.header_layout.children: + self.header_layout.add_widget(self.header_content) + elif self.header_content in self.header_layout.children: + self.header_layout.remove_widget(self.header_content) + @cached_property def header(self: MenuAppHeader) -> Widget | None: - self.header_layout = RelativeLayout() + self.header_content = RelativeLayout() original_header = super().header if not original_header: return None original_header.pos = (0, 0) - self.header_layout.add_widget(original_header) + self.header_content.add_widget(original_header) - progress_layout = BoxLayout( + self.progress_layout = BoxLayout( orientation='horizontal', padding=dp(4), spacing=dp(2), ) - self.header_layout.add_widget(progress_layout) + self.header_content.add_widget(self.progress_layout) + + self.notification_widgets = {} - @store.autorun( + self.header_layout = BoxLayout() + self.header_layout.add_widget(self.header_content) + + store.autorun( lambda state: [ notification for notification in state.notifications.notifications if notification.progress is not None ], - ) - def _(notifications: list[Notification]) -> None: - for i in range(len(notifications)): - if i < len(progress_layout.children): - progress_layout.children[i].progress = notifications[i].progress - progress_layout.children[i].color = notifications[i].color - else: - progress_layout.add_widget( - ProgressRingWidget( - background_color=(0.3, 0.3, 0.3, 1), - color=notifications[i].color, - progress=notifications[i].progress, - height=dp(16), - band_width=dp(7), - size_hint=(None, None), - pos_hint={'center_y': 0.5}, - ), - ) - for _ in range(len(notifications), len(progress_layout.children)): - progress_layout.remove_widget(progress_layout.children[-1]) + options=AutorunOptions(keep_ref=False), + )(self.set_notification_widgets) - progress_layout.width = progress_layout.minimum_width + store.autorun( + lambda state: state.main.is_header_visible, + options=AutorunOptions(keep_ref=False), + )(self.handle_is_header_visible_change) return self.header_layout diff --git a/ubo_app/menu_app/menu_notification_handler.py b/ubo_app/menu_app/menu_notification_handler.py index 31788e1a..1fa37593 100644 --- a/ubo_app/menu_app/menu_notification_handler.py +++ b/ubo_app/menu_app/menu_notification_handler.py @@ -14,7 +14,7 @@ from ubo_gui.page import PAGE_MAX_ITEMS from ubo_app.menu_app.notification_info import NotificationInfo -from ubo_app.store.core import CloseApplicationAction, OpenApplicationAction +from ubo_app.store.core.types import CloseApplicationAction, OpenApplicationAction from ubo_app.store.main import store from ubo_app.store.services.notifications import ( Notification, diff --git a/ubo_app/rpc/generate_proto.py b/ubo_app/rpc/generate_proto.py index e731cb31..63f63203 100644 --- a/ubo_app/rpc/generate_proto.py +++ b/ubo_app/rpc/generate_proto.py @@ -77,10 +77,12 @@ def get_proto( current_package: str | None, ) -> str: _ = name, current_package - if self.type == 'UboAction': + if self.type in ('BaseAction', 'UboAction'): return 'Action' if self.type == 'UboEvent': return 'Event' + if self.type == 'PageWidget': # Not supported + return 'string' if self.type == 'Color': # Assuming it is kivy color return 'string' """ This version is for the case where we have a separate proto file for each @@ -122,7 +124,7 @@ def package(self: Self) -> str | None: return global_enums[self.type] if self.type in global_types: return global_types[self.type] - if self.type in ('Color', 'UboAction', 'UboEvent'): + if self.type in ('Color', 'UboAction', 'UboEvent', 'BaseAction'): return None msg = f'Unknown type "{self.type}"' raise TypeError(msg) @@ -639,16 +641,24 @@ def parse(input_module: ModuleType) -> _ProtoGenerator: import ubo_gui.menu.types + import ubo_app.store.core.types import ubo_app.store.dispatch_action - import ubo_app.store.operations + import ubo_app.store.input.types + import ubo_app.store.settings.types + import ubo_app.store.status_icons.types + import ubo_app.store.update_manager.types generators: list[_ProtoGenerator] = [] generators.append(parse(ubo_gui.menu.types)) - generators.append(parse(ubo_app.store.operations)) + generators.append(parse(ubo_app.store.core.types)) generators.append( parse(ubo_app.store.dispatch_action), ) + generators.append(parse(ubo_app.store.input.types)) + generators.append(parse(ubo_app.store.settings.types)) + generators.append(parse(ubo_app.store.status_icons.types)) + generators.append(parse(ubo_app.store.update_manager.types)) generators.extend( parse(importlib.import_module(f'ubo_app.store.services.{file.stem}')) for file in sorted(Path('ubo_app/store/services/').glob('*.py')) diff --git a/ubo_app/rpc/generated/ubo/v1/__init__.py b/ubo_app/rpc/generated/ubo/v1/__init__.py index f3e0d1a0..5982bafb 100644 --- a/ubo_app/rpc/generated/ubo/v1/__init__.py +++ b/ubo_app/rpc/generated/ubo/v1/__init__.py @@ -8,6 +8,44 @@ import betterproto +class SettingsCategory(betterproto.Enum): + UBO_APP_DOT_STORE_DOT_CORE_DOT_TYPES_UNSPECIFIED = 0 + NETWORK = 1 + REMOTE = 2 + GENERAL = 3 + SPEECH = 4 + DOCKER = 5 + + +class MenuScrollDirection(betterproto.Enum): + UBO_APP_DOT_STORE_DOT_CORE_DOT_TYPES_UNSPECIFIED = 0 + UP = 1 + DOWN = 2 + + +class InputFieldType(betterproto.Enum): + UBO_APP_DOT_STORE_DOT_INPUT_DOT_TYPES_UNSPECIFIED = 0 + LONG = 1 + TEXT = 2 + PASSWORD = 3 + NUMBER = 4 + CHECKBOX = 5 + COLOR = 6 + SELECT = 7 + FILE = 8 + DATE = 9 + TIME = 10 + + +class UpdateStatus(betterproto.Enum): + UBO_APP_DOT_STORE_DOT_UPDATE_MANAGER_DOT_TYPES_UNSPECIFIED = 0 + CHECKING = 1 + FAILED_TO_CHECK = 2 + UP_TO_DATE = 3 + OUTDATED = 4 + UPDATING = 5 + + class AudioDevice(betterproto.Enum): UBO_APP_DOT_STORE_DOT_SERVICES_DOT_AUDIO_UNSPECIFIED = 0 INPUT = 1 @@ -34,7 +72,7 @@ class ImageStatus(betterproto.Enum): ERROR = 6 -class GlobalEthernetState(betterproto.Enum): +class NetState(betterproto.Enum): UBO_APP_DOT_STORE_DOT_SERVICES_DOT_ETHERNET_UNSPECIFIED = 0 CONNECTED = 1 DISCONNECTED = 2 @@ -106,15 +144,6 @@ class ConnectionState(betterproto.Enum): UNKNOWN = 4 -class GlobalWiFiState(betterproto.Enum): - UBO_APP_DOT_STORE_DOT_SERVICES_DOT_WIFI_UNSPECIFIED = 0 - CONNECTED = 1 - DISCONNECTED = 2 - PENDING = 3 - NEEDS_ATTENTION = 4 - UNKNOWN = 5 - - @dataclass(eq=False, repr=False) class BaseMenu(betterproto.Message): meta_field_package_name_ubo_gui_dot_menu_dot_types: 'str | None' = ( @@ -222,23 +251,373 @@ class Menu(betterproto.Message): headless_menu: 'HeadlessMenu' = betterproto.message_field(2, group='menu') +@dataclass(eq=False, repr=False) +class MainAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class UpdateLightDmState(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + is_active: bool = betterproto.bool_field(2) + is_enable: bool = betterproto.bool_field(3) + + +@dataclass(eq=False, repr=False) +class RegisterAppAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + menu_item: 'Item' = betterproto.message_field(2) + service: 'str | None' = betterproto.string_field(3, optional=True) + key: 'str | None' = betterproto.string_field(4, optional=True) + + +@dataclass(eq=False, repr=False) +class RegisterRegularAppAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + menu_item: 'Item' = betterproto.message_field(2) + service: 'str | None' = betterproto.string_field(3, optional=True) + key: 'str | None' = betterproto.string_field(4, optional=True) + + +@dataclass(eq=False, repr=False) +class RegisterSettingAppAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + category: 'SettingsCategory' = betterproto.enum_field(2) + priority: 'int | None' = betterproto.int64_field(3, optional=True) + menu_item: 'Item' = betterproto.message_field(4) + service: 'str | None' = betterproto.string_field(5, optional=True) + key: 'str | None' = betterproto.string_field(6, optional=True) + + +@dataclass(eq=False, repr=False) +class PowerAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class PowerOffAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class RebootAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class SetMenuPathAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + path: 'list[str]' = betterproto.string_field(2) + depth: int = betterproto.int64_field(3) + + +@dataclass(eq=False, repr=False) +class SetAreEnclosuresVisibleAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + is_header_visible: 'bool | None' = betterproto.bool_field(2, optional=True) + is_footer_visible: 'bool | None' = betterproto.bool_field(3, optional=True) + + +@dataclass(eq=False, repr=False) +class MenuAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuGoBackAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuGoHomeAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuChooseByIconAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + icon: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class MenuChooseByLabelAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + label: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class MenuChooseByIndexAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + index: int = betterproto.int64_field(2) + + +@dataclass(eq=False, repr=False) +class MenuScrollAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + direction: 'MenuScrollDirection' = betterproto.enum_field(2) + + +@dataclass(eq=False, repr=False) +class OpenApplicationAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + application: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class CloseApplicationAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + application: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class MainEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class InitEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuGoBackEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuGoHomeEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MenuChooseByIconEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + icon: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class MenuChooseByLabelEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + label: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class MenuChooseByIndexEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + index: int = betterproto.int64_field(2) + + +@dataclass(eq=False, repr=False) +class MenuScrollEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + direction: 'MenuScrollDirection' = betterproto.enum_field(2) + + +@dataclass(eq=False, repr=False) +class OpenApplicationEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + application: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class CloseApplicationEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + application: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class PowerEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class PowerOffEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class RebootEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + @dataclass(eq=False, repr=False) class ScreenshotEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) @dataclass(eq=False, repr=False) class SnapshotEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class StoreRecordedSequenceEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + recorded_sequence: 'list[Action]' = betterproto.message_field(2) + + +@dataclass(eq=False, repr=False) +class ReplayRecordedSequenceEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class MainState(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_core_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + menu: 'Menu | None' = betterproto.message_field(2, optional=True) + path: 'MainStatePath | None' = betterproto.message_field(3, optional=True) + depth: 'int | None' = betterproto.int64_field(4, optional=True) + is_header_visible: 'bool | None' = betterproto.bool_field(5, optional=True) + is_footer_visible: 'bool | None' = betterproto.bool_field(6, optional=True) + settings_items_priorities: 'MainStateSettingsItemsPrioritiesDict | None' = ( + betterproto.message_field(7, optional=True) + ) + is_recording: 'bool | None' = betterproto.bool_field(8, optional=True) + recorded_sequence: 'MainStateRecordedSequence | None' = betterproto.message_field( + 9, optional=True, + ) + + +@dataclass(eq=False, repr=False) +class MainStatePath(betterproto.Message): + items: 'list[str]' = betterproto.string_field(1) + + +@dataclass(eq=False, repr=False) +class MainStateSettingsItemsPrioritiesDict(betterproto.Message): + items: 'dict[str, int]' = betterproto.map_field( + 1, betterproto.TYPE_STRING, betterproto.TYPE_INT64, + ) + + +@dataclass(eq=False, repr=False) +class MainStateRecordedSequence(betterproto.Message): + items: 'list[Action]' = betterproto.message_field(1) + + +@dataclass(eq=False, repr=False) +class DispatchItem(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_dispatch_action: 'str | None' = ( betterproto.string_field(1000, optional=True) ) + store_action: 'Action' = betterproto.message_field(2) + key: 'str | None' = betterproto.string_field(3, optional=True) + label: 'str | None' = betterproto.string_field(4, optional=True) + color: 'str | None' = betterproto.string_field(5, optional=True) + background_color: 'str | None' = betterproto.string_field(6, optional=True) + icon: 'str | None' = betterproto.string_field(7, optional=True) + is_short: 'bool | None' = betterproto.bool_field(8, optional=True) + opacity: 'float | None' = betterproto.float_field(9, optional=True) + progress: 'float | None' = betterproto.float_field(10, optional=True) + + +@dataclass(eq=False, repr=False) +class InputFieldDescription(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + name: str = betterproto.string_field(2) + label: str = betterproto.string_field(3) + type: 'InputFieldType' = betterproto.enum_field(4) + description: 'str | None' = betterproto.string_field(5, optional=True) + title: 'str | None' = betterproto.string_field(6, optional=True) + pattern: 'str | None' = betterproto.string_field(7, optional=True) + default: 'str | None' = betterproto.string_field(8, optional=True) + options: 'InputFieldDescriptionOptions | None' = betterproto.message_field( + 9, optional=True, + ) + required: 'bool | None' = betterproto.bool_field(10, optional=True) + + +@dataclass(eq=False, repr=False) +class InputFieldDescriptionOptions(betterproto.Message): + items: 'list[str]' = betterproto.string_field(1) @dataclass(eq=False, repr=False) class InputDescription(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) title: str = betterproto.string_field(2) @@ -248,18 +627,26 @@ class InputDescription(betterproto.Message): ) id: str = betterproto.string_field(5) pattern: str = betterproto.string_field(6) + fields: 'InputDescriptionFields | None' = betterproto.message_field( + 7, optional=True, + ) + + +@dataclass(eq=False, repr=False) +class InputDescriptionFields(betterproto.Message): + items: 'list[InputFieldDescription]' = betterproto.message_field(1) @dataclass(eq=False, repr=False) class InputAction(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) @dataclass(eq=False, repr=False) class InputDemandAction(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) description: 'InputDescription' = betterproto.message_field(2) @@ -267,7 +654,7 @@ class InputDemandAction(betterproto.Message): @dataclass(eq=False, repr=False) class InputResolveAction(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) id: str = betterproto.string_field(2) @@ -275,7 +662,7 @@ class InputResolveAction(betterproto.Message): @dataclass(eq=False, repr=False) class InputCancelAction(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) id: str = betterproto.string_field(2) @@ -283,7 +670,7 @@ class InputCancelAction(betterproto.Message): @dataclass(eq=False, repr=False) class InputProvideAction(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) value: str = betterproto.string_field(2) @@ -295,7 +682,7 @@ class InputProvideAction(betterproto.Message): @dataclass(eq=False, repr=False) class InputResolveEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) id: str = betterproto.string_field(2) @@ -303,7 +690,7 @@ class InputResolveEvent(betterproto.Message): @dataclass(eq=False, repr=False) class InputCancelEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) id: str = betterproto.string_field(2) @@ -311,7 +698,7 @@ class InputCancelEvent(betterproto.Message): @dataclass(eq=False, repr=False) class InputProvideEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_operations: 'str | None' = ( + meta_field_package_name_ubo_app_dot_store_dot_input_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) value: str = betterproto.string_field(2) @@ -322,25 +709,146 @@ class InputProvideEvent(betterproto.Message): @dataclass(eq=False, repr=False) -class DispatchItem(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_dispatch_action: 'str | None' = ( +class SettingsAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types: 'str | None' = ( betterproto.string_field(1000, optional=True) ) - operation: 'DispatchItemOperation' = betterproto.message_field(2) - key: 'str | None' = betterproto.string_field(3, optional=True) - label: 'str | None' = betterproto.string_field(4, optional=True) - color: 'str | None' = betterproto.string_field(5, optional=True) - background_color: 'str | None' = betterproto.string_field(6, optional=True) - icon: 'str | None' = betterproto.string_field(7, optional=True) - is_short: 'bool | None' = betterproto.bool_field(8, optional=True) - opacity: 'float | None' = betterproto.float_field(9, optional=True) - progress: 'float | None' = betterproto.float_field(10, optional=True) @dataclass(eq=False, repr=False) -class DispatchItemOperation(betterproto.Message): - ubo_action: 'Action' = betterproto.message_field(1, group='operation') - ubo_event: 'Event' = betterproto.message_field(2, group='operation') +class SettingsToggleDebugModeAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class SettingsEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + + +@dataclass(eq=False, repr=False) +class SettingsSetDebugModeEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + is_enabled: bool = betterproto.bool_field(2) + + +@dataclass(eq=False, repr=False) +class SettingsState(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + is_debug_enabled: 'bool | None' = betterproto.bool_field(2, optional=True) + + +@dataclass(eq=False, repr=False) +class IconState(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + symbol: str = betterproto.string_field(2) + color: str = betterproto.string_field(3) + priority: int = betterproto.int64_field(4) + id: str = betterproto.string_field(5) + + +@dataclass(eq=False, repr=False) +class StatusIconsState(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + icons: 'list[IconState]' = betterproto.message_field(2) + + +@dataclass(eq=False, repr=False) +class StatusIconsAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + + +@dataclass(eq=False, repr=False) +class StatusIconsRegisterAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + icon: str = betterproto.string_field(2) + color: 'str | None' = betterproto.string_field(3, optional=True) + priority: 'int | None' = betterproto.int64_field(4, optional=True) + id: 'str | None' = betterproto.string_field(5, optional=True) + + +@dataclass(eq=False, repr=False) +class UpdateManagerAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + + +@dataclass(eq=False, repr=False) +class UpdateManagerSetVersionsAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + flash_notification: bool = betterproto.bool_field(2) + current_version: str = betterproto.string_field(3) + base_image_variant: str = betterproto.string_field(4) + latest_version: str = betterproto.string_field(5) + serial_number: str = betterproto.string_field(6) + + +@dataclass(eq=False, repr=False) +class UpdateManagerSetStatusAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + status: 'UpdateStatus' = betterproto.enum_field(2) + + +@dataclass(eq=False, repr=False) +class UpdateManagerSetUpdateServiceStatusAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + is_active: bool = betterproto.bool_field(2) + + +@dataclass(eq=False, repr=False) +class UpdateManagerEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + + +@dataclass(eq=False, repr=False) +class UpdateManagerCheckEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + + +@dataclass(eq=False, repr=False) +class UpdateManagerUpdateEvent(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + + +@dataclass(eq=False, repr=False) +class UpdateManagerState(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + serial_number: 'str | None' = betterproto.string_field(2, optional=True) + current_version: 'str | None' = betterproto.string_field(3, optional=True) + base_image_variant: 'str | None' = betterproto.string_field(4, optional=True) + latest_version: 'str | None' = betterproto.string_field(5, optional=True) + update_status: 'UpdateStatus | None' = betterproto.enum_field(6, optional=True) + is_update_service_active: 'bool | None' = betterproto.bool_field(7, optional=True) @dataclass(eq=False, repr=False) @@ -405,6 +913,14 @@ class AudioPlayAudioAction(betterproto.Message): width: int = betterproto.int64_field(6) +@dataclass(eq=False, repr=False) +class AudioPlaybackDoneAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_services_dot_audio: 'str | None' = ( + betterproto.string_field(1000, optional=True) + ) + id: str = betterproto.string_field(2) + + @dataclass(eq=False, repr=False) class AudioEvent(betterproto.Message): meta_field_package_name_ubo_app_dot_store_dot_services_dot_audio: 'str | None' = ( @@ -541,8 +1057,7 @@ class DisplayRenderEvent(betterproto.Message): betterproto.string_field(1000, optional=True) ) data: bytes = betterproto.bytes_field(2) - data_hash: int = betterproto.int64_field(3) - rectangle: 'list[int]' = betterproto.int64_field(4) + rectangle: 'list[int]' = betterproto.int64_field(3) @dataclass(eq=False, repr=False) @@ -551,8 +1066,7 @@ class DisplayCompressedRenderEvent(betterproto.Message): betterproto.string_field(1000, optional=True) ) compressed_data: bytes = betterproto.bytes_field(2) - data_hash: int = betterproto.int64_field(3) - rectangle: 'list[int]' = betterproto.int64_field(4) + rectangle: 'list[int]' = betterproto.int64_field(3) @dataclass(eq=False, repr=False) @@ -750,7 +1264,8 @@ class KeypadAction(betterproto.Message): betterproto.string_field(1000, optional=True) ) key: 'Key' = betterproto.enum_field(2) - time: 'float | None' = betterproto.float_field(3, optional=True) + pressed_keys: 'list[Key]' = betterproto.enum_field(3) + time: 'float | None' = betterproto.float_field(4, optional=True) @dataclass(eq=False, repr=False) @@ -759,7 +1274,8 @@ class KeypadKeyUpAction(betterproto.Message): betterproto.string_field(1000, optional=True) ) key: 'Key' = betterproto.enum_field(2) - time: 'float | None' = betterproto.float_field(3, optional=True) + pressed_keys: 'list[Key]' = betterproto.enum_field(3) + time: 'float | None' = betterproto.float_field(4, optional=True) @dataclass(eq=False, repr=False) @@ -768,7 +1284,8 @@ class KeypadKeyDownAction(betterproto.Message): betterproto.string_field(1000, optional=True) ) key: 'Key' = betterproto.enum_field(2) - time: 'float | None' = betterproto.float_field(3, optional=True) + pressed_keys: 'list[Key]' = betterproto.enum_field(3) + time: 'float | None' = betterproto.float_field(4, optional=True) @dataclass(eq=False, repr=False) @@ -777,7 +1294,8 @@ class KeypadKeyPressAction(betterproto.Message): betterproto.string_field(1000, optional=True) ) key: 'Key' = betterproto.enum_field(2) - time: 'float | None' = betterproto.float_field(3, optional=True) + pressed_keys: 'list[Key]' = betterproto.enum_field(3) + time: 'float | None' = betterproto.float_field(4, optional=True) @dataclass(eq=False, repr=False) @@ -786,34 +1304,8 @@ class KeypadKeyReleaseAction(betterproto.Message): betterproto.string_field(1000, optional=True) ) key: 'Key' = betterproto.enum_field(2) - time: 'float | None' = betterproto.float_field(3, optional=True) - - -@dataclass(eq=False, repr=False) -class KeypadEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_services_dot_keypad: 'str | None' = ( - betterproto.string_field(1000, optional=True) - ) - key: 'Key' = betterproto.enum_field(2) - time: float = betterproto.float_field(3) - - -@dataclass(eq=False, repr=False) -class KeypadKeyPressEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_services_dot_keypad: 'str | None' = ( - betterproto.string_field(1000, optional=True) - ) - key: 'Key' = betterproto.enum_field(2) - time: float = betterproto.float_field(3) - - -@dataclass(eq=False, repr=False) -class KeypadKeyReleaseEvent(betterproto.Message): - meta_field_package_name_ubo_app_dot_store_dot_services_dot_keypad: 'str | None' = ( - betterproto.string_field(1000, optional=True) - ) - key: 'Key' = betterproto.enum_field(2) - time: float = betterproto.float_field(3) + pressed_keys: 'list[Key]' = betterproto.enum_field(3) + time: 'float | None' = betterproto.float_field(4, optional=True) @dataclass(eq=False, repr=False) @@ -873,7 +1365,7 @@ class NotificationDispatchItem(betterproto.Message): meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications: ( 'str | None' ) = betterproto.string_field(1000, optional=True) - operation: 'NotificationDispatchItemOperation' = betterproto.message_field(2) + store_action: 'Action' = betterproto.message_field(2) key: 'str | None' = betterproto.string_field(3, optional=True) label: 'str | None' = betterproto.string_field(4, optional=True) color: 'str | None' = betterproto.string_field(5, optional=True) @@ -885,12 +1377,6 @@ class NotificationDispatchItem(betterproto.Message): dismiss_notification: 'bool | None' = betterproto.bool_field(11, optional=True) -@dataclass(eq=False, repr=False) -class NotificationDispatchItemOperation(betterproto.Message): - ubo_action: 'Action' = betterproto.message_field(1, group='operation') - ubo_event: 'Event' = betterproto.message_field(2, group='operation') - - @dataclass(eq=False, repr=False) class NotificationExtraInformation(betterproto.Message): meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications: ( @@ -970,6 +1456,16 @@ class NotificationsAddAction(betterproto.Message): notification: 'Notification' = betterproto.message_field(2) +@dataclass(eq=False, repr=False) +class NotificationsDisplayAction(betterproto.Message): + meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications: ( + 'str | None' + ) = betterproto.string_field(1000, optional=True) + notification: 'Notification' = betterproto.message_field(2) + index: 'int | None' = betterproto.int64_field(3, optional=True) + count: 'int | None' = betterproto.int64_field(4, optional=True) + + @dataclass(eq=False, repr=False) class NotificationsClearAction(betterproto.Message): meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications: ( @@ -1639,7 +2135,7 @@ class WiFiUpdateAction(betterproto.Message): betterproto.string_field(1000, optional=True) ) connections: 'list[WiFiConnection]' = betterproto.message_field(2) - state: 'GlobalWiFiState' = betterproto.enum_field(3) + state: 'NetState' = betterproto.enum_field(3) current_connection: 'WiFiConnection' = betterproto.message_field(4) @@ -1671,7 +2167,7 @@ class WiFiState(betterproto.Message): betterproto.string_field(1000, optional=True) ) connections: 'list[WiFiConnection]' = betterproto.message_field(2) - state: 'GlobalWiFiState' = betterproto.enum_field(3) + state: 'NetState' = betterproto.enum_field(3) current_connection: 'WiFiConnection' = betterproto.message_field(4) has_visited_onboarding: 'bool | None' = betterproto.bool_field(5, optional=True) @@ -1688,226 +2184,298 @@ class Action(betterproto.Message): audio_play_chime_action: 'AudioPlayChimeAction' = betterproto.message_field( 4, group='action', ) + audio_playback_done_action: 'AudioPlaybackDoneAction' = betterproto.message_field( + 5, group='action', + ) audio_set_mute_status_action: 'AudioSetMuteStatusAction' = ( - betterproto.message_field(5, group='action') + betterproto.message_field(6, group='action') ) audio_set_volume_action: 'AudioSetVolumeAction' = betterproto.message_field( - 6, group='action', + 7, group='action', ) audio_toggle_mute_status_action: 'AudioToggleMuteStatusAction' = ( - betterproto.message_field(7, group='action') + betterproto.message_field(8, group='action') ) - camera_action: 'CameraAction' = betterproto.message_field(8, group='action') + camera_action: 'CameraAction' = betterproto.message_field(9, group='action') camera_report_barcode_action: 'CameraReportBarcodeAction' = ( - betterproto.message_field(9, group='action') + betterproto.message_field(10, group='action') ) camera_start_viewfinder_action: 'CameraStartViewfinderAction' = ( - betterproto.message_field(10, group='action') + betterproto.message_field(11, group='action') ) - display_action: 'DisplayAction' = betterproto.message_field(11, group='action') - display_pause_action: 'DisplayPauseAction' = betterproto.message_field( + close_application_action: 'CloseApplicationAction' = betterproto.message_field( 12, group='action', ) + display_action: 'DisplayAction' = betterproto.message_field(13, group='action') + display_pause_action: 'DisplayPauseAction' = betterproto.message_field( + 14, group='action', + ) display_resume_action: 'DisplayResumeAction' = betterproto.message_field( - 13, group='action', + 15, group='action', ) - docker_action: 'DockerAction' = betterproto.message_field(14, group='action') + docker_action: 'DockerAction' = betterproto.message_field(16, group='action') docker_image_action: 'DockerImageAction' = betterproto.message_field( - 15, group='action', + 17, group='action', ) docker_image_set_docker_id_action: 'DockerImageSetDockerIdAction' = ( - betterproto.message_field(16, group='action') + betterproto.message_field(18, group='action') ) docker_image_set_status_action: 'DockerImageSetStatusAction' = ( - betterproto.message_field(17, group='action') + betterproto.message_field(19, group='action') ) docker_remove_username_action: 'DockerRemoveUsernameAction' = ( - betterproto.message_field(18, group='action') + betterproto.message_field(20, group='action') ) docker_set_status_action: 'DockerSetStatusAction' = betterproto.message_field( - 19, group='action', + 21, group='action', ) docker_store_username_action: 'DockerStoreUsernameAction' = ( - betterproto.message_field(20, group='action') + betterproto.message_field(22, group='action') ) - input_action: 'InputAction' = betterproto.message_field(21, group='action') + input_action: 'InputAction' = betterproto.message_field(23, group='action') input_cancel_action: 'InputCancelAction' = betterproto.message_field( - 22, group='action', + 24, group='action', ) input_demand_action: 'InputDemandAction' = betterproto.message_field( - 23, group='action', + 25, group='action', ) input_provide_action: 'InputProvideAction' = betterproto.message_field( - 24, group='action', + 26, group='action', ) input_resolve_action: 'InputResolveAction' = betterproto.message_field( - 25, group='action', + 27, group='action', ) - ip_action: 'IpAction' = betterproto.message_field(26, group='action') + ip_action: 'IpAction' = betterproto.message_field(28, group='action') ip_set_is_connected_action: 'IpSetIsConnectedAction' = betterproto.message_field( - 27, group='action', + 29, group='action', ) ip_update_interfaces_action: 'IpUpdateInterfacesAction' = betterproto.message_field( - 28, group='action', + 30, group='action', ) - keypad_action: 'KeypadAction' = betterproto.message_field(29, group='action') + keypad_action: 'KeypadAction' = betterproto.message_field(31, group='action') keypad_key_down_action: 'KeypadKeyDownAction' = betterproto.message_field( - 30, group='action', + 32, group='action', ) keypad_key_press_action: 'KeypadKeyPressAction' = betterproto.message_field( - 31, group='action', + 33, group='action', ) keypad_key_release_action: 'KeypadKeyReleaseAction' = betterproto.message_field( - 32, group='action', + 34, group='action', ) keypad_key_up_action: 'KeypadKeyUpAction' = betterproto.message_field( - 33, group='action', + 35, group='action', ) - light_dm_action: 'LightDmAction' = betterproto.message_field(34, group='action') + light_dm_action: 'LightDmAction' = betterproto.message_field(36, group='action') light_dm_clear_enabled_state_action: 'LightDmClearEnabledStateAction' = ( - betterproto.message_field(35, group='action') + betterproto.message_field(37, group='action') ) light_dm_update_state_action: 'LightDmUpdateStateAction' = ( - betterproto.message_field(36, group='action') + betterproto.message_field(38, group='action') + ) + main_action: 'MainAction' = betterproto.message_field(39, group='action') + menu_action: 'MenuAction' = betterproto.message_field(40, group='action') + menu_choose_by_icon_action: 'MenuChooseByIconAction' = betterproto.message_field( + 41, group='action', + ) + menu_choose_by_index_action: 'MenuChooseByIndexAction' = betterproto.message_field( + 42, group='action', + ) + menu_choose_by_label_action: 'MenuChooseByLabelAction' = betterproto.message_field( + 43, group='action', + ) + menu_go_back_action: 'MenuGoBackAction' = betterproto.message_field( + 44, group='action', + ) + menu_go_home_action: 'MenuGoHomeAction' = betterproto.message_field( + 45, group='action', + ) + menu_scroll_action: 'MenuScrollAction' = betterproto.message_field( + 46, group='action', ) notifications_action: 'NotificationsAction' = betterproto.message_field( - 37, group='action', + 47, group='action', ) notifications_add_action: 'NotificationsAddAction' = betterproto.message_field( - 38, group='action', + 48, group='action', ) notifications_clear_action: 'NotificationsClearAction' = betterproto.message_field( - 39, group='action', + 49, group='action', ) notifications_clear_all_action: 'NotificationsClearAllAction' = ( - betterproto.message_field(40, group='action') + betterproto.message_field(50, group='action') ) notifications_clear_by_id_action: 'NotificationsClearByIdAction' = ( - betterproto.message_field(41, group='action') + betterproto.message_field(51, group='action') + ) + notifications_display_action: 'NotificationsDisplayAction' = ( + betterproto.message_field(52, group='action') ) + open_application_action: 'OpenApplicationAction' = betterproto.message_field( + 53, group='action', + ) + power_action: 'PowerAction' = betterproto.message_field(54, group='action') + power_off_action: 'PowerOffAction' = betterproto.message_field(55, group='action') r_pi_connect_action: 'RPiConnectAction' = betterproto.message_field( - 42, group='action', + 56, group='action', ) r_pi_connect_done_downloading_action: 'RPiConnectDoneDownloadingAction' = ( - betterproto.message_field(43, group='action') + betterproto.message_field(57, group='action') ) r_pi_connect_set_pending_action: 'RPiConnectSetPendingAction' = ( - betterproto.message_field(44, group='action') + betterproto.message_field(58, group='action') ) r_pi_connect_set_status_action: 'RPiConnectSetStatusAction' = ( - betterproto.message_field(45, group='action') + betterproto.message_field(59, group='action') ) r_pi_connect_start_downloading_action: 'RPiConnectStartDownloadingAction' = ( - betterproto.message_field(46, group='action') + betterproto.message_field(60, group='action') ) r_pi_connect_update_service_state_action: 'RPiConnectUpdateServiceStateAction' = ( - betterproto.message_field(47, group='action') + betterproto.message_field(61, group='action') ) - rgb_ring_action: 'RgbRingAction' = betterproto.message_field(48, group='action') + reboot_action: 'RebootAction' = betterproto.message_field(62, group='action') + register_app_action: 'RegisterAppAction' = betterproto.message_field( + 63, group='action', + ) + register_regular_app_action: 'RegisterRegularAppAction' = betterproto.message_field( + 64, group='action', + ) + register_setting_app_action: 'RegisterSettingAppAction' = betterproto.message_field( + 65, group='action', + ) + rgb_ring_action: 'RgbRingAction' = betterproto.message_field(66, group='action') rgb_ring_blank_action: 'RgbRingBlankAction' = betterproto.message_field( - 49, group='action', + 67, group='action', ) rgb_ring_blink_action: 'RgbRingBlinkAction' = betterproto.message_field( - 50, group='action', + 68, group='action', ) rgb_ring_colorful_command_action: 'RgbRingColorfulCommandAction' = ( - betterproto.message_field(51, group='action') + betterproto.message_field(69, group='action') ) rgb_ring_command_action: 'RgbRingCommandAction' = betterproto.message_field( - 52, group='action', + 70, group='action', ) rgb_ring_fill_downfrom_action: 'RgbRingFillDownfromAction' = ( - betterproto.message_field(53, group='action') + betterproto.message_field(71, group='action') ) rgb_ring_fill_upto_action: 'RgbRingFillUptoAction' = betterproto.message_field( - 54, group='action', + 72, group='action', ) rgb_ring_progress_wheel_action: 'RgbRingProgressWheelAction' = ( - betterproto.message_field(55, group='action') + betterproto.message_field(73, group='action') ) rgb_ring_progress_wheel_step_action: 'RgbRingProgressWheelStepAction' = ( - betterproto.message_field(56, group='action') + betterproto.message_field(74, group='action') ) rgb_ring_pulse_action: 'RgbRingPulseAction' = betterproto.message_field( - 57, group='action', + 75, group='action', ) rgb_ring_rainbow_action: 'RgbRingRainbowAction' = betterproto.message_field( - 58, group='action', + 76, group='action', ) rgb_ring_set_all_action: 'RgbRingSetAllAction' = betterproto.message_field( - 59, group='action', + 77, group='action', ) rgb_ring_set_brightness_action: 'RgbRingSetBrightnessAction' = ( - betterproto.message_field(60, group='action') + betterproto.message_field(78, group='action') ) rgb_ring_set_enabled_action: 'RgbRingSetEnabledAction' = betterproto.message_field( - 61, group='action', + 79, group='action', ) rgb_ring_set_is_busy_action: 'RgbRingSetIsBusyAction' = betterproto.message_field( - 62, group='action', + 80, group='action', ) rgb_ring_set_is_connected_action: 'RgbRingSetIsConnectedAction' = ( - betterproto.message_field(63, group='action') + betterproto.message_field(81, group='action') ) rgb_ring_spinning_wheel_action: 'RgbRingSpinningWheelAction' = ( - betterproto.message_field(64, group='action') + betterproto.message_field(82, group='action') ) rgb_ring_waitable_command_action: 'RgbRingWaitableCommandAction' = ( - betterproto.message_field(65, group='action') + betterproto.message_field(83, group='action') ) - ssh_action: 'SshAction' = betterproto.message_field(66, group='action') + ssh_action: 'SshAction' = betterproto.message_field(84, group='action') ssh_clear_enabled_state_action: 'SshClearEnabledStateAction' = ( - betterproto.message_field(67, group='action') + betterproto.message_field(85, group='action') ) ssh_update_state_action: 'SshUpdateStateAction' = betterproto.message_field( - 68, group='action', + 86, group='action', ) - sensors_action: 'SensorsAction' = betterproto.message_field(69, group='action') + sensors_action: 'SensorsAction' = betterproto.message_field(87, group='action') sensors_report_reading_action: 'SensorsReportReadingAction' = ( - betterproto.message_field(70, group='action') + betterproto.message_field(88, group='action') + ) + set_are_enclosures_visible_action: 'SetAreEnclosuresVisibleAction' = ( + betterproto.message_field(89, group='action') + ) + set_menu_path_action: 'SetMenuPathAction' = betterproto.message_field( + 90, group='action', + ) + settings_action: 'SettingsAction' = betterproto.message_field(91, group='action') + settings_toggle_debug_mode_action: 'SettingsToggleDebugModeAction' = ( + betterproto.message_field(92, group='action') + ) + status_icons_action: 'StatusIconsAction' = betterproto.message_field( + 93, group='action', + ) + status_icons_register_action: 'StatusIconsRegisterAction' = ( + betterproto.message_field(94, group='action') + ) + update_manager_action: 'UpdateManagerAction' = betterproto.message_field( + 95, group='action', + ) + update_manager_set_status_action: 'UpdateManagerSetStatusAction' = ( + betterproto.message_field(96, group='action') + ) + update_manager_set_update_service_status_action: ( + 'UpdateManagerSetUpdateServiceStatusAction' + ) = betterproto.message_field(97, group='action') + update_manager_set_versions_action: 'UpdateManagerSetVersionsAction' = ( + betterproto.message_field(98, group='action') ) - users_action: 'UsersAction' = betterproto.message_field(71, group='action') + users_action: 'UsersAction' = betterproto.message_field(99, group='action') users_create_user_action: 'UsersCreateUserAction' = betterproto.message_field( - 72, group='action', + 100, group='action', ) users_delete_user_action: 'UsersDeleteUserAction' = betterproto.message_field( - 73, group='action', + 101, group='action', ) users_reset_password_action: 'UsersResetPasswordAction' = betterproto.message_field( - 74, group='action', + 102, group='action', ) users_set_users_action: 'UsersSetUsersAction' = betterproto.message_field( - 75, group='action', + 103, group='action', ) - vs_code_action: 'VsCodeAction' = betterproto.message_field(76, group='action') + vs_code_action: 'VsCodeAction' = betterproto.message_field(104, group='action') vs_code_done_downloading_action: 'VsCodeDoneDownloadingAction' = ( - betterproto.message_field(77, group='action') + betterproto.message_field(105, group='action') ) vs_code_set_pending_action: 'VsCodeSetPendingAction' = betterproto.message_field( - 78, group='action', + 106, group='action', ) vs_code_set_status_action: 'VsCodeSetStatusAction' = betterproto.message_field( - 79, group='action', + 107, group='action', ) vs_code_start_downloading_action: 'VsCodeStartDownloadingAction' = ( - betterproto.message_field(80, group='action') + betterproto.message_field(108, group='action') ) - voice_action: 'VoiceAction' = betterproto.message_field(81, group='action') + voice_action: 'VoiceAction' = betterproto.message_field(109, group='action') voice_read_text_action: 'VoiceReadTextAction' = betterproto.message_field( - 82, group='action', + 110, group='action', ) voice_set_engine_action: 'VoiceSetEngineAction' = betterproto.message_field( - 83, group='action', + 111, group='action', ) - wi_fi_action: 'WiFiAction' = betterproto.message_field(84, group='action') + wi_fi_action: 'WiFiAction' = betterproto.message_field(112, group='action') wi_fi_set_has_visited_onboarding_action: 'WiFiSetHasVisitedOnboardingAction' = ( - betterproto.message_field(85, group='action') + betterproto.message_field(113, group='action') ) wi_fi_update_action: 'WiFiUpdateAction' = betterproto.message_field( - 86, group='action', + 114, group='action', ) wi_fi_update_request_action: 'WiFiUpdateRequestAction' = betterproto.message_field( - 87, group='action', + 115, group='action', ) @@ -1930,78 +2498,114 @@ class Event(betterproto.Message): camera_stop_viewfinder_event: 'CameraStopViewfinderEvent' = ( betterproto.message_field(7, group='event') ) + close_application_event: 'CloseApplicationEvent' = betterproto.message_field( + 8, group='event', + ) display_compressed_render_event: 'DisplayCompressedRenderEvent' = ( - betterproto.message_field(8, group='event') + betterproto.message_field(9, group='event') ) - display_event: 'DisplayEvent' = betterproto.message_field(9, group='event') + display_event: 'DisplayEvent' = betterproto.message_field(10, group='event') display_render_event: 'DisplayRenderEvent' = betterproto.message_field( - 10, group='event', + 11, group='event', ) - docker_event: 'DockerEvent' = betterproto.message_field(11, group='event') + docker_event: 'DockerEvent' = betterproto.message_field(12, group='event') docker_image_event: 'DockerImageEvent' = betterproto.message_field( - 12, group='event', + 13, group='event', ) docker_image_register_app_event: 'DockerImageRegisterAppEvent' = ( - betterproto.message_field(13, group='event') + betterproto.message_field(14, group='event') ) + init_event: 'InitEvent' = betterproto.message_field(15, group='event') input_cancel_event: 'InputCancelEvent' = betterproto.message_field( - 14, group='event', + 16, group='event', ) input_provide_event: 'InputProvideEvent' = betterproto.message_field( - 15, group='event', + 17, group='event', ) input_resolve_event: 'InputResolveEvent' = betterproto.message_field( - 16, group='event', + 18, group='event', + ) + ip_event: 'IpEvent' = betterproto.message_field(19, group='event') + main_event: 'MainEvent' = betterproto.message_field(20, group='event') + menu_choose_by_icon_event: 'MenuChooseByIconEvent' = betterproto.message_field( + 21, group='event', ) - ip_event: 'IpEvent' = betterproto.message_field(17, group='event') - keypad_event: 'KeypadEvent' = betterproto.message_field(18, group='event') - keypad_key_press_event: 'KeypadKeyPressEvent' = betterproto.message_field( - 19, group='event', + menu_choose_by_index_event: 'MenuChooseByIndexEvent' = betterproto.message_field( + 22, group='event', ) - keypad_key_release_event: 'KeypadKeyReleaseEvent' = betterproto.message_field( - 20, group='event', + menu_choose_by_label_event: 'MenuChooseByLabelEvent' = betterproto.message_field( + 23, group='event', ) + menu_event: 'MenuEvent' = betterproto.message_field(24, group='event') + menu_go_back_event: 'MenuGoBackEvent' = betterproto.message_field(25, group='event') + menu_go_home_event: 'MenuGoHomeEvent' = betterproto.message_field(26, group='event') + menu_scroll_event: 'MenuScrollEvent' = betterproto.message_field(27, group='event') notifications_clear_event: 'NotificationsClearEvent' = betterproto.message_field( - 21, group='event', + 28, group='event', ) notifications_display_event: 'NotificationsDisplayEvent' = ( - betterproto.message_field(22, group='event') + betterproto.message_field(29, group='event') ) notifications_event: 'NotificationsEvent' = betterproto.message_field( - 23, group='event', + 30, group='event', ) - r_pi_connect_event: 'RPiConnectEvent' = betterproto.message_field(24, group='event') + open_application_event: 'OpenApplicationEvent' = betterproto.message_field( + 31, group='event', + ) + power_event: 'PowerEvent' = betterproto.message_field(32, group='event') + power_off_event: 'PowerOffEvent' = betterproto.message_field(33, group='event') + r_pi_connect_event: 'RPiConnectEvent' = betterproto.message_field(34, group='event') r_pi_connect_login_event: 'RPiConnectLoginEvent' = betterproto.message_field( - 25, group='event', + 35, group='event', + ) + reboot_event: 'RebootEvent' = betterproto.message_field(36, group='event') + replay_recorded_sequence_event: 'ReplayRecordedSequenceEvent' = ( + betterproto.message_field(37, group='event') ) rgb_ring_command_event: 'RgbRingCommandEvent' = betterproto.message_field( - 26, group='event', + 38, group='event', + ) + rgb_ring_event: 'RgbRingEvent' = betterproto.message_field(39, group='event') + screenshot_event: 'ScreenshotEvent' = betterproto.message_field(40, group='event') + settings_event: 'SettingsEvent' = betterproto.message_field(41, group='event') + settings_set_debug_mode_event: 'SettingsSetDebugModeEvent' = ( + betterproto.message_field(42, group='event') + ) + snapshot_event: 'SnapshotEvent' = betterproto.message_field(43, group='event') + store_recorded_sequence_event: 'StoreRecordedSequenceEvent' = ( + betterproto.message_field(44, group='event') + ) + update_manager_check_event: 'UpdateManagerCheckEvent' = betterproto.message_field( + 45, group='event', + ) + update_manager_event: 'UpdateManagerEvent' = betterproto.message_field( + 46, group='event', + ) + update_manager_update_event: 'UpdateManagerUpdateEvent' = betterproto.message_field( + 47, group='event', ) - rgb_ring_event: 'RgbRingEvent' = betterproto.message_field(27, group='event') - screenshot_event: 'ScreenshotEvent' = betterproto.message_field(28, group='event') - snapshot_event: 'SnapshotEvent' = betterproto.message_field(29, group='event') users_create_user_event: 'UsersCreateUserEvent' = betterproto.message_field( - 30, group='event', + 48, group='event', ) users_delete_user_event: 'UsersDeleteUserEvent' = betterproto.message_field( - 31, group='event', + 49, group='event', ) - users_event: 'UsersEvent' = betterproto.message_field(32, group='event') + users_event: 'UsersEvent' = betterproto.message_field(50, group='event') users_reset_password_event: 'UsersResetPasswordEvent' = betterproto.message_field( - 33, group='event', + 51, group='event', ) - vs_code_event: 'VsCodeEvent' = betterproto.message_field(34, group='event') + vs_code_event: 'VsCodeEvent' = betterproto.message_field(52, group='event') vs_code_login_event: 'VsCodeLoginEvent' = betterproto.message_field( - 35, group='event', + 53, group='event', ) vs_code_restart_event: 'VsCodeRestartEvent' = betterproto.message_field( - 36, group='event', + 54, group='event', ) - voice_event: 'VoiceEvent' = betterproto.message_field(37, group='event') + voice_event: 'VoiceEvent' = betterproto.message_field(55, group='event') voice_synthesize_text_event: 'VoiceSynthesizeTextEvent' = betterproto.message_field( - 38, group='event', + 56, group='event', ) - wi_fi_event: 'WiFiEvent' = betterproto.message_field(39, group='event') + wi_fi_event: 'WiFiEvent' = betterproto.message_field(57, group='event') wi_fi_update_request_event: 'WiFiUpdateRequestEvent' = betterproto.message_field( - 40, group='event', + 58, group='event', ) diff --git a/ubo_app/rpc/proto/ubo/v1/ubo.proto b/ubo_app/rpc/proto/ubo/v1/ubo.proto index 70498909..1c531d4e 100644 --- a/ubo_app/rpc/proto/ubo/v1/ubo.proto +++ b/ubo_app/rpc/proto/ubo/v1/ubo.proto @@ -95,8 +95,276 @@ message Menu { HeadlessMenu headless_menu = 2; } } +enum SettingsCategory { + SETTINGS_CATEGORY_UBO_APP_DOT_STORE_DOT_CORE_DOT_TYPES_UNSPECIFIED = 0; + SETTINGS_CATEGORY_NETWORK = 1; + SETTINGS_CATEGORY_REMOTE = 2; + SETTINGS_CATEGORY_GENERAL = 3; + SETTINGS_CATEGORY_SPEECH = 4; + SETTINGS_CATEGORY_DOCKER = 5; +} + +enum MenuScrollDirection { + MENU_SCROLL_DIRECTION_UBO_APP_DOT_STORE_DOT_CORE_DOT_TYPES_UNSPECIFIED = 0; + MENU_SCROLL_DIRECTION_UP = 1; + MENU_SCROLL_DIRECTION_DOWN = 2; +} + +message MainAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message UpdateLightDMState { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + bool is_active = 2; + bool is_enable = 3; +} + +message RegisterAppAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + Item menu_item = 2; + optional string service = 3; + optional string key = 4; +} + +message RegisterRegularAppAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + Item menu_item = 2; + optional string service = 3; + optional string key = 4; +} + +message RegisterSettingAppAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + SettingsCategory category = 2; + optional int64 priority = 3; + Item menu_item = 4; + optional string service = 5; + optional string key = 6; +} + +message PowerAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message PowerOffAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message RebootAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message SetMenuPathAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + repeated string path = 2; + int64 depth = 3; +} + +message SetAreEnclosuresVisibleAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + optional bool is_header_visible = 2; + optional bool is_footer_visible = 3; +} + +message MenuAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuGoBackAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuGoHomeAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuChooseByIconAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string icon = 2; +} + +message MenuChooseByLabelAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string label = 2; +} + +message MenuChooseByIndexAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + int64 index = 2; +} + +message MenuScrollAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + MenuScrollDirection direction = 2; +} + +message OpenApplicationAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string application = 2; +} + +message CloseApplicationAction { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string application = 2; +} + +message MainEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message InitEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuGoBackEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuGoHomeEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MenuChooseByIconEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string icon = 2; +} + +message MenuChooseByLabelEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string label = 2; +} + +message MenuChooseByIndexEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + int64 index = 2; +} + +message MenuScrollEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + MenuScrollDirection direction = 2; +} + +message OpenApplicationEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string application = 2; +} + +message CloseApplicationEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + string application = 2; +} + +message PowerEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message PowerOffEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message RebootEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message ScreenshotEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message SnapshotEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message StoreRecordedSequenceEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + repeated Action recorded_sequence = 2; +} + +message ReplayRecordedSequenceEvent { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; +} + +message MainState { + option (package_info.v1.package_name) = "ubo_app.store.core.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_core_dot_types = 1000; + + message Path { + repeated string items = 1; + } + + message SettingsItemsPrioritiesDict { + map items = 1; + } + message RecordedSequence { + repeated Action items = 1; + } + optional Menu menu = 2; + optional Path path = 3; + optional int64 depth = 4; + optional bool is_header_visible = 5; + optional bool is_footer_visible = 6; + optional SettingsItemsPrioritiesDict settings_items_priorities = 7; + optional bool is_recording = 8; + optional RecordedSequence recorded_sequence = 9; +} + +message DispatchItem { + option (package_info.v1.package_name) = "ubo_app.store.dispatch_action"; + optional string meta_field_package_name_ubo_app_dot_store_dot_dispatch_action = 1000; + Action store_action = 2; + optional string key = 3; + optional string label = 4; + optional string color = 5; + optional string background_color = 6; + optional string icon = 7; + optional bool is_short = 8; + optional float opacity = 9; + optional float progress = 10; +} + enum InputFieldType { - INPUT_FIELD_TYPE_UBO_APP_DOT_STORE_DOT_OPERATIONS_UNSPECIFIED = 0; + INPUT_FIELD_TYPE_UBO_APP_DOT_STORE_DOT_INPUT_DOT_TYPES_UNSPECIFIED = 0; INPUT_FIELD_TYPE_LONG = 1; INPUT_FIELD_TYPE_TEXT = 2; INPUT_FIELD_TYPE_PASSWORD = 3; @@ -110,8 +378,8 @@ enum InputFieldType { } message InputFieldDescription { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; message Options { repeated string items = 1; @@ -128,8 +396,8 @@ message InputFieldDescription { } message InputDescription { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; message Fields { repeated InputFieldDescription items = 1; @@ -143,31 +411,31 @@ message InputDescription { } message InputAction { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; } message InputDemandAction { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; InputDescription description = 2; } message InputResolveAction { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; string id = 2; } message InputCancelAction { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; string id = 2; } message InputProvideAction { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; string value = 2; map data = 3; @@ -175,45 +443,142 @@ message InputProvideAction { } message InputResolveEvent { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; string id = 2; } message InputCancelEvent { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; string id = 2; } message InputProvideEvent { - option (package_info.v1.package_name) = "ubo_app.store.operations"; - optional string meta_field_package_name_ubo_app_dot_store_dot_operations = 1000; + option (package_info.v1.package_name) = "ubo_app.store.input.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_input_dot_types = 1000; string value = 2; map data = 3; string id = 4; } -message DispatchItem { - option (package_info.v1.package_name) = "ubo_app.store.dispatch_action"; - optional string meta_field_package_name_ubo_app_dot_store_dot_dispatch_action = 1000; +message SettingsAction { + option (package_info.v1.package_name) = "ubo_app.store.settings.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types = 1000; +} - message Operation { - oneof operation { - Action ubo_action = 1; - Event ubo_event = 2; - } - } - Operation operation = 2; - optional string key = 3; - optional string label = 4; - optional string color = 5; - optional string background_color = 6; - optional string icon = 7; - optional bool is_short = 8; - optional float opacity = 9; - optional float progress = 10; +message SettingsToggleDebugModeAction { + option (package_info.v1.package_name) = "ubo_app.store.settings.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types = 1000; +} + +message SettingsEvent { + option (package_info.v1.package_name) = "ubo_app.store.settings.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types = 1000; +} + +message SettingsSetDebugModeEvent { + option (package_info.v1.package_name) = "ubo_app.store.settings.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types = 1000; + bool is_enabled = 2; +} + +message SettingsState { + option (package_info.v1.package_name) = "ubo_app.store.settings.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_settings_dot_types = 1000; + optional bool is_debug_enabled = 2; +} + +message IconState { + option (package_info.v1.package_name) = "ubo_app.store.status_icons.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types = 1000; + string symbol = 2; + string color = 3; + int64 priority = 4; + string id = 5; +} + +message StatusIconsState { + option (package_info.v1.package_name) = "ubo_app.store.status_icons.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types = 1000; + repeated IconState icons = 2; +} + +message StatusIconsAction { + option (package_info.v1.package_name) = "ubo_app.store.status_icons.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types = 1000; +} + +message StatusIconsRegisterAction { + option (package_info.v1.package_name) = "ubo_app.store.status_icons.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_status_icons_dot_types = 1000; + string icon = 2; + optional string color = 3; + optional int64 priority = 4; + optional string id = 5; +} + +enum UpdateStatus { + UPDATE_STATUS_UBO_APP_DOT_STORE_DOT_UPDATE_MANAGER_DOT_TYPES_UNSPECIFIED = 0; + UPDATE_STATUS_CHECKING = 1; + UPDATE_STATUS_FAILED_TO_CHECK = 2; + UPDATE_STATUS_UP_TO_DATE = 3; + UPDATE_STATUS_OUTDATED = 4; + UPDATE_STATUS_UPDATING = 5; +} + +message UpdateManagerAction { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; +} + +message UpdateManagerSetVersionsAction { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; + bool flash_notification = 2; + string current_version = 3; + string base_image_variant = 4; + string latest_version = 5; + string serial_number = 6; +} + +message UpdateManagerSetStatusAction { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; + UpdateStatus status = 2; +} + +message UpdateManagerSetUpdateServiceStatusAction { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; + bool is_active = 2; +} + +message UpdateManagerEvent { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; +} + +message UpdateManagerCheckEvent { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; +} + +message UpdateManagerUpdateEvent { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; +} + +message UpdateManagerState { + option (package_info.v1.package_name) = "ubo_app.store.update_manager.types"; + optional string meta_field_package_name_ubo_app_dot_store_dot_update_manager_dot_types = 1000; + optional string serial_number = 2; + optional string current_version = 3; + optional string base_image_variant = 4; + optional string latest_version = 5; + optional UpdateStatus update_status = 6; + optional bool is_update_service_active = 7; } enum AudioDevice { @@ -378,16 +743,14 @@ message DisplayRenderEvent { option (package_info.v1.package_name) = "ubo_app.store.services.display"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_display = 1000; bytes data = 2; - int64 data_hash = 3; - repeated int64 rectangle = 4; + repeated int64 rectangle = 3; } message DisplayCompressedRenderEvent { option (package_info.v1.package_name) = "ubo_app.store.services.display"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_display = 1000; bytes compressed_data = 2; - int64 data_hash = 3; - repeated int64 rectangle = 4; + repeated int64 rectangle = 3; } message DisplayState { @@ -514,13 +877,13 @@ message DockerState { DockerServiceState service = 2; } -enum GlobalEthernetState { - GLOBAL_ETHERNET_STATE_UBO_APP_DOT_STORE_DOT_SERVICES_DOT_ETHERNET_UNSPECIFIED = 0; - GLOBAL_ETHERNET_STATE_CONNECTED = 1; - GLOBAL_ETHERNET_STATE_DISCONNECTED = 2; - GLOBAL_ETHERNET_STATE_PENDING = 3; - GLOBAL_ETHERNET_STATE_NEEDS_ATTENTION = 4; - GLOBAL_ETHERNET_STATE_UNKNOWN = 5; +enum NetState { + NET_STATE_UBO_APP_DOT_STORE_DOT_SERVICES_DOT_ETHERNET_UNSPECIFIED = 0; + NET_STATE_CONNECTED = 1; + NET_STATE_DISCONNECTED = 2; + NET_STATE_PENDING = 3; + NET_STATE_NEEDS_ATTENTION = 4; + NET_STATE_UNKNOWN = 5; } message IpAction { @@ -679,14 +1042,7 @@ message NotificationActionItem { message NotificationDispatchItem { option (package_info.v1.package_name) = "ubo_app.store.services.notifications"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications = 1000; - - message Operation { - oneof operation { - Action ubo_action = 1; - Event ubo_event = 2; - } - } - Operation operation = 2; + Action store_action = 2; optional string key = 3; optional string label = 4; optional string color = 5; @@ -756,6 +1112,14 @@ message NotificationsAddAction { Notification notification = 2; } +message NotificationsDisplayAction { + option (package_info.v1.package_name) = "ubo_app.store.services.notifications"; + optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications = 1000; + Notification notification = 2; + optional int64 index = 3; + optional int64 count = 4; +} + message NotificationsClearAction { option (package_info.v1.package_name) = "ubo_app.store.services.notifications"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_notifications = 1000; @@ -1267,15 +1631,6 @@ enum ConnectionState { CONNECTION_STATE_UNKNOWN = 4; } -enum GlobalWiFiState { - GLOBAL_WI_FI_STATE_UBO_APP_DOT_STORE_DOT_SERVICES_DOT_WIFI_UNSPECIFIED = 0; - GLOBAL_WI_FI_STATE_CONNECTED = 1; - GLOBAL_WI_FI_STATE_DISCONNECTED = 2; - GLOBAL_WI_FI_STATE_PENDING = 3; - GLOBAL_WI_FI_STATE_NEEDS_ATTENTION = 4; - GLOBAL_WI_FI_STATE_UNKNOWN = 5; -} - message WiFiConnection { option (package_info.v1.package_name) = "ubo_app.store.services.wifi"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_wifi = 1000; @@ -1302,7 +1657,7 @@ message WiFiUpdateAction { option (package_info.v1.package_name) = "ubo_app.store.services.wifi"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_wifi = 1000; repeated WiFiConnection connections = 2; - GlobalWiFiState state = 3; + NetState state = 3; WiFiConnection current_connection = 4; } @@ -1326,7 +1681,7 @@ message WiFiState { option (package_info.v1.package_name) = "ubo_app.store.services.wifi"; optional string meta_field_package_name_ubo_app_dot_store_dot_services_dot_wifi = 1000; repeated WiFiConnection connections = 2; - GlobalWiFiState state = 3; + NetState state = 3; WiFiConnection current_connection = 4; optional bool has_visited_onboarding = 5; } @@ -1344,83 +1699,110 @@ message Action { CameraAction camera_action = 9; CameraReportBarcodeAction camera_report_barcode_action = 10; CameraStartViewfinderAction camera_start_viewfinder_action = 11; - DisplayAction display_action = 12; - DisplayPauseAction display_pause_action = 13; - DisplayResumeAction display_resume_action = 14; - DockerAction docker_action = 15; - DockerImageAction docker_image_action = 16; - DockerImageSetDockerIdAction docker_image_set_docker_id_action = 17; - DockerImageSetStatusAction docker_image_set_status_action = 18; - DockerRemoveUsernameAction docker_remove_username_action = 19; - DockerSetStatusAction docker_set_status_action = 20; - DockerStoreUsernameAction docker_store_username_action = 21; - InputAction input_action = 22; - InputCancelAction input_cancel_action = 23; - InputDemandAction input_demand_action = 24; - InputProvideAction input_provide_action = 25; - InputResolveAction input_resolve_action = 26; - IpAction ip_action = 27; - IpSetIsConnectedAction ip_set_is_connected_action = 28; - IpUpdateInterfacesAction ip_update_interfaces_action = 29; - KeypadAction keypad_action = 30; - KeypadKeyDownAction keypad_key_down_action = 31; - KeypadKeyPressAction keypad_key_press_action = 32; - KeypadKeyReleaseAction keypad_key_release_action = 33; - KeypadKeyUpAction keypad_key_up_action = 34; - LightDMAction light_dm_action = 35; - LightDMClearEnabledStateAction light_dm_clear_enabled_state_action = 36; - LightDMUpdateStateAction light_dm_update_state_action = 37; - NotificationsAction notifications_action = 38; - NotificationsAddAction notifications_add_action = 39; - NotificationsClearAction notifications_clear_action = 40; - NotificationsClearAllAction notifications_clear_all_action = 41; - NotificationsClearByIdAction notifications_clear_by_id_action = 42; - RPiConnectAction r_pi_connect_action = 43; - RPiConnectDoneDownloadingAction r_pi_connect_done_downloading_action = 44; - RPiConnectSetPendingAction r_pi_connect_set_pending_action = 45; - RPiConnectSetStatusAction r_pi_connect_set_status_action = 46; - RPiConnectStartDownloadingAction r_pi_connect_start_downloading_action = 47; - RPiConnectUpdateServiceStateAction r_pi_connect_update_service_state_action = 48; - RgbRingAction rgb_ring_action = 49; - RgbRingBlankAction rgb_ring_blank_action = 50; - RgbRingBlinkAction rgb_ring_blink_action = 51; - RgbRingColorfulCommandAction rgb_ring_colorful_command_action = 52; - RgbRingCommandAction rgb_ring_command_action = 53; - RgbRingFillDownfromAction rgb_ring_fill_downfrom_action = 54; - RgbRingFillUptoAction rgb_ring_fill_upto_action = 55; - RgbRingProgressWheelAction rgb_ring_progress_wheel_action = 56; - RgbRingProgressWheelStepAction rgb_ring_progress_wheel_step_action = 57; - RgbRingPulseAction rgb_ring_pulse_action = 58; - RgbRingRainbowAction rgb_ring_rainbow_action = 59; - RgbRingSetAllAction rgb_ring_set_all_action = 60; - RgbRingSetBrightnessAction rgb_ring_set_brightness_action = 61; - RgbRingSetEnabledAction rgb_ring_set_enabled_action = 62; - RgbRingSetIsBusyAction rgb_ring_set_is_busy_action = 63; - RgbRingSetIsConnectedAction rgb_ring_set_is_connected_action = 64; - RgbRingSpinningWheelAction rgb_ring_spinning_wheel_action = 65; - RgbRingWaitableCommandAction rgb_ring_waitable_command_action = 66; - SSHAction ssh_action = 67; - SSHClearEnabledStateAction ssh_clear_enabled_state_action = 68; - SSHUpdateStateAction ssh_update_state_action = 69; - SensorsAction sensors_action = 70; - SensorsReportReadingAction sensors_report_reading_action = 71; - UsersAction users_action = 72; - UsersCreateUserAction users_create_user_action = 73; - UsersDeleteUserAction users_delete_user_action = 74; - UsersResetPasswordAction users_reset_password_action = 75; - UsersSetUsersAction users_set_users_action = 76; - VSCodeAction vs_code_action = 77; - VSCodeDoneDownloadingAction vs_code_done_downloading_action = 78; - VSCodeSetPendingAction vs_code_set_pending_action = 79; - VSCodeSetStatusAction vs_code_set_status_action = 80; - VSCodeStartDownloadingAction vs_code_start_downloading_action = 81; - VoiceAction voice_action = 82; - VoiceReadTextAction voice_read_text_action = 83; - VoiceSetEngineAction voice_set_engine_action = 84; - WiFiAction wi_fi_action = 85; - WiFiSetHasVisitedOnboardingAction wi_fi_set_has_visited_onboarding_action = 86; - WiFiUpdateAction wi_fi_update_action = 87; - WiFiUpdateRequestAction wi_fi_update_request_action = 88; + CloseApplicationAction close_application_action = 12; + DisplayAction display_action = 13; + DisplayPauseAction display_pause_action = 14; + DisplayResumeAction display_resume_action = 15; + DockerAction docker_action = 16; + DockerImageAction docker_image_action = 17; + DockerImageSetDockerIdAction docker_image_set_docker_id_action = 18; + DockerImageSetStatusAction docker_image_set_status_action = 19; + DockerRemoveUsernameAction docker_remove_username_action = 20; + DockerSetStatusAction docker_set_status_action = 21; + DockerStoreUsernameAction docker_store_username_action = 22; + InputAction input_action = 23; + InputCancelAction input_cancel_action = 24; + InputDemandAction input_demand_action = 25; + InputProvideAction input_provide_action = 26; + InputResolveAction input_resolve_action = 27; + IpAction ip_action = 28; + IpSetIsConnectedAction ip_set_is_connected_action = 29; + IpUpdateInterfacesAction ip_update_interfaces_action = 30; + KeypadAction keypad_action = 31; + KeypadKeyDownAction keypad_key_down_action = 32; + KeypadKeyPressAction keypad_key_press_action = 33; + KeypadKeyReleaseAction keypad_key_release_action = 34; + KeypadKeyUpAction keypad_key_up_action = 35; + LightDMAction light_dm_action = 36; + LightDMClearEnabledStateAction light_dm_clear_enabled_state_action = 37; + LightDMUpdateStateAction light_dm_update_state_action = 38; + MainAction main_action = 39; + MenuAction menu_action = 40; + MenuChooseByIconAction menu_choose_by_icon_action = 41; + MenuChooseByIndexAction menu_choose_by_index_action = 42; + MenuChooseByLabelAction menu_choose_by_label_action = 43; + MenuGoBackAction menu_go_back_action = 44; + MenuGoHomeAction menu_go_home_action = 45; + MenuScrollAction menu_scroll_action = 46; + NotificationsAction notifications_action = 47; + NotificationsAddAction notifications_add_action = 48; + NotificationsClearAction notifications_clear_action = 49; + NotificationsClearAllAction notifications_clear_all_action = 50; + NotificationsClearByIdAction notifications_clear_by_id_action = 51; + NotificationsDisplayAction notifications_display_action = 52; + OpenApplicationAction open_application_action = 53; + PowerAction power_action = 54; + PowerOffAction power_off_action = 55; + RPiConnectAction r_pi_connect_action = 56; + RPiConnectDoneDownloadingAction r_pi_connect_done_downloading_action = 57; + RPiConnectSetPendingAction r_pi_connect_set_pending_action = 58; + RPiConnectSetStatusAction r_pi_connect_set_status_action = 59; + RPiConnectStartDownloadingAction r_pi_connect_start_downloading_action = 60; + RPiConnectUpdateServiceStateAction r_pi_connect_update_service_state_action = 61; + RebootAction reboot_action = 62; + RegisterAppAction register_app_action = 63; + RegisterRegularAppAction register_regular_app_action = 64; + RegisterSettingAppAction register_setting_app_action = 65; + RgbRingAction rgb_ring_action = 66; + RgbRingBlankAction rgb_ring_blank_action = 67; + RgbRingBlinkAction rgb_ring_blink_action = 68; + RgbRingColorfulCommandAction rgb_ring_colorful_command_action = 69; + RgbRingCommandAction rgb_ring_command_action = 70; + RgbRingFillDownfromAction rgb_ring_fill_downfrom_action = 71; + RgbRingFillUptoAction rgb_ring_fill_upto_action = 72; + RgbRingProgressWheelAction rgb_ring_progress_wheel_action = 73; + RgbRingProgressWheelStepAction rgb_ring_progress_wheel_step_action = 74; + RgbRingPulseAction rgb_ring_pulse_action = 75; + RgbRingRainbowAction rgb_ring_rainbow_action = 76; + RgbRingSetAllAction rgb_ring_set_all_action = 77; + RgbRingSetBrightnessAction rgb_ring_set_brightness_action = 78; + RgbRingSetEnabledAction rgb_ring_set_enabled_action = 79; + RgbRingSetIsBusyAction rgb_ring_set_is_busy_action = 80; + RgbRingSetIsConnectedAction rgb_ring_set_is_connected_action = 81; + RgbRingSpinningWheelAction rgb_ring_spinning_wheel_action = 82; + RgbRingWaitableCommandAction rgb_ring_waitable_command_action = 83; + SSHAction ssh_action = 84; + SSHClearEnabledStateAction ssh_clear_enabled_state_action = 85; + SSHUpdateStateAction ssh_update_state_action = 86; + SensorsAction sensors_action = 87; + SensorsReportReadingAction sensors_report_reading_action = 88; + SetAreEnclosuresVisibleAction set_are_enclosures_visible_action = 89; + SetMenuPathAction set_menu_path_action = 90; + SettingsAction settings_action = 91; + SettingsToggleDebugModeAction settings_toggle_debug_mode_action = 92; + StatusIconsAction status_icons_action = 93; + StatusIconsRegisterAction status_icons_register_action = 94; + UpdateManagerAction update_manager_action = 95; + UpdateManagerSetStatusAction update_manager_set_status_action = 96; + UpdateManagerSetUpdateServiceStatusAction update_manager_set_update_service_status_action = 97; + UpdateManagerSetVersionsAction update_manager_set_versions_action = 98; + UsersAction users_action = 99; + UsersCreateUserAction users_create_user_action = 100; + UsersDeleteUserAction users_delete_user_action = 101; + UsersResetPasswordAction users_reset_password_action = 102; + UsersSetUsersAction users_set_users_action = 103; + VSCodeAction vs_code_action = 104; + VSCodeDoneDownloadingAction vs_code_done_downloading_action = 105; + VSCodeSetPendingAction vs_code_set_pending_action = 106; + VSCodeSetStatusAction vs_code_set_status_action = 107; + VSCodeStartDownloadingAction vs_code_start_downloading_action = 108; + VoiceAction voice_action = 109; + VoiceReadTextAction voice_read_text_action = 110; + VoiceSetEngineAction voice_set_engine_action = 111; + WiFiAction wi_fi_action = 112; + WiFiSetHasVisitedOnboardingAction wi_fi_set_has_visited_onboarding_action = 113; + WiFiUpdateAction wi_fi_update_action = 114; + WiFiUpdateRequestAction wi_fi_update_request_action = 115; } } @@ -1433,33 +1815,56 @@ message Event { CameraEvent camera_event = 5; CameraStartViewfinderEvent camera_start_viewfinder_event = 6; CameraStopViewfinderEvent camera_stop_viewfinder_event = 7; - DisplayCompressedRenderEvent display_compressed_render_event = 8; - DisplayEvent display_event = 9; - DisplayRenderEvent display_render_event = 10; - DockerEvent docker_event = 11; - DockerImageEvent docker_image_event = 12; - DockerImageRegisterAppEvent docker_image_register_app_event = 13; - InputCancelEvent input_cancel_event = 14; - InputProvideEvent input_provide_event = 15; - InputResolveEvent input_resolve_event = 16; - IpEvent ip_event = 17; - NotificationsClearEvent notifications_clear_event = 18; - NotificationsDisplayEvent notifications_display_event = 19; - NotificationsEvent notifications_event = 20; - RPiConnectEvent r_pi_connect_event = 21; - RPiConnectLoginEvent r_pi_connect_login_event = 22; - RgbRingCommandEvent rgb_ring_command_event = 23; - RgbRingEvent rgb_ring_event = 24; - UsersCreateUserEvent users_create_user_event = 25; - UsersDeleteUserEvent users_delete_user_event = 26; - UsersEvent users_event = 27; - UsersResetPasswordEvent users_reset_password_event = 28; - VSCodeEvent vs_code_event = 29; - VSCodeLoginEvent vs_code_login_event = 30; - VSCodeRestartEvent vs_code_restart_event = 31; - VoiceEvent voice_event = 32; - VoiceSynthesizeTextEvent voice_synthesize_text_event = 33; - WiFiEvent wi_fi_event = 34; - WiFiUpdateRequestEvent wi_fi_update_request_event = 35; + CloseApplicationEvent close_application_event = 8; + DisplayCompressedRenderEvent display_compressed_render_event = 9; + DisplayEvent display_event = 10; + DisplayRenderEvent display_render_event = 11; + DockerEvent docker_event = 12; + DockerImageEvent docker_image_event = 13; + DockerImageRegisterAppEvent docker_image_register_app_event = 14; + InitEvent init_event = 15; + InputCancelEvent input_cancel_event = 16; + InputProvideEvent input_provide_event = 17; + InputResolveEvent input_resolve_event = 18; + IpEvent ip_event = 19; + MainEvent main_event = 20; + MenuChooseByIconEvent menu_choose_by_icon_event = 21; + MenuChooseByIndexEvent menu_choose_by_index_event = 22; + MenuChooseByLabelEvent menu_choose_by_label_event = 23; + MenuEvent menu_event = 24; + MenuGoBackEvent menu_go_back_event = 25; + MenuGoHomeEvent menu_go_home_event = 26; + MenuScrollEvent menu_scroll_event = 27; + NotificationsClearEvent notifications_clear_event = 28; + NotificationsDisplayEvent notifications_display_event = 29; + NotificationsEvent notifications_event = 30; + OpenApplicationEvent open_application_event = 31; + PowerEvent power_event = 32; + PowerOffEvent power_off_event = 33; + RPiConnectEvent r_pi_connect_event = 34; + RPiConnectLoginEvent r_pi_connect_login_event = 35; + RebootEvent reboot_event = 36; + ReplayRecordedSequenceEvent replay_recorded_sequence_event = 37; + RgbRingCommandEvent rgb_ring_command_event = 38; + RgbRingEvent rgb_ring_event = 39; + ScreenshotEvent screenshot_event = 40; + SettingsEvent settings_event = 41; + SettingsSetDebugModeEvent settings_set_debug_mode_event = 42; + SnapshotEvent snapshot_event = 43; + StoreRecordedSequenceEvent store_recorded_sequence_event = 44; + UpdateManagerCheckEvent update_manager_check_event = 45; + UpdateManagerEvent update_manager_event = 46; + UpdateManagerUpdateEvent update_manager_update_event = 47; + UsersCreateUserEvent users_create_user_event = 48; + UsersDeleteUserEvent users_delete_user_event = 49; + UsersEvent users_event = 50; + UsersResetPasswordEvent users_reset_password_event = 51; + VSCodeEvent vs_code_event = 52; + VSCodeLoginEvent vs_code_login_event = 53; + VSCodeRestartEvent vs_code_restart_event = 54; + VoiceEvent voice_event = 55; + VoiceSynthesizeTextEvent voice_synthesize_text_event = 56; + WiFiEvent wi_fi_event = 57; + WiFiUpdateRequestEvent wi_fi_update_request_event = 58; } } diff --git a/ubo_app/services/000-audio/reducer.py b/ubo_app/services/000-audio/reducer.py index c0505d26..ef851cbd 100644 --- a/ubo_app/services/000-audio/reducer.py +++ b/ubo_app/services/000-audio/reducer.py @@ -28,7 +28,7 @@ AudioToggleMuteStatusAction, ) from ubo_app.store.services.notifications import Chime -from ubo_app.store.status_icons import StatusIconsRegisterAction +from ubo_app.store.status_icons.types import StatusIconsRegisterAction Action = InitAction | AudioAction | StatusIconsRegisterAction diff --git a/ubo_app/services/000-audio/setup.py b/ubo_app/services/000-audio/setup.py index 788116e7..07efa62b 100644 --- a/ubo_app/services/000-audio/setup.py +++ b/ubo_app/services/000-audio/setup.py @@ -15,7 +15,7 @@ AudioPlayAudioEvent, AudioPlayChimeEvent, ) -from ubo_app.store.status_icons import StatusIconsRegisterAction +from ubo_app.store.status_icons.types import StatusIconsRegisterAction from ubo_app.utils.async_ import to_thread from ubo_app.utils.persistent_store import register_persistent_store diff --git a/ubo_app/services/000-display/setup.py b/ubo_app/services/000-display/setup.py index 5c2258af..7c81b5ab 100644 --- a/ubo_app/services/000-display/setup.py +++ b/ubo_app/services/000-display/setup.py @@ -7,10 +7,3 @@ def init_service() -> None: """Initialize the display service.""" - from ubo_app import display - from ubo_app.constants import HEIGHT, WIDTH - - if splash_screen: - display.render_block((0, 0, WIDTH - 1, HEIGHT - 1), splash_screen) - else: - display.render_blank() diff --git a/ubo_app/services/010-voice/setup.py b/ubo_app/services/010-voice/setup.py index ecee85b8..5676ebf3 100644 --- a/ubo_app/services/010-voice/setup.py +++ b/ubo_app/services/010-voice/setup.py @@ -16,7 +16,7 @@ from ubo_gui.menu.types import ActionItem, HeadedMenu, HeadlessMenu, SubMenuItem from ubo_app.constants import PICOVOICE_ACCESS_KEY -from ubo_app.store.core import RegisterSettingAppAction, SettingsCategory +from ubo_app.store.core.types import RegisterSettingAppAction, SettingsCategory from ubo_app.store.main import store from ubo_app.store.services.audio import AudioPlayAudioAction, AudioPlaybackDoneEvent from ubo_app.store.services.notifications import NotificationExtraInformation diff --git a/ubo_app/services/020-keyboard/setup.py b/ubo_app/services/020-keyboard/setup.py index 75beab12..312791a4 100644 --- a/ubo_app/services/020-keyboard/setup.py +++ b/ubo_app/services/020-keyboard/setup.py @@ -52,27 +52,81 @@ pressed_keys=set(), ), Keyboard.keycodes['m']: AudioToggleMuteStatusAction(device=AudioDevice.INPUT), - Keyboard.keycodes['p']: KeypadKeyPressAction( + }, + 'ctrl': { + Keyboard.keycodes['up']: KeypadKeyPressAction( + key=Key.UP, + pressed_keys={Key.BACK, Key.UP}, + ), + Keyboard.keycodes['k']: KeypadKeyPressAction( + key=Key.UP, + pressed_keys={Key.BACK, Key.UP}, + ), + Keyboard.keycodes['down']: KeypadKeyPressAction( + key=Key.DOWN, + pressed_keys={Key.BACK, Key.DOWN}, + ), + Keyboard.keycodes['j']: KeypadKeyPressAction( + key=Key.DOWN, + pressed_keys={Key.BACK, Key.DOWN}, + ), + Keyboard.keycodes['1']: KeypadKeyPressAction( + key=Key.L1, + pressed_keys={Key.BACK, Key.L1}, + ), + Keyboard.keycodes['2']: KeypadKeyPressAction( + key=Key.L2, + pressed_keys={Key.BACK, Key.L2}, + ), + Keyboard.keycodes['3']: KeypadKeyPressAction( + key=Key.L3, + pressed_keys={Key.BACK, Key.L3}, + ), + Keyboard.keycodes['backspace']: KeypadKeyPressAction( + key=Key.HOME, + pressed_keys={Key.BACK, Key.HOME}, + ), + }, + 'shift': { + Keyboard.keycodes['up']: KeypadKeyPressAction( + key=Key.UP, + pressed_keys={Key.HOME, Key.UP}, + ), + Keyboard.keycodes['k']: KeypadKeyPressAction( + key=Key.UP, + pressed_keys={Key.HOME, Key.UP}, + ), + Keyboard.keycodes['down']: KeypadKeyPressAction( + key=Key.DOWN, + pressed_keys={Key.HOME, Key.DOWN}, + ), + Keyboard.keycodes['j']: KeypadKeyPressAction( + key=Key.DOWN, + pressed_keys={Key.HOME, Key.DOWN}, + ), + Keyboard.keycodes['1']: KeypadKeyPressAction( key=Key.L1, pressed_keys={Key.HOME, Key.L1}, ), - Keyboard.keycodes['s']: KeypadKeyPressAction( + Keyboard.keycodes['2']: KeypadKeyPressAction( key=Key.L2, pressed_keys={Key.HOME, Key.L2}, ), - Keyboard.keycodes['r']: KeypadKeyPressAction( + Keyboard.keycodes['3']: KeypadKeyPressAction( key=Key.L3, pressed_keys={Key.HOME, Key.L3}, ), - Keyboard.keycodes['q']: KeypadKeyPressAction( + Keyboard.keycodes['left']: KeypadKeyPressAction( key=Key.BACK, pressed_keys={Key.HOME, Key.BACK}, ), - }, - 'ctrl': { - Keyboard.keycodes['r']: KeypadKeyPressAction( - key=Key.L3, - pressed_keys={Key.BACK, Key.L3}, + Keyboard.keycodes['escape']: KeypadKeyPressAction( + key=Key.BACK, + pressed_keys={Key.HOME, Key.BACK}, + ), + Keyboard.keycodes['h']: KeypadKeyPressAction( + key=Key.BACK, + pressed_keys={Key.HOME, Key.BACK}, ), }, } @@ -93,6 +147,8 @@ def on_keyboard( store.dispatch(KEY_MAP['no_modifier'][key]) elif modifier == ['ctrl'] and key in KEY_MAP['ctrl']: store.dispatch(KEY_MAP['ctrl'][key]) + elif modifier == ['shift'] and key in KEY_MAP['shift']: + store.dispatch(KEY_MAP['shift'][key]) def init_service() -> None: diff --git a/ubo_app/services/030-ethernet/setup.py b/ubo_app/services/030-ethernet/setup.py index 08b2c105..368fcce5 100644 --- a/ubo_app/services/030-ethernet/setup.py +++ b/ubo_app/services/030-ethernet/setup.py @@ -7,7 +7,7 @@ from ubo_app.store.main import store from ubo_app.store.services.ethernet import NetState -from ubo_app.store.status_icons import StatusIconsRegisterAction +from ubo_app.store.status_icons.types import StatusIconsRegisterAction from ubo_app.utils.async_ import create_task diff --git a/ubo_app/services/030-ip/setup.py b/ubo_app/services/030-ip/setup.py index d80d132b..5876a865 100644 --- a/ubo_app/services/030-ip/setup.py +++ b/ubo_app/services/030-ip/setup.py @@ -11,7 +11,7 @@ from ubo_gui.constants import DANGER_COLOR from ubo_gui.menu.types import HeadlessMenu, Item, SubMenuItem -from ubo_app.store.core import RegisterSettingAppAction, SettingsCategory +from ubo_app.store.core.types import RegisterSettingAppAction, SettingsCategory from ubo_app.store.main import store from ubo_app.store.services.ethernet import NetState from ubo_app.store.services.ip import ( @@ -19,7 +19,7 @@ IpSetIsConnectedAction, IpUpdateInterfacesAction, ) -from ubo_app.store.status_icons import StatusIconsRegisterAction +from ubo_app.store.status_icons.types import StatusIconsRegisterAction from ubo_app.utils.server import send_command if TYPE_CHECKING: diff --git a/ubo_app/services/030-wifi/pages/create_wireless_connection.py b/ubo_app/services/030-wifi/pages/create_wireless_connection.py index 5248afaf..50559b47 100644 --- a/ubo_app/services/030-wifi/pages/create_wireless_connection.py +++ b/ubo_app/services/030-wifi/pages/create_wireless_connection.py @@ -13,9 +13,9 @@ from wifi_manager import add_wireless_connection from ubo_app.logging import logger -from ubo_app.store.core import CloseApplicationAction +from ubo_app.store.core.types import CloseApplicationAction +from ubo_app.store.input.types import InputFieldDescription, InputFieldType from ubo_app.store.main import store -from ubo_app.store.operations import InputFieldDescription, InputFieldType from ubo_app.store.services.notifications import ( Chime, Notification, diff --git a/ubo_app/services/030-wifi/pages/main.py b/ubo_app/services/030-wifi/pages/main.py index eedae63c..351567de 100644 --- a/ubo_app/services/030-wifi/pages/main.py +++ b/ubo_app/services/030-wifi/pages/main.py @@ -23,7 +23,7 @@ get_wifi_device, ) -from ubo_app.store.core import CloseApplicationAction +from ubo_app.store.core.types import CloseApplicationAction from ubo_app.store.main import store from ubo_app.store.services.wifi import ( ConnectionState, diff --git a/ubo_app/services/030-wifi/reducer.py b/ubo_app/services/030-wifi/reducer.py index 6765802c..e8881653 100644 --- a/ubo_app/services/030-wifi/reducer.py +++ b/ubo_app/services/030-wifi/reducer.py @@ -22,7 +22,7 @@ WiFiUpdateRequestAction, WiFiUpdateRequestEvent, ) -from ubo_app.store.status_icons import StatusIconsRegisterAction +from ubo_app.store.status_icons.types import StatusIconsRegisterAction def reducer( diff --git a/ubo_app/services/030-wifi/setup.py b/ubo_app/services/030-wifi/setup.py index 89e3f5e7..124da1a3 100644 --- a/ubo_app/services/030-wifi/setup.py +++ b/ubo_app/services/030-wifi/setup.py @@ -13,7 +13,7 @@ ) from ubo_app.logging import logger -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( RegisterSettingAppAction, SettingsCategory, ) diff --git a/ubo_app/services/040-camera/reducer.py b/ubo_app/services/040-camera/reducer.py index 5a7714dd..86b1f450 100644 --- a/ubo_app/services/040-camera/reducer.py +++ b/ubo_app/services/040-camera/reducer.py @@ -12,7 +12,7 @@ ReducerResult, ) -from ubo_app.store.operations import ( +from ubo_app.store.input.types import ( InputCancelAction, InputDemandAction, InputProvideAction, diff --git a/ubo_app/services/040-camera/setup.py b/ubo_app/services/040-camera/setup.py index 7713a378..25d77fb0 100644 --- a/ubo_app/services/040-camera/setup.py +++ b/ubo_app/services/040-camera/setup.py @@ -15,7 +15,7 @@ from typing_extensions import override from ubo_gui.page import PageWidget -from ubo_app.store.core import CloseApplicationAction, OpenApplicationAction +from ubo_app.store.core.types import CloseApplicationAction, OpenApplicationAction from ubo_app.store.main import store from ubo_app.store.services.camera import ( CameraReportBarcodeAction, diff --git a/ubo_app/services/050-lightdm/setup.py b/ubo_app/services/050-lightdm/setup.py index 65b151ef..6109f0f2 100644 --- a/ubo_app/services/050-lightdm/setup.py +++ b/ubo_app/services/050-lightdm/setup.py @@ -8,7 +8,7 @@ from ubo_gui.constants import DANGER_COLOR from ubo_gui.menu.types import ActionItem, HeadedMenu, HeadlessMenu, Item, Menu -from ubo_app.store.core import RegisterSettingAppAction, SettingsCategory +from ubo_app.store.core.types import RegisterSettingAppAction, SettingsCategory from ubo_app.store.main import store from ubo_app.store.services.lightdm import ( LightDMClearEnabledStateAction, @@ -187,7 +187,7 @@ def init_service() -> None: store.dispatch( RegisterSettingAppAction( priority=0, - category=SettingsCategory.OS, + category=SettingsCategory.SYSTEM, menu_item=ActionItem( label='Desktop', icon=lightdm_icon, diff --git a/ubo_app/services/050-rpi-connect/setup.py b/ubo_app/services/050-rpi-connect/setup.py index 19c09273..57211e36 100644 --- a/ubo_app/services/050-rpi-connect/setup.py +++ b/ubo_app/services/050-rpi-connect/setup.py @@ -18,7 +18,7 @@ from ubo_gui.menu.types import ActionItem, ApplicationItem, HeadedMenu from ubo_gui.page import PageWidget -from ubo_app.store.core import RegisterSettingAppAction, SettingsCategory +from ubo_app.store.core.types import RegisterSettingAppAction, SettingsCategory from ubo_app.store.main import store from ubo_app.utils.async_ import create_task diff --git a/ubo_app/services/050-rpi-connect/sign_in_page.py b/ubo_app/services/050-rpi-connect/sign_in_page.py index d7542ea5..12777872 100644 --- a/ubo_app/services/050-rpi-connect/sign_in_page.py +++ b/ubo_app/services/050-rpi-connect/sign_in_page.py @@ -14,7 +14,7 @@ from ubo_gui.page import PageWidget from ubo_app.logging import logger -from ubo_app.store.core import CloseApplicationAction +from ubo_app.store.core.types import CloseApplicationAction from ubo_app.store.main import store from ubo_app.store.services.notifications import ( Chime, diff --git a/ubo_app/services/050-ssh/setup.py b/ubo_app/services/050-ssh/setup.py index 406c4840..2e8a74e1 100644 --- a/ubo_app/services/050-ssh/setup.py +++ b/ubo_app/services/050-ssh/setup.py @@ -7,7 +7,7 @@ from ubo_gui.menu.types import ActionItem, HeadlessMenu, Item, Menu -from ubo_app.store.core import RegisterSettingAppAction, SettingsCategory +from ubo_app.store.core.types import RegisterSettingAppAction, SettingsCategory from ubo_app.store.main import store from ubo_app.store.services.ssh import SSHClearEnabledStateAction, SSHUpdateStateAction from ubo_app.utils.async_ import create_task diff --git a/ubo_app/services/050-users/setup.py b/ubo_app/services/050-users/setup.py index dfd65522..8c774ecd 100644 --- a/ubo_app/services/050-users/setup.py +++ b/ubo_app/services/050-users/setup.py @@ -22,7 +22,7 @@ ) from ubo_app.logging import logger -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( RegisterSettingAppAction, SettingsCategory, ) @@ -284,7 +284,7 @@ async def init_service() -> None: store.dispatch( RegisterSettingAppAction( priority=1, - category=SettingsCategory.OS, + category=SettingsCategory.SYSTEM, menu_item=SubMenuItem( label='Users', icon='󰡉', diff --git a/ubo_app/services/050-vscode/login_page.py b/ubo_app/services/050-vscode/login_page.py index 6342f0f6..96999295 100644 --- a/ubo_app/services/050-vscode/login_page.py +++ b/ubo_app/services/050-vscode/login_page.py @@ -15,7 +15,7 @@ from ubo_gui.page import PageWidget from ubo_app.logging import logger -from ubo_app.store.core import CloseApplicationAction +from ubo_app.store.core.types import CloseApplicationAction from ubo_app.store.main import store from ubo_app.store.services.notifications import ( Chime, diff --git a/ubo_app/services/050-vscode/setup.py b/ubo_app/services/050-vscode/setup.py index 7458b620..0755fbf0 100644 --- a/ubo_app/services/050-vscode/setup.py +++ b/ubo_app/services/050-vscode/setup.py @@ -17,7 +17,7 @@ from ubo_gui.page import PageWidget from ubo_app.constants import INSTALLATION_PATH -from ubo_app.store.core import RegisterSettingAppAction, SettingsCategory +from ubo_app.store.core.types import RegisterSettingAppAction, SettingsCategory from ubo_app.store.main import store from ubo_app.store.services.notifications import ( Chime, @@ -183,7 +183,7 @@ def vscode_menu(state: VSCodeState) -> HeadedMenu: status = '' if state.is_pending: - status = '[size=48dp]󰔟[/size]' + status = '[size=48dp][/size]' elif state.status: if state.status.is_running: if state.status.name: diff --git a/ubo_app/services/080-docker/setup.py b/ubo_app/services/080-docker/setup.py index 9fb7640e..ec4c907b 100644 --- a/ubo_app/services/080-docker/setup.py +++ b/ubo_app/services/080-docker/setup.py @@ -17,13 +17,13 @@ from ubo_gui.menu.types import ActionItem, HeadedMenu, Item, SubMenuItem from ubo_app.constants import DOCKER_CREDENTIALS_TEMPLATE -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( RegisterRegularAppAction, RegisterSettingAppAction, SettingsCategory, ) +from ubo_app.store.input.types import InputFieldDescription, InputFieldType from ubo_app.store.main import store -from ubo_app.store.operations import InputFieldDescription, InputFieldType from ubo_app.store.services.docker import ( DockerImageRegisterAppEvent, DockerRemoveUsernameAction, diff --git a/ubo_app/services/090-web-ui/reducer.py b/ubo_app/services/090-web-ui/reducer.py index ae369b59..46f3fcff 100644 --- a/ubo_app/services/090-web-ui/reducer.py +++ b/ubo_app/services/090-web-ui/reducer.py @@ -6,7 +6,7 @@ from redux import InitAction, InitializationActionError -from ubo_app.store.operations import ( +from ubo_app.store.input.types import ( InputAction, InputDemandAction, InputResolveAction, diff --git a/ubo_app/services/090-web-ui/setup.py b/ubo_app/services/090-web-ui/setup.py index 3a6c5d43..53edd631 100644 --- a/ubo_app/services/090-web-ui/setup.py +++ b/ubo_app/services/090-web-ui/setup.py @@ -8,12 +8,12 @@ from redux import FinishEvent from ubo_app.constants import WEB_UI_DEBUG_MODE, WEB_UI_LISTEN_HOST, WEB_UI_LISTEN_PORT -from ubo_app.store.main import store -from ubo_app.store.operations import ( +from ubo_app.store.input.types import ( InputCancelAction, InputDescription, InputProvideAction, ) +from ubo_app.store.main import store async def init_service() -> None: diff --git a/ubo_app/side_effects.py b/ubo_app/side_effects.py index 931ce63c..b7aa2b68 100644 --- a/ubo_app/side_effects.py +++ b/ubo_app/side_effects.py @@ -11,7 +11,7 @@ from redux import FinishAction, FinishEvent from ubo_app import display -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( PowerOffEvent, RebootEvent, ReplayRecordedSequenceEvent, @@ -22,7 +22,7 @@ from ubo_app.store.main import store from ubo_app.store.services.audio import AudioPlayChimeAction from ubo_app.store.services.notifications import Chime -from ubo_app.store.update_manager import ( +from ubo_app.store.update_manager.types import ( UpdateManagerCheckEvent, UpdateManagerSetStatusAction, UpdateManagerUpdateEvent, diff --git a/ubo_app/store/core/_menus.py b/ubo_app/store/core/menus.py similarity index 75% rename from ubo_app/store/core/_menus.py rename to ubo_app/store/core/menus.py index b0f01648..3eb9a212 100644 --- a/ubo_app/store/core/_menus.py +++ b/ubo_app/store/core/menus.py @@ -1,5 +1,8 @@ +"""Menu definitions for the Ubo GUI.""" + from __future__ import annotations +import math import socket from datetime import UTC, datetime from typing import TYPE_CHECKING @@ -11,7 +14,7 @@ SubMenuItem, ) -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( SETTINGS_ICONS, PowerOffAction, RebootAction, @@ -23,6 +26,7 @@ Notification, NotificationsDisplayAction, ) +from ubo_app.store.settings.types import SettingsToggleDebugModeAction from ubo_app.store.update_manager.utils import ( BASE_IMAGE, CURRENT_VERSION, @@ -41,6 +45,36 @@ placeholder='No apps', ) + +@store.autorun(lambda state: state.settings.is_debug_enabled) +def _debug_icon(is_debug_eanbled: bool) -> str: # noqa: FBT001 + return '󰱒' if is_debug_eanbled else '󰄱' + + +SETTINGS_ITEMS: dict[SettingsCategory, list[Item]] = { + SettingsCategory.NETWORK: [], + SettingsCategory.REMOTE: [], + SettingsCategory.SYSTEM: [ + SubMenuItem( + key='general', + label='General', + icon='󰒓', + sub_menu=HeadlessMenu( + title='󰒓General', + items=[ + DispatchItem( + label='Debug', + store_action=SettingsToggleDebugModeAction(), + icon=_debug_icon, + ), + ], + ), + ), + ], + SettingsCategory.SPEECH: [], + SettingsCategory.DOCKER: [], +} + SETTINGS_MENU = HeadlessMenu( title='Settings', items=[ @@ -50,7 +84,7 @@ icon=SETTINGS_ICONS[category], sub_menu=HeadlessMenu( title=SETTINGS_ICONS[category] + category, - items=[], + items=SETTINGS_ITEMS[category], placeholder='No settings in this category', ), ) @@ -93,7 +127,7 @@ lambda state: state.notifications.unread_count, options=AutorunOptions(default_value='Notifications (not loaded)'), ) -def notifications_title(unread_count: int) -> str: +def _notifications_title(unread_count: int) -> str: return f'Notifications ({unread_count})' @@ -115,7 +149,9 @@ def notifications_menu_items(notifications: Sequence[Notification]) -> list[Item index=index, count=len(notifications), ), - progress=notification.progress, + progress=None + if notification.progress is None or math.isnan(notification.progress) + else notification.progress, ) for index, notification in enumerate(notifications) if notification.expiration_timestamp is None @@ -127,7 +163,7 @@ def notifications_menu_items(notifications: Sequence[Notification]) -> list[Item lambda state: len(state.notifications.notifications), options=AutorunOptions(default_value='white'), ) -def notifications_color(unread_count: int) -> str: +def _notifications_color(unread_count: int) -> str: return 'yellow' if unread_count > 0 else 'white' @@ -145,11 +181,11 @@ def notifications_color(unread_count: int) -> str: key='notifications', label='', sub_menu=HeadlessMenu( - title=notifications_title, + title=_notifications_title, items=notifications_menu_items, placeholder='No notifications', ), - color=notifications_color, + color=_notifications_color, icon='', is_short=True, ), diff --git a/ubo_app/store/core/reducer.py b/ubo_app/store/core/reducer.py index f0458ffd..d2a72ed2 100644 --- a/ubo_app/store/core/reducer.py +++ b/ubo_app/store/core/reducer.py @@ -1,6 +1,7 @@ # ruff: noqa: D100, D101, D102, D103, D104, D107 from __future__ import annotations +import math from collections.abc import Sequence from dataclasses import replace from typing import cast @@ -13,7 +14,7 @@ ReducerResult, ) -from ubo_app.store.core import ( +from ubo_app.store.core.types import ( CloseApplicationAction, CloseApplicationEvent, InitEvent, @@ -44,6 +45,7 @@ RegisterSettingAppAction, ReplayRecordedSequenceEvent, ScreenshotEvent, + SetAreEnclosuresVisibleAction, SetMenuPathAction, SnapshotEvent, StoreRecordedSequenceEvent, @@ -54,6 +56,7 @@ KeypadKeyPressAction, KeypadKeyReleaseAction, ) +from ubo_app.store.services.notifications import Notification, NotificationsAddAction def reducer( @@ -61,14 +64,14 @@ def reducer( action: MainAction, ) -> ReducerResult[ MainState, - AudioChangeVolumeAction, + AudioChangeVolumeAction | NotificationsAddAction, InitEvent | MenuEvent | FinishEvent | MainEvent, ]: from ubo_gui.menu.types import Item, Menu, SubMenuItem, menu_items if state is None: if isinstance(action, InitAction): - from ._menus import HOME_MENU + from .menus import HOME_MENU return CompleteReducerResult( state=MainState(menu=HOME_MENU), @@ -216,6 +219,36 @@ def reducer( state=state, events=[FinishEvent()], ) + + # DEMO { + if action.pressed_keys == {Key.HOME, Key.UP} and action.key == Key.UP: + return CompleteReducerResult( + state=state, + actions=[ + NotificationsAddAction( + notification=Notification( + title='Test notification with progress', + content='This is a test notification with progress', + progress=0.5, + ), + ), + ], + ) + if action.pressed_keys == {Key.HOME, Key.DOWN} and action.key == Key.DOWN: + return CompleteReducerResult( + state=state, + actions=[ + NotificationsAddAction( + notification=Notification( + icon='', + title='Test notification with spinner', + content='This is a test notification with spinner', + progress=math.nan, + ), + ), + ], + ) + # DEMO } return state if isinstance(action, KeypadKeyReleaseAction): @@ -409,6 +442,13 @@ def sort_key(item: Item) -> tuple[int, str]: if isinstance(action, SetMenuPathAction): return replace(state, path=action.path, depth=action.depth) + if isinstance(action, SetAreEnclosuresVisibleAction): + return replace( + state, + is_header_visible=action.is_header_visible, + is_footer_visible=action.is_footer_visible, + ) + if isinstance(action, PowerOffAction): return CompleteReducerResult( state=state, diff --git a/ubo_app/store/core/__init__.py b/ubo_app/store/core/types.py similarity index 93% rename from ubo_app/store/core/__init__.py rename to ubo_app/store/core/types.py index 13042e09..4b773e44 100644 --- a/ubo_app/store/core/__init__.py +++ b/ubo_app/store/core/types.py @@ -12,7 +12,7 @@ class SettingsCategory(StrEnum): NETWORK = 'Network' REMOTE = 'Remote' - OS = 'OS' + SYSTEM = 'System' SPEECH = 'Speech' DOCKER = 'Docker' @@ -25,7 +25,7 @@ class MenuScrollDirection(StrEnum): SETTINGS_ICONS = { SettingsCategory.NETWORK: '󰛳', SettingsCategory.REMOTE: '󰑔', - SettingsCategory.OS: '󰕈', + SettingsCategory.SYSTEM: '󰒔', SettingsCategory.SPEECH: '󰔊', SettingsCategory.DOCKER: '󰡨', } @@ -80,6 +80,11 @@ class SetMenuPathAction(MainAction): depth: int +class SetAreEnclosuresVisibleAction(MainAction): + is_header_visible: bool = True + is_footer_visible: bool = True + + class MenuAction(MainAction): ... @@ -183,6 +188,8 @@ class MainState(Immutable): menu: Menu | None = None path: Sequence[str] = field(default_factory=list) depth: int = 0 + is_header_visible: bool = True + is_footer_visible: bool = True settings_items_priorities: dict[str, int] = field(default_factory=dict) is_recording: bool = False recorded_sequence: list[BaseAction] = field(default_factory=list) diff --git a/ubo_app/store/input/reducer.py b/ubo_app/store/input/reducer.py index 126484e4..8fb6f2ae 100644 --- a/ubo_app/store/input/reducer.py +++ b/ubo_app/store/input/reducer.py @@ -4,7 +4,7 @@ from redux import CompleteReducerResult, ReducerResult -from ubo_app.store.operations import ( +from .types import ( InputAction, InputCancelAction, InputCancelEvent, diff --git a/ubo_app/store/operations.py b/ubo_app/store/input/types.py similarity index 99% rename from ubo_app/store/operations.py rename to ubo_app/store/input/types.py index 939779a7..10868305 100644 --- a/ubo_app/store/operations.py +++ b/ubo_app/store/input/types.py @@ -94,3 +94,4 @@ class InputProvideEvent(InputResolveEvent): value: str data: dict[str, str | None] | None + diff --git a/ubo_app/store/main.py b/ubo_app/store/main.py index 9bed5a68..8c037f4f 100644 --- a/ubo_app/store/main.py +++ b/ubo_app/store/main.py @@ -27,10 +27,10 @@ from ubo_app.constants import DEBUG_MODE, STORE_GRACE_PERIOD from ubo_app.logging import logger -from ubo_app.store.core import MainAction, MainEvent from ubo_app.store.core.reducer import reducer as main_reducer +from ubo_app.store.core.types import MainAction, MainEvent from ubo_app.store.input.reducer import reducer as input_reducer -from ubo_app.store.operations import ( +from ubo_app.store.input.types import ( InputAction, InputResolveEvent, ) @@ -53,10 +53,12 @@ from ubo_app.store.services.voice import VoiceAction from ubo_app.store.services.vscode import VSCodeAction from ubo_app.store.services.wifi import WiFiAction, WiFiEvent -from ubo_app.store.status_icons import StatusIconsAction +from ubo_app.store.settings.reducer import reducer as settings_reducer +from ubo_app.store.settings.types import SettingsAction, SettingsState from ubo_app.store.status_icons.reducer import reducer as status_icons_reducer -from ubo_app.store.update_manager import UpdateManagerAction +from ubo_app.store.status_icons.types import StatusIconsAction from ubo_app.store.update_manager.reducer import reducer as update_manager_reducer +from ubo_app.store.update_manager.types import UpdateManagerAction from ubo_app.utils.serializer import add_type_field if TYPE_CHECKING: @@ -64,7 +66,7 @@ from redux.basic_types import SnapshotAtom, TaskCreatorCallback - from ubo_app.store.core import MainState + from ubo_app.store.core.types import MainState from ubo_app.store.services.audio import AudioState from ubo_app.store.services.camera import CameraState from ubo_app.store.services.display import DisplayState @@ -81,18 +83,19 @@ from ubo_app.store.services.vscode import VSCodeState from ubo_app.store.services.web_ui import WebUIState from ubo_app.store.services.wifi import WiFiState - from ubo_app.store.status_icons import StatusIconsState - from ubo_app.store.update_manager import UpdateManagerState + from ubo_app.store.status_icons.types import StatusIconsState + from ubo_app.store.update_manager.types import UpdateManagerState UboAction: TypeAlias = ( # Core Actions CombineReducerAction + | InitAction + | FinishAction + | MainAction + | SettingsAction | StatusIconsAction | UpdateManagerAction - | MainAction | InputAction - | InitAction - | FinishAction # Services Actions | AudioAction | CameraAction @@ -142,6 +145,7 @@ def scheduler(callback: Callable[[], None], *, interval: bool) -> None: class RootState(BaseCombineReducerState): main: MainState + settings: SettingsState status_icons: StatusIconsState update_manager: UpdateManagerState @@ -168,6 +172,7 @@ class RootState(BaseCombineReducerState): action_type=UboAction, # pyright: ignore [reportArgumentType] event_type=UboEvent, # pyright: ignore [reportArgumentType] main=main_reducer, + settings=settings_reducer, status_icons=status_icons_reducer, update_manager=update_manager_reducer, input=input_reducer, diff --git a/ubo_app/store/services/camera.py b/ubo_app/store/services/camera.py index 167618bb..53b2faa9 100644 --- a/ubo_app/store/services/camera.py +++ b/ubo_app/store/services/camera.py @@ -7,7 +7,7 @@ from redux import BaseAction, BaseEvent if TYPE_CHECKING: - from ubo_app.store.operations import InputDescription + from ubo_app.store.input.types import InputDescription class CameraAction(BaseAction): ... diff --git a/ubo_app/store/services/display.py b/ubo_app/store/services/display.py index 420e8cb8..5d81035f 100644 --- a/ubo_app/store/services/display.py +++ b/ubo_app/store/services/display.py @@ -19,13 +19,11 @@ class DisplayResumeAction(DisplayAction): ... class DisplayRenderEvent(DisplayEvent): data: bytes - data_hash: int rectangle: tuple[int, int, int, int] class DisplayCompressedRenderEvent(DisplayEvent): compressed_data: bytes - data_hash: int rectangle: tuple[int, int, int, int] diff --git a/ubo_app/store/services/web_ui.py b/ubo_app/store/services/web_ui.py index ac3dff71..3e38dbb2 100644 --- a/ubo_app/store/services/web_ui.py +++ b/ubo_app/store/services/web_ui.py @@ -6,7 +6,7 @@ from immutable import Immutable if TYPE_CHECKING: - from ubo_app.store.operations import InputDescription + from ubo_app.store.input.types import InputDescription class WebUIState(Immutable): diff --git a/ubo_app/store/settings/reducer.py b/ubo_app/store/settings/reducer.py new file mode 100644 index 00000000..fef3cc33 --- /dev/null +++ b/ubo_app/store/settings/reducer.py @@ -0,0 +1,40 @@ +"""Reducer for the settings state.""" + +from __future__ import annotations + +from dataclasses import replace + +from redux import ( + CompleteReducerResult, + InitAction, + InitializationActionError, + ReducerResult, +) + +from ubo_app.store.settings.types import ( + SettingsAction, + SettingsEvent, + SettingsSetDebugModeEvent, + SettingsState, + SettingsToggleDebugModeAction, +) + + +def reducer( + state: SettingsState | None, + action: SettingsAction | InitAction, +) -> ReducerResult[SettingsState, None, SettingsEvent]: + """Reducer for the settings state.""" + if state is None: + if isinstance(action, InitAction): + return SettingsState() + + raise InitializationActionError(action) + + if isinstance(action, SettingsToggleDebugModeAction): + return CompleteReducerResult( + state=replace(state, is_debug_enabled=not state.is_debug_enabled), + events=[SettingsSetDebugModeEvent(is_enabled=not state.is_debug_enabled)], + ) + + return state diff --git a/ubo_app/store/settings/types.py b/ubo_app/store/settings/types.py new file mode 100644 index 00000000..4968cfd5 --- /dev/null +++ b/ubo_app/store/settings/types.py @@ -0,0 +1,30 @@ +"""Settings state module.""" + +from __future__ import annotations + +from immutable import Immutable +from redux import BaseAction, BaseEvent + + +class SettingsAction(BaseAction): + """Settings action.""" + + +class SettingsToggleDebugModeAction(SettingsAction): + """Toggle debug mode action.""" + + +class SettingsEvent(BaseEvent): + """Settings event.""" + + +class SettingsSetDebugModeEvent(SettingsEvent): + """Set debug mode event.""" + + is_enabled: bool + + +class SettingsState(Immutable): + """Settings state.""" + + is_debug_enabled: bool = False diff --git a/ubo_app/store/status_icons/reducer.py b/ubo_app/store/status_icons/reducer.py index 74d8870a..605f4300 100644 --- a/ubo_app/store/status_icons/reducer.py +++ b/ubo_app/store/status_icons/reducer.py @@ -5,7 +5,7 @@ from redux import InitAction, InitializationActionError -from ubo_app.store.status_icons import ( +from ubo_app.store.status_icons.types import ( IconState, StatusIconsAction, StatusIconsRegisterAction, diff --git a/ubo_app/store/status_icons/__init__.py b/ubo_app/store/status_icons/types.py similarity index 100% rename from ubo_app/store/status_icons/__init__.py rename to ubo_app/store/status_icons/types.py diff --git a/ubo_app/store/update_manager/reducer.py b/ubo_app/store/update_manager/reducer.py index 55c3aace..34470514 100644 --- a/ubo_app/store/update_manager/reducer.py +++ b/ubo_app/store/update_manager/reducer.py @@ -20,7 +20,7 @@ NotificationsAction, NotificationsAddAction, ) -from ubo_app.store.update_manager import ( +from ubo_app.store.update_manager.types import ( UPDATE_MANAGER_NOTIFICATION_ID, UpdateManagerAction, UpdateManagerCheckEvent, diff --git a/ubo_app/store/update_manager/__init__.py b/ubo_app/store/update_manager/types.py similarity index 100% rename from ubo_app/store/update_manager/__init__.py rename to ubo_app/store/update_manager/types.py diff --git a/ubo_app/store/update_manager/utils.py b/ubo_app/store/update_manager/utils.py index 1f352789..f790860e 100644 --- a/ubo_app/store/update_manager/utils.py +++ b/ubo_app/store/update_manager/utils.py @@ -6,7 +6,6 @@ import importlib.metadata import shutil import subprocess -import time from pathlib import Path import aiohttp @@ -14,6 +13,7 @@ from kivy.clock import Clock from redux import FinishEvent from ubo_gui.constants import DANGER_COLOR, INFO_COLOR, SUCCESS_COLOR +from ubo_gui.menu.menu_widget import math from ubo_gui.menu.types import Item from ubo_app.constants import ( @@ -23,7 +23,7 @@ UPDATE_LOCK_PATH, ) from ubo_app.logging import logger -from ubo_app.store.core import RebootAction +from ubo_app.store.core.types import RebootAction from ubo_app.store.dispatch_action import DispatchItem from ubo_app.store.main import store from ubo_app.store.services.notifications import ( @@ -36,7 +36,7 @@ NotificationsAddAction, NotificationsClearByIdAction, ) -from ubo_app.store.update_manager import ( +from ubo_app.store.update_manager.types import ( UPDATE_MANAGER_NOTIFICATION_ID, UPDATE_MANAGER_SECOND_PHASE_NOTIFICATION_ID, UpdateManagerSetStatusAction, @@ -184,7 +184,7 @@ async def download_files() -> None: UPDATE_ASSETS_PATH, 'setuptools', 'wheel', - 'ubo-app[default]', + 'ubo-app', stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) @@ -353,14 +353,14 @@ def dispatch_notification(is_presented: bool, _: float = 0) -> None: # noqa: FB Please keep the device powered on. This may take around 20 minutes to complete.""", importance=Importance.LOW, - icon='󰚰', + 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, + progress=math.nan, blink=not is_presented, ), ), diff --git a/ubo_app/system/install.sh b/ubo_app/system/install.sh index 83b91e90..2d59fa5d 100755 --- a/ubo_app/system/install.sh +++ b/ubo_app/system/install.sh @@ -111,16 +111,16 @@ virtualenv --system-site-packages "$INSTALLATION_PATH/env" # Install the latest version of ubo-app if [ "$UPDATE" = true ]; then if [ "$ALPHA" = true ]; then - "$INSTALLATION_PATH/env/bin/python" -m pip install --pre --no-index --upgrade --find-links "$INSTALLATION_PATH/_update/" "$SOURCE"[default] + "$INSTALLATION_PATH/env/bin/python" -m pip install --pre --no-index --upgrade --find-links "$INSTALLATION_PATH/_update/" "$SOURCE" else - "$INSTALLATION_PATH/env/bin/python" -m pip install --no-index --upgrade --find-links "$INSTALLATION_PATH/_update/" "$SOURCE"[default] + "$INSTALLATION_PATH/env/bin/python" -m pip install --no-index --upgrade --find-links "$INSTALLATION_PATH/_update/" "$SOURCE" fi else if [ "$ALPHA" = true ]; then - "$INSTALLATION_PATH/env/bin/python" -m pip install --pre "$SOURCE"[default] | grep -c '^Collecting ' > $INSTALLATION_PATH/.packages-count + "$INSTALLATION_PATH/env/bin/python" -m pip install --pre "$SOURCE" | grep -c '^Collecting ' > $INSTALLATION_PATH/.packages-count else # Count number of Collecting instances - "$INSTALLATION_PATH/env/bin/python" -m pip install "$SOURCE"[default] | grep -c '^Collecting ' > $INSTALLATION_PATH/.packages-count + "$INSTALLATION_PATH/env/bin/python" -m pip install "$SOURCE" | grep -c '^Collecting ' > $INSTALLATION_PATH/.packages-count fi fi diff --git a/ubo_app/utils/bus_provider.py b/ubo_app/utils/bus_provider.py index 9d493930..e30bd27a 100644 --- a/ubo_app/utils/bus_provider.py +++ b/ubo_app/utils/bus_provider.py @@ -3,17 +3,13 @@ from __future__ import annotations -from threading import current_thread -from typing import TYPE_CHECKING +from threading import Thread, current_thread from redux import FinishEvent from sdbus import SdBus, sd_bus_open_system, sd_bus_open_user, set_default_bus from ubo_app.store.main import store -if TYPE_CHECKING: - from headless_kivy.config import Thread - system_buses: dict[Thread, SdBus] = {} user_buses: dict[Thread, SdBus] = {} diff --git a/ubo_app/utils/input.py b/ubo_app/utils/input.py index 2bf00ad6..e60fc4a1 100644 --- a/ubo_app/utils/input.py +++ b/ubo_app/utils/input.py @@ -9,14 +9,14 @@ from typing_extensions import TypeVar -from ubo_app.store.main import store -from ubo_app.store.operations import ( +from ubo_app.store.input.types import ( InputCancelEvent, InputDemandAction, InputDescription, InputFieldDescription, InputProvideEvent, ) +from ubo_app.store.main import store from ubo_app.store.services.camera import CameraStopViewfinderEvent from ubo_app.store.services.rgb_ring import RgbRingBlinkAction diff --git a/ubo_app/utils/server.py b/ubo_app/utils/server.py index 626f06dd..12b25a76 100644 --- a/ubo_app/utils/server.py +++ b/ubo_app/utils/server.py @@ -24,7 +24,7 @@ async def send_command(*command_: str, has_output: bool = False) -> str | None: try: reader, writer = await asyncio.open_unix_connection(SERVER_SOCKET_PATH) - logger.info('Sending command:', extra={'command': command}) + logger.debug('Sending command:', extra={'command': command}) response = None writer.write(command.encode() + b'\0') @@ -32,7 +32,7 @@ async def send_command(*command_: str, has_output: bool = False) -> str | None: datagram = (await reader.readuntil(b'\0'))[:-1] if datagram: response = datagram.decode('utf-8') - logger.info('Server response:', extra={'response': response}) + logger.debug('Server response:', extra={'response': response}) writer.close() except Exception: diff --git a/uv.lock b/uv.lock index 4eb503a2..4dd62bfc 100644 --- a/uv.lock +++ b/uv.lock @@ -761,17 +761,16 @@ wheels = [ [[package]] name = "headless-kivy" -version = "0.9.8" +version = "0.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "kivy" }, { name = "numpy" }, { name = "python-strtobool" }, - { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/8d/4eeeef63a59b788be235e553ccc84626e9174582a5d970b787fbdabfcd96/headless_kivy-0.9.8.tar.gz", hash = "sha256:deae8fd400cca370f285aaaa1499011f9129d943aa2cf6feb04820e30d006c9c", size = 14617 } +sdist = { url = "https://files.pythonhosted.org/packages/a8/8a/8a6ad4efc4aa717868da1ca23cbe73b133d760fbeff595ab891da5f81c1b/headless_kivy-0.12.1.tar.gz", hash = "sha256:f8ca69235d28098d28037d76a6a46b128240a5cedb44ed233550035a9cd0b807", size = 16286 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/fd/24597fc9cf25ca27994a1cf536ba468b6e84b3243e25d7332bfb3cf8a07e/headless_kivy-0.9.8-py3-none-any.whl", hash = "sha256:a08eaa488ca16bbe37bc40d65f2074972c646f7d30540f8cff17a58885a3ec48", size = 15855 }, + { url = "https://files.pythonhosted.org/packages/ec/bd/bac2f7fa173aed21aa14328b23acc528b7e5e63345a8513483d8a03fffc4/headless_kivy-0.12.1-py3-none-any.whl", hash = "sha256:89a78367b003a591ec94c619b1a8dd37dc9dead1ae80618a3b6e8e8f1bb994af", size = 19932 }, ] [package.optional-dependencies] @@ -1645,16 +1644,14 @@ wheels = [ [[package]] name = "qrcode" -version = "7.4.2" +version = "8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, - { name = "pypng" }, - { name = "typing-extensions" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/30/35/ad6d4c5a547fe9a5baf85a9edbafff93fc6394b014fab30595877305fa59/qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845", size = 535974 } +sdist = { url = "https://files.pythonhosted.org/packages/d7/db/6fc9631cac1327f609d2c8ae3680ecd987a2e97472437f2de7ead1235156/qrcode-8.0.tar.gz", hash = "sha256:025ce2b150f7fe4296d116ee9bad455a6643ab4f6e7dce541613a4758cbce347", size = 42743 } wheels = [ - { url = "https://files.pythonhosted.org/packages/24/79/aaf0c1c7214f2632badb2771d770b1500d3d7cbdf2590ae62e721ec50584/qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a", size = 46197 }, + { url = "https://files.pythonhosted.org/packages/74/ab/df8d889fd01139db68ae9e5cb5c8f0ea016823559a6ecb427582d52b07dc/qrcode-8.0-py3-none-any.whl", hash = "sha256:9fc05f03305ad27a709eb742cf3097fa19e6f6f93bb9e2f039c0979190f6f1b1", size = 45710 }, ] [[package]] @@ -1882,7 +1879,7 @@ wheels = [ [[package]] name = "ubo-app" -version = "1.0.1.dev11+unknown" +version = "1.0.1.dev13+unknown" source = { editable = "." } dependencies = [ { name = "adafruit-circuitpython-aw9523" }, @@ -1951,7 +1948,7 @@ requires-dist = [ { name = "docker", specifier = ">=7.1.0" }, { name = "fasteners", specifier = ">=0.19" }, { name = "gpiozero", marker = "platform_machine != 'aarch64'", specifier = ">=2.0.1" }, - { name = "headless-kivy", specifier = ">=0.9.8" }, + { name = "headless-kivy", specifier = ">=0.12.1" }, { name = "piper-tts", marker = "sys_platform == 'linux'", specifier = ">=1.2.0" }, { name = "platformdirs", specifier = ">=4.2.0" }, { name = "psutil", specifier = ">=6.0.0" }, @@ -1971,13 +1968,13 @@ requires-dist = [ { name = "semver", specifier = ">=3.0.2" }, { name = "sentry-sdk", specifier = ">=1.43.0" }, { name = "simpleaudio", specifier = ">=1.0.4" }, - { name = "ubo-gui", specifier = ">=0.13.3" }, + { name = "ubo-gui", specifier = ">=0.13.7" }, ] [package.metadata.requires-dev] dev = [ { name = "grpcio-tools", specifier = ">=1.66.1" }, - { name = "headless-kivy", extras = ["test"], specifier = ">=0.9.8" }, + { name = "headless-kivy", extras = ["test"], specifier = ">=0.12.1" }, { name = "ipython", specifier = ">=8.23.0" }, { name = "poethepoet", specifier = ">=0.24.4" }, { name = "pyfakefs", git = "https://github.com/pytest-dev/pyfakefs.git" }, @@ -1995,16 +1992,16 @@ dev = [ [[package]] name = "ubo-gui" -version = "0.13.3" +version = "0.13.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "headless-kivy" }, { name = "python-immutable" }, { name = "qrcode" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/1f/22376278590aa8dea170291ebba733882da43660017349076493f9c050f1/ubo_gui-0.13.3.tar.gz", hash = "sha256:a2d82b68ec56f114d7bbdd890e73c706d6ea37a5808f3ef74f047c0d60c0bd00", size = 8582266 } +sdist = { url = "https://files.pythonhosted.org/packages/e9/cc/f0a4474bf4f3c2d6f2566c3d99a21c046421d86929e4983d24d7ba832794/ubo_gui-0.13.7.tar.gz", hash = "sha256:d6b036376a8944f90207d263a26ff8616fb4ccbc83502136c0fab3b5b53b5b18", size = 8579473 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/e2/c25f84e93490bb475688766b9bfa202f530c616df1d8f5f192004d7022c4/ubo_gui-0.13.3-py3-none-any.whl", hash = "sha256:04e0792ce81d7422baebfbd2b515c26644cdd59e1b93a3ba49dfb3e942519d5a", size = 8601143 }, + { url = "https://files.pythonhosted.org/packages/92/2a/0e1f874afaf23a0f90ced8f34b2ee52fe0cccc4767f2a8e6620eef91a0f6/ubo_gui-0.13.7-py3-none-any.whl", hash = "sha256:20c747c8c8219a3459b438da57d005cf2d9425c5e93a73ee89963cb2a7d47d7a", size = 8602661 }, ] [[package]]