diff options
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.kt | 51 |
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() |
