summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-09-29 07:12:48 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-09-29 07:12:48 +0000
commita492e2def3dabe5e8de5ef4486b92859850503db (patch)
tree5b8ca48f754b26fbbbbdbebda9686d0b758b9a31 /app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
parentcf8ff865f7764953ded1b93c8ec42d4aff589e81 (diff)
Reflow reader text live while pinching, and let a zoomed image pan
Pinching in the reader used to scale the whole WebView like a photo and snap back to the real font size on release. It now drives WebSettings.textZoom as the fingers move, so the text itself resizes and reflows during the gesture with nothing to snap back from; images and margins stay put. The reload at the new saved size is what returns textZoom to 100%, so the two never overlap -- and loading reader HTML now goes through ReaderWebView.loadReaderHtml, which does both together, so a future load site can't forget the reset. Reader view for a tapped link now honors the saved font size and the same pinch gesture, instead of always rendering at the 18px default. A zoomed image can be panned again. The viewer computed its pan bounds from values captured when the dialog first composed -- an empty viewport around a not-yet-decoded image -- because a pointerInput(Unit) block keeps the lambda it was created with. Those bounds allowed exactly one offset, 0, so zooming worked and dragging did nothing. The whole pinch/pan step is now one pure function the gesture callback calls with values it reads fresh each time.
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt')
-rw-r--r--app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt42
1 files changed, 32 insertions, 10 deletions
diff --git a/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt b/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
index b8956f2..4ed0722 100644
--- a/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
+++ b/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
@@ -31,10 +31,12 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -45,6 +47,8 @@ import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.launch
import org.terst.feedreader.data.AppDatabase
import org.terst.feedreader.data.ArticleEntity
+import org.terst.feedreader.data.DEFAULT_READER_FONT_SIZE_PX
+import org.terst.feedreader.data.Settings
import org.terst.feedreader.data.ensureStandaloneArticle
import org.terst.feedreader.data.saveArticleToStash
import org.terst.feedreader.data.urlToArticleId
@@ -58,7 +62,9 @@ import java.net.URLEncoder
* dropping into the system browser. Brought to parity with the main article reader:
* save locally / save to Stash (lazily creates a standalone ArticleEntity, feedId=null,
* keyed by a hash of the URL -- same scheme ShareReceiverActivity uses, so sharing the
- * same link later lands on the same row instead of duplicating it), a reader-mode
+ * same link later lands on the same row instead of duplicating it), the saved reader font
+ * size and its pinch-to-resize gesture (a link read here is the same reading surface as an
+ * article, so it shouldn't ignore a size the article view respects), a reader-mode
* toggle (falls back to the live page, JS on, when the user wants the original instead
* of the extracted view or extraction failed), and the same login/search-alternate menu.
*/
@@ -68,9 +74,11 @@ import java.net.URLEncoder
fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Unit, onOpenBrowser: (String) -> Unit) {
val context = LocalContext.current
val db = remember { AppDatabase.get(context) }
+ val settings = remember { Settings(context) }
val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
val articleId = remember(url) { urlToArticleId(url) }
+ val fontSizePx by settings.readerFontSizePx.collectAsState(initial = DEFAULT_READER_FONT_SIZE_PX)
var article by remember(url) { mutableStateOf<ArticleEntity?>(null) }
var extractedTitle by remember(url) { mutableStateOf<String?>(null) }
@@ -229,7 +237,12 @@ fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Un
val currentExtractedContent = extractedContent
when {
isReaderMode && currentExtractedContent != null -> {
- val loadedContent = remember(url) { mutableStateOf<String?>(null) }
+ // Keyed on font size as well as content, exactly like ReaderScreen: a link
+ // opened in reader view is the same reading surface as an article, so it
+ // honors the same saved size and the same pinch-to-resize gesture, and picks
+ // up a size changed elsewhere while this screen stayed open.
+ val loadedKey = remember(url) { mutableStateOf<Pair<String?, Int>?>(null) }
+ val latestFontSizePx by rememberUpdatedState(fontSizePx)
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { ctx ->
@@ -239,17 +252,21 @@ fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Un
onOpenLink = onOpenLink,
onLongPressLink = { longPressedLink = it },
onYouTubeVideo = { youtubeVideoId = it },
- onImageTap = { zoomedImageUrl = it }
+ onImageTap = { zoomedImageUrl = it },
+ currentFontSizePx = { latestFontSizePx },
+ onFontSizeChanged = { newSizePx -> scope.launch { settings.setReaderFontSizePx(newSizePx) } }
)
).apply {
- loadDataWithBaseURL(url, wrapReaderHtml(currentExtractedContent, extractedTitle), "text/html", "UTF-8", null)
- loadedContent.value = currentExtractedContent
+ val html = wrapReaderHtml(currentExtractedContent, extractedTitle, fontSizePx = fontSizePx)
+ loadReaderHtml(url, html, fontSizePx)
+ loadedKey.value = currentExtractedContent to fontSizePx
}
},
update = { webView ->
- if (loadedContent.value != currentExtractedContent) {
- webView.loadDataWithBaseURL(url, wrapReaderHtml(currentExtractedContent, extractedTitle), "text/html", "UTF-8", null)
- loadedContent.value = currentExtractedContent
+ if (loadedKey.value != currentExtractedContent to fontSizePx) {
+ val html = wrapReaderHtml(currentExtractedContent, extractedTitle, fontSizePx = fontSizePx)
+ webView.loadReaderHtml(url, html, fontSizePx)
+ loadedKey.value = currentExtractedContent to fontSizePx
}
},
onRelease = { webView -> webView.destroy() }
@@ -276,8 +293,13 @@ fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Un
modifier = Modifier.fillMaxSize(),
factory = { ctx ->
WebView(ctx).apply {
- settings.javaScriptEnabled = true
- settings.domStorageEnabled = true
+ // Qualified: `settings` unqualified would now reach this
+ // screen's app Settings (reader font size), which shadows
+ // the WebView's own WebSettings inside this apply block.
+ // JS on here is this screen's documented fallback -- see the
+ // @SuppressLint and the http(s)-only guard just above.
+ this.settings.javaScriptEnabled = true
+ this.settings.domStorageEnabled = true
loadUrl(url)
}
},