Skip to content

App Chrome

Source: ui/app_chrome.py

Registry of shared Shell chrome controls (AppBar, bottom bar, FAB, drawer) created at startup. Declarative per-route flags live in Chrome configuration; how they work together is in Chrome and wrappers. Startup order is in Startup.

Registry of shared Shell chrome controls created at startup.

AppChrome

Holds references to the shared AppBar, bottom bar, FAB, and drawer.

app.py builds the controls once, then calls register and set_drawer. The router applies SHELL_CHROME visibility and titles through these getters when entering Shell routes, and hides chrome for Deep routes. This is the live control registry — not the declarative config in chrome_config.py.

Callers must register before the first Shell view is built. Getters raise AssertionError if registration (or the drawer) is missing.

Source code in src/learning_app/ui/app_chrome.py
class AppChrome:
    """Holds references to the shared AppBar, bottom bar, FAB, and drawer.

    ``app.py`` builds the controls once, then calls ``register`` and
    ``set_drawer``. The router applies ``SHELL_CHROME`` visibility and titles
    through these getters when entering Shell routes, and hides chrome for
    Deep routes. This is the live control registry — not the declarative
    config in ``chrome_config.py``.

    Callers must register before the first Shell view is built. Getters raise
    ``AssertionError`` if registration (or the drawer) is missing.
    """

    _appbar: ft.AppBar | None = None
    _bottom_appbar: ft.BottomAppBar | None = None
    _floating_action_button: ft.FloatingActionButton | None = None
    _floating_action_button_location: ft.FloatingActionButtonLocation | None = None
    _horizontal_alignment: ft.CrossAxisAlignment | None = None
    _vertical_alignment: ft.MainAxisAlignment | None = None
    _appbar_menu_button: ft.IconButton | None = None
    _appbar_title: ft.Text | None = None
    _search_button: ft.IconButton | None = None
    _drawer: ft.NavigationDrawer | None = None

    @classmethod
    def register(
        cls,
        *,
        appbar: ft.AppBar,
        bottom_appbar: ft.BottomAppBar,
        floating_action_button: ft.FloatingActionButton,
        floating_action_button_location: ft.FloatingActionButtonLocation,
        horizontal_alignment: ft.CrossAxisAlignment,
        vertical_alignment: ft.MainAxisAlignment,
        appbar_menu_button: ft.IconButton,
        search_button: ft.IconButton,
    ):
        """Store shared chrome controls and page alignment defaults.

        Args:
            appbar: Shared top app bar.
            bottom_appbar: Shared bottom app bar.
            floating_action_button: Shared FAB (Create set).
            floating_action_button_location: FAB dock location.
            horizontal_alignment: Default view horizontal alignment.
            vertical_alignment: Default view vertical alignment.
            appbar_menu_button: Leading menu button used when config enables it.
            search_button: Search action on the bottom app bar.
        """
        cls._appbar = appbar
        cls._bottom_appbar = bottom_appbar
        cls._floating_action_button = floating_action_button
        cls._floating_action_button_location = floating_action_button_location
        cls._horizontal_alignment = horizontal_alignment
        cls._vertical_alignment = vertical_alignment
        cls._appbar_menu_button = appbar_menu_button
        cls._appbar_title = appbar.title if isinstance(appbar.title, ft.Text) else None
        cls._search_button = search_button
        cls._allow_bottom_appbar_system_inset(bottom_appbar)

    @classmethod
    def set_drawer(cls, drawer: ft.NavigationDrawer):
        """Attach the shared navigation drawer reference.

        Args:
            drawer: ``AppDrawer`` (or compatible) instance assigned to the page.
        """
        cls._drawer = drawer

    @classmethod
    def set_bottom_appbar_height(cls, height: float) -> None:
        """Set the bottom app bar content height without clipping system insets.

        ``height`` is the interactive content box (menu/search row), not the
        final on-screen bar size. Flutter's ``BottomAppBar`` already wraps that
        box in ``SafeArea`` and grows by the system navigation inset. Flet's
        ``LayoutControl`` must not clamp the outer height to the same value, or
        buttons are squeezed under the system navigation bar.

        Args:
            height: Content height in logical pixels (for example ``80`` or
                ``50``).
        """
        bottom_appbar = cls.get_bottom_appbar()
        cls._allow_bottom_appbar_system_inset(bottom_appbar)
        bottom_appbar.height = height

    @classmethod
    def _allow_bottom_appbar_system_inset(cls, bottom_appbar: ft.BottomAppBar) -> None:
        """Keep ``height`` as Flutter content height, not an outer SizedBox clamp."""
        bottom_appbar._internals["skip_properties"] = ["height"]

    @classmethod
    def get_appbar(cls) -> ft.AppBar:
        """Return the registered app bar."""
        assert cls._appbar is not None, "App chrome is not registered"
        return cls._appbar

    @classmethod
    def get_bottom_appbar(cls) -> ft.BottomAppBar:
        """Return the registered bottom app bar."""
        assert cls._bottom_appbar is not None, "App chrome is not registered"
        return cls._bottom_appbar

    @classmethod
    def get_floating_action_button(cls) -> ft.FloatingActionButton:
        """Return the registered floating action button."""
        assert cls._floating_action_button is not None, "App chrome is not registered"
        return cls._floating_action_button

    @classmethod
    def get_floating_action_button_location(cls) -> ft.FloatingActionButtonLocation:
        """Return the registered FAB location."""
        assert cls._floating_action_button_location is not None, "App chrome is not registered"
        return cls._floating_action_button_location

    @classmethod
    def get_horizontal_alignment(cls) -> ft.CrossAxisAlignment:
        """Return the default view horizontal alignment."""
        assert cls._horizontal_alignment is not None, "App chrome is not registered"
        return cls._horizontal_alignment

    @classmethod
    def get_vertical_alignment(cls) -> ft.MainAxisAlignment:
        """Return the default view vertical alignment."""
        assert cls._vertical_alignment is not None, "App chrome is not registered"
        return cls._vertical_alignment

    @classmethod
    def get_appbar_menu_button(cls) -> ft.IconButton:
        """Return the leading drawer-menu button for Shell routes that show it."""
        assert cls._appbar_menu_button is not None, "App chrome is not registered"
        return cls._appbar_menu_button

    @classmethod
    def get_appbar_title(cls) -> ft.Text:
        """Return the shared app bar title text control."""
        assert cls._appbar_title is not None, "App chrome is not registered"
        return cls._appbar_title

    @classmethod
    def show_appbar_title(cls, text: str) -> None:
        """Restore the greeting/title ``Text`` after in-place search replaces it."""
        appbar = cls.get_appbar()
        title = cls.get_appbar_title()
        title.value = text
        appbar.title = title
        appbar.center_title = True

    @classmethod
    def get_search_button(cls) -> ft.IconButton:
        """Return the bottom-bar search button."""
        assert cls._search_button is not None, "App chrome is not registered"
        return cls._search_button

    @classmethod
    def get_drawer(cls) -> ft.NavigationDrawer:
        """Return the registered navigation drawer."""
        assert cls._drawer is not None, "App drawer is not set"
        return cls._drawer

    @classmethod
    def has_drawer(cls) -> bool:
        """Return whether a drawer has been set."""
        return cls._drawer is not None

register classmethod

register(
    *,
    appbar: AppBar,
    bottom_appbar: BottomAppBar,
    floating_action_button: FloatingActionButton,
    floating_action_button_location: FloatingActionButtonLocation,
    horizontal_alignment: CrossAxisAlignment,
    vertical_alignment: MainAxisAlignment,
    appbar_menu_button: IconButton,
    search_button: IconButton,
)

Store shared chrome controls and page alignment defaults.

Parameters:

Name Type Description Default
appbar AppBar

Shared top app bar.

required
bottom_appbar BottomAppBar

Shared bottom app bar.

required
floating_action_button FloatingActionButton

Shared FAB (Create set).

required
floating_action_button_location FloatingActionButtonLocation

FAB dock location.

required
horizontal_alignment CrossAxisAlignment

Default view horizontal alignment.

required
vertical_alignment MainAxisAlignment

Default view vertical alignment.

required
appbar_menu_button IconButton

Leading menu button used when config enables it.

required
search_button IconButton

Search action on the bottom app bar.

required
Source code in src/learning_app/ui/app_chrome.py
@classmethod
def register(
    cls,
    *,
    appbar: ft.AppBar,
    bottom_appbar: ft.BottomAppBar,
    floating_action_button: ft.FloatingActionButton,
    floating_action_button_location: ft.FloatingActionButtonLocation,
    horizontal_alignment: ft.CrossAxisAlignment,
    vertical_alignment: ft.MainAxisAlignment,
    appbar_menu_button: ft.IconButton,
    search_button: ft.IconButton,
):
    """Store shared chrome controls and page alignment defaults.

    Args:
        appbar: Shared top app bar.
        bottom_appbar: Shared bottom app bar.
        floating_action_button: Shared FAB (Create set).
        floating_action_button_location: FAB dock location.
        horizontal_alignment: Default view horizontal alignment.
        vertical_alignment: Default view vertical alignment.
        appbar_menu_button: Leading menu button used when config enables it.
        search_button: Search action on the bottom app bar.
    """
    cls._appbar = appbar
    cls._bottom_appbar = bottom_appbar
    cls._floating_action_button = floating_action_button
    cls._floating_action_button_location = floating_action_button_location
    cls._horizontal_alignment = horizontal_alignment
    cls._vertical_alignment = vertical_alignment
    cls._appbar_menu_button = appbar_menu_button
    cls._appbar_title = appbar.title if isinstance(appbar.title, ft.Text) else None
    cls._search_button = search_button
    cls._allow_bottom_appbar_system_inset(bottom_appbar)

set_drawer classmethod

set_drawer(drawer: NavigationDrawer)

Attach the shared navigation drawer reference.

Parameters:

Name Type Description Default
drawer NavigationDrawer

AppDrawer (or compatible) instance assigned to the page.

required
Source code in src/learning_app/ui/app_chrome.py
@classmethod
def set_drawer(cls, drawer: ft.NavigationDrawer):
    """Attach the shared navigation drawer reference.

    Args:
        drawer: ``AppDrawer`` (or compatible) instance assigned to the page.
    """
    cls._drawer = drawer

set_bottom_appbar_height classmethod

set_bottom_appbar_height(height: float) -> None

Set the bottom app bar content height without clipping system insets.

height is the interactive content box (menu/search row), not the final on-screen bar size. Flutter's BottomAppBar already wraps that box in SafeArea and grows by the system navigation inset. Flet's LayoutControl must not clamp the outer height to the same value, or buttons are squeezed under the system navigation bar.

Parameters:

Name Type Description Default
height float

Content height in logical pixels (for example 80 or 50).

required
Source code in src/learning_app/ui/app_chrome.py
@classmethod
def set_bottom_appbar_height(cls, height: float) -> None:
    """Set the bottom app bar content height without clipping system insets.

    ``height`` is the interactive content box (menu/search row), not the
    final on-screen bar size. Flutter's ``BottomAppBar`` already wraps that
    box in ``SafeArea`` and grows by the system navigation inset. Flet's
    ``LayoutControl`` must not clamp the outer height to the same value, or
    buttons are squeezed under the system navigation bar.

    Args:
        height: Content height in logical pixels (for example ``80`` or
            ``50``).
    """
    bottom_appbar = cls.get_bottom_appbar()
    cls._allow_bottom_appbar_system_inset(bottom_appbar)
    bottom_appbar.height = height

get_appbar classmethod

get_appbar() -> AppBar

Return the registered app bar.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_appbar(cls) -> ft.AppBar:
    """Return the registered app bar."""
    assert cls._appbar is not None, "App chrome is not registered"
    return cls._appbar

get_bottom_appbar classmethod

get_bottom_appbar() -> BottomAppBar

Return the registered bottom app bar.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_bottom_appbar(cls) -> ft.BottomAppBar:
    """Return the registered bottom app bar."""
    assert cls._bottom_appbar is not None, "App chrome is not registered"
    return cls._bottom_appbar

get_floating_action_button classmethod

get_floating_action_button() -> FloatingActionButton

Return the registered floating action button.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_floating_action_button(cls) -> ft.FloatingActionButton:
    """Return the registered floating action button."""
    assert cls._floating_action_button is not None, "App chrome is not registered"
    return cls._floating_action_button

get_floating_action_button_location classmethod

get_floating_action_button_location() -> (
    FloatingActionButtonLocation
)

Return the registered FAB location.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_floating_action_button_location(cls) -> ft.FloatingActionButtonLocation:
    """Return the registered FAB location."""
    assert cls._floating_action_button_location is not None, "App chrome is not registered"
    return cls._floating_action_button_location

get_horizontal_alignment classmethod

get_horizontal_alignment() -> CrossAxisAlignment

Return the default view horizontal alignment.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_horizontal_alignment(cls) -> ft.CrossAxisAlignment:
    """Return the default view horizontal alignment."""
    assert cls._horizontal_alignment is not None, "App chrome is not registered"
    return cls._horizontal_alignment

get_vertical_alignment classmethod

get_vertical_alignment() -> MainAxisAlignment

Return the default view vertical alignment.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_vertical_alignment(cls) -> ft.MainAxisAlignment:
    """Return the default view vertical alignment."""
    assert cls._vertical_alignment is not None, "App chrome is not registered"
    return cls._vertical_alignment

get_appbar_menu_button classmethod

get_appbar_menu_button() -> IconButton

Return the leading drawer-menu button for Shell routes that show it.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_appbar_menu_button(cls) -> ft.IconButton:
    """Return the leading drawer-menu button for Shell routes that show it."""
    assert cls._appbar_menu_button is not None, "App chrome is not registered"
    return cls._appbar_menu_button

get_appbar_title classmethod

get_appbar_title() -> Text

Return the shared app bar title text control.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_appbar_title(cls) -> ft.Text:
    """Return the shared app bar title text control."""
    assert cls._appbar_title is not None, "App chrome is not registered"
    return cls._appbar_title

show_appbar_title classmethod

show_appbar_title(text: str) -> None

Restore the greeting/title Text after in-place search replaces it.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def show_appbar_title(cls, text: str) -> None:
    """Restore the greeting/title ``Text`` after in-place search replaces it."""
    appbar = cls.get_appbar()
    title = cls.get_appbar_title()
    title.value = text
    appbar.title = title
    appbar.center_title = True

get_search_button classmethod

get_search_button() -> IconButton

Return the bottom-bar search button.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_search_button(cls) -> ft.IconButton:
    """Return the bottom-bar search button."""
    assert cls._search_button is not None, "App chrome is not registered"
    return cls._search_button

get_drawer classmethod

get_drawer() -> NavigationDrawer

Return the registered navigation drawer.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def get_drawer(cls) -> ft.NavigationDrawer:
    """Return the registered navigation drawer."""
    assert cls._drawer is not None, "App drawer is not set"
    return cls._drawer

has_drawer classmethod

has_drawer() -> bool

Return whether a drawer has been set.

Source code in src/learning_app/ui/app_chrome.py
@classmethod
def has_drawer(cls) -> bool:
    """Return whether a drawer has been set."""
    return cls._drawer is not None