In this post, we will explore how to structure the UI in a Compose for Desktop project, apply dark mode themes, and implement navigation functionality.
Additionally, we will introduce reusable UI components (Components) and demonstrate how to utilize them effectively.
Project Structure
For this example, we will organize the project as follows:
π src/jvmMain/kotlin/
π ui/ βββ π HomeScreen.kt # Home screen βββ π SettingsScreen.kt # Settings screen βββ π Navigation.kt # Screen navigation management βββ π Theme.kt # Light/Dark theme management βββ π Components.kt # Reusable UI components π Main.kt # Application entry point
Theme.kt (Dark/Light Theme Application)
To support theme switching, we use a global ThemeController to manage theme state.
package ui import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue private val DarkColorPalette = darkColors( primary = androidx.compose.ui.graphics.Color(0xFFBB86FC), primaryVariant = androidx.compose.ui.graphics.Color(0xFF3700B3), secondary = androidx.compose.ui.graphics.Color(0xFF03DAC5) ) private val LightColorPalette = lightColors( primary = androidx.compose.ui.graphics.Color(0xFF6200EE), primaryVariant = androidx.compose.ui.graphics.Color(0xFF3700B3), secondary = androidx.compose.ui.graphics.Color(0xFF03DAC5) ) object ThemeController { var isDarkMode by mutableStateOf(false) } @Composable fun AppTheme(content: @Composable () -> Unit) { val colors = if (ThemeController.isDarkMode) DarkColorPalette else LightColorPalette MaterialTheme( colors = colors, typography = Typography(), shapes = Shapes(), content = content ) }
- ThemeController.isDarkMode manages the global theme state.
- AppTheme applies the dark or light theme dynamically based on the theme state.
HomeScreen.kt (Home Screen)
The home screen displays a welcome card using a reusable UI component (SimpleCard).
package ui.screens import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import ui.Screen @Composable fun HomeScreen(onNavigate: (Screen) -> Unit) { Scaffold( topBar = { TopAppBar(title = { Text("Home") }) } ) { Column( modifier = Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.Center ) { Text("Welcome to Compose for Desktop!", style = MaterialTheme.typography.h5) Spacer(modifier = Modifier.height(20.dp)) Button(onClick = { onNavigate(Screen.SETTINGS) }) { Text("Go to Settings") } } } }
- Uses SimpleCard for consistent UI elements.
- Clicking the button triggers onNavigate(Screen.SETTINGS), navigating to the Settings screen.
SettingsScreen.kt (Settings Screen)
The settings screen features a dark mode toggle switch.
package ui.screens import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import ui.Screen import ui.ThemeController import ui.components.SimpleCard @Composable fun SettingsScreen(onNavigate: (Screen) -> Unit) { Scaffold( topBar = { TopAppBar(title = { Text("Settings") }) } ) { Column( modifier = Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.Center ) { SimpleCard(title = "Settings", content = "Customize your app preferences.") Spacer(modifier = Modifier.height(10.dp)) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Text("Dark Mode") Switch( checked = ThemeController.isDarkMode, onCheckedChange = { ThemeController.isDarkMode = it } ) } Spacer(modifier = Modifier.height(20.dp)) Button(onClick = { onNavigate(Screen.HOME) }) { Text("Back to Home") } } } }
- The Switch button toggles dark mode on/off.
- Updating ThemeController.isDarkMode instantly changes the theme across the app.
Components.kt (Reusable UI Components)
We define reusable UI elements such as SimpleCard.
package ui.components import androidx.compose.foundation.layout.* import androidx.compose.material.Card import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun SimpleCard(title: String, content: String) { Card( modifier = Modifier.fillMaxWidth().padding(8.dp), elevation = 4.dp ) { Column(modifier = Modifier.padding(16.dp)) { Text(text = title, style = MaterialTheme.typography.h6) Spacer(modifier = Modifier.height(8.dp)) Text(text = content, style = MaterialTheme.typography.body2) } } }
- SimpleCard provides a consistent UI structure.
- Used in both HomeScreen and SettingsScreen for uniform styling.
Main.kt (Application Entry Point)
Finally, we wrap everything inside AppTheme and launch NavigationController.
import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import ui.AppTheme import ui.NavigationController fun main() = application { Window(onCloseRequest = ::exitApplication, title = "Compose Desktop App") { AppTheme { NavigationController() } } }
π Running the Application
Run the following command to start the application:
gradle run
- The Home Screen is displayed by default.
- Clicking βGo to Settingsβ navigates to the Settings screen.
- Toggling the Dark Mode switch updates the entire appβs theme instantly.
Now, you can expand this template with more features and additional screens as needed! π
Top comments (0)