diff options
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 | 112 |
1 files changed, 112 insertions, 0 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 new file mode 100644 index 0000000..ff764c4 --- /dev/null +++ b/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt @@ -0,0 +1,112 @@ +package org.terst.feedreader.ui + +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.OpenInBrowser +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import org.terst.feedreader.readability.ReaderExtractor + +/** + * A lightweight, non-persisted reader view for links tapped inside an article's + * WebView -- extracts the linked page with the same Readability pipeline as the + * main reader, but doesn't touch the DB (it's not a subscribed article), and + * recursively re-opens itself for any further links tapped inside, so link-hopping + * stays inside the app's reader instead of dropping into a raw WebView or the + * system browser. + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Unit) { + val context = LocalContext.current + var title by remember(url) { mutableStateOf<String?>(null) } + var content by remember(url) { mutableStateOf<String?>(null) } + var failed by remember(url) { mutableStateOf(false) } + + LaunchedEffect(url) { + val extracted = ReaderExtractor.extract(context, url) + val extractedContent = extracted?.content + if (extractedContent != null) { + title = extracted.title + content = extractedContent + } else { + failed = true + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { + Text(title ?: Uri.parse(url).host ?: "Article", maxLines = 1, overflow = TextOverflow.Ellipsis) + }, + navigationIcon = { + IconButton(onClick = onBack) { + Icon(Icons.Default.ArrowBack, contentDescription = "Back") + } + }, + actions = { + IconButton(onClick = { + context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) + }) { + Icon(Icons.Default.OpenInBrowser, contentDescription = "Open in browser") + } + } + ) + } + ) { padding -> + Box(modifier = Modifier.fillMaxSize().padding(padding)) { + val currentContent = content + when { + currentContent != null -> { + val loadedContent = remember(url) { mutableStateOf<String?>(null) } + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { ctx -> + newReaderWebView(ctx, onOpenLink).apply { + loadDataWithBaseURL(url, wrapReaderHtml(currentContent), "text/html", "UTF-8", null) + loadedContent.value = currentContent + } + }, + update = { webView -> + if (loadedContent.value != currentContent) { + webView.loadDataWithBaseURL(url, wrapReaderHtml(currentContent), "text/html", "UTF-8", null) + loadedContent.value = currentContent + } + }, + onRelease = { webView -> webView.destroy() } + ) + } + failed -> Text( + "Couldn't extract a reader view for this page -- try \"Open in browser\" instead.", + modifier = Modifier.align(Alignment.Center).padding(24.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + else -> CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + } + } +} |
