diff --git a/python_payload/st3m/application.py b/python_payload/st3m/application.py
index d91306e3b3eb1bb334dd9af6c4a4bdefb3d104f9..da27f383be986f563c979c9a79a49d88e014d9a0 100644
--- a/python_payload/st3m/application.py
+++ b/python_payload/st3m/application.py
@@ -2,7 +2,6 @@ from st3m.ui.view import (
     BaseView,
     ViewTransitionSwipeLeft,
     ViewManager,
-    ViewTransitionDirection,
 )
 from st3m.ui.menu import MenuItem
 from st3m.input import InputState
@@ -50,51 +49,21 @@ class ApplicationContext:
         return self._bundle_metadata
 
 
+def setup_for_app(app_ctx: Optional[ApplicationContext]) -> None:
+    if app_ctx and app_ctx.bundle_metadata and settings.onoff_wifi_preference.value:
+        wifi_preference = app_ctx.bundle_metadata["app"].get("wifi_preference")
+        if wifi_preference is True and not st3m.wifi.is_connected():
+            st3m.wifi.setup_wifi()
+        elif wifi_preference is False:
+            st3m.wifi.disable()
+    leds.set_slew_rate(settings.num_leds_speed.value)
+
+
 class Application(BaseView):
     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:
-            self._wifi_preference = app_ctx.bundle_metadata["app"].get(
-                "wifi_preference"
-            )
-        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()
-        elif self._wifi_preference is False:
-            st3m.wifi.disable()
-        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 BundleLoadException(BaseException):
     MSG = "failed to load"
@@ -149,7 +118,7 @@ class BundleMetadata:
     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:
         self.path = path.rstrip("/")
@@ -188,6 +157,8 @@ class BundleMetadata:
 
         self._t = t
 
+        self.ctx = ApplicationContext(self.path, self._t)
+
     @staticmethod
     def _sys_path_set(v: List[str]) -> None:
         # Can't just assign to sys.path in Micropython.
@@ -221,7 +192,7 @@ class BundleMetadata:
             log.info(f"Loaded {self.name} module: {m}")
             klass = getattr(m, class_entry)
             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}")
             return inst  # type: ignore
         except Exception as e:
@@ -350,6 +321,8 @@ class MenuItemAppLaunch(MenuItem):
                 vm.push(err)
                 return
         assert self._instance is not None
+
+        setup_for_app(self._bundle.ctx)
         vm.push(self._instance, ViewTransitionSwipeLeft())
 
     def label(self) -> str:
diff --git a/python_payload/st3m/run.py b/python_payload/st3m/run.py
index 8be8c1c9efd23800536e7f58d1c9c8a28fcaa6a3..54f259f9f35f22065b56ceb1d86a9c862b4695b3 100644
--- a/python_payload/st3m/run.py
+++ b/python_payload/st3m/run.py
@@ -9,17 +9,19 @@ from st3m.ui.menu import (
     MenuItemLaunchPersistentView,
 )
 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.application import (
     BundleManager,
     BundleMetadata,
     MenuItemAppLaunch,
     ApplicationContext,
+    setup_for_app,
 )
 from st3m.about import About
 from st3m import settings_menu as settings, logging, processors, wifi
 from st3m import led_patterns
+import st3m.wifi
 
 import captouch, audio, leds, gc, sys_buttons, sys_display, sys_mode
 import os
@@ -60,13 +62,40 @@ def run_responder(r: Responder) -> None:
     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:
     entries: List[MenuItem] = [MenuItemBack()]
     ids = sorted(mgr.bundles.keys())
     for id in ids:
         bundle = mgr.bundles[id]
         entries += bundle.menu_entries(kind)
-    return SimpleMenu(entries)
+    return ApplicationMenu(entries)
 
 
 def _make_compositor(reactor: Reactor, vm: ViewManager) -> overlays.Compositor:
@@ -134,7 +163,9 @@ def run_view(v: View, debug_vm=True) -> 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:
@@ -176,7 +207,7 @@ def run_main() -> None:
         log.error(f"Failed to set hostname {e}")
 
     menu_settings = settings.build_menu()
-    menu_system = SimpleMenu(
+    menu_system = ApplicationMenu(
         [
             MenuItemBack(),
             MenuItemForeground("Settings", menu_settings),