diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioShelfComponents.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioShelfComponents.kt index 5bf613e9..822625a2 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioShelfComponents.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/NuvioShelfComponents.kt @@ -15,8 +15,12 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight @@ -28,15 +32,19 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.Dp import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage +import com.nuvio.app.isDesktop import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.home_view_all import nuvio.composeapp.generated.resources.poster_logo_content_description import org.jetbrains.compose.resources.stringResource +import kotlin.math.abs enum class NuvioPosterShape { Poster, @@ -64,6 +72,7 @@ fun NuvioShelfSection( itemContent: @Composable (T) -> Unit, ) { val tokens = MaterialTheme.nuvio + val rowState = rememberLazyListState() Column( modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(tokens.spacing.controlGap + NuvioTokens.Space.s2), @@ -78,6 +87,8 @@ fun NuvioShelfSection( ) } LazyRow( + state = rowState, + modifier = Modifier.desktopShelfDragScroll(rowState), contentPadding = rowContentPadding, horizontalArrangement = Arrangement.spacedBy(itemSpacing), ) { @@ -97,6 +108,47 @@ fun NuvioShelfSection( } } +private fun Modifier.desktopShelfDragScroll( + state: LazyListState, +): Modifier { + if (!isDesktop) return this + + return pointerInput(state) { + awaitEachGesture { + val down = awaitFirstDown(pass = PointerEventPass.Initial) + var totalDx = 0f + var totalDy = 0f + var dragging = false + + while (true) { + val event = awaitPointerEvent(pass = PointerEventPass.Initial) + val change = event.changes.firstOrNull { it.id == down.id } ?: break + if (!change.pressed) break + + val delta = change.position - change.previousPosition + totalDx += delta.x + totalDy += delta.y + + if (!dragging) { + val horizontalDrag = + abs(totalDx) > viewConfiguration.touchSlop && abs(totalDx) > abs(totalDy) + val verticalDrag = + abs(totalDy) > viewConfiguration.touchSlop && abs(totalDy) > abs(totalDx) + + when { + verticalDrag -> break + horizontalDrag -> dragging = true + else -> continue + } + } + + state.dispatchRawDelta(-delta.x) + change.consume() + } + } + } +} + @Composable fun NuvioPosterCard( title: String,