- UiText sealed interface (DynamicString / StringResource) — Compose-free type so the
UI-agnostic presentation module can hold UiText? in state without depending on Compose.
- Two resolvers: @Composable UiText.asString() (Compose renderer) and
UiText.asString(context) (Views renderer).
- ObserveAsEvents: lifecycle-aware one-time event collection on Main.immediate.
- DataError.toUiText() covering all displayed cases with else -> unknown; error strings here.