UI Components
Reusable Compose controls, feedback states, media components, and gallery demos.
Reusable Compose UI lives under core/ui/components, while the Component tab
shows a live, data-driven catalog of those controls. Treat the tab as the
visual reference when composing new screens.
What it provides
| Surface | Status | Implementation |
|---|---|---|
| Shared controls | Integrated | core/ui/components/*.kt |
| Component gallery | Integrated | feature/component/ComponentCatalog.kt and nested component graph |
| Toast overlay | Integrated | ToastController + ToastHost at the activity root |
| Haptics | Integrated | Haptics singleton with selection, success, warning, and error feedback |
| Remote images | Example | AppAsyncImage wraps Coil 3 |
Component inventory
| File | Use it for |
|---|---|
AppButton.kt | Primary, secondary, outline, destructive, ghost, and link buttons in multiple sizes |
AppTextField.kt | Labeled inputs with leading/trailing icons, secure entry, and error text |
AppCard.kt | Grouped surface cards for rows, widgets, and settings sections |
AppAsyncImage.kt | Coil-backed remote image with placeholder/fallback behavior |
DetailScaffold.kt | Detail pages with a centered top app bar and back action |
OfflineBanner.kt | Slim connectivity banner driven by NetworkObserver state |
OtpInput.kt | Six-box one-time-code input |
PasswordStrengthBar.kt | Password strength meter and pure passwordStrength() helper |
SectionHeader.kt | Uppercase grouped-section labels |
SectionedDocument.kt | Legal/guide-style document sections |
State.kt | EmptyState, LoadingState, and ErrorState placeholders |
ThemeToggle.kt | Segmented theme picker for System/Light/Dark |
Component gallery
The Component tab is implemented as a feature-local graph:
ComponentGraph
-> ComponentHome
-> ComponentDetail(route: ComponentRoute)ComponentCatalog groups entries into Controls, Inputs, Containers, Feedback,
and Media. Current detail demos cover:
| Route | Demo |
|---|---|
Buttons | Button variants, loading/disabled states |
ThemeToggle | Live theme segmented control |
TextFields | Inputs, icons, password transformation, errors |
PasswordStrength | Interactive password meter |
OtpInput | OTP boxes with completion callback |
Cards | Grouped-surface containers |
SectionHeaders | Settings-style section labels |
States | Loading, empty, and error placeholders |
OfflineBanner | Connectivity banner |
Toast | Info/success/error transient messages |
AsyncImage | Remote image rendering via Coil |
Some gallery titles and summaries are plain Kotlin strings today. If you need
the gallery itself localized, convert ComponentEntry.title and summary to
string resource ids.
Toasts
ToastController exposes a buffered SharedFlow<ToastEvent> and variants:
enum class ToastVariant { Info, Success, Error }MainActivity renders one ToastHost above the root AppNavGraph, aligned to
the top center and padded for status bars. Success and error toasts trigger
haptics automatically through ToastController.
Use it from a ViewModel or controller:
toastController.showSuccess("Saved")
toastController.showError("Could not save")Haptics
Haptics resolves VibratorManager.defaultVibrator on Android 12+ and falls
back to Vibrator on older versions. It no-ops when the device has no
vibrator.
Available calls:
| Method | Use |
|---|---|
selection() / light() | small UI ticks |
medium() / heavy() | stronger press feedback |
success() | success waveform |
warning() | warning waveform |
error() | error waveform |
Compose a new screen
- Start with a route composable that gets its ViewModel via
hiltViewModel(). - Collect the ViewModel state and pass plain values/callbacks into a stateless screen composable.
- Use
DetailScaffoldfor pushed detail screens. - Use
AppTextField,AppButton, andAppCardbefore creating one-off controls. - Render loading, empty, and error states with
State.ktcomponents. - Use
MaterialTheme.colorScheme.groupedBackgroundand grouped surfaces for app screens. - Trigger transient feedback through
ToastController; it already handles haptics for success and error.
