# Released under the MIT License. See LICENSE for details.
#
"""Routes for the doc-ui test domain."""
from __future__ import annotations # Docs-generation hack.
from enum import Enum
from dataclasses import dataclass
from typing import TYPE_CHECKING, Annotated, override
from efro.dataclassio import ioprepped, IOAttrs
import bacommon.docui.v2 as dui2
from bacommon.docui.routes import (
DocUIRoute,
DocUILocalActionBase,
DocUIState,
family_members,
)
if TYPE_CHECKING:
import bacommon.docui.v2
[docs]
class TestRoute(DocUIRoute):
"""Family class for doc-ui test routes."""
[docs]
@override
@classmethod
def get_route_types(cls) -> tuple[type[DocUIRoute], ...]:
return family_members(AnyTestRoute)
[docs]
@ioprepped
@dataclass
class Root(TestRoute, path='/'):
"""The root test page."""
#: Draw bounds and other debug bits.
debug: bool = False
#: Have the response include some client-effects.
test_effects: bool = False
#: Have the response include a local-action.
test_action: bool = False
[docs]
@ioprepped
@dataclass
class Test2(TestRoute, path='/test2'):
"""A second simple page."""
[docs]
@ioprepped
@dataclass
class Slow(TestRoute, path='/slow'):
"""A page that takes a while to load."""
[docs]
@ioprepped
@dataclass
class TimedActions(TestRoute, path='/timedactions'):
"""A page that counts down via timed-actions and then closes."""
val: int = 5
[docs]
@ioprepped
@dataclass
class DisplayItems(TestRoute, path='/displayitems'):
"""Display-item tests."""
debug: bool = False
[docs]
@ioprepped
@dataclass
class TextImages(TestRoute, path='/textimages'):
"""Text-with-images tests."""
debug: bool = False
[docs]
@ioprepped
@dataclass
class Depictions(TestRoute, path='/depictions'):
"""Depiction tests."""
debug: bool = False
[docs]
@ioprepped
@dataclass
class Names(TestRoute, path='/names'):
"""Name depiction tests (basic and capsule forms)."""
debug: bool = False
[docs]
@ioprepped
@dataclass
class EmptyPage(TestRoute, path='/emptypage'):
"""A page with nothing on it."""
[docs]
@ioprepped
@dataclass
class BoundsTests(TestRoute, path='/boundstests'):
"""Button-style bounds tests."""
[docs]
class ControlRowKind(Enum):
"""Kinds of control row (for :class:`NavTest`)."""
CHECKBOX = 'checkbox'
TEXT_INPUT = 'text'
CHOICE = 'choice'
SLIDER = 'slider'
NUMBER = 'number'
COLOR = 'color'
BUTTON = 'button'
[docs]
@ioprepped
@dataclass
class NavTest(TestRoute, path='/navtest'):
"""A button row, then one control row of some kind as the last row.
For checking directional navigation on control rows: down from the
last row should reach the toolbars, left should reach the back
button, and right from a row's rightmost control should do nothing.
"""
kind: ControlRowKind = ControlRowKind.CHECKBOX
[docs]
@ioprepped
@dataclass
class Sections(TestRoute, path='/sections'):
"""Sections: headings, notes, backings and spacing between them."""
debug: bool = False
[docs]
@override
@classmethod
def get_window_layout(cls) -> dui2.WindowLayout:
# A column, like the settings pages sections mostly live in.
return dui2.WindowLayout.SMALL_TALLER
[docs]
@ioprepped
@dataclass
class WindowLayouts(TestRoute, path='/windowlayouts'):
"""Assorted rows for judging window layouts (browse to it at each).
Control rows, titles and button rows at every alignment, and long
rows, which in a narrow column scroll within it.
"""
debug: bool = False
[docs]
@ioprepped
@dataclass
class WideFit(TestRoute, path='/widefit'):
"""A row exactly as big as wide pages get (browse at each layout).
It should fill the page's height (wide and wider) and width (wide)
with no scrolling, at every ui-scale; with ``over`` / ``wide_over``
set it's a hair taller / wider, which should scroll.
"""
over: bool = False
wide_over: bool = False
[docs]
class Flavor(Enum):
"""Something to pick from on the widgets test page."""
VANILLA = 'v'
CHOCOLATE = 'c'
STRAWBERRY = 's'
MINT = 'm'
[docs]
class Size(Enum):
"""Something else to pick from on the widgets test page."""
S = 's'
M = 'm'
L = 'l'
XL = 'x'
[docs]
@ioprepped
@dataclass
class WebTestGet(TestRoute, path='/webtest/get'):
"""A page fetched from a web server via GET."""
[docs]
@ioprepped
@dataclass
class WebTestPost(
TestRoute, path='/webtest/post', method=dui2.RequestMethod.POST
):
"""A page fetched from a web server via POST."""
[docs]
@ioprepped
@dataclass
class CloudMsgTestGet(TestRoute, path='/cloudmsgtest/get'):
"""A page fetched through our cloud connection via GET."""
[docs]
@ioprepped
@dataclass
class CloudMsgTestPost(
TestRoute, path='/cloudmsgtest/post', method=dui2.RequestMethod.POST
):
"""A page fetched through our cloud connection via POST."""
# All routes in the family. Handlers can match against this with
# assert_never to be sure they cover everything.
AnyTestRoute = (
Root
| Test2
| Slow
| TimedActions
| DisplayItems
| TextImages
| Depictions
| Names
| EmptyPage
| BoundsTests
| Widgets
| NavTest
| Sections
| WindowLayouts
| WideFit
| WebTestGet
| WebTestPost
| CloudMsgTestGet
| CloudMsgTestPost
)
[docs]
class TestLocalAction(DocUILocalActionBase):
"""Family class for doc-ui test local-actions."""
[docs]
@override
@classmethod
def get_action_types(cls) -> tuple[type[DocUILocalActionBase], ...]:
return family_members(AnyTestLocalAction)
[docs]
@ioprepped
@dataclass
class TestAction(TestLocalAction, name='testaction'):
"""Show a message proving we got here."""
testparam: int
# All local-actions in the family (just the one for now).
[docs]
@ioprepped
@dataclass
class ShowVolume(TestLocalAction, name='showvolume'):
"""Show the volume slider's live value (fired while dragging)."""
AnyTestLocalAction = TestAction | ShowVolume
# Docs-generation hack; import some stuff that we likely only forward-declared
# in our actual source code so that docs tools can find it.
from typing import (Coroutine, Any, Literal, Callable,
Generator, Awaitable, Sequence, Self, TypeIs)
import asyncio
from concurrent.futures import Future
from pathlib import Path
from enum import Enum