Add compose dependencies for Android and empty NetplaySetupActivity

Derive compose colour theming from the existing XML styles already set at the activity level.
This commit is contained in:
Tom Pratt 2026-04-06 13:32:57 +01:00
parent 6d5399246e
commit ec8253ebff
9 changed files with 252 additions and 0 deletions

View File

@ -1,5 +1,6 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.androidx.baselineprofile)
}
@ -10,6 +11,7 @@ android {
ndkVersion = "29.0.14206865"
buildFeatures {
compose = true
viewBinding = true
buildConfig = true
resValues = true
@ -150,6 +152,15 @@ dependencies {
implementation(libs.kotlinx.coroutines.android)
implementation(libs.filepicker)
// Jetpack Compose
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material.icons)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.ui)
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.tooling.preview)
}
fun getGitVersion(): String {

View File

@ -133,6 +133,11 @@
android:label="@string/user_data_submenu"
android:theme="@style/Theme.Dolphin.Main" />
<activity
android:name=".features.netplay.ui.NetplaySetupActivity"
android:exported="false"
android:theme="@style/Theme.Dolphin.Main" />
<activity
android:name=".features.riivolution.ui.RiivolutionBootActivity"
android:exported="false"

View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0-or-later
@file:OptIn(ExperimentalMaterial3Api::class)
package org.dolphinemu.dolphinemu.features.netplay.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.ui.main.ThemeProvider
import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme
import org.dolphinemu.dolphinemu.utils.ThemeHelper
class NetplaySetupActivity : AppCompatActivity(), ThemeProvider {
override var themeId: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
ThemeHelper.setTheme(this)
enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent {
DolphinTheme {
NetplaySetupScreen(
onBackClicked = { finish() },
)
}
}
}
override fun setTheme(themeId: Int) {
super.setTheme(themeId)
this.themeId = themeId
}
override fun onResume() {
ThemeHelper.setCorrectTheme(this)
super.onResume()
}
companion object {
@JvmStatic
fun launch(context: Context) {
context.startActivity(Intent(context, NetplaySetupActivity::class.java))
}
}
}
@Composable
private fun NetplaySetupScreen(
onBackClicked: () -> Unit,
) {
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text(stringResource(R.string.netplay_setup_title)) },
navigationIcon = {
IconButton(onClick = onBackClicked) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back"
)
}
},
)
}
) { innerPadding ->
Column(
modifier = Modifier
.consumeWindowInsets(innerPadding)
.padding(innerPadding)
.padding(horizontal = DolphinTheme.scaffoldPadding)
.verticalScroll(rememberScrollState()),
) {
}
}
}
@Preview
@Composable
private fun NetplaySetupScreenPreview() {
MaterialTheme {
NetplayScreen(onBackClicked = {})
}
}

View File

@ -21,6 +21,7 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag
import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemMenuNotInstalledDialogFragment
import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemUpdateProgressBarDialogFragment
import org.dolphinemu.dolphinemu.features.sysupdate.ui.SystemUpdateViewModel
import org.dolphinemu.dolphinemu.features.netplay.ui.NetplaySetupActivity
import org.dolphinemu.dolphinemu.fragments.AboutDialogFragment
import org.dolphinemu.dolphinemu.model.GameFileCache
import org.dolphinemu.dolphinemu.services.GameFileCacheManager
@ -188,6 +189,11 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme
true
}
R.id.menu_netplay -> {
NetplaySetupActivity.launch(activity)
true
}
R.id.menu_about -> {
showAboutDialog()
false

View File

@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.ui.theme
import android.content.Context
import androidx.annotation.AttrRes
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.google.android.material.color.MaterialColors
import androidx.appcompat.R as AppCompatR
import com.google.android.material.R as MaterialR
object DolphinTheme {
val scaffoldPadding = 16.dp
}
@Composable
fun DolphinTheme(content: @Composable () -> Unit) {
val context = LocalContext.current
val isDark = isSystemInDarkTheme()
val colorScheme = remember(context, isDark) { context.toDolphinColorScheme(isDark) }
MaterialTheme(
colorScheme = colorScheme,
content = content
)
}
private fun Context.toDolphinColorScheme(isDark: Boolean): ColorScheme {
fun attr(@AttrRes attr: Int) = Color(MaterialColors.getColor(this, attr, 0))
val background = obtainStyledAttributes(intArrayOf(android.R.attr.colorBackground)).use {
Color(it.getColor(0, 0))
}
return if (isDark) {
darkColorScheme(
primary = attr(AppCompatR.attr.colorPrimary),
onPrimary = attr(MaterialR.attr.colorOnPrimary),
primaryContainer = attr(MaterialR.attr.colorPrimaryContainer),
onPrimaryContainer = attr(MaterialR.attr.colorOnPrimaryContainer),
secondary = attr(MaterialR.attr.colorSecondary),
onSecondary = attr(MaterialR.attr.colorOnSecondary),
secondaryContainer = attr(MaterialR.attr.colorSecondaryContainer),
onSecondaryContainer = attr(MaterialR.attr.colorOnSecondaryContainer),
tertiary = attr(MaterialR.attr.colorTertiary),
onTertiary = attr(MaterialR.attr.colorOnTertiary),
tertiaryContainer = attr(MaterialR.attr.colorTertiaryContainer),
onTertiaryContainer = attr(MaterialR.attr.colorOnTertiaryContainer),
error = attr(AppCompatR.attr.colorError),
onError = attr(MaterialR.attr.colorOnError),
errorContainer = attr(MaterialR.attr.colorErrorContainer),
onErrorContainer = attr(MaterialR.attr.colorOnErrorContainer),
background = background,
onBackground = attr(MaterialR.attr.colorOnBackground),
surface = attr(MaterialR.attr.colorSurface),
onSurface = attr(MaterialR.attr.colorOnSurface),
surfaceVariant = attr(MaterialR.attr.colorSurfaceVariant),
onSurfaceVariant = attr(MaterialR.attr.colorOnSurfaceVariant),
outline = attr(MaterialR.attr.colorOutline),
inverseSurface = attr(MaterialR.attr.colorSurfaceInverse),
inverseOnSurface = attr(MaterialR.attr.colorOnSurfaceInverse),
inversePrimary = attr(MaterialR.attr.colorPrimaryInverse),
)
} else {
lightColorScheme(
primary = attr(AppCompatR.attr.colorPrimary),
onPrimary = attr(MaterialR.attr.colorOnPrimary),
primaryContainer = attr(MaterialR.attr.colorPrimaryContainer),
onPrimaryContainer = attr(MaterialR.attr.colorOnPrimaryContainer),
secondary = attr(MaterialR.attr.colorSecondary),
onSecondary = attr(MaterialR.attr.colorOnSecondary),
secondaryContainer = attr(MaterialR.attr.colorSecondaryContainer),
onSecondaryContainer = attr(MaterialR.attr.colorOnSecondaryContainer),
tertiary = attr(MaterialR.attr.colorTertiary),
onTertiary = attr(MaterialR.attr.colorOnTertiary),
tertiaryContainer = attr(MaterialR.attr.colorTertiaryContainer),
onTertiaryContainer = attr(MaterialR.attr.colorOnTertiaryContainer),
error = attr(AppCompatR.attr.colorError),
onError = attr(MaterialR.attr.colorOnError),
errorContainer = attr(MaterialR.attr.colorErrorContainer),
onErrorContainer = attr(MaterialR.attr.colorOnErrorContainer),
background = background,
onBackground = attr(MaterialR.attr.colorOnBackground),
surface = attr(MaterialR.attr.colorSurface),
onSurface = attr(MaterialR.attr.colorOnSurface),
surfaceVariant = attr(MaterialR.attr.colorSurfaceVariant),
onSurfaceVariant = attr(MaterialR.attr.colorOnSurfaceVariant),
outline = attr(MaterialR.attr.colorOutline),
inverseSurface = attr(MaterialR.attr.colorSurfaceInverse),
inverseOnSurface = attr(MaterialR.attr.colorOnSurfaceInverse),
inversePrimary = attr(MaterialR.attr.colorPrimaryInverse),
)
}
}

View File

@ -51,6 +51,11 @@
android:title="@string/grid_menu_online_system_update"
app:showAsAction="never"/>
<item
android:id="@+id/menu_netplay"
android:title="@string/grid_menu_netplay"
app:showAsAction="never"/>
<item
android:id="@+id/menu_about"
android:title="@string/grid_menu_about"

View File

@ -495,6 +495,7 @@
<string name="grid_menu_import_wii_save">Import Wii Save</string>
<string name="grid_menu_import_nand_backup">Import BootMii NAND Backup</string>
<string name="grid_menu_online_system_update">Perform Online System Update</string>
<string name="grid_menu_netplay">Netplay</string>
<string name="grid_menu_load_wii_system_menu">Load Wii System Menu</string>
<string name="grid_menu_load_wii_system_menu_installed">Load Wii System Menu (%s)</string>
<string name="grid_menu_load_vwii_system_menu_installed">Load vWii System Menu (%s)</string>
@ -980,4 +981,8 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="achievements_logout">Log Out</string>
<string name="achievements_login_in_progress">Logging In</string>
<string name="achievements_login_failed">Login Failed</string>
<!-- Netplay -->
<string name="netplay_setup_title">Netplay Setup</string>
<string name="netplay_nickname_label">Nickname</string>
</resources>

View File

@ -4,6 +4,7 @@ plugins {
alias(libs.plugins.android.library) apply false
alias(libs.plugins.android.test) apply false
alias(libs.plugins.androidx.baselineprofile) apply false
alias(libs.plugins.kotlin.compose) apply false
}
buildscript {

View File

@ -4,6 +4,7 @@ appcompat = "1.7.1"
benchmarkMacroJunit4 = "1.5.0-alpha04"
cardview = "1.0.0"
coil = "2.7.0"
compose-bom = "2025.04.00"
constraintlayout = "2.2.1"
coreKtx = "1.18.0"
coreSplashscreen = "1.2.0"
@ -27,9 +28,16 @@ tvprovider = "1.1.0"
uiautomator = "2.3.0"
[libraries]
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
androidx-benchmark-macro-junit4 = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "benchmarkMacroJunit4" }
androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "cardview" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-compose-material-icons = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "coreSplashscreen" }
@ -58,4 +66,5 @@ android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
android-test = { id = "com.android.test", version.ref = "agp" }
androidx-baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmarkMacroJunit4" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }