summaryrefslogtreecommitdiff
path: root/Source/Android/app/src/main/java
diff options
context:
space:
mode:
authorTom Pratt <tom.pratt@outlook.com>2026-05-19 09:46:22 +0200
committerTom Pratt <tompratt@squareup.com>2026-05-19 12:03:02 +0200
commit5b49060a9d8f091cc4d1ebe967e01fb3e0d67515 (patch)
tree839f8f637d460fad811d2649ccc2cb36ecfd9d29 /Source/Android/app/src/main/java
parentfde035dc0c716e86173478fb30751f349a168e1e (diff)
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.
Diffstat (limited to 'Source/Android/app/src/main/java')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt24
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/theme/DolphinTheme.kt49
2 files changed, 68 insertions, 5 deletions
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 c4831391a5..54ea403eeb 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
@@ -108,6 +108,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.bottomFadeOverlay
import org.dolphinemu.dolphinemu.ui.theme.rememberSheetState
import org.dolphinemu.dolphinemu.utils.CoilUtils
import java.util.Locale
@@ -164,7 +165,6 @@ fun NetplayScreen(
val modifier = Modifier
.fillMaxSize()
.consumeWindowInsets(innerPadding)
- .padding(innerPadding)
// State which must live above the landscape/portrait split.
var showChat by rememberSaveable { mutableStateOf(false) }
@@ -202,6 +202,7 @@ fun NetplayScreen(
joinAddresses = joinAddresses,
selectedJoinInfoType = selectedJoinInfoType,
onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it },
+ contentPadding = innerPadding,
modifier = modifier
)
} else {
@@ -227,6 +228,7 @@ fun NetplayScreen(
joinAddresses = joinAddresses,
selectedJoinInfoType = selectedJoinInfoType,
onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it },
+ contentPadding = innerPadding,
modifier = modifier
)
}
@@ -344,11 +346,13 @@ private fun PortraitContent(
joinAddresses: Map<JoinInfoType, JoinAddress>,
selectedJoinInfoType: JoinInfoType,
onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit,
+ contentPadding: PaddingValues,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.verticalScroll(rememberScrollState())
+ .padding(contentPadding)
) {
Chat(
messages = messages,
@@ -414,11 +418,11 @@ private fun LandscapeContent(
joinAddresses: Map<JoinInfoType, JoinAddress>,
selectedJoinInfoType: JoinInfoType,
onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit,
+ contentPadding: PaddingValues,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
- .padding(horizontal = DolphinTheme.scaffoldPadding)
) {
Chat(
messages = messages,
@@ -426,16 +430,26 @@ private fun LandscapeContent(
showBottomSheet = showChat,
onShowBottomSheetChanged = onShowChatChanged,
modifier = Modifier
+ .padding(contentPadding)
+ .padding(
+ start = DolphinTheme.scaffoldPadding,
+ end = DolphinTheme.scaffoldPadding / 2,
+ )
.weight(1f)
.fillMaxHeight()
)
- Spacer(modifier = Modifier.width(16.dp))
-
+ val scrollState = rememberScrollState()
Column(
modifier = Modifier
.weight(1f)
- .verticalScroll(rememberScrollState())
+ .bottomFadeOverlay(scrollState, contentPadding.calculateBottomPadding())
+ .verticalScroll(scrollState)
+ .padding(contentPadding)
+ .padding(
+ start = DolphinTheme.scaffoldPadding / 2,
+ end = DolphinTheme.scaffoldPadding
+ )
) {
PlayersAndSettings(
game = game,
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 37085b06d9..c142a44d73 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
@@ -5,11 +5,13 @@ package org.dolphinemu.dolphinemu.ui.theme
import android.content.Context
import androidx.annotation.AttrRes
import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -28,10 +30,15 @@ import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
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.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.Color
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),
+ )
+ }
+ }
+}