feat: Compose 动态生成贴子内容

This commit is contained in:
HuanCheng65 2023-03-11 00:14:07 +08:00
parent ac5998d840
commit ba837abd86
No known key found for this signature in database
GPG Key ID: E9031EF91A805148
2 changed files with 240 additions and 1 deletions

View File

@ -1,10 +1,27 @@
package com.huanchengfly.tieba.post.api package com.huanchengfly.tieba.post.api
import android.os.Build import android.os.Build
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withAnnotation
import androidx.compose.ui.text.withStyle
import com.huanchengfly.tieba.post.App import com.huanchengfly.tieba.post.App
import com.huanchengfly.tieba.post.App.ScreenInfo import com.huanchengfly.tieba.post.App.ScreenInfo
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.api.models.protos.PbContent
import com.huanchengfly.tieba.post.api.models.protos.Post
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
import com.huanchengfly.tieba.post.ui.common.PbContentRender
import com.huanchengfly.tieba.post.ui.common.PicContentRender
import com.huanchengfly.tieba.post.ui.common.TextContentRender
import com.huanchengfly.tieba.post.ui.common.theme.utils.ThemeUtils
import com.huanchengfly.tieba.post.ui.utils.getPhotoViewData
import com.huanchengfly.tieba.post.utils.EmoticonManager import com.huanchengfly.tieba.post.utils.EmoticonManager
import com.huanchengfly.tieba.post.utils.EmoticonUtil.emoticonString
import com.huanchengfly.tieba.post.utils.ImageUtil
private val defaultUserAgent: String = private val defaultUserAgent: String =
@ -68,3 +85,152 @@ fun ThreadInfo.updateAgreeStatus(
agreeNum = if (hasAgree == 1) agreeNum + 1 else agreeNum - 1 agreeNum = if (hasAgree == 1) agreeNum + 1 else agreeNum - 1
) )
} }
private val PbContent.picUrl: String
get() =
ImageUtil.getUrl(
App.INSTANCE,
true,
originSrc,
bigCdnSrc,
bigSrc,
dynamic_,
cdnSrc,
cdnSrcActive,
src
)
@OptIn(ExperimentalTextApi::class)
val List<PbContent>.renders: List<PbContentRender>
get() {
val renders = mutableListOf<PbContentRender>()
forEach {
when (it.type) {
0, 9, 27 -> {
val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) {
lastRender.append(it.text)
} else
renders.add(TextContentRender(it.text))
}
1 -> {
val text = buildAnnotatedString {
appendInlineContent("link_icon", alternateText = "🔗")
withAnnotation(tag = "url", annotation = it.link) {
withStyle(
SpanStyle(
color = Color(
ThemeUtils.getColorByAttr(
App.INSTANCE,
R.attr.colorPrimary
)
)
)
) {
append(it.text)
}
}
}
val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) {
lastRender.append(text)
} else
renders.add(TextContentRender(text))
}
2 -> {
EmoticonManager.registerEmoticon(
it.text,
it.c
)
val emoticonText = "#(${it.c})".emoticonString
val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) {
lastRender.append(emoticonText)
} else
renders.add(TextContentRender(emoticonText))
}
3 -> {
val width = it.bsize.split(",")[0].toInt()
val height = it.bsize.split(",")[1].toInt()
renders.add(
PicContentRender(
picUrl = it.picUrl,
originUrl = it.originSrc,
showOriginBtn = it.showOriginalBtn == 1,
originSize = it.originSize,
picId = ImageUtil.getPicId(it.originSrc),
width = width,
height = height
)
)
}
4 -> {
val text = buildAnnotatedString {
appendInlineContent("user_icon", alternateText = "🧑")
withAnnotation(tag = "user", annotation = "${it.uid}") {
withStyle(
SpanStyle(
color = Color(
ThemeUtils.getColorByAttr(
App.INSTANCE,
R.attr.colorPrimary
)
)
)
) {
append(it.text)
}
}
}
val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) {
lastRender.append(text)
} else
renders.add(TextContentRender(text))
}
20 -> {
val width = it.bsize.split(",")[0].toInt()
val height = it.bsize.split(",")[1].toInt()
renders.add(
PicContentRender(
picUrl = it.src,
originUrl = it.src,
showOriginBtn = it.showOriginalBtn == 1,
originSize = it.originSize,
picId = ImageUtil.getPicId(it.src),
width = width,
height = height
)
)
}
}
}
return renders
}
val Post.contentRenders: List<PbContentRender>
get() {
val renders = content.renders
renders.forEach {
if (it is PicContentRender) {
it.photoViewData = getPhotoViewData(
this,
it.picId,
it.picUrl,
it.originUrl,
it.showOriginBtn,
it.originSize
)
}
}
return renders
}

View File

@ -0,0 +1,73 @@
package com.huanchengfly.tieba.post.ui.common
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.huanchengfly.tieba.post.arch.BaseComposeActivity.Companion.LocalWindowSizeClass
import com.huanchengfly.tieba.post.models.protos.PhotoViewData
import com.huanchengfly.tieba.post.ui.common.windowsizeclass.WindowWidthSizeClass
import com.huanchengfly.tieba.post.ui.widgets.compose.EmoticonText
import com.huanchengfly.tieba.post.ui.widgets.compose.NetworkImage
import com.huanchengfly.tieba.post.utils.appPreferences
interface PbContentRender {
@Composable
fun Render()
}
data class TextContentRender(
var text: AnnotatedString
) : PbContentRender {
constructor(text: String) : this(AnnotatedString(text))
fun append(text: String) {
append(AnnotatedString(text))
}
fun append(text: AnnotatedString) {
this.text += text
}
@Composable
override fun Render() {
EmoticonText(text = text, style = MaterialTheme.typography.body1, fontSize = 15.sp)
}
}
data class PicContentRender(
val picUrl: String,
val originUrl: String,
val showOriginBtn: Boolean,
val originSize: Int,
val width: Int,
val height: Int,
val picId: String,
var photoViewData: PhotoViewData? = null
) : PbContentRender {
@Composable
override fun Render() {
val widthFraction =
if (LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact) 1f else 0.5f
val context = LocalContext.current
NetworkImage(
imageUri = picUrl,
contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(context.appPreferences.radius.dp))
.fillMaxWidth(widthFraction)
.aspectRatio(width * 1f / height),
photoViewData = photoViewData,
contentScale = ContentScale.Crop
)
}
}