diff options
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt | 77 |
1 files changed, 70 insertions, 7 deletions
diff --git a/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt b/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt index 8c2f64e..9b53f8c 100644 --- a/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt +++ b/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt @@ -3,6 +3,7 @@ package org.terst.feedreader.ui import android.content.Intent import android.net.Uri import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -40,8 +41,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch @@ -54,6 +58,7 @@ import org.terst.feedreader.readability.ReaderExtractor import org.terst.feedreader.stash.StashClient import org.terst.feedreader.stash.StashSaveResult import java.net.URLEncoder +import kotlin.math.abs // Below this length (of the plain feed-provided HTML), assume it's a teaser/summary, // not the real article body, and auto-fall-back to on-device Readability extraction. @@ -100,14 +105,72 @@ fun ReaderScreen( val safeIds = if (ids.contains(initialArticleId)) ids else listOf(initialArticleId) val initialIndex = safeIds.indexOf(initialArticleId).coerceAtLeast(0) val pagerState = rememberPagerState(initialPage = initialIndex) { safeIds.size } + val scope = rememberCoroutineScope() + val directionLockPx = with(LocalDensity.current) { 16.dp.toPx() } + val swipeThresholdPx = with(LocalDensity.current) { 80.dp.toPx() } - HorizontalPager(state = pagerState, modifier = Modifier.fillMaxSize()) { page -> - ReaderContent( - articleId = safeIds[page], - onBack = onBack, - onOpenLink = onOpenLink, - onOpenBrowser = onOpenBrowser - ) + // HorizontalPager's own full-surface drag detection was grabbing ordinary vertical + // scrolling inside the embedded WebView (a native View, which doesn't arbitrate with + // Compose's gesture system the way a pure-Compose scrollable child would) as an + // attempted horizontal page-turn on anything less than a perfectly vertical swipe -- + // which is most real thumb scrolling. An edge-zone-gated version of this was tried + // first, but on gesture-nav Android the screen edges belong to the OS's own back + // gesture, which wins before the app ever sees the touch (confirmed live: an edge + // swipe triggered system back, not the pager). So instead: disable the Pager's own + // gesture and drive it from a detector that works anywhere on screen but only commits + // to a page turn once the drag is clearly horizontal-dominant (>2x the vertical + // movement) -- ordinary scrolling, even sloppy/diagonal, stays vertical-dominant and + // is left completely unconsumed for the WebView to handle normally. + Box( + modifier = Modifier + .fillMaxSize() + .pointerInput(safeIds.size) { + var totalDx = 0f + var totalDy = 0f + var committedHorizontal = false + detectDragGestures( + onDragStart = { + totalDx = 0f + totalDy = 0f + committedHorizontal = false + }, + onDragCancel = { committedHorizontal = false }, + onDragEnd = { + if (committedHorizontal) { + val direction = when { + totalDx <= -swipeThresholdPx -> 1 + totalDx >= swipeThresholdPx -> -1 + else -> 0 + } + if (direction != 0) { + val target = (pagerState.currentPage + direction).coerceIn(0, safeIds.size - 1) + scope.launch { pagerState.animateScrollToPage(target) } + } + } + committedHorizontal = false + }, + onDrag = { change, dragAmount -> + totalDx += dragAmount.x + totalDy += dragAmount.y + if (!committedHorizontal && + abs(totalDx) > directionLockPx && + abs(totalDx) > abs(totalDy) * 2f + ) { + committedHorizontal = true + } + if (committedHorizontal) change.consume() + } + ) + } + ) { + HorizontalPager(state = pagerState, userScrollEnabled = false, modifier = Modifier.fillMaxSize()) { page -> + ReaderContent( + articleId = safeIds[page], + onBack = onBack, + onOpenLink = onOpenLink, + onOpenBrowser = onOpenBrowser + ) + } } } |
