From cc7c4eedf650b056deb2f736417504a9a55a5115 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Thu, 11 Jun 2026 01:45:57 +0530 Subject: [PATCH] Fix header touch handling Fixes #1187 Fixes #1210 Fixes #1251 --- .../com/nuvio/app/core/ui/NuvioComponents.kt | 74 ++++++++++--------- .../app/features/library/LibraryScreen.kt | 55 +++++++------- .../nuvio/app/features/search/SearchScreen.kt | 69 +++++++++-------- .../features/settings/SettingsComponents.kt | 54 ++++++++------ 4 files changed, 139 insertions(+), 113 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt index 27029a306..7b0be071b 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioComponents.kt @@ -100,7 +100,7 @@ fun NuvioScreen( ) } -internal fun Modifier.nuvioBlockPointerPassthrough(): Modifier = +internal fun Modifier.nuvioConsumePointerEvents(): Modifier = pointerInput(Unit) { awaitPointerEventScope { while (true) { @@ -144,45 +144,53 @@ fun NuvioScreenHeader( val tokens = MaterialTheme.nuvio val statusBarTop = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() val resolvedTopPadding = topPadding ?: if (includeStatusBarPadding) statusBarTop else NuvioTokens.Space.none - Row( - modifier = modifier - .fillMaxWidth() - .nuvioBlockPointerPassthrough() - .background(tokens.colors.background) - .padding(top = resolvedTopPadding, bottom = NuvioTokens.Space.s4), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Bottom, + Box( + modifier = modifier.fillMaxWidth(), ) { Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(tokens.spacing.controlGap), + modifier = Modifier + .matchParentSize() + .background(tokens.colors.background) + .nuvioConsumePointerEvents(), + ) {} + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = resolvedTopPadding, bottom = NuvioTokens.Space.s4), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Bottom, ) { - if (onBack != null) { - IconButton(onClick = onBack) { - Icon( - imageVector = Icons.AutoMirrored.Rounded.ArrowBack, - contentDescription = stringResource(Res.string.action_back), - tint = tokens.colors.textPrimary, + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(tokens.spacing.controlGap), + ) { + if (onBack != null) { + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.AutoMirrored.Rounded.ArrowBack, + contentDescription = stringResource(Res.string.action_back), + tint = tokens.colors.textPrimary, + ) + } + } + AnimatedContent( + targetState = title, + transitionSpec = { fadeIn() togetherWith fadeOut() }, + label = "screen_header_title", + ) { currentTitle -> + Text( + text = currentTitle, + style = MaterialTheme.typography.displayLarge, + color = tokens.colors.textPrimary, ) } } - AnimatedContent( - targetState = title, - transitionSpec = { fadeIn() togetherWith fadeOut() }, - label = "screen_header_title", - ) { currentTitle -> - Text( - text = currentTitle, - style = MaterialTheme.typography.displayLarge, - color = tokens.colors.textPrimary, - ) - } + Row( + horizontalArrangement = Arrangement.spacedBy(NuvioTokens.Space.s2), + verticalAlignment = Alignment.CenterVertically, + content = actions, + ) } - Row( - horizontalArrangement = Arrangement.spacedBy(NuvioTokens.Space.s2), - verticalAlignment = Alignment.CenterVertically, - content = actions, - ) } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt index f5ecf93ce..4826efa00 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt @@ -65,7 +65,7 @@ import com.nuvio.app.core.ui.NuvioNetworkOfflineCard import com.nuvio.app.core.ui.NuvioScreenHeader import com.nuvio.app.core.ui.NuvioViewAllPillSize import com.nuvio.app.core.ui.NuvioShelfSection -import com.nuvio.app.core.ui.nuvioBlockPointerPassthrough +import com.nuvio.app.core.ui.nuvioConsumePointerEvents import com.nuvio.app.features.cloud.CloudLibraryFile import com.nuvio.app.features.cloud.CloudLibraryItem import com.nuvio.app.features.cloud.CloudLibraryItemType @@ -179,31 +179,36 @@ fun LibraryScreen( listState = listState, ) { stickyHeader { - androidx.compose.foundation.layout.Column( - modifier = Modifier - .fillMaxWidth() - .nuvioBlockPointerPassthrough() - .background(MaterialTheme.colorScheme.background), - ) { - NuvioScreenHeader( - title = if (sourceMode == LibraryViewMode.Cloud) { - stringResource(Res.string.library_title) - } else if (isTraktSource) { - stringResource(Res.string.library_trakt_title) - } else { - stringResource(Res.string.library_title) - }, - modifier = Modifier.padding(horizontal = 16.dp), - topPadding = topChromePadding, + Box(modifier = Modifier.fillMaxWidth()) { + Box( + modifier = Modifier + .matchParentSize() + .background(MaterialTheme.colorScheme.background) + .nuvioConsumePointerEvents(), ) - LibrarySourceSwitch( - selectedMode = sourceMode, - onModeSelected = { mode -> - sourceModeName = mode.name - }, - modifier = Modifier.padding(horizontal = 16.dp), - ) - Spacer(modifier = Modifier.height(6.dp)) + androidx.compose.foundation.layout.Column( + modifier = Modifier.fillMaxWidth(), + ) { + NuvioScreenHeader( + title = if (sourceMode == LibraryViewMode.Cloud) { + stringResource(Res.string.library_title) + } else if (isTraktSource) { + stringResource(Res.string.library_trakt_title) + } else { + stringResource(Res.string.library_title) + }, + modifier = Modifier.padding(horizontal = 16.dp), + topPadding = topChromePadding, + ) + LibrarySourceSwitch( + selectedMode = sourceMode, + onModeSelected = { mode -> + sourceModeName = mode.name + }, + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(6.dp)) + } } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt index 389aa5ff2..7b8f781a2 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt @@ -46,7 +46,7 @@ import com.nuvio.app.core.ui.NuvioInputField import com.nuvio.app.core.ui.NuvioScreen import com.nuvio.app.core.ui.NuvioNetworkOfflineCard import com.nuvio.app.core.ui.NuvioScreenHeader -import com.nuvio.app.core.ui.nuvioBlockPointerPassthrough +import com.nuvio.app.core.ui.nuvioConsumePointerEvents import com.nuvio.app.core.ui.withDuplicateSafeLazyKeys import com.nuvio.app.features.addons.AddonRepository import com.nuvio.app.features.addons.enabledAddons @@ -244,40 +244,45 @@ fun SearchScreen( modifier = Modifier.fillMaxSize(), ) { stickyHeader { - androidx.compose.foundation.layout.Column( - modifier = Modifier - .fillMaxWidth() - .nuvioBlockPointerPassthrough() - .background(MaterialTheme.colorScheme.background), - ) { - NuvioScreenHeader( - title = headerTitle, - modifier = Modifier.padding(horizontal = 16.dp), - topPadding = topChromePadding, + Box(modifier = Modifier.fillMaxWidth()) { + Box( + modifier = Modifier + .matchParentSize() + .background(MaterialTheme.colorScheme.background) + .nuvioConsumePointerEvents(), ) - androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(6.dp)) - androidx.compose.foundation.layout.Box(modifier = Modifier.padding(horizontal = 16.dp)) { - NuvioInputField( - value = query, - onValueChange = { query = it }, - placeholder = stringResource(Res.string.compose_search_placeholder), - modifier = Modifier.focusRequester(focusRequester), - trailingContent = if (query.isNotBlank()) { - { - IconButton(onClick = { query = "" }) { - Icon( - imageVector = Icons.Rounded.Close, - contentDescription = stringResource(Res.string.compose_search_clear), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - } - } else { - null - }, + androidx.compose.foundation.layout.Column( + modifier = Modifier.fillMaxWidth(), + ) { + NuvioScreenHeader( + title = headerTitle, + modifier = Modifier.padding(horizontal = 16.dp), + topPadding = topChromePadding, ) - } + androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(6.dp)) + androidx.compose.foundation.layout.Box(modifier = Modifier.padding(horizontal = 16.dp)) { + NuvioInputField( + value = query, + onValueChange = { query = it }, + placeholder = stringResource(Res.string.compose_search_placeholder), + modifier = Modifier.focusRequester(focusRequester), + trailingContent = if (query.isNotBlank()) { + { + IconButton(onClick = { query = "" }) { + Icon( + imageVector = Icons.Rounded.Close, + contentDescription = stringResource(Res.string.compose_search_clear), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + } else { + null + }, + ) + } androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(14.dp)) + } } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsComponents.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsComponents.kt index edfc75da2..f44bb8d31 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsComponents.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsComponents.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row @@ -50,7 +51,7 @@ import com.nuvio.app.core.ui.NuvioActionLabel import com.nuvio.app.core.ui.NuvioBackButton import com.nuvio.app.core.ui.NuvioSectionLabel import com.nuvio.app.core.ui.nuvio -import com.nuvio.app.core.ui.nuvioBlockPointerPassthrough +import com.nuvio.app.core.ui.nuvioConsumePointerEvents import com.nuvio.app.features.home.HomeCatalogSettingsItem import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.settings_homescreen_collection_with_addon @@ -116,31 +117,38 @@ internal fun TabletPageHeader( onBack: () -> Unit, ) { val tokens = MaterialTheme.nuvio - Row( - modifier = Modifier - .fillMaxWidth() - .nuvioBlockPointerPassthrough(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(tokens.spacing.listGap), + Box( + modifier = Modifier.fillMaxWidth(), ) { - if (showBack) { - NuvioBackButton( - onClick = onBack, - modifier = Modifier - .size(36.dp), - shape = tokens.shapes.compactCard, - containerColor = tokens.colors.surface, - contentColor = tokens.colors.textPrimary, - buttonSize = NuvioTokens.Space.s36, - iconSize = tokens.icons.md, + Box( + modifier = Modifier + .matchParentSize() + .nuvioConsumePointerEvents(), + ) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(tokens.spacing.listGap), + ) { + if (showBack) { + NuvioBackButton( + onClick = onBack, + modifier = Modifier + .size(36.dp), + shape = tokens.shapes.compactCard, + containerColor = tokens.colors.surface, + contentColor = tokens.colors.textPrimary, + buttonSize = NuvioTokens.Space.s36, + iconSize = tokens.icons.md, + ) + } + Text( + text = title, + style = MaterialTheme.typography.headlineLarge, + color = tokens.colors.textPrimary, + fontWeight = FontWeight.SemiBold, ) } - Text( - text = title, - style = MaterialTheme.typography.headlineLarge, - color = tokens.colors.textPrimary, - fontWeight = FontWeight.SemiBold, - ) } }