From a422e42f71f1dee670d3dc7f73d0cef7ff420a92 Mon Sep 17 00:00:00 2001 From: Josiah Campbell <9521010+jocmp@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:45:29 -0600 Subject: [PATCH 1/3] wip --- .../app/ui/articles/ArticleLayout.kt | 4 +-- .../app/ui/articles/detail/ArticleReader.kt | 2 +- .../capyreader/app/ui/components/WebView.kt | 36 ++----------------- article_forge/views/template.liquid | 4 +-- .../jocmp/capy/articles/ArticleRenderer.kt | 2 -- .../com/jocmp/capy/articles/CleanLinks.kt | 17 --------- .../java/com/jocmp/capy/articles/ParseHTML.kt | 2 -- capy/src/main/res/raw/template.html | 4 +-- .../android/en-US/changelogs/1071.txt | 6 ++++ 9 files changed, 16 insertions(+), 61 deletions(-) delete mode 100644 capy/src/main/java/com/jocmp/capy/articles/CleanLinks.kt diff --git a/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt b/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt index 8f2a64ab..a9f82511 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt @@ -133,7 +133,7 @@ fun ArticleLayout( scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail) } - val scrollState = rememberSaveable(key = article?.id, saver = ScrollState.Saver) { + val scrollState = rememberSaveable(saver = ScrollState.Saver) { ScrollState(initial = 0) } val webViewState = rememberWebViewState( @@ -141,7 +141,7 @@ fun ArticleLayout( mediaUrl = it }, onPageStarted = { - coroutineScope.launch { + coroutineScope.launchUI { scrollState.scrollTo(0) } } diff --git a/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt b/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt index 5857d965..4b9e2f6c 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt @@ -40,7 +40,7 @@ fun ArticleReader( lastScrollY = scrollState.value }, ) - Spacer(modifier = Modifier.height(150.dp)) + Spacer(modifier = Modifier.height(120.dp)) } } diff --git a/app/src/main/java/com/capyreader/app/ui/components/WebView.kt b/app/src/main/java/com/capyreader/app/ui/components/WebView.kt index 41351d83..77dc8555 100644 --- a/app/src/main/java/com/capyreader/app/ui/components/WebView.kt +++ b/app/src/main/java/com/capyreader/app/ui/components/WebView.kt @@ -16,14 +16,10 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.graphics.drawable.toBitmap import androidx.webkit.WebViewAssetLoader import androidx.webkit.WebViewAssetLoader.AssetsPathHandler import androidx.webkit.WebViewAssetLoader.DEFAULT_DOMAIN import androidx.webkit.WebViewAssetLoader.ResourcesPathHandler -import coil.executeBlocking -import coil.imageLoader -import coil.request.ImageRequest import com.capyreader.app.common.AppPreferences import com.capyreader.app.common.WebViewInterface import com.capyreader.app.common.openLink @@ -74,7 +70,7 @@ fun WebView( class AccompanistWebViewClient( private val assetLoader: WebViewAssetLoader, - private val onPageStarted: () -> Unit + private val onPageStarted: () -> Unit, ) : WebViewClient(), KoinComponent { lateinit var state: WebViewState @@ -84,10 +80,10 @@ class AccompanistWebViewClient( override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) { super.onPageStarted(view, url, favicon) + onPageStarted() view.postVisualStateCallback(requestId, object : WebView.VisualStateCallback() { override fun onComplete(requestId: Long) { - onPageStarted() view.visibility = View.VISIBLE } }) @@ -95,36 +91,10 @@ class AccompanistWebViewClient( private val requestId = 1200L - override fun onPageFinished(view: WebView, url: String?) { - super.onPageFinished(view, url) - } - override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { - val accept = request.requestHeaders.getOrDefault("Accept", null) - - if (accept != null && accept.contains("image")) { - try { - val imageRequest = ImageRequest.Builder(view.context) - .data(request.url) - .build() - val bitmap = - view.context.imageLoader.executeBlocking(imageRequest).drawable?.toBitmap() - - if (bitmap != null) { - return WebResourceResponse( - "image/jpg", - "UTF-8", - jpegStream(bitmap) - ) - } - } catch (exception: Exception) { - return null - } - } - return assetLoader.shouldInterceptRequest(request.url) } @@ -171,7 +141,7 @@ class WebViewState( withContext(Dispatchers.Main) { webView.loadDataWithBaseURL( - ASSET_BASE_URL, + null, html, null, "UTF-8", diff --git a/article_forge/views/template.liquid b/article_forge/views/template.liquid index 7656c4c9..22a371b2 100644 --- a/article_forge/views/template.liquid +++ b/article_forge/views/template.liquid @@ -17,8 +17,8 @@ } {{font_preload}} - - + +
diff --git a/capy/src/main/java/com/jocmp/capy/articles/ArticleRenderer.kt b/capy/src/main/java/com/jocmp/capy/articles/ArticleRenderer.kt index 225f29a3..ccece280 100644 --- a/capy/src/main/java/com/jocmp/capy/articles/ArticleRenderer.kt +++ b/capy/src/main/java/com/jocmp/capy/articles/ArticleRenderer.kt @@ -48,8 +48,6 @@ class ArticleRenderer( document.getElementById("article-body-content")?.append(article.content) - cleanLinks(document) - return document.html() } diff --git a/capy/src/main/java/com/jocmp/capy/articles/CleanLinks.kt b/capy/src/main/java/com/jocmp/capy/articles/CleanLinks.kt deleted file mode 100644 index 55dd58a8..00000000 --- a/capy/src/main/java/com/jocmp/capy/articles/CleanLinks.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.jocmp.capy.articles - -import org.jsoup.nodes.Element - -internal fun cleanLinks(element: Element) { - element.getElementsByTag("img").forEachIndexed{ index, child -> - child.attr("src", child.absUrl("src")) - - if (index > 0) { - child.attr("loading", "lazy") - } - } - - element.select("img[data-src]").forEach { child -> - child.attr("src", child.absUrl("data-src")) - } -} diff --git a/capy/src/main/java/com/jocmp/capy/articles/ParseHTML.kt b/capy/src/main/java/com/jocmp/capy/articles/ParseHTML.kt index 40dc473b..e932ceaa 100644 --- a/capy/src/main/java/com/jocmp/capy/articles/ParseHTML.kt +++ b/capy/src/main/java/com/jocmp/capy/articles/ParseHTML.kt @@ -13,8 +13,6 @@ fun parseHtml(article: Article, html: String): String { element.append(" ") } - cleanLinks(content) - return content.html() } catch (ex: Throwable) { return "" diff --git a/capy/src/main/res/raw/template.html b/capy/src/main/res/raw/template.html index 1d557c25..e77a5ebe 100644 --- a/capy/src/main/res/raw/template.html +++ b/capy/src/main/res/raw/template.html @@ -17,8 +17,8 @@ } {{font_preload}} - - + +
diff --git a/fastlane/metadata/android/en-US/changelogs/1071.txt b/fastlane/metadata/android/en-US/changelogs/1071.txt index e91e98d8..05048e66 100644 --- a/fastlane/metadata/android/en-US/changelogs/1071.txt +++ b/fastlane/metadata/android/en-US/changelogs/1071.txt @@ -1 +1,7 @@ +Added + • Add initial support for FreshRSS and Google Reader API + +Fixed + +• Fixed missing images on some articles From 8a1e1ba9c3e72faaa423196e295c50cf19153e6c Mon Sep 17 00:00:00 2001 From: Josiah Campbell <9521010+jocmp@users.noreply.github.com> Date: Sun, 10 Nov 2024 21:23:57 -0600 Subject: [PATCH 2/3] Use OR instead of AND for visibility --- .../com/capyreader/app/ui/components/WebView.kt | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/capyreader/app/ui/components/WebView.kt b/app/src/main/java/com/capyreader/app/ui/components/WebView.kt index 77dc8555..76ab2651 100644 --- a/app/src/main/java/com/capyreader/app/ui/components/WebView.kt +++ b/app/src/main/java/com/capyreader/app/ui/components/WebView.kt @@ -27,6 +27,7 @@ import com.capyreader.app.ui.articles.detail.articleTemplateColors import com.capyreader.app.ui.articles.detail.byline import com.jocmp.capy.Article import com.jocmp.capy.articles.ArticleRenderer +import com.jocmp.capy.common.launchUI import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -34,9 +35,6 @@ import kotlinx.coroutines.withContext import org.koin.compose.koinInject import org.koin.core.component.KoinComponent import org.koin.core.component.inject -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import java.io.InputStream /** * Doesn't really fetch from androidplatform.net. This is used as a placeholder domain: @@ -126,7 +124,7 @@ class WebViewState( val id = article.id scope.launch { - if (htmlId != null && id != htmlId) { + if (htmlId == null || id != htmlId) { webView.visibility = View.INVISIBLE } @@ -207,13 +205,4 @@ fun rememberWebViewState( client.state = it } } -} - -private fun jpegStream( - bitmap: Bitmap, -): InputStream { - val byteArrayOutputStream = ByteArrayOutputStream() - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream) - val bitmapData = byteArrayOutputStream.toByteArray() - return ByteArrayInputStream(bitmapData) -} +} \ No newline at end of file From 92f91837eabde233c8e8544f0302d8edd5b62371 Mon Sep 17 00:00:00 2001 From: Josiah Campbell <9521010+jocmp@users.noreply.github.com> Date: Sun, 10 Nov 2024 21:45:59 -0600 Subject: [PATCH 3/3] Fix scroll bug --- .../app/ui/articles/ArticleLayout.kt | 10 ------- .../app/ui/articles/detail/ArticleReader.kt | 5 +++- .../app/ui/articles/detail/ArticleView.kt | 28 ++++++++--------- .../capyreader/app/ui/components/WebView.kt | 30 ++----------------- 4 files changed, 20 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt b/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt index a9f82511..864cfd18 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/ArticleLayout.kt @@ -4,7 +4,6 @@ import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -133,18 +132,10 @@ fun ArticleLayout( scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail) } - val scrollState = rememberSaveable(saver = ScrollState.Saver) { - ScrollState(initial = 0) - } val webViewState = rememberWebViewState( onNavigateToMedia = { mediaUrl = it }, - onPageStarted = { - coroutineScope.launchUI { - scrollState.scrollTo(0) - } - } ) fun scrollToArticle(index: Int) { @@ -373,7 +364,6 @@ fun ArticleLayout( ArticleView( article = article, webViewState = webViewState, - scrollState = scrollState, articles = indexedArticles, onBackPressed = { coroutineScope.launchUI { diff --git a/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt b/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt index 4b9e2f6c..5de49c51 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleReader.kt @@ -23,9 +23,12 @@ import com.jocmp.capy.Article @Composable fun ArticleReader( article: Article, - scrollState: ScrollState, webViewState: WebViewState, ) { + val scrollState = rememberSaveable(saver = ScrollState.Saver) { + ScrollState(initial = 0) + } + var lastScrollY by rememberSaveable { mutableIntStateOf(0) } ColumnScrollbar(state = scrollState) { diff --git a/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleView.kt b/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleView.kt index 89b4f3a5..a45a8adb 100644 --- a/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleView.kt +++ b/app/src/main/java/com/capyreader/app/ui/articles/detail/ArticleView.kt @@ -8,7 +8,6 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -26,6 +25,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.key import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment @@ -49,7 +49,6 @@ import org.koin.compose.koinInject fun ArticleView( article: Article, webViewState: WebViewState, - scrollState: ScrollState, articles: IndexedArticles, onBackPressed: () -> Unit, onToggleRead: () -> Unit, @@ -93,18 +92,19 @@ fun ArticleView( ) }, reader = { - ArticlePullRefresh( - toolbars.show && !toolbars.pinned, - onToggleFullContent = onToggleFullContent, - onRequestNext = onRequestNext, - onRequestPrevious = onRequestPrevious, - articles = articles, - ) { - ArticleReader( - article = article, - webViewState = webViewState, - scrollState = scrollState, - ) + key(article.id) { + ArticlePullRefresh( + toolbars.show && !toolbars.pinned, + onToggleFullContent = onToggleFullContent, + onRequestNext = onRequestNext, + onRequestPrevious = onRequestPrevious, + articles = articles, + ) { + ArticleReader( + article = article, + webViewState = webViewState, + ) + } } }, bottomBar = { diff --git a/app/src/main/java/com/capyreader/app/ui/components/WebView.kt b/app/src/main/java/com/capyreader/app/ui/components/WebView.kt index 76ab2651..d5dab306 100644 --- a/app/src/main/java/com/capyreader/app/ui/components/WebView.kt +++ b/app/src/main/java/com/capyreader/app/ui/components/WebView.kt @@ -1,8 +1,6 @@ package com.capyreader.app.ui.components import android.annotation.SuppressLint -import android.graphics.Bitmap -import android.view.View import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebView @@ -27,7 +25,6 @@ import com.capyreader.app.ui.articles.detail.articleTemplateColors import com.capyreader.app.ui.articles.detail.byline import com.jocmp.capy.Article import com.jocmp.capy.articles.ArticleRenderer -import com.jocmp.capy.common.launchUI import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -68,7 +65,6 @@ fun WebView( class AccompanistWebViewClient( private val assetLoader: WebViewAssetLoader, - private val onPageStarted: () -> Unit, ) : WebViewClient(), KoinComponent { lateinit var state: WebViewState @@ -76,19 +72,6 @@ class AccompanistWebViewClient( private val appPreferences by inject() - override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) { - super.onPageStarted(view, url, favicon) - onPageStarted() - - view.postVisualStateCallback(requestId, object : WebView.VisualStateCallback() { - override fun onComplete(requestId: Long) { - view.visibility = View.VISIBLE - } - }) - } - - private val requestId = 1200L - override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest @@ -124,12 +107,6 @@ class WebViewState( val id = article.id scope.launch { - if (htmlId == null || id != htmlId) { - webView.visibility = View.INVISIBLE - } - - htmlId = id - withContext(Dispatchers.IO) { val html = renderer.render( article, @@ -163,7 +140,6 @@ class WebViewState( fun rememberWebViewState( renderer: ArticleRenderer = koinInject(), onNavigateToMedia: (url: String) -> Unit, - onPageStarted: () -> Unit, ): WebViewState { val colors = articleTemplateColors() val scope = rememberCoroutineScope() @@ -171,13 +147,11 @@ fun rememberWebViewState( val client = remember { AccompanistWebViewClient( - assetLoader = - WebViewAssetLoader.Builder() + assetLoader = WebViewAssetLoader.Builder() .setDomain(DEFAULT_DOMAIN) .addPathHandler("/assets/", AssetsPathHandler(context)) .addPathHandler("/res/", ResourcesPathHandler(context)) .build(), - onPageStarted = onPageStarted, ) } @@ -205,4 +179,4 @@ fun rememberWebViewState( client.state = it } } -} \ No newline at end of file +}