Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ scripts

# Local MPVKit iOS build environment (sparse APFS image, see MPVKit docs)
.mpvkit-build.sparseimage

composeApp/hs_err_pid*.log
hs_err_pid*.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.nuvio.app.core.ui

import androidx.compose.runtime.Composable

@Composable
actual fun PlatformKeyboardNavigation() {
// No-op on Android — keyboard navigation is handled by the platform.
}
2 changes: 2 additions & 0 deletions composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import coil3.request.crossfade
import coil3.svg.SvgDecoder
import com.nuvio.app.core.ui.NativeProfileSwitcherController
import com.nuvio.app.core.ui.NuvioTheme
import com.nuvio.app.core.ui.PlatformKeyboardNavigation
import com.nuvio.app.core.ui.configurePlatformImageLoader
import com.nuvio.app.core.ui.desktopUiScaleForWindow
import com.nuvio.app.features.settings.ThemeSettingsRepository
Expand Down Expand Up @@ -102,6 +103,7 @@ internal fun AppEnvironment(content: @Composable () -> Unit) {
amoled = amoledEnabled,
desktopUiScale = desktopUiScaleForWindow(maxWidth.value, maxHeight.value),
) {
PlatformKeyboardNavigation()
content()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,13 @@ private class NuvioNavigationBarScopeImpl(
)

with(rowScope) {
val navItemShape = RoundedCornerShape(NuvioTokens.Radius.full)
Column(
modifier = modifier
.weight(1f)
.clip(RoundedCornerShape(NuvioTokens.Radius.full))
.clip(navItemShape)
.background(selectedBgColor)
.nuvioFocusBorder(navItemShape)
.selectable(
selected = selected,
enabled = true,
Expand Down Expand Up @@ -315,11 +317,13 @@ private class NuvioNavigationBarScopeImpl(
)

with(rowScope) {
val navItemShape = RoundedCornerShape(NuvioTokens.Radius.full)
Column(
modifier = modifier
.weight(1f)
.clip(RoundedCornerShape(NuvioTokens.Radius.full))
.clip(navItemShape)
.background(selectedBgColor)
.nuvioFocusBorder(navItemShape)
.selectable(
selected = selected,
enabled = true,
Expand Down Expand Up @@ -362,11 +366,13 @@ private class NuvioNavigationBarScopeImpl(
)

with(rowScope) {
val navItemShape = RoundedCornerShape(NuvioTokens.Radius.full)
Column(
modifier = modifier
.weight(1f)
.clip(RoundedCornerShape(NuvioTokens.Radius.full))
.clip(navItemShape)
.background(selectedBgColor)
.nuvioFocusBorder(navItemShape)
.selectable(
selected = selected,
enabled = true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.nuvio.app.core.ui

import androidx.compose.foundation.border
import androidx.compose.foundation.focusable
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.nuvio.app.isDesktop

fun Modifier.nuvioFocusBorder(
shape: Shape,
borderWidth: Dp = 3.dp,
): Modifier = composed {
var focused by remember { mutableStateOf(false) }
val tokens = MaterialTheme.nuvio
this
.onFocusChanged { focused = it.isFocused }
.then(if (isDesktop) Modifier.focusable() else Modifier)
.then(
if (focused) Modifier.border(
width = borderWidth,
color = tokens.colors.focusRing,
shape = shape,
) else Modifier,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.nuvio.app.core.ui

import androidx.compose.runtime.Composable

@Composable
expect fun PlatformKeyboardNavigation()
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ fun NuvioPosterCard(
shape = cardShape,
surface = NuvioCardDepthSurface.Posters,
)
.nuvioFocusBorder(cardShape)
.posterCardClickable(
onClick = onClick,
onLongClick = onLongClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.nuvio.app.core.ui.AppIconResource
import com.nuvio.app.core.ui.appIconPainter
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.core.ui.secondaryClick
import nuvio.composeapp.generated.resources.Res
import nuvio.composeapp.generated.resources.action_play
Expand Down Expand Up @@ -94,7 +95,8 @@ fun DetailActionButtons(
Surface(
modifier = Modifier
.weight(1f)
.height(buttonHeight),
.height(buttonHeight)
.nuvioFocusBorder(playShape),
shape = playShape,
color = MaterialTheme.colorScheme.onBackground,
contentColor = MaterialTheme.colorScheme.background,
Expand Down Expand Up @@ -175,7 +177,9 @@ fun DetailActionButtons(

if (hasSecondaryActions) {
Surface(
modifier = Modifier.size(iconButtonSize),
modifier = Modifier
.size(iconButtonSize)
.nuvioFocusBorder(CircleShape),
shape = CircleShape,
color = if (actionsExpanded) {
MaterialTheme.colorScheme.onBackground
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.nuvio.app.core.ui.NuvioAsyncImage as AsyncImage
import coil3.compose.LocalPlatformContext
import coil3.request.ImageRequest
import com.nuvio.app.core.ui.NuvioCardDepthSurface
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.core.ui.nuvioHorizontalScrollBleed
import com.nuvio.app.core.ui.nuvioCardDepth
import com.nuvio.app.core.ui.nuvioDesktopDragScroll
Expand Down Expand Up @@ -174,7 +175,8 @@ private fun CastItem(
.nuvioCardDepth(
shape = CircleShape,
surface = NuvioCardDepthSurface.Cast,
),
)
.nuvioFocusBorder(CircleShape),
contentAlignment = Alignment.Center,
) {
if (person.photo != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import com.nuvio.app.core.ui.NuvioCardDepthSurface
import com.nuvio.app.core.ui.NuvioProgressBar
import com.nuvio.app.core.ui.nuvioCardDepth
import com.nuvio.app.core.ui.nuvioDesktopDragScroll
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.core.ui.nuvioHorizontalScrollBleed
import com.nuvio.app.core.ui.posterCardClickable
import com.nuvio.app.core.ui.secondaryClick
Expand Down Expand Up @@ -527,16 +528,18 @@ private fun SeasonTextChipScrollRow(
items(seasons, key = { season -> season }) { season ->
val isSelected = season == currentSeason
val onSecondaryClick = onLongPress?.let { handler -> { handler(season) } }
val chipShape = RoundedCornerShape(sizing.seasonChipRadius)
Box(
modifier = Modifier
.clip(RoundedCornerShape(sizing.seasonChipRadius))
.clip(chipShape)
.background(
if (isSelected) {
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f)
} else {
Color.Transparent
},
)
.nuvioFocusBorder(chipShape)
.combinedClickable(
onClick = { onSelect(season) },
onLongClick = onSecondaryClick,
Expand Down Expand Up @@ -641,6 +644,7 @@ private fun SeasonPosterButton(
Column(
modifier = Modifier
.width(sizing.seasonPosterWidth)
.nuvioFocusBorder(RoundedCornerShape(sizing.seasonPosterRadius))
.posterCardClickable(onClick = onClick, onLongClick = onLongClick),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Expand Down Expand Up @@ -823,6 +827,7 @@ private fun EpisodeHorizontalCard(
surface = NuvioCardDepthSurface.EpisodeCards,
fallbackBorderAlpha = 0.12f,
)
.nuvioFocusBorder(cardShape)
.posterCardClickable(
onClick = onClick,
onLongClick = onLongPress,
Expand Down Expand Up @@ -1195,6 +1200,7 @@ private fun EpisodeListCard(
color = Color.White.copy(alpha = 0.1f),
shape = cardShape,
)
.nuvioFocusBorder(cardShape)
.combinedClickable(
enabled = onClick != null || onLongPress != null,
onClick = { onClick?.invoke() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.nuvio.app.isDesktop
import com.nuvio.app.core.ui.NuvioAsyncImage as AsyncImage
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.features.membership.CosmeticEntitlement
import com.nuvio.app.features.settings.MemberBrandWordmark
import kotlinx.coroutines.delay
Expand Down Expand Up @@ -383,6 +384,7 @@ private fun ProfileAvatarCard(
}
}

val profileShape = RoundedCornerShape(20.dp)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
Expand All @@ -393,14 +395,15 @@ private fun ProfileAvatarCard(
scaleY = animScale.value * pressScale
translationY = animOffset.value
}
.clip(RoundedCornerShape(20.dp))
.clip(profileShape)
.then(
if (isDesktop) {
Modifier.hoverable(interactionSource)
} else {
Modifier
},
)
.nuvioFocusBorder(profileShape)
.clickable(
enabled = enabled,
interactionSource = interactionSource,
Expand Down Expand Up @@ -540,6 +543,7 @@ private fun AddProfileCard(
val isPressed by interactionSource.collectIsPressedAsState()
val pressScale = if (isPressed) 0.95f else 1f

val addProfileShape = RoundedCornerShape(20.dp)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
Expand All @@ -550,7 +554,8 @@ private fun AddProfileCard(
scaleY = animScale.value * pressScale
translationY = animOffset.value
}
.clip(RoundedCornerShape(20.dp))
.clip(addProfileShape)
.nuvioFocusBorder(addProfileShape)
.clickable(
enabled = enabled,
interactionSource = interactionSource,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ 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.nuvioConsumePointerEvents
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.features.home.HomeCatalogSettingsItem
import nuvio.composeapp.generated.resources.Res
import nuvio.composeapp.generated.resources.settings_homescreen_collection_with_addon
Expand Down Expand Up @@ -165,11 +166,13 @@ internal fun SettingsSidebarItem(
val iconChip = if (selected) primary.copy(alpha = tokens.opacity.selected) else Color.Transparent
val contentColor = if (selected) tokens.colors.textPrimary else tokens.colors.textMuted

val sidebarItemShape = RoundedCornerShape(NuvioTokens.Space.s10)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = tokens.spacing.listGap, vertical = NuvioTokens.Space.s2)
.background(background, RoundedCornerShape(NuvioTokens.Space.s10))
.background(background, sidebarItemShape)
.nuvioFocusBorder(sidebarItemShape)
.clickable(onClick = onClick)
.padding(horizontal = tokens.spacing.screenHorizontal, vertical = tokens.spacing.listGap),
verticalAlignment = Alignment.CenterVertically,
Expand Down Expand Up @@ -246,6 +249,7 @@ internal fun SettingsNavigationRow(
Row(
modifier = Modifier
.fillMaxWidth()
.nuvioFocusBorder(RoundedCornerShape(NuvioTokens.Space.s4))
.clickable(enabled = enabled, onClick = onClick)
.padding(horizontal = horizontalPadding, vertical = verticalPadding)
.alpha(if (enabled) NuvioTokens.Opacity.visible else tokens.opacity.medium),
Expand Down Expand Up @@ -326,6 +330,7 @@ internal fun SettingsSwitchRow(
Row(
modifier = Modifier
.fillMaxWidth()
.nuvioFocusBorder(RoundedCornerShape(NuvioTokens.Space.s4))
.clickable(enabled = enabled) { onCheckedChange(!checked) }
.padding(horizontal = horizontalPadding, vertical = verticalPadding),
horizontalArrangement = Arrangement.Start,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import com.nuvio.app.core.ui.secondaryClickAt
import com.nuvio.app.core.ui.nuvioDesktopDragScroll
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.features.debrid.DebridProviders
import com.nuvio.app.isDesktop

Expand Down Expand Up @@ -99,6 +100,7 @@ internal fun StreamCard(
Modifier
},
)
.nuvioFocusBorder(cardShape)
.then(
if (isDesktop) {
Modifier.onGloballyPositioned { coordinates ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import com.nuvio.app.core.ui.NuvioModalBottomSheet
import com.nuvio.app.core.ui.NuvioToastController
import com.nuvio.app.core.ui.dismissNuvioBottomSheet
import com.nuvio.app.core.ui.nuvioDesktopDragScroll
import com.nuvio.app.core.ui.nuvioFocusBorder
import com.nuvio.app.core.ui.withDuplicateSafeLazyKeys
import com.nuvio.app.features.downloads.DownloadsRepository
import com.nuvio.app.features.details.MetaScreenSettingsRepository
Expand Down Expand Up @@ -883,15 +884,17 @@ private fun FilterChip(
animationSpec = tween(durationMillis = 180),
label = "filter_chip_content",
)
val chipShape = RoundedCornerShape(16.dp)
Box(
modifier = Modifier
.graphicsLayer {
scaleX = scale
scaleY = scale
}
.height(36.dp)
.clip(RoundedCornerShape(16.dp))
.clip(chipShape)
.background(containerColor)
.nuvioFocusBorder(chipShape)
.clickable(
interactionSource = interactionSource,
indication = null,
Expand Down
Loading