Fix NetplayScreen edge to edge

NetplayScreen was not drawing under the bottom nav bar like other screens. In landscape mode half of the screen scrolls and half is fixed, to make this look natural with edge to edge, provide a fade on the bottom of the scrolling side so things look natural when the screens loads and is resting at 0 scroll offset.
This commit is contained in:
Tom Pratt authored and Tom Pratt committed 2026-05-19 12:03:02 +02:00
1 parent fde035dc0c
commit 5b49060a9d
2 files changed
+68 -5

No files matched your search

@@ -108,6 +108,7 @@ import org.dolphinemu.dolphinemu.ui.theme.MenuSpacer
import org.dolphinemu.dolphinemu.ui.theme.OutlinedBox import org.dolphinemu.dolphinemu.ui.theme.OutlinedBox
import org.dolphinemu.dolphinemu.ui.theme.PreviewTheme import org.dolphinemu.dolphinemu.ui.theme.PreviewTheme
import org.dolphinemu.dolphinemu.ui.theme.ReadOnlyTextField import org.dolphinemu.dolphinemu.ui.theme.ReadOnlyTextField
import org.dolphinemu.dolphinemu.ui.theme.bottomFadeOverlay
import org.dolphinemu.dolphinemu.ui.theme.rememberSheetState import org.dolphinemu.dolphinemu.ui.theme.rememberSheetState
import org.dolphinemu.dolphinemu.utils.CoilUtils import org.dolphinemu.dolphinemu.utils.CoilUtils
import java.util.Locale import java.util.Locale
@@ -164,7 +165,6 @@ fun NetplayScreen(
val modifier = Modifier val modifier = Modifier
.fillMaxSize() .fillMaxSize()
.consumeWindowInsets(innerPadding) .consumeWindowInsets(innerPadding)
.padding(innerPadding)
// State which must live above the landscape/portrait split. // State which must live above the landscape/portrait split.
var showChat by rememberSaveable { mutableStateOf(false) } var showChat by rememberSaveable { mutableStateOf(false) }
@@ -202,6 +202,7 @@ fun NetplayScreen(
joinAddresses = joinAddresses, joinAddresses = joinAddresses,
selectedJoinInfoType = selectedJoinInfoType, selectedJoinInfoType = selectedJoinInfoType,
onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it }, onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it },
contentPadding = innerPadding,
modifier = modifier modifier = modifier
) )
} else { } else {
@@ -227,6 +228,7 @@ fun NetplayScreen(
joinAddresses = joinAddresses, joinAddresses = joinAddresses,
selectedJoinInfoType = selectedJoinInfoType, selectedJoinInfoType = selectedJoinInfoType,
onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it }, onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it },
contentPadding = innerPadding,
modifier = modifier modifier = modifier
) )
} }
@@ -344,11 +346,13 @@ private fun PortraitContent(
joinAddresses: Map<JoinInfoType, JoinAddress>, joinAddresses: Map<JoinInfoType, JoinAddress>,
selectedJoinInfoType: JoinInfoType, selectedJoinInfoType: JoinInfoType,
onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit, onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit,
contentPadding: PaddingValues,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Column( Column(
modifier = modifier modifier = modifier
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(contentPadding)
) { ) {
Chat( Chat(
messages = messages, messages = messages,
@@ -414,11 +418,11 @@ private fun LandscapeContent(
joinAddresses: Map<JoinInfoType, JoinAddress>, joinAddresses: Map<JoinInfoType, JoinAddress>,
selectedJoinInfoType: JoinInfoType, selectedJoinInfoType: JoinInfoType,
onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit, onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit,
contentPadding: PaddingValues,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Row( Row(
modifier = modifier modifier = modifier
.padding(horizontal = DolphinTheme.scaffoldPadding)
) { ) {
Chat( Chat(
messages = messages, messages = messages,
@@ -426,16 +430,26 @@ private fun LandscapeContent(
showBottomSheet = showChat, showBottomSheet = showChat,
onShowBottomSheetChanged = onShowChatChanged, onShowBottomSheetChanged = onShowChatChanged,
modifier = Modifier modifier = Modifier
.padding(contentPadding)
.padding(
start = DolphinTheme.scaffoldPadding,
end = DolphinTheme.scaffoldPadding / 2,
)
.weight(1f) .weight(1f)
.fillMaxHeight() .fillMaxHeight()
) )
Spacer(modifier = Modifier.width(16.dp)) val scrollState = rememberScrollState()
Column( Column(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.verticalScroll(rememberScrollState()) .bottomFadeOverlay(scrollState, contentPadding.calculateBottomPadding())
.verticalScroll(scrollState)
.padding(contentPadding)
.padding(
start = DolphinTheme.scaffoldPadding / 2,
end = DolphinTheme.scaffoldPadding
)
) { ) {
PlayersAndSettings( PlayersAndSettings(
game = game, game = game,
@@ -5,11 +5,13 @@ package org.dolphinemu.dolphinemu.ui.theme
import android.content.Context import android.content.Context
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -28,10 +30,15 @@ import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -286,3 +293,45 @@ fun rememberSheetState(
) )
} }
} }
@Composable
fun Modifier.bottomFadeOverlay(
scrollState: ScrollState,
fadeHeight: Dp,
): Modifier {
val surfaceColor = MaterialTheme.colorScheme.surface
val bottomPaddingPx = with(LocalDensity.current) {
fadeHeight.toPx()
}
val fadeDelayPx = with(LocalDensity.current) { 8.dp.toPx() }
val fadeDurationPx = with(LocalDensity.current) { 48.dp.toPx() }
val scrollProgress by remember {
derivedStateOf {
if (bottomPaddingPx <= 0f) 1f
else ((scrollState.value.coerceAtLeast(0) - fadeDelayPx) / fadeDurationPx)
.coerceIn(0f, 1f)
}
}
val surfaceStopFraction = (scrollProgress * 2f).coerceIn(0f, 1f)
val transparentStopFraction = ((scrollProgress * 2f) - 1f).coerceIn(0f, 1f)
return drawWithContent {
drawContent()
if (transparentStopFraction < 1f) {
drawRect(
brush = Brush.verticalGradient(
colorStops = arrayOf(
0f to Color.Transparent,
transparentStopFraction to Color.Transparent,
surfaceStopFraction to surfaceColor,
1f to surfaceColor,
),
startY = size.height - bottomPaddingPx,
endY = size.height,
),
topLeft = Offset(0f, size.height - bottomPaddingPx),
size = Size(size.width, bottomPaddingPx),
)
}
}
}