Extract views from ItemScreen

This commit is contained in:
Shinokuni 2024-04-13 14:12:55 +02:00
parent 91378f0a54
commit 02a3f82b72
3 changed files with 163 additions and 88 deletions

View File

@ -1,12 +1,7 @@
package com.readrops.app.compose.item package com.readrops.app.compose.item
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.util.Base64
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import android.widget.RelativeLayout import android.widget.RelativeLayout
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -33,12 +28,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -46,15 +39,14 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.ViewCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import cafe.adriel.voyager.koin.getScreenModel import cafe.adriel.voyager.koin.getScreenModel
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.readrops.api.utils.DateUtils import com.readrops.api.utils.DateUtils
import com.readrops.app.compose.R import com.readrops.app.compose.R
import com.readrops.app.compose.util.Utils import com.readrops.app.compose.item.view.ItemNestedScrollView
import com.readrops.app.compose.item.view.ItemWebView
import com.readrops.app.compose.util.components.AndroidScreen import com.readrops.app.compose.util.components.AndroidScreen
import com.readrops.app.compose.util.components.CenteredProgressIndicator import com.readrops.app.compose.util.components.CenteredProgressIndicator
import com.readrops.app.compose.util.components.IconText import com.readrops.app.compose.util.components.IconText
@ -69,7 +61,6 @@ class ItemScreen(
private val itemId: Int private val itemId: Int
) : AndroidScreen() { ) : AndroidScreen() {
@SuppressLint("ResourceType", "SetJavaScriptEnabled")
@Composable @Composable
override fun Content() { override fun Content() {
val context = LocalContext.current val context = LocalContext.current
@ -150,31 +141,18 @@ class ItemScreen(
) { ) {
AndroidView( AndroidView(
factory = { context -> factory = { context ->
NestedScrollView(context).apply { ItemNestedScrollView(
val treeObserver = viewTreeObserver context = context,
treeObserver.addOnGlobalLayoutListener { onGlobalLayoutListener = { viewHeight, contentHeight ->
val viewHeight = this.measuredHeight
val contentHeight = getChildAt(0).height
isScrollable = viewHeight - contentHeight < 0 isScrollable = viewHeight - contentHeight < 0
} }
) {
addView(
RelativeLayout(context).apply {
ViewCompat.setNestedScrollingEnabled(this, true)
val composeView = ComposeView(context).apply {
id = 1
setContent {
if (item.imageLink != null) { if (item.imageLink != null) {
BackgroundTitle( BackgroundTitle(
itemWithFeed = itemWithFeed itemWithFeed = itemWithFeed
) )
} else { } else {
val tintColor = val tintColor = if (itemWithFeed.bgColor != 0) {
if (itemWithFeed.bgColor != 0) {
Color(itemWithFeed.bgColor) Color(itemWithFeed.bgColor)
} else { } else {
MaterialTheme.colorScheme.onBackground MaterialTheme.colorScheme.onBackground
@ -189,53 +167,18 @@ class ItemScreen(
) )
} }
} }
}
val webView = WebView(context).apply {
id = 2
ViewCompat.setNestedScrollingEnabled(this, true)
settings.javaScriptEnabled = true
webViewClient = WebViewClient()
settings.builtInZoomControls = true
settings.displayZoomControls = false
settings.setSupportZoom(false)
isVerticalScrollBarEnabled = false
setBackgroundColor(backgroundColor.toArgb())
}
val params = RelativeLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
params.addRule(RelativeLayout.BELOW, composeView.id)
webView.layoutParams = params
addView(composeView)
addView(webView)
}
)
}
}, },
update = { nestedScrollView -> update = { nestedScrollView ->
val relativeLayout = val relativeLayout =
(nestedScrollView.children.toList()[0] as RelativeLayout) (nestedScrollView.children.toList()[0] as RelativeLayout)
val webView = relativeLayout.children.toList()[1] as WebView val webView = relativeLayout.children.toList()[1] as ItemWebView
val string = context.getString( webView.loadText(
R.string.webview_html_template, itemWithFeed = itemWithFeed,
Utils.getCssColor(accentColor.toArgb()), accentColor = accentColor,
Utils.getCssColor(onBackgroundColor.toArgb()), backgroundColor = backgroundColor,
Utils.getCssColor(backgroundColor.toArgb()), onBackgroundColor = onBackgroundColor
screenModel.formatText()
) )
val data =
Base64.encodeToString(string.encodeToByteArray(), Base64.NO_PADDING)
webView.loadData(data, "text/html; charset=utf-8", "base64")
} }
) )
} }
@ -326,7 +269,8 @@ fun SimpleTitle(
Text( Text(
text = itemWithFeed.feedName, text = itemWithFeed.feedName,
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = baseColor color = baseColor,
textAlign = TextAlign.Center
) )
ShortSpacer() ShortSpacer()

View File

@ -0,0 +1,63 @@
package com.readrops.app.compose.item.view
import android.annotation.SuppressLint
import android.content.Context
import android.widget.RelativeLayout
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.ViewCompat
import androidx.core.widget.NestedScrollView
@SuppressLint("ResourceType")
class ItemNestedScrollView(
context: Context,
onGlobalLayoutListener: (viewHeight: Int, contentHeight: Int) -> Unit,
composeViewContent: @Composable () -> Unit
) : NestedScrollView(context) {
init {
addView(
RelativeLayout(context).apply {
ViewCompat.setNestedScrollingEnabled(this, true)
val composeView = ComposeView(context).apply {
id = 1
setContent {
composeViewContent()
}
}
val composeViewParams = RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
)
composeViewParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
composeView.layoutParams = composeViewParams
val webView = ItemWebView(context).apply {
id = 2
ViewCompat.setNestedScrollingEnabled(this, true)
}
val webViewParams = RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
)
webViewParams.addRule(RelativeLayout.BELOW, composeView.id)
webView.layoutParams = webViewParams
addView(composeView)
addView(webView)
}
)
viewTreeObserver.addOnGlobalLayoutListener {
val viewHeight = this.measuredHeight
val contentHeight = getChildAt(0).height
onGlobalLayoutListener(viewHeight, contentHeight)
}
}
}

View File

@ -0,0 +1,68 @@
package com.readrops.app.compose.item.view
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.util.Base64
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import com.readrops.app.compose.R
import com.readrops.app.compose.util.Utils
import com.readrops.db.pojo.ItemWithFeed
import org.jsoup.Jsoup
import org.jsoup.parser.Parser
@SuppressLint("SetJavaScriptEnabled")
class ItemWebView(
context: Context,
attrs: AttributeSet?,
) : WebView(context, attrs) {
constructor(context: Context): this(context, null)
init {
settings.javaScriptEnabled = true
settings.builtInZoomControls = true
settings.displayZoomControls = false
settings.setSupportZoom(false)
webViewClient = WebViewClient()
isVerticalScrollBarEnabled = false
}
fun loadText(
itemWithFeed: ItemWithFeed,
accentColor: Color,
backgroundColor: Color,
onBackgroundColor: Color
) {
val string = context.getString(
R.string.webview_html_template,
Utils.getCssColor(accentColor.toArgb()),
Utils.getCssColor(onBackgroundColor.toArgb()),
Utils.getCssColor(backgroundColor.toArgb()),
formatText(itemWithFeed)
)
val data = Base64.encodeToString(string.encodeToByteArray(), Base64.NO_PADDING)
loadData(data, "text/html; charset=utf-8", "base64")
}
private fun formatText(itemWithFeed: ItemWithFeed): String {
return if (itemWithFeed.item.content != null) {
val document = if (itemWithFeed.websiteUrl != null) Jsoup.parse(
Parser.unescapeEntities(itemWithFeed.item.text, false), itemWithFeed.websiteUrl
) else Jsoup.parse(
Parser.unescapeEntities(itemWithFeed.item.text, false)
)
document.select("div,span").forEach { it.clearAttributes() }
return document.body().html()
} else {
""
}
}
}