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 index 6613a719c0..15221a4bf3 100644 --- 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 @@ -33,6 +33,7 @@ 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.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Remove @@ -57,7 +58,6 @@ import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold -import androidx.compose.material3.SheetState import androidx.compose.material3.SheetValue import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -86,6 +86,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import coil.compose.AsyncImage import coil.request.ImageRequest import kotlinx.coroutines.flow.Flow @@ -105,6 +106,7 @@ import org.dolphinemu.dolphinemu.ui.theme.MenuSpacer import org.dolphinemu.dolphinemu.ui.theme.OutlinedBox import org.dolphinemu.dolphinemu.ui.theme.PreviewTheme import org.dolphinemu.dolphinemu.ui.theme.ReadOnlyTextField +import org.dolphinemu.dolphinemu.ui.theme.rememberSheetState import org.dolphinemu.dolphinemu.utils.CoilUtils import java.util.Locale @@ -564,7 +566,13 @@ private fun Chat( fun LazyListScope.messages() { items(messages.size) { index -> - Text(text = messages[index].message(context)) + Text( + text = messages[index].message(context), + style = MaterialTheme.typography.bodyMedium.copy(lineHeight = 18.sp), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 2.dp) + ) } } @@ -574,14 +582,10 @@ private fun Chat( draftMessage = "" } - val density = LocalDensity.current - val bottomSheetState = remember { - SheetState( - skipPartiallyExpanded = true, - density = density, - initialValue = if (showBottomSheet) SheetValue.Expanded else SheetValue.Hidden, - ) - } + val bottomSheetState = rememberSheetState( + skipPartiallyExpanded = true, + initialValue = if (showBottomSheet) SheetValue.Expanded else SheetValue.Hidden, + ) if (showBottomSheet) { ModalBottomSheet( @@ -594,7 +598,7 @@ private fun Chat( reverseLayout = true, contentPadding = PaddingValues(bottom = 4.dp), modifier = Modifier - .weight(1f) + .weight(1f, fill = false) .padding(horizontal = DolphinTheme.scaffoldPadding) ) { messages() @@ -605,7 +609,7 @@ private fun Chat( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(horizontal = 8.dp) + .padding(8.dp) ) { OutlinedTextField( value = draftMessage, @@ -615,11 +619,14 @@ private fun Chat( modifier = Modifier .weight(1f) ) - TextButton( + IconButton( onClick = submitMessage, enabled = draftMessage.isNotBlank(), ) { - Text(stringResource(R.string.netplay_chat_send)) + Icon( + imageVector = Icons.AutoMirrored.Filled.Send, + contentDescription = stringResource(R.string.netplay_chat_send), + ) } } } @@ -652,14 +659,10 @@ private fun GamePicker( onShowGamePickerChanged: (Boolean) -> Unit, isHosting: Boolean, ) { - val density = LocalDensity.current - val bottomSheetState = remember { - SheetState( - skipPartiallyExpanded = true, - density = density, - initialValue = if (showGamePicker) SheetValue.Expanded else SheetValue.Hidden, - ) - } + val bottomSheetState = rememberSheetState( + skipPartiallyExpanded = true, + initialValue = if (showGamePicker) SheetValue.Expanded else SheetValue.Hidden, + ) if (showGamePicker) { ModalBottomSheet( diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt index c5fa746346..37085b06d9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt @@ -21,18 +21,24 @@ import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.SheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.SheetValue.Hidden import androidx.compose.material3.Text import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.google.android.material.color.MaterialColors import androidx.appcompat.R as AppCompatR @@ -241,3 +247,42 @@ fun ReadOnlyTextField( } } } + +// A copy-paste of the internal function used in rememberModalBottomSheetState since +// rememberModalBottomSheetState doesn't expose a way to set the initial value. +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun rememberSheetState( + skipPartiallyExpanded: Boolean = false, + confirmValueChange: (SheetValue) -> Boolean = { true }, + initialValue: SheetValue = Hidden, + skipHiddenState: Boolean = false, + positionalThreshold: Dp = 56.dp, + velocityThreshold: Dp = 125.dp, +): SheetState { + val density = LocalDensity.current + val positionalThresholdToPx = { with(density) { positionalThreshold.toPx() } } + val velocityThresholdToPx = { with(density) { velocityThreshold.toPx() } } + return rememberSaveable( + skipPartiallyExpanded, + confirmValueChange, + skipHiddenState, + saver = + SheetState.Saver( + skipPartiallyExpanded = skipPartiallyExpanded, + positionalThreshold = positionalThresholdToPx, + velocityThreshold = velocityThresholdToPx, + confirmValueChange = confirmValueChange, + skipHiddenState = skipHiddenState, + ), + ) { + SheetState( + skipPartiallyExpanded, + positionalThresholdToPx, + velocityThresholdToPx, + initialValue, + confirmValueChange, + skipHiddenState, + ) + } +} diff --git a/Source/Android/gradle/libs.versions.toml b/Source/Android/gradle/libs.versions.toml index f4811334ac..0f91ab31b7 100644 --- a/Source/Android/gradle/libs.versions.toml +++ b/Source/Android/gradle/libs.versions.toml @@ -4,7 +4,7 @@ appcompat = "1.7.1" benchmarkMacroJunit4 = "1.5.0-alpha04" cardview = "1.0.0" coil = "2.7.0" -compose-bom = "2025.04.00" +compose-bom = "2026.04.01" constraintlayout = "2.2.1" coreKtx = "1.18.0" coreSplashscreen = "1.2.0"