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
import android.annotation.SuppressLint
import android.content.Intent
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 androidx.compose.foundation.layout.Box
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.geometry.Offset
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.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
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.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.ViewCompat
import androidx.core.view.children
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import cafe.adriel.voyager.koin.getScreenModel
import coil.compose.AsyncImage
import com.readrops.api.utils.DateUtils
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.CenteredProgressIndicator
import com.readrops.app.compose.util.components.IconText
@ -69,7 +61,6 @@ class ItemScreen(
private val itemId: Int
) : AndroidScreen() {
@SuppressLint("ResourceType", "SetJavaScriptEnabled")
@Composable
override fun Content() {
val context = LocalContext.current
@ -150,92 +141,44 @@ class ItemScreen(
) {
AndroidView(
factory = { context ->
NestedScrollView(context).apply {
val treeObserver = viewTreeObserver
treeObserver.addOnGlobalLayoutListener {
val viewHeight = this.measuredHeight
val contentHeight = getChildAt(0).height
ItemNestedScrollView(
context = context,
onGlobalLayoutListener = { viewHeight, contentHeight ->
isScrollable = viewHeight - contentHeight < 0
}
addView(
RelativeLayout(context).apply {
ViewCompat.setNestedScrollingEnabled(this, true)
val composeView = ComposeView(context).apply {
id = 1
setContent {
if (item.imageLink != null) {
BackgroundTitle(
itemWithFeed = itemWithFeed
)
} else {
val tintColor =
if (itemWithFeed.bgColor != 0) {
Color(itemWithFeed.bgColor)
} else {
MaterialTheme.colorScheme.onBackground
}
SimpleTitle(
itemWithFeed = itemWithFeed,
titleColor = tintColor,
accentColor = tintColor,
baseColor = MaterialTheme.colorScheme.onBackground,
bottomPadding = true
)
}
}
}
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)
) {
if (item.imageLink != null) {
BackgroundTitle(
itemWithFeed = itemWithFeed
)
} else {
val tintColor = if (itemWithFeed.bgColor != 0) {
Color(itemWithFeed.bgColor)
} else {
MaterialTheme.colorScheme.onBackground
}
)
SimpleTitle(
itemWithFeed = itemWithFeed,
titleColor = tintColor,
accentColor = tintColor,
baseColor = MaterialTheme.colorScheme.onBackground,
bottomPadding = true
)
}
}
},
update = { nestedScrollView ->
val 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(
R.string.webview_html_template,
Utils.getCssColor(accentColor.toArgb()),
Utils.getCssColor(onBackgroundColor.toArgb()),
Utils.getCssColor(backgroundColor.toArgb()),
screenModel.formatText()
webView.loadText(
itemWithFeed = itemWithFeed,
accentColor = accentColor,
backgroundColor = backgroundColor,
onBackgroundColor = onBackgroundColor
)
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 = itemWithFeed.feedName,
style = MaterialTheme.typography.labelLarge,
color = baseColor
color = baseColor,
textAlign = TextAlign.Center
)
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 {
""
}
}
}