diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-09-29 07:12:48 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-09-29 07:12:48 +0000 |
| commit | a492e2def3dabe5e8de5ef4486b92859850503db (patch) | |
| tree | 5b8ca48f754b26fbbbbdbebda9686d0b758b9a31 /app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt | |
| parent | cf8ff865f7764953ded1b93c8ec42d4aff589e81 (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.kt | 42 |
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) } }, |
