Theming
Light, dark, and system themes powered by Compose Material 3.
The Kotlin template uses Compose Material 3 with custom light/dark color schemes, DataStore-persisted theme choice, optional Material You dynamic color, and edge-to-edge system bars that follow the active theme.
What it provides
| Surface | Status | Implementation |
|---|---|---|
| Theme modes | Integrated | AppTheme.Light, Dark, and System |
| Persistence | Integrated | DataStore keys theme_tag and dynamic_color_enabled |
| Material 3 scheme | Integrated | SoarStarterKotlinTheme wraps MaterialTheme |
| Dynamic color | Integrated | Available on Android 12+ when enabled; off by default |
| System bars | Integrated | MainActivity.ApplySystemBarTheme() updates SystemBarStyle |
Key files
Theme selection
AppTheme stores three modes:
Light("light")
Dark("dark")
System("system")ThemeController maps the DataStore theme_tag into StateFlow<AppTheme> and
maps dynamic_color_enabled into StateFlow<Boolean>. MainActivity resolves
the selected mode against isSystemInDarkTheme(), then passes both values to
SoarStarterKotlinTheme.
The drawer and Component gallery reuse ThemeToggle, a segmented Compose
control that switches between System, Light, and Dark.
Color system
Color.kt defines:
- iOS-style accent and semantic colors, including
IosTint,IosDestructive,IosGreen,IosIndigo, andIosOrange. - Light and dark base colors for background, foreground, muted, border, input, and ring values.
ColorSchemeextension properties such asgroupedBackground,groupedSurface,groupedInput,labelSecondary,separatorSoft, andtint.
Theme.kt builds explicit Material 3 light and dark color schemes from those
tokens. If dynamic color is enabled and the device is Android 12 or newer,
dynamicLightColorScheme() or dynamicDarkColorScheme() replaces the custom
scheme.
Dynamic color is implemented, persisted, and passed into the root theme, but
the stored default is false. Turn it on from your own settings UI if you
want Material You behavior exposed to users.
Typography
Type.kt customizes the Material 3 typography scale with default Android fonts,
semibold/bold headings, and letterSpacing = 0.sp. Use
MaterialTheme.typography in screens instead of hardcoding text sizes.
Edge-to-edge
MainActivity calls enableEdgeToEdge() and uses SystemBarStyle.dark() or
SystemBarStyle.light() based on the resolved theme. That keeps status and
navigation bar icons readable when the user switches theme.
Most screen backgrounds use MaterialTheme.colorScheme.groupedBackground,
matching the starter's grouped mobile settings style.
Rebrand checklist
- Replace
IosTintand related semantic colors inColor.kt. - Adjust light/dark color schemes in
Theme.kt. - Change typography in
Type.ktif your brand uses a custom font. - Replace launcher assets under
res/drawable,res/mipmap-*, andres/mipmap-anydpi. - Update
app_nameinstrings.xml. - Change
applicationId, namespace, and any Play/App Links identifiers when making a real product fork. - Revisit
LINKING_DOMAIN,assetlinks.json, release signing, Firebase, and RevenueCat after changing the package name.
Verify
- Theme choice persists after process restart.
- System mode follows the device dark-mode setting.
- Dynamic color only changes the scheme on Android 12+ when enabled.
- Status and navigation bar icons stay readable in light and dark themes.
- Launcher icons, display name, package name, and App Links all match the rebranded app.
