Skip to content
Snippets Groups Projects
Verified Commit 8e5dae5a authored by dos's avatar dos
Browse files

py,st3m: Move WiFi and LED state handling out of Application class

Application class is the user's code, we shouldn't rely on it
implementing system-level functionality as there are several
ways for the user to accidentally break it.

This isn't a perfect place for it either, but it's at least better
than before. It's going to be revisited in the future, perhaps
by giving each app their own ViewManager instance that could
then properly track application's lifecycle.

One functional difference is that st3m.wifi._onoff_wifi_update()
is now being called when quitting any app, not just those
that request a particular WiFi state in their config.
parent 029ec006
No related branches found
No related tags found
No related merge requests found
...@@ -2,7 +2,6 @@ from st3m.ui.view import ( ...@@ -2,7 +2,6 @@ from st3m.ui.view import (
BaseView, BaseView,
ViewTransitionSwipeLeft, ViewTransitionSwipeLeft,
ViewManager, ViewManager,
ViewTransitionDirection,
) )
from st3m.ui.menu import MenuItem from st3m.ui.menu import MenuItem
from st3m.input import InputState from st3m.input import InputState
...@@ -50,50 +49,20 @@ class ApplicationContext: ...@@ -50,50 +49,20 @@ class ApplicationContext:
return self._bundle_metadata return self._bundle_metadata
class Application(BaseView): def setup_for_app(app_ctx: Optional[ApplicationContext]) -> None:
def __init__(self, app_ctx: ApplicationContext) -> None:
self._app_ctx = app_ctx
if app_ctx and app_ctx.bundle_metadata and settings.onoff_wifi_preference.value: if app_ctx and app_ctx.bundle_metadata and settings.onoff_wifi_preference.value:
self._wifi_preference = app_ctx.bundle_metadata["app"].get( wifi_preference = app_ctx.bundle_metadata["app"].get("wifi_preference")
"wifi_preference" if wifi_preference is True and not st3m.wifi.is_connected():
)
else:
self._wifi_preference = None
super().__init__()
def on_enter(self, vm: Optional[ViewManager]) -> None:
# Try to connect/disconnect from wifi if requested by app
if self._wifi_preference is True and not st3m.wifi.is_connected():
st3m.wifi.setup_wifi() st3m.wifi.setup_wifi()
elif self._wifi_preference is False: elif wifi_preference is False:
st3m.wifi.disable() st3m.wifi.disable()
leds.set_slew_rate(settings.num_leds_speed.value) leds.set_slew_rate(settings.num_leds_speed.value)
super().on_enter(vm)
def on_exit(self) -> None:
fully_exiting = self.vm.direction == ViewTransitionDirection.BACKWARD
# If the app requested to change wifi state
# fall back to system defaults on exit
if fully_exiting and self._wifi_preference is not None:
st3m.wifi._onoff_wifi_update()
super().on_exit()
# set the default graphics mode, this is a no-op if
# it is already set
if fully_exiting:
sys_display.set_mode(0)
if fully_exiting:
leds.set_slew_rate(100)
led_patterns.set_menu_colors()
def on_exit_done(self):
fully_exiting = self.vm.direction == ViewTransitionDirection.BACKWARD
if fully_exiting:
leds.set_slew_rate(100)
led_patterns.set_menu_colors()
leds.update()
def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms) class Application(BaseView):
def __init__(self, app_ctx: ApplicationContext) -> None:
self._app_ctx = app_ctx
super().__init__()
class BundleLoadException(BaseException): class BundleLoadException(BaseException):
...@@ -149,7 +118,7 @@ class BundleMetadata: ...@@ -149,7 +118,7 @@ class BundleMetadata:
This data is used to discover bundles and load them as applications. This data is used to discover bundles and load them as applications.
""" """
__slots__ = ["path", "name", "menu", "_t", "version"] __slots__ = ["path", "name", "menu", "_t", "version", "ctx"]
def __init__(self, path: str) -> None: def __init__(self, path: str) -> None:
self.path = path.rstrip("/") self.path = path.rstrip("/")
...@@ -188,6 +157,8 @@ class BundleMetadata: ...@@ -188,6 +157,8 @@ class BundleMetadata:
self._t = t self._t = t
self.ctx = ApplicationContext(self.path, self._t)
@staticmethod @staticmethod
def _sys_path_set(v: List[str]) -> None: def _sys_path_set(v: List[str]) -> None:
# Can't just assign to sys.path in Micropython. # Can't just assign to sys.path in Micropython.
...@@ -221,7 +192,7 @@ class BundleMetadata: ...@@ -221,7 +192,7 @@ class BundleMetadata:
log.info(f"Loaded {self.name} module: {m}") log.info(f"Loaded {self.name} module: {m}")
klass = getattr(m, class_entry) klass = getattr(m, class_entry)
log.info(f"Loaded {self.name} class: {klass}") log.info(f"Loaded {self.name} class: {klass}")
inst = klass(ApplicationContext(self.path, self._t)) inst = klass(self.ctx)
log.info(f"Instantiated {self.name} class: {inst}") log.info(f"Instantiated {self.name} class: {inst}")
return inst # type: ignore return inst # type: ignore
except Exception as e: except Exception as e:
...@@ -350,6 +321,8 @@ class MenuItemAppLaunch(MenuItem): ...@@ -350,6 +321,8 @@ class MenuItemAppLaunch(MenuItem):
vm.push(err) vm.push(err)
return return
assert self._instance is not None assert self._instance is not None
setup_for_app(self._bundle.ctx)
vm.push(self._instance, ViewTransitionSwipeLeft()) vm.push(self._instance, ViewTransitionSwipeLeft())
def label(self) -> str: def label(self) -> str:
......
...@@ -9,17 +9,19 @@ from st3m.ui.menu import ( ...@@ -9,17 +9,19 @@ from st3m.ui.menu import (
MenuItemLaunchPersistentView, MenuItemLaunchPersistentView,
) )
from st3m.ui.elements import overlays from st3m.ui.elements import overlays
from st3m.ui.view import View, ViewManager, ViewTransitionBlend from st3m.ui.view import View, ViewManager, ViewTransitionBlend, ViewTransitionDirection
from st3m.ui.elements.menus import SimpleMenu, SunMenu from st3m.ui.elements.menus import SimpleMenu, SunMenu
from st3m.application import ( from st3m.application import (
BundleManager, BundleManager,
BundleMetadata, BundleMetadata,
MenuItemAppLaunch, MenuItemAppLaunch,
ApplicationContext, ApplicationContext,
setup_for_app,
) )
from st3m.about import About from st3m.about import About
from st3m import settings_menu as settings, logging, processors, wifi from st3m import settings_menu as settings, logging, processors, wifi
from st3m import led_patterns from st3m import led_patterns
import st3m.wifi
import captouch, audio, leds, gc, sys_buttons, sys_display, sys_mode import captouch, audio, leds, gc, sys_buttons, sys_display, sys_mode
import os import os
...@@ -60,13 +62,40 @@ def run_responder(r: Responder) -> None: ...@@ -60,13 +62,40 @@ def run_responder(r: Responder) -> None:
reactor.run() reactor.run()
class ApplicationMenu(SimpleMenu):
def _restore_sys_defaults(self) -> None:
if (
not self.vm
or not self.is_active()
or self.vm.direction != ViewTransitionDirection.BACKWARD
):
return
# fall back to system defaults on app exit
st3m.wifi._onoff_wifi_update()
# set the default graphics mode, this is a no-op if
# it is already set
sys_display.set_mode(0)
leds.set_slew_rate(100)
led_patterns.set_menu_colors()
def on_enter(self, vm: Optional[ViewManager]) -> None:
super().on_enter(vm)
self._restore_sys_defaults()
def on_enter_done(self):
# set the defaults again in case the app continued
# doing stuff during the transition
self._restore_sys_defaults()
leds.update()
def _make_bundle_menu(mgr: BundleManager, kind: str) -> SimpleMenu: def _make_bundle_menu(mgr: BundleManager, kind: str) -> SimpleMenu:
entries: List[MenuItem] = [MenuItemBack()] entries: List[MenuItem] = [MenuItemBack()]
ids = sorted(mgr.bundles.keys()) ids = sorted(mgr.bundles.keys())
for id in ids: for id in ids:
bundle = mgr.bundles[id] bundle = mgr.bundles[id]
entries += bundle.menu_entries(kind) entries += bundle.menu_entries(kind)
return SimpleMenu(entries) return ApplicationMenu(entries)
def _make_compositor(reactor: Reactor, vm: ViewManager) -> overlays.Compositor: def _make_compositor(reactor: Reactor, vm: ViewManager) -> overlays.Compositor:
...@@ -134,7 +163,9 @@ def run_view(v: View, debug_vm=True) -> None: ...@@ -134,7 +163,9 @@ def run_view(v: View, debug_vm=True) -> None:
def run_app(klass, bundle_path=None): def run_app(klass, bundle_path=None):
run_view(klass(ApplicationContext(bundle_path)), debug_vm=True) app_ctx = ApplicationContext(bundle_path)
setup_for_app(app_ctx)
run_view(klass(app_ctx), debug_vm=True)
def _yeet_local_changes() -> None: def _yeet_local_changes() -> None:
...@@ -176,7 +207,7 @@ def run_main() -> None: ...@@ -176,7 +207,7 @@ def run_main() -> None:
log.error(f"Failed to set hostname {e}") log.error(f"Failed to set hostname {e}")
menu_settings = settings.build_menu() menu_settings = settings.build_menu()
menu_system = SimpleMenu( menu_system = ApplicationMenu(
[ [
MenuItemBack(), MenuItemBack(),
MenuItemForeground("Settings", menu_settings), MenuItemForeground("Settings", menu_settings),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment