summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt
diff options
context:
space:
mode:
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.kt77
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
+ )
+ }
}
}