summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-08-22 01:00:02 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-08-22 01:00:02 +0000
commitfd49bacfb92ef8d29cbad56419acd016ff40f357 (patch)
tree015caea07a9c556d39705c62a77b4a25f2b79219 /app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
parentfb69196f961eeaa30432c33db3003effcdbced53 (diff)
In-app YouTube playback, shared ConfirmDialog, hardened link handling
- ReaderWebView/LinkReaderScreen/ReaderScreen: tapping a YouTube link inside an article now opens an in-app player (youtube-nocookie.com, JS scoped to just that dialog) instead of handing off to the YouTube app/browser. Falls back to external-open when a confident video ID can't be extracted (playlist/channel links). - A subframe (ad/embed iframe) auto-navigating is now blocked outright instead of being treated like a real link tap -- it fired the exact same callback as a user tap, with no interaction required. - wrapReaderHtml can now show a fallback hero image + date when the feed's own body HTML has no image of its own. - ConfirmDialog: the generic "confirm before doing something irreversible" dialog shape was independently rebuilt from scratch at FeedListScreen's unsubscribe and ArticleListScreen's mark-read-from- here confirmations. Both now share one composable; the latter also chunks its batch update (markReadBatchChunked) so a long-unread feed can't exceed SQLite's per-statement bound-variable limit.
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.kt49
1 files changed, 37 insertions, 12 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 3451833..0f7540d 100644
--- a/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
+++ b/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
@@ -39,6 +39,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.launch
@@ -80,6 +81,7 @@ fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Un
var isReextracting by remember(url) { mutableStateOf(false) }
var moreMenuExpanded by remember(url) { mutableStateOf(false) }
var longPressedLink by remember(url) { mutableStateOf<String?>(null) }
+ var youtubeVideoId by remember(url) { mutableStateOf<String?>(null) }
LaunchedEffect(url) {
val existing = db.articleDao().getById(articleId)
@@ -230,7 +232,12 @@ fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Un
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { ctx ->
- newReaderWebView(ctx, onOpenLink, onLongPressLink = { longPressedLink = it }).apply {
+ newReaderWebView(
+ ctx,
+ onOpenLink,
+ onLongPressLink = { longPressedLink = it },
+ onYouTubeVideo = { youtubeVideoId = it }
+ ).apply {
loadDataWithBaseURL(url, wrapReaderHtml(currentExtractedContent, extractedTitle), "text/html", "UTF-8", null)
loadedContent.value = currentExtractedContent
}
@@ -247,21 +254,39 @@ fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Un
// Reader mode off, or extraction failed -- fall back to the live page
// itself (JS on) rather than leaving the screen blank.
!isReaderMode || extractionFailed -> {
- AndroidView(
- modifier = Modifier.fillMaxSize(),
- factory = { ctx ->
- WebView(ctx).apply {
- settings.javaScriptEnabled = true
- settings.domStorageEnabled = true
- loadUrl(url)
- }
- },
- onRelease = { webView -> webView.destroy() }
- )
+ if (!url.startsWith("http://", ignoreCase = true) && !url.startsWith("https://", ignoreCase = true)) {
+ // `url` isn't necessarily a link the user themselves tapped: it can
+ // also be whatever a WebView's shouldOverrideUrlLoading reported for
+ // ANY navigation attempt inside an article (see ReaderWebView's
+ // onOpenLink), including one triggered by the article's own HTML
+ // linking to a non-http scheme (intent://, tel:, etc.). Refusing to
+ // load anything but http(s) here means this JS-enabled WebView can't
+ // become a sink for whatever scheme a crafted article handed it.
+ Text(
+ "Can't open this link: $url",
+ modifier = Modifier.fillMaxSize().padding(16.dp),
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ } else {
+ AndroidView(
+ modifier = Modifier.fillMaxSize(),
+ factory = { ctx ->
+ WebView(ctx).apply {
+ settings.javaScriptEnabled = true
+ settings.domStorageEnabled = true
+ loadUrl(url)
+ }
+ },
+ onRelease = { webView -> webView.destroy() }
+ )
+ }
}
else -> CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
}
+ youtubeVideoId?.let { videoId ->
+ YouTubePlayerDialog(videoId = videoId, onDismiss = { youtubeVideoId = null })
+ }
longPressedLink?.let { linkUrl ->
LinkActionsDialog(
url = linkUrl,