mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-05-09 04:13:28 -05:00
Move NetplaySetupScreen to its own file
This commit is contained in:
parent
b2e900ce40
commit
43d592c912
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package org.dolphinemu.dolphinemu.features.netplay.ui
|
||||
|
||||
import android.content.Context
|
||||
|
|
@ -10,74 +8,20 @@ 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.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SecondaryTabRow
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.dolphinemu.dolphinemu.R
|
||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity
|
||||
import org.dolphinemu.dolphinemu.features.netplay.Netplay
|
||||
import org.dolphinemu.dolphinemu.features.netplay.model.ConnectionRole
|
||||
import org.dolphinemu.dolphinemu.features.netplay.model.ConnectionType
|
||||
import org.dolphinemu.dolphinemu.features.netplay.model.NetplaySetupViewModel
|
||||
import org.dolphinemu.dolphinemu.ui.main.ThemeProvider
|
||||
import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme
|
||||
import org.dolphinemu.dolphinemu.ui.theme.MenuSpacer
|
||||
import org.dolphinemu.dolphinemu.utils.ThemeHelper
|
||||
|
||||
private data class ErrorDialogState(val message: String) {
|
||||
val onDismissed = CompletableDeferred<Unit>()
|
||||
}
|
||||
|
||||
class NetplaySetupActivity : AppCompatActivity(), ThemeProvider {
|
||||
override var themeId: Int = 0
|
||||
private lateinit var viewModel: NetplaySetupViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ThemeHelper.setTheme(this)
|
||||
|
|
@ -88,7 +32,7 @@ class NetplaySetupActivity : AppCompatActivity(), ThemeProvider {
|
|||
.onEach { EmulationActivity.launch(this, it, false) }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
viewModel = ViewModelProvider(this)[NetplaySetupViewModel::class.java]
|
||||
val viewModel = ViewModelProvider(this)[NetplaySetupViewModel::class.java]
|
||||
|
||||
viewModel.showNetplayScreen
|
||||
.onEach { /* launch NetplayActivity */ }
|
||||
|
|
@ -135,271 +79,3 @@ class NetplaySetupActivity : AppCompatActivity(), ThemeProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetplaySetupScreen(
|
||||
onBackClicked: () -> Unit,
|
||||
connecting: Boolean,
|
||||
errors: Flow<String>,
|
||||
connectionRole: ConnectionRole,
|
||||
onConnectionRoleChanged: (ConnectionRole) -> Unit,
|
||||
nickname: String,
|
||||
onNicknameChanged: (String) -> Unit,
|
||||
connectionType: ConnectionType,
|
||||
onConnectionTypeChanged: (ConnectionType) -> Unit,
|
||||
ipAddress: String,
|
||||
onIpAddressChanged: (String) -> Unit,
|
||||
connectPort: String,
|
||||
onConnectPortChanged: (String) -> Unit,
|
||||
hostCode: String,
|
||||
onHostCodeChanged: (String) -> Unit,
|
||||
onConnectClicked: () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
MediumTopAppBar(
|
||||
title = { Text(stringResource(R.string.netplay_setup_title)) },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBackClicked) {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = onConnectClicked,
|
||||
) {
|
||||
if (connecting) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(18.dp),
|
||||
strokeWidth = 2.dp,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
)
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(stringResource(connectionRole.loadingLabelId))
|
||||
} else {
|
||||
Text(stringResource(connectionRole.labelId))
|
||||
}
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
var activeErrorDialog by remember { mutableStateOf<ErrorDialogState?>(null) }
|
||||
LaunchedEffect(Unit) {
|
||||
errors.collect { message ->
|
||||
activeErrorDialog = ErrorDialogState(message)
|
||||
activeErrorDialog?.onDismissed?.await()
|
||||
activeErrorDialog = null
|
||||
}
|
||||
}
|
||||
activeErrorDialog?.let { activeErrorDialog ->
|
||||
AlertDialog(
|
||||
text = { Text(activeErrorDialog.message) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { activeErrorDialog.onDismissed.complete(Unit) }) {
|
||||
Text("Dismiss")
|
||||
}
|
||||
},
|
||||
onDismissRequest = { activeErrorDialog.onDismissed.complete(Unit) },
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.consumeWindowInsets(innerPadding)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(innerPadding)
|
||||
) {
|
||||
SecondaryTabRow(selectedTabIndex = ConnectionRole.all.indexOf(connectionRole)) {
|
||||
ConnectionRole.all.forEach { role ->
|
||||
Tab(
|
||||
selected = connectionRole == role,
|
||||
onClick = { onConnectionRoleChanged(role) },
|
||||
text = { Text(stringResource(role.labelId)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = DolphinTheme.scaffoldPadding)
|
||||
) {
|
||||
NetplaySetupContent(
|
||||
nickname = nickname,
|
||||
onNicknameChanged = onNicknameChanged,
|
||||
connectionType = connectionType,
|
||||
onConnectionTypeChanged = onConnectionTypeChanged,
|
||||
ipAddress = ipAddress,
|
||||
onIpAddressChanged = onIpAddressChanged,
|
||||
hostCode = hostCode,
|
||||
onHostCodeChanged = onHostCodeChanged,
|
||||
connectPort = connectPort,
|
||||
onConnectPortChanged = onConnectPortChanged,
|
||||
connectionRole = connectionRole,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetplaySetupContent(
|
||||
nickname: String,
|
||||
onNicknameChanged: (String) -> Unit,
|
||||
connectionType: ConnectionType,
|
||||
onConnectionTypeChanged: (ConnectionType) -> Unit,
|
||||
ipAddress: String,
|
||||
onIpAddressChanged: (String) -> Unit,
|
||||
hostCode: String,
|
||||
onHostCodeChanged: (String) -> Unit,
|
||||
connectPort: String,
|
||||
onConnectPortChanged: (String) -> Unit,
|
||||
connectionRole: ConnectionRole,
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = nickname,
|
||||
onValueChange = onNicknameChanged,
|
||||
label = { Text(stringResource(R.string.netplay_nickname_label)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
ConnectionTypePicker(
|
||||
connectionType = connectionType,
|
||||
onConnectionTypeChanged = onConnectionTypeChanged,
|
||||
)
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
when (connectionRole) {
|
||||
ConnectionRole.Connect -> ConnectMenu(
|
||||
connectionType = connectionType,
|
||||
ipAddress = ipAddress,
|
||||
onIpAddressChanged = onIpAddressChanged,
|
||||
hostCode = hostCode,
|
||||
onHostCodeChanged = onHostCodeChanged,
|
||||
port = connectPort,
|
||||
onPortChanged = onConnectPortChanged,
|
||||
)
|
||||
|
||||
ConnectionRole.Host -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConnectionTypePicker(
|
||||
connectionType: ConnectionType,
|
||||
onConnectionTypeChanged: (ConnectionType) -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
) {
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
) {
|
||||
ConnectionType.all.forEach { connectionType ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(connectionType.labelId)) },
|
||||
onClick = {
|
||||
onConnectionTypeChanged(connectionType)
|
||||
expanded = false
|
||||
},
|
||||
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
|
||||
)
|
||||
}
|
||||
}
|
||||
OutlinedTextField(
|
||||
value = stringResource(connectionType.labelId),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
label = { Text(stringResource(R.string.netplay_connection_type)) },
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded) },
|
||||
modifier = Modifier
|
||||
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ConnectMenu(
|
||||
connectionType: ConnectionType,
|
||||
ipAddress: String,
|
||||
onIpAddressChanged: (String) -> Unit,
|
||||
hostCode: String,
|
||||
onHostCodeChanged: (String) -> Unit,
|
||||
port: String,
|
||||
onPortChanged: (String) -> Unit,
|
||||
) {
|
||||
when (connectionType) {
|
||||
ConnectionType.DirectConnection -> {
|
||||
OutlinedTextField(
|
||||
value = ipAddress,
|
||||
onValueChange = onIpAddressChanged,
|
||||
label = { Text(stringResource(R.string.netplay_ip_address_label)) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
OutlinedTextField(
|
||||
value = port,
|
||||
onValueChange = onPortChanged,
|
||||
label = { Text(stringResource(R.string.netplay_port_label)) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
ConnectionType.TraversalServer -> OutlinedTextField(
|
||||
value = hostCode,
|
||||
onValueChange = onHostCodeChanged,
|
||||
label = { Text(stringResource(R.string.netplay_host_code_label)) },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun NetplaySetupScreenPreview() {
|
||||
MaterialTheme {
|
||||
NetplaySetupScreen(
|
||||
onBackClicked = {},
|
||||
connecting = false,
|
||||
errors = emptyFlow(),
|
||||
connectionRole = ConnectionRole.Connect,
|
||||
onConnectionRoleChanged = {},
|
||||
nickname = "Preview nickname",
|
||||
onNicknameChanged = {},
|
||||
connectionType = ConnectionType.DirectConnection,
|
||||
onConnectionTypeChanged = {},
|
||||
ipAddress = "127.0.0.1",
|
||||
onIpAddressChanged = {},
|
||||
connectPort = "2626",
|
||||
onConnectPortChanged = {},
|
||||
hostCode = "",
|
||||
onHostCodeChanged = {},
|
||||
onConnectClicked = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,330 @@
|
|||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package org.dolphinemu.dolphinemu.features.netplay.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SecondaryTabRow
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import org.dolphinemu.dolphinemu.R
|
||||
import org.dolphinemu.dolphinemu.features.netplay.model.ConnectionRole
|
||||
import org.dolphinemu.dolphinemu.features.netplay.model.ConnectionType
|
||||
import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme
|
||||
import org.dolphinemu.dolphinemu.ui.theme.MenuSpacer
|
||||
|
||||
private data class ErrorDialogState(val message: String) {
|
||||
val onDismissed = CompletableDeferred<Unit>()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NetplaySetupScreen(
|
||||
onBackClicked: () -> Unit,
|
||||
connecting: Boolean,
|
||||
errors: Flow<String>,
|
||||
connectionRole: ConnectionRole,
|
||||
onConnectionRoleChanged: (ConnectionRole) -> Unit,
|
||||
nickname: String,
|
||||
onNicknameChanged: (String) -> Unit,
|
||||
connectionType: ConnectionType,
|
||||
onConnectionTypeChanged: (ConnectionType) -> Unit,
|
||||
ipAddress: String,
|
||||
onIpAddressChanged: (String) -> Unit,
|
||||
connectPort: String,
|
||||
onConnectPortChanged: (String) -> Unit,
|
||||
hostCode: String,
|
||||
onHostCodeChanged: (String) -> Unit,
|
||||
onConnectClicked: () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
MediumTopAppBar(
|
||||
title = { Text(stringResource(R.string.netplay_setup_title)) },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBackClicked) {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = onConnectClicked,
|
||||
) {
|
||||
if (connecting) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(18.dp),
|
||||
strokeWidth = 2.dp,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
)
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(stringResource(connectionRole.loadingLabelId))
|
||||
} else {
|
||||
Text(stringResource(connectionRole.labelId))
|
||||
}
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
var activeErrorDialog by remember { mutableStateOf<ErrorDialogState?>(null) }
|
||||
LaunchedEffect(Unit) {
|
||||
errors.collect { message ->
|
||||
activeErrorDialog = ErrorDialogState(message)
|
||||
activeErrorDialog?.onDismissed?.await()
|
||||
activeErrorDialog = null
|
||||
}
|
||||
}
|
||||
activeErrorDialog?.let { activeErrorDialog ->
|
||||
AlertDialog(
|
||||
text = { Text(activeErrorDialog.message) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { activeErrorDialog.onDismissed.complete(Unit) }) {
|
||||
Text("Dismiss")
|
||||
}
|
||||
},
|
||||
onDismissRequest = { activeErrorDialog.onDismissed.complete(Unit) },
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.consumeWindowInsets(innerPadding)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(innerPadding)
|
||||
) {
|
||||
SecondaryTabRow(selectedTabIndex = ConnectionRole.all.indexOf(connectionRole)) {
|
||||
ConnectionRole.all.forEach { role ->
|
||||
Tab(
|
||||
selected = connectionRole == role,
|
||||
onClick = { onConnectionRoleChanged(role) },
|
||||
text = { Text(stringResource(role.labelId)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = DolphinTheme.scaffoldPadding)
|
||||
) {
|
||||
NetplaySetupContent(
|
||||
nickname = nickname,
|
||||
onNicknameChanged = onNicknameChanged,
|
||||
connectionType = connectionType,
|
||||
onConnectionTypeChanged = onConnectionTypeChanged,
|
||||
ipAddress = ipAddress,
|
||||
onIpAddressChanged = onIpAddressChanged,
|
||||
hostCode = hostCode,
|
||||
onHostCodeChanged = onHostCodeChanged,
|
||||
connectPort = connectPort,
|
||||
onConnectPortChanged = onConnectPortChanged,
|
||||
connectionRole = connectionRole,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetplaySetupContent(
|
||||
nickname: String,
|
||||
onNicknameChanged: (String) -> Unit,
|
||||
connectionType: ConnectionType,
|
||||
onConnectionTypeChanged: (ConnectionType) -> Unit,
|
||||
ipAddress: String,
|
||||
onIpAddressChanged: (String) -> Unit,
|
||||
hostCode: String,
|
||||
onHostCodeChanged: (String) -> Unit,
|
||||
connectPort: String,
|
||||
onConnectPortChanged: (String) -> Unit,
|
||||
connectionRole: ConnectionRole,
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = nickname,
|
||||
onValueChange = onNicknameChanged,
|
||||
label = { Text(stringResource(R.string.netplay_nickname_label)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
ConnectionTypePicker(
|
||||
connectionType = connectionType,
|
||||
onConnectionTypeChanged = onConnectionTypeChanged,
|
||||
)
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
when (connectionRole) {
|
||||
ConnectionRole.Connect -> ConnectMenu(
|
||||
connectionType = connectionType,
|
||||
ipAddress = ipAddress,
|
||||
onIpAddressChanged = onIpAddressChanged,
|
||||
hostCode = hostCode,
|
||||
onHostCodeChanged = onHostCodeChanged,
|
||||
port = connectPort,
|
||||
onPortChanged = onConnectPortChanged,
|
||||
)
|
||||
|
||||
ConnectionRole.Host -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConnectionTypePicker(
|
||||
connectionType: ConnectionType,
|
||||
onConnectionTypeChanged: (ConnectionType) -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
) {
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
) {
|
||||
ConnectionType.all.forEach { connectionType ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(connectionType.labelId)) },
|
||||
onClick = {
|
||||
onConnectionTypeChanged(connectionType)
|
||||
expanded = false
|
||||
},
|
||||
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
|
||||
)
|
||||
}
|
||||
}
|
||||
OutlinedTextField(
|
||||
value = stringResource(connectionType.labelId),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
label = { Text(stringResource(R.string.netplay_connection_type)) },
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded) },
|
||||
modifier = Modifier
|
||||
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ConnectMenu(
|
||||
connectionType: ConnectionType,
|
||||
ipAddress: String,
|
||||
onIpAddressChanged: (String) -> Unit,
|
||||
hostCode: String,
|
||||
onHostCodeChanged: (String) -> Unit,
|
||||
port: String,
|
||||
onPortChanged: (String) -> Unit,
|
||||
) {
|
||||
when (connectionType) {
|
||||
ConnectionType.DirectConnection -> {
|
||||
OutlinedTextField(
|
||||
value = ipAddress,
|
||||
onValueChange = onIpAddressChanged,
|
||||
label = { Text(stringResource(R.string.netplay_ip_address_label)) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
MenuSpacer()
|
||||
|
||||
OutlinedTextField(
|
||||
value = port,
|
||||
onValueChange = onPortChanged,
|
||||
label = { Text(stringResource(R.string.netplay_port_label)) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
ConnectionType.TraversalServer -> OutlinedTextField(
|
||||
value = hostCode,
|
||||
onValueChange = onHostCodeChanged,
|
||||
label = { Text(stringResource(R.string.netplay_host_code_label)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun NetplaySetupScreenPreview() {
|
||||
MaterialTheme {
|
||||
NetplaySetupScreen(
|
||||
onBackClicked = {},
|
||||
connecting = false,
|
||||
errors = emptyFlow(),
|
||||
connectionRole = ConnectionRole.Connect,
|
||||
onConnectionRoleChanged = {},
|
||||
nickname = "Preview nickname",
|
||||
onNicknameChanged = {},
|
||||
connectionType = ConnectionType.DirectConnection,
|
||||
onConnectionTypeChanged = {},
|
||||
ipAddress = "127.0.0.1",
|
||||
onIpAddressChanged = {},
|
||||
connectPort = "2626",
|
||||
onConnectPortChanged = {},
|
||||
hostCode = "",
|
||||
onHostCodeChanged = {},
|
||||
onConnectClicked = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user