DEV Community

Chanbong Park
Chanbong Park

Posted on

Compose for Desktop - Project UI Structure and Theme Application

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 
Enter fullscreen mode Exit fullscreen mode

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 ) } 
Enter fullscreen mode Exit fullscreen mode
  • 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") } } } } 
Enter fullscreen mode Exit fullscreen mode
  • 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") } } } } 
Enter fullscreen mode Exit fullscreen mode
  • 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) } } } 
Enter fullscreen mode Exit fullscreen mode
  • 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() } } } 
Enter fullscreen mode Exit fullscreen mode

πŸš€ Running the Application

Run the following command to start the application:

gradle run 
Enter fullscreen mode Exit fullscreen mode
  • 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.

Home Screen

Settings Screen

Settings Screen with Dark Theme Applied

Now, you can expand this template with more features and additional screens as needed! πŸ˜ƒ

Top comments (0)