diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index e68fa9f757..96876acd46 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -138,6 +138,11 @@ android:exported="false" android:theme="@style/Theme.Dolphin.Main" /> + + (CONFLATED) + val goBack = _goBack.receiveAsFlow() + + init { + if (!Netplay.isClientConnected()) { + _goBack.trySend(Unit) + } + } + + @OptIn(DelicateCoroutinesApi::class) + override fun onCleared() { + super.onCleared() + GlobalScope.launch { + Netplay.quit() + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt new file mode 100644 index 0000000000..7f199bd45e --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +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.lifecycle.Lifecycle +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import org.dolphinemu.dolphinemu.activities.EmulationActivity +import org.dolphinemu.dolphinemu.features.netplay.Netplay +import org.dolphinemu.dolphinemu.features.netplay.model.NetplayViewModel +import org.dolphinemu.dolphinemu.ui.main.ThemeProvider +import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme +import org.dolphinemu.dolphinemu.utils.ThemeHelper + +class NetplayActivity : AppCompatActivity(), ThemeProvider { + override var themeId: Int = 0 + + override fun onCreate(savedInstanceState: Bundle?) { + ThemeHelper.setTheme(this) + enableEdgeToEdge() + super.onCreate(savedInstanceState) + + val viewModel = ViewModelProvider(this)[NetplayViewModel::class.java] + + viewModel.goBack + .onEach { finish() } + .launchIn(lifecycleScope) + + viewModel.launchGame + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .onEach { EmulationActivity.launch(this, it, false) } + .launchIn(lifecycleScope) + + setContent { + DolphinTheme { + NetplayScreen( + 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, NetplayActivity::class.java)) + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt new file mode 100644 index 0000000000..de3b89d6c1 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.netplay.ui + +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.MediumTopAppBar +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import org.dolphinemu.dolphinemu.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun NetplayScreen( + onBackClicked: () -> Unit, +) { + Scaffold( + topBar = { + MediumTopAppBar( + title = { Text(stringResource(R.string.netplay_title)) }, + navigationIcon = { + IconButton(onClick = onBackClicked) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back" + ) + } + }, + ) + }, + ) { _ -> } +} + +@Preview +@Composable +private fun NetplayScreenPreview() { + NetplayScreen( + onBackClicked = {}, + ) +} \ No newline at end of file diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt index 8e9cf05422..8058b3ad96 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt @@ -9,12 +9,12 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.collectAsState +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import org.dolphinemu.dolphinemu.activities.EmulationActivity -import org.dolphinemu.dolphinemu.features.netplay.Netplay import org.dolphinemu.dolphinemu.features.netplay.model.NetplaySetupViewModel import org.dolphinemu.dolphinemu.ui.main.ThemeProvider import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme @@ -28,14 +28,11 @@ class NetplaySetupActivity : AppCompatActivity(), ThemeProvider { enableEdgeToEdge() super.onCreate(savedInstanceState) - Netplay.launchGame - .onEach { EmulationActivity.launch(this, it, false) } - .launchIn(lifecycleScope) - val viewModel = ViewModelProvider(this)[NetplaySetupViewModel::class.java] viewModel.showNetplayScreen - .onEach { /* launch NetplayActivity */ } + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .onEach { NetplayActivity.launch(this) } .launchIn(lifecycleScope) setContent { diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 1944cc4911..903a414af3 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -995,4 +995,5 @@ It can efficiently compress both junk data and encrypted Wii data. IP address Host code Port + Netplay