feat: Compose 动态生成贴子内容
This commit is contained in:
parent
ac5998d840
commit
ba837abd86
|
|
@ -1,10 +1,27 @@
|
|||
package com.huanchengfly.tieba.post.api
|
||||
|
||||
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.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.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.EmoticonUtil.emoticonString
|
||||
import com.huanchengfly.tieba.post.utils.ImageUtil
|
||||
|
||||
|
||||
private val defaultUserAgent: String =
|
||||
|
|
@ -67,4 +84,153 @@ fun ThreadInfo.updateAgreeStatus(
|
|||
copy(
|
||||
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
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue