Fix header touch handling

Fixes #1187

Fixes #1210

Fixes #1251
This commit is contained in:
tapframe 2026-06-11 01:45:57 +05:30
parent 3bcf74dd75
commit cc7c4eedf6
4 changed files with 139 additions and 113 deletions

View file

@ -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,
)
}
}

View file

@ -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))
}
}
}

View file

@ -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))
}
}
}

View file

@ -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,
)
}
}