Jetpack Compose UI Components
The :speed-ui module provides drop-in, hardware-accelerated Jetpack Compose widgets designed for automotive dashboards, driver safety HUDs, and telematics settings screens.
🏎️ The SpeedGauge Component
SpeedGauge is a circular speedometer gauge rendering custom vector arcs, dynamic speed ticks, smoothed needle motion, and real-time GPS accuracy status.
📦 Basic Usage
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.vegsahayyak.speedui.components.SpeedGauge
import com.vegsahayyak.speedui.components.ThemeMode
import com.vegsahayyak.speedcore.units.SpeedUnit
@Composable
fun SpeedometerScreen(
currentSpeed: Float,
warningLimit: Float = 80f,
minCorridorLimit: Float = 40f
) {
SpeedGauge(
speed = currentSpeed,
warningSpeed = warningLimit, // Maximum speed ceiling
minSpeedLimit = minCorridorLimit, // Minimum highway corridor
isTrackingActive = true,
isOverLimit = currentSpeed > warningLimit,
themeMode = ThemeMode.DARK_GRAY,
unitLabel = "km/h",
showGpsAccuracy = true,
gpsAccuracyMeters = 3.5f,
onUnitSelected = { selectedIndex ->
// Handle unit change (e.g. km/h vs mph)
}
)
}⚙️ Component Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
speed | Float | Required | Current instantaneous vehicle speed. |
warningSpeed | Float | Required | Maximum speed ceiling threshold. |
isTrackingActive | Boolean | Required | Whether GPS tracking is actively running or in standby. |
isOverLimit | Boolean | false | When true, renders red alert glowing tones and warning styles. |
modifier | Modifier | Modifier | Modifier to be applied to the gauge container. |
minSpeedLimit | Float | 0f | Optional minimum speed corridor limit. |
maxSpeed | Float | 180f | Maximum dial scale value (e.g. 180 for km/h, 120 for mph). |
unitLabel | String | "km/h" | Text label displayed beneath the digital readout. |
unitOptions | List<UiSpeedUnit> | UiSpeedUnit.entries | Supported selectable units dropdown options (KMH, MPH, MPS, FPS). |
labelStep | Int | 20 | Numeric interval between major dial tick marks. |
onUnitSelected | ((Int) -> Unit)? | null | Callback triggered when the driver taps the unit selector. |
themeMode | ThemeMode | ThemeMode.SYSTEM | Color mode: SYSTEM, DARK_GRAY, OLED_BLACK, HIGH_CONTRAST. |
colorScheme | SpeedUiColorScheme? | null | Optional custom client branding color scheme. |
showGpsAccuracy | Boolean | true | Toggles the real-time GPS accuracy badge on/off. |
gpsAccuracyMeters | Float | -1f | Precision in meters (≤ 5m Good, ≤ 20m Fair, > 20m Weak). |
isHudMirrored | Boolean | false | When true, flips the gauge vertically for windshield reflection. |
🎨 Theme Modes & OLED Optimization
The SpeedGauge supports built-in theme presets configured via the ThemeMode enum:
enum class ThemeMode {
SYSTEM, // Automatically follows Android system Dark/Light mode
DARK_GRAY, // Deep charcoal gray background with vibrant accents
OLED_BLACK, // Pure true black (#000000) for maximum OLED battery savings
HIGH_CONTRAST, // Ultra-high visibility yellow/white accents for direct sunlight
HUD_MIRRORED // Inverts and mirrors layout vertically for windshield projection
}🎨 Custom Brand Color Schemes (SpeedUiColorScheme)
You can supply fully customized color palettes to SpeedGauge and HudDisplay:
val myBrandColors = SpeedUiColorScheme(
safeColor = Color(0xFF00E676),
warningApproachColor = Color(0xFFFF9100),
overSpeedColor = Color(0xFFFF1744),
underSpeedColor = Color(0xFF00E5FF),
warningGlowColor = Color(0x88FF1744),
needleColor = Color(0xFF2979FF)
)
SpeedGauge(
speed = currentSpeed,
warningSpeed = 80f,
isTrackingActive = true,
colorScheme = myBrandColors
)🌙 HUD Mode & Windshield Reflection (HudDisplay)
The HudDisplay composable offers a dedicated, large-digit (120sp) night-driving display that reflects off a vehicle's windshield. It is strictly rendered against a pure OLED black (#000000) background to minimize battery drain and reduce peripheral glare distractions.
import com.vegsahayyak.speedui.components.HudDisplay
import com.vegsahayyak.speedui.components.HudMirrorAxis
import com.vegsahayyak.speedui.components.hudMirror
// Dedicated digital HUD composable
HudDisplay(
speed = currentSpeed,
warningSpeed = 80f,
minSpeedLimit = 40f,
isTrackingActive = true,
isMirrored = true,
unitLabel = "km/h",
onMirrorToggle = { isMirrored -> /* toggle state */ }
)
// Or mirror any Composable using the hudMirror modifier
Box(modifier = Modifier.hudMirror(isMirrored = true, axis = HudMirrorAxis.VERTICAL)) {
SpeedGauge(speed = currentSpeed, warningSpeed = 80f, isTrackingActive = true)
}High Contrast Mode for Daylight Driving
When commercial drivers operate in bright, direct sunlight, enable ThemeMode.HIGH_CONTRAST to boost needle visibility:
SpeedGauge(
speed = currentSpeed,
warningSpeed = 80f,
isTrackingActive = true,
themeMode = ThemeMode.HIGH_CONTRAST
)🧩 Accessibility & Screen Readers
SpeedGauge implements Android Accessibility semantics out-of-the-box via SpeedGaugeTokens.contentDescriptionFor(...). Screen readers (TalkBack) will announce contextual updates such as:
"Current speed 78 kilometers per hour, speed limit 80 kilometers per hour. Warning status: normal."
🖼️ XML Layout & ViewBinding Interoperability
If your project is built with traditional XML layouts, you can embed SpeedGauge directly using AndroidX ComposeView:
<androidx.compose.ui.platform.ComposeView
android:id="@+id/speedometerComposeView"
android:layout_width="match_parent"
android:layout_height="220dp" />In your Activity or Fragment:
binding.speedometerComposeView.setContent {
SpeedGauge(
speed = currentSpeedKmh,
warningSpeed = 80f,
minSpeedLimit = 40f,
isTrackingActive = true,
isOverLimit = currentSpeedKmh > 80f
)
}🪟 The PipWidget Component (:speed-overlay)
PipWidget is a floating circular speedometer overlay designed to render over third-party applications (Google Maps, Waze, delivery apps) using SYSTEM_ALERT_WINDOW.
import com.vegsahayyak.speedoverlay.PipWidget
import com.vegsahayyak.speedoverlay.PipWidgetConfig
PipWidget(
speed = currentSpeed,
unitLabel = "km/h",
isOverLimit = isOverLimit,
isUnderLimit = isUnderLimit,
config = PipWidgetConfig(
size = 100.dp,
safeColor = Color(0xFF1FC95E),
warningColor = Color(0xFFE31D23)
)
)PipWidgetConfig Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
size | Dp | 100.dp | Outer diameter of the circular floating bubble. |
safeColor | Color | 0xFF1FC95E | Outer border color when driving within normal limits. |
warningColor | Color | 0xFFE31D23 | Outer border color during over-speed violations. |
underSpeedColor | Color | 0xFF29B6F6 | Outer border color during under-speed violations. |
backgroundColor | Color | 0x66000000 | Translucent glassmorphism background color. |
speedTextSize | TextUnit | 36.sp | Digital speed readout typography size. |
unitTextSize | TextUnit | 14.sp | Speed unit label typography size. |
textColor | Color | Color.White | Text color for speed digits and unit. |
🎙️ The VoiceCommandButton Component (:speed-ui)
A Floating Action Button (FAB) that captures spoken audio from the driver and triggers speed limit adjustments hands-free.
import com.vegsahayyak.speedui.components.VoiceCommandButton
import com.vegsahayyak.speedui.api.VoiceAction
VoiceCommandButton(
// parser defaults to null (uses built-in internal parser)
onCommandParsed = { action ->
when (action) {
is VoiceAction.SetProfile -> {
SpeedAssistant.with(context, "YOUR_JWT_LICENSE").setDrivingProfile(action.profile)
}
is VoiceAction.ChangeUnit -> {
println("Switched unit to: ${action.unitName}")
}
is VoiceAction.Unknown -> {
println("Unrecognized voice command")
}
}
}
)