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.kt51
1 files changed, 25 insertions, 26 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 2177d72..ced9482 100644
--- a/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt
+++ b/app/src/main/java/org/terst/feedreader/ui/ReaderScreen.kt
@@ -2,7 +2,6 @@ package org.terst.feedreader.ui
import android.content.Intent
import android.net.Uri
-import android.webkit.WebView
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -15,6 +14,8 @@ import androidx.compose.material.icons.filled.Article
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Bookmark
import androidx.compose.material.icons.filled.BookmarkBorder
+import androidx.compose.material.icons.filled.CloudDone
+import androidx.compose.material.icons.filled.CloudUpload
import androidx.compose.material.icons.filled.OpenInBrowser
import androidx.compose.material.icons.outlined.Article
import androidx.compose.material3.CircularProgressIndicator
@@ -63,7 +64,7 @@ private const val THIN_CONTENT_THRESHOLD = 500
*/
@OptIn(ExperimentalFoundationApi::class)
@Composable
-fun ReaderScreen(feedId: String, initialArticleId: String, onBack: () -> Unit) {
+fun ReaderScreen(feedId: String, initialArticleId: String, onBack: () -> Unit, onOpenLink: (String) -> Unit) {
val context = LocalContext.current
val db = remember { AppDatabase.get(context) }
var articleIds by remember(feedId) { mutableStateOf<List<String>?>(null) }
@@ -91,13 +92,13 @@ fun ReaderScreen(feedId: String, initialArticleId: String, onBack: () -> Unit) {
val pagerState = rememberPagerState(initialPage = initialIndex) { safeIds.size }
HorizontalPager(state = pagerState, modifier = Modifier.fillMaxSize()) { page ->
- ReaderContent(articleId = safeIds[page], onBack = onBack)
+ ReaderContent(articleId = safeIds[page], onBack = onBack, onOpenLink = onOpenLink)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-private fun ReaderContent(articleId: String, onBack: () -> Unit) {
+private fun ReaderContent(articleId: String, onBack: () -> Unit, onOpenLink: (String) -> Unit) {
val context = LocalContext.current
val db = remember { AppDatabase.get(context) }
val scope = rememberCoroutineScope()
@@ -204,6 +205,20 @@ private fun ReaderContent(articleId: String, onBack: () -> Unit) {
}) {
Icon(Icons.Default.OpenInBrowser, contentDescription = "Open in browser")
}
+ // Purely local: just flips isSaved (shows up in the Saved list). Does NOT
+ // touch Stash -- that's a separate, explicit action below, since archiving
+ // to Stash is a heavier/networked action the user should trigger on purpose.
+ IconButton(onClick = {
+ val a = currentArticle ?: return@IconButton
+ val newSaved = !a.isSaved
+ article = a.copy(isSaved = newSaved)
+ scope.launch { db.articleDao().setSaved(a.id, newSaved) }
+ }) {
+ Icon(
+ if (currentArticle?.isSaved == true) Icons.Default.Bookmark else Icons.Default.BookmarkBorder,
+ contentDescription = "Save locally"
+ )
+ }
IconButton(
enabled = !isSaving,
onClick = {
@@ -214,13 +229,13 @@ private fun ReaderContent(articleId: String, onBack: () -> Unit) {
val client = StashClient(Net.client, settings.stashBaseUrlNow(), settings.stashApiKeyNow())
when (val result = client.saveArticle(a.link, a.title)) {
is StashSaveResult.Saved -> {
- db.articleDao().setSaved(a.id, true)
db.articleDao().setStashArtifactId(a.id, result.artifact.id)
+ article = a.copy(stashArtifactId = result.artifact.id)
snackbarHostState.showSnackbar("Saved to Stash")
}
is StashSaveResult.AlreadySaved -> {
- db.articleDao().setSaved(a.id, true)
db.articleDao().setStashArtifactId(a.id, result.existingId)
+ article = a.copy(stashArtifactId = result.existingId)
snackbarHostState.showSnackbar("Already in Stash")
}
is StashSaveResult.Failed ->
@@ -231,7 +246,7 @@ private fun ReaderContent(articleId: String, onBack: () -> Unit) {
}
) {
Icon(
- if (currentArticle?.isSaved == true) Icons.Default.Bookmark else Icons.Default.BookmarkBorder,
+ if (currentArticle?.stashArtifactId != null) Icons.Default.CloudDone else Icons.Default.CloudUpload,
contentDescription = "Save to Stash"
)
}
@@ -254,15 +269,14 @@ private fun ReaderContent(articleId: String, onBack: () -> Unit) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { ctx ->
- WebView(ctx).apply {
- settings.javaScriptEnabled = false
- loadDataWithBaseURL(baseUrl, wrapHtml(content), "text/html", "UTF-8", null)
+ newReaderWebView(ctx, onOpenLink).apply {
+ loadDataWithBaseURL(baseUrl, wrapReaderHtml(content), "text/html", "UTF-8", null)
loadedContent.value = content
}
},
update = { webView ->
if (loadedContent.value != content) {
- webView.loadDataWithBaseURL(baseUrl, wrapHtml(content), "text/html", "UTF-8", null)
+ webView.loadDataWithBaseURL(baseUrl, wrapReaderHtml(content), "text/html", "UTF-8", null)
loadedContent.value = content
}
},
@@ -278,18 +292,3 @@ private fun ReaderContent(articleId: String, onBack: () -> Unit) {
}
}
}
-
-// Hardcoded dark palette, not @media (prefers-color-scheme) -- the app itself always
-// forces dark colorScheme() regardless of system setting (see MainActivity), so the
-// reader content should match rather than following a system light/dark that the rest
-// of the app ignores.
-private fun wrapHtml(bodyContent: String): String = """
- <html><head><meta name="viewport" content="width=device-width, initial-scale=1">
- <style>
- body { font-family: sans-serif; font-size: 18px; line-height: 1.5; padding: 16px;
- background-color: #121212; color: #e1e1e1; }
- a { color: #8ab4f8; }
- img { max-width: 100%; height: auto; }
- </style></head>
- <body>$bodyContent</body></html>
-""".trimIndent()