@@ -53,7 +53,8 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.App.Starting"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:configChanges="fontScale|orientation|screenSize|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -22,6 +23,8 @@ import androidx.compose.animation.SharedTransitionScope
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
@@ -57,6 +60,21 @@ class MainActivity : ComponentActivity() {
|
||||
private val scope = CoroutineScope(Dispatchers.Main)
|
||||
val context = this
|
||||
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
// 禁用字体缩放,固定字体大小为系统默认大小
|
||||
val configuration = Configuration(newBase.resources.configuration)
|
||||
configuration.fontScale = 1.0f
|
||||
val context = newBase.createConfigurationContext(configuration)
|
||||
super.attachBaseContext(context)
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
// 确保配置变化时字体缩放保持为 1.0
|
||||
val config = Configuration(newConfig)
|
||||
config.fontScale = 1.0f
|
||||
super.onConfigurationChanged(config)
|
||||
}
|
||||
|
||||
// 请求通知权限
|
||||
private val requestPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission(),
|
||||
@@ -128,6 +146,15 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
setContent {
|
||||
// 强制字体缩放为 1.0 - 通过覆盖 Density 来实现
|
||||
val density = LocalDensity.current
|
||||
val fixedDensity = remember {
|
||||
androidx.compose.ui.unit.Density(
|
||||
density = density.density,
|
||||
fontScale = 1.0f
|
||||
)
|
||||
}
|
||||
|
||||
var showSplash by remember { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -139,7 +166,8 @@ class MainActivity : ComponentActivity() {
|
||||
SplashScreen()
|
||||
} else {
|
||||
CompositionLocalProvider(
|
||||
LocalAppTheme provides AppState.appTheme
|
||||
LocalAppTheme provides AppState.appTheme,
|
||||
LocalDensity provides fixedDensity
|
||||
) {
|
||||
CheckUpdateDialog()
|
||||
// 全局挂载积分底部弹窗 Host
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.aiosman.ravenow
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import com.google.firebase.FirebaseApp
|
||||
import com.google.firebase.perf.FirebasePerformance
|
||||
@@ -11,6 +12,14 @@ import com.google.firebase.perf.FirebasePerformance
|
||||
*/
|
||||
class RaveNowApplication : Application() {
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
// 禁用字体缩放,固定字体大小为系统默认大小
|
||||
val configuration = Configuration(base.resources.configuration)
|
||||
configuration.fontScale = 1.0f
|
||||
val context = base.createConfigurationContext(configuration)
|
||||
super.attachBaseContext(context)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.entity.CommentEntity
|
||||
import com.aiosman.ravenow.ui.composables.EditCommentBottomModal
|
||||
@@ -88,6 +89,7 @@ fun CommentModalContent(
|
||||
}
|
||||
)
|
||||
val commentViewModel = model.commentsViewModel
|
||||
val AppColors = LocalAppTheme.current
|
||||
var navBarHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
|
||||
LaunchedEffect(Unit) {
|
||||
|
||||
@@ -99,10 +101,24 @@ fun CommentModalContent(
|
||||
var bottomPadding by remember { mutableStateOf(0.dp) }
|
||||
var softwareKeyboardController = LocalSoftwareKeyboardController.current
|
||||
var replyComment by remember { mutableStateOf<CommentEntity?>(null) }
|
||||
var shouldAutoFocus by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(imePadding) {
|
||||
bottomPadding = imePadding.dp
|
||||
}
|
||||
|
||||
// 当设置回复评论时,自动聚焦到输入框
|
||||
LaunchedEffect(replyComment) {
|
||||
if (replyComment != null) {
|
||||
// 延迟一下,确保输入框已经渲染
|
||||
kotlinx.coroutines.delay(100)
|
||||
shouldAutoFocus = true
|
||||
// 请求显示键盘
|
||||
softwareKeyboardController?.show()
|
||||
} else {
|
||||
shouldAutoFocus = false
|
||||
}
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
onDismiss()
|
||||
@@ -113,7 +129,7 @@ fun CommentModalContent(
|
||||
onDismissRequest = {
|
||||
showCommentMenu = false
|
||||
},
|
||||
containerColor = Color.White,
|
||||
containerColor = AppColors.background,
|
||||
sheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
),
|
||||
@@ -152,12 +168,13 @@ fun CommentModalContent(
|
||||
stringResource(R.string.comment),
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = AppColors.text,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
color = Color(0xFFF7F7F7)
|
||||
color = AppColors.divider
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -169,7 +186,7 @@ fun CommentModalContent(
|
||||
Text(
|
||||
text = stringResource(id = R.string.comment_count, commentCount),
|
||||
fontSize = 14.sp,
|
||||
color = Color(0xff666666)
|
||||
color = AppColors.secondaryText
|
||||
)
|
||||
OrderSelectionComponent {
|
||||
commentViewModel.order = it
|
||||
@@ -193,7 +210,9 @@ fun CommentModalContent(
|
||||
|
||||
},
|
||||
onReply = { parentComment, _, _, _ ->
|
||||
|
||||
// 设置回复的评论,这样 EditCommentBottomModal 会显示回复输入框
|
||||
// CommentContent 内部已经处理了游客模式检查,所以这里直接设置即可
|
||||
replyComment = parentComment
|
||||
},
|
||||
)
|
||||
Spacer(modifier = Modifier.height(72.dp))
|
||||
@@ -204,9 +223,12 @@ fun CommentModalContent(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color(0xfff7f7f7))
|
||||
.background(AppColors.secondaryBackground)
|
||||
) {
|
||||
EditCommentBottomModal(
|
||||
replyComment = replyComment,
|
||||
autoFocus = shouldAutoFocus
|
||||
) {
|
||||
EditCommentBottomModal(replyComment) {
|
||||
commentViewModel.viewModelScope.launch {
|
||||
if (replyComment != null) {
|
||||
if (replyComment?.parentCommentId != null) {
|
||||
@@ -224,6 +246,13 @@ fun CommentModalContent(
|
||||
// 顶级评论
|
||||
commentViewModel.createComment(it)
|
||||
}
|
||||
// 评论创建成功后调用回调
|
||||
onCommentAdded()
|
||||
// 清空回复状态和自动聚焦状态
|
||||
replyComment = null
|
||||
shouldAutoFocus = false
|
||||
// 隐藏键盘
|
||||
softwareKeyboardController?.hide()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
@@ -60,10 +61,15 @@ fun EditCommentBottomModal(
|
||||
var navBarHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val context = LocalContext.current
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
LaunchedEffect(autoFocus) {
|
||||
if (autoFocus) {
|
||||
// 延迟一下,确保输入框已经渲染完成
|
||||
kotlinx.coroutines.delay(150)
|
||||
focusRequester.requestFocus()
|
||||
// 显示键盘
|
||||
keyboardController?.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +89,7 @@ fun EditCommentBottomModal(
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color.Gray.copy(alpha = 0.1f))
|
||||
.background(AppColors.inputBackground)
|
||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||
) {
|
||||
Row(
|
||||
@@ -100,7 +106,7 @@ fun EditCommentBottomModal(
|
||||
.weight(1f)
|
||||
.focusRequester(focusRequester),
|
||||
textStyle = TextStyle(
|
||||
color = Color.Black,
|
||||
color = AppColors.text,
|
||||
fontWeight = FontWeight.Normal
|
||||
),
|
||||
decorationBox = { innerTextField ->
|
||||
|
||||
@@ -155,6 +155,17 @@ fun FavouriteListPage() {
|
||||
) {
|
||||
items(moments.itemCount) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
// 获取缩略图URL:优先使用图片,如果没有图片则使用视频缩略图
|
||||
val thumbnailUrl = when {
|
||||
momentItem.images.isNotEmpty() -> momentItem.images[0].thumbnail
|
||||
momentItem.videos != null && momentItem.videos.isNotEmpty() -> {
|
||||
momentItem.videos.first().thumbnailUrl ?: momentItem.videos.first().thumbnailDirectUrl
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (thumbnailUrl == null) return@items
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -169,7 +180,7 @@ fun FavouriteListPage() {
|
||||
}
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
imageUrl = momentItem.images[0].thumbnail,
|
||||
imageUrl = thumbnailUrl,
|
||||
contentDescription = "",
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
||||
@@ -154,13 +154,13 @@ fun ShortVideoScreen() {
|
||||
}
|
||||
},
|
||||
onCommentClick = { moment ->
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
} else {
|
||||
// 点击评论图标只是打开评论弹窗,不应该增加评论数
|
||||
},
|
||||
onCommentAdded = { moment ->
|
||||
// 评论添加后的回调,更新评论数
|
||||
scope.launch {
|
||||
viewModel.onAddComment(moment.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFavoriteClick = { moment ->
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
|
||||
@@ -178,6 +178,15 @@ fun ShortVideoScreen() {
|
||||
onShareClick = { moment ->
|
||||
// TODO: 实现分享功能
|
||||
},
|
||||
onAvatarClick = { moment ->
|
||||
// 点击头像进入用户界面
|
||||
navController.navigate(
|
||||
com.aiosman.ravenow.ui.NavigationRoute.AccountProfile.route.replace(
|
||||
"{id}",
|
||||
moment.authorId.toString()
|
||||
)
|
||||
)
|
||||
},
|
||||
onPageChanged = { idx -> currentIndex.value = idx }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -43,7 +44,9 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@@ -67,6 +70,7 @@ import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||
import androidx.media3.ui.AspectRatioFrameLayout
|
||||
import androidx.media3.ui.PlayerView
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.entity.MomentEntity
|
||||
import com.aiosman.ravenow.ui.comment.CommentModalContent
|
||||
@@ -75,6 +79,9 @@ import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
// 激活状态的颜色(点赞/收藏时的红色)
|
||||
private val ActiveIconColor = Color(0xFFD80264)
|
||||
|
||||
@Composable
|
||||
fun ShortViewCompose(
|
||||
videoItemsUrl: List<String> = emptyList(),
|
||||
@@ -84,8 +91,10 @@ fun ShortViewCompose(
|
||||
videoBottom: @Composable ((MomentEntity) -> Unit)? = null,
|
||||
onLikeClick: ((MomentEntity) -> Unit)? = null,
|
||||
onCommentClick: ((MomentEntity) -> Unit)? = null,
|
||||
onCommentAdded: ((MomentEntity) -> Unit)? = null,
|
||||
onFavoriteClick: ((MomentEntity) -> Unit)? = null,
|
||||
onShareClick: ((MomentEntity) -> Unit)? = null,
|
||||
onAvatarClick: ((MomentEntity) -> Unit)? = null,
|
||||
onPageChanged: ((Int) -> Unit)? = null
|
||||
) {
|
||||
// 优先使用 videoMoments,如果没有则使用 videoItemsUrl
|
||||
@@ -159,8 +168,10 @@ fun ShortViewCompose(
|
||||
VideoBottom = videoBottom,
|
||||
onLikeClick = onLikeClick,
|
||||
onCommentClick = onCommentClick,
|
||||
onCommentAdded = onCommentAdded,
|
||||
onFavoriteClick = onFavoriteClick,
|
||||
onShareClick = onShareClick
|
||||
onShareClick = onShareClick,
|
||||
onAvatarClick = onAvatarClick
|
||||
)
|
||||
}
|
||||
|
||||
@@ -183,8 +194,10 @@ private fun SingleVideoItemContent(
|
||||
VideoBottom: @Composable ((MomentEntity) -> Unit)? = null,
|
||||
onLikeClick: ((MomentEntity) -> Unit)? = null,
|
||||
onCommentClick: ((MomentEntity) -> Unit)? = null,
|
||||
onCommentAdded: ((MomentEntity) -> Unit)? = null,
|
||||
onFavoriteClick: ((MomentEntity) -> Unit)? = null,
|
||||
onShareClick: ((MomentEntity) -> Unit)? = null
|
||||
onShareClick: ((MomentEntity) -> Unit)? = null,
|
||||
onAvatarClick: ((MomentEntity) -> Unit)? = null
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@@ -199,8 +212,10 @@ private fun SingleVideoItemContent(
|
||||
pauseIconVisibleState = pauseIconVisibleState,
|
||||
onLikeClick = onLikeClick,
|
||||
onCommentClick = onCommentClick,
|
||||
onCommentAdded = onCommentAdded,
|
||||
onFavoriteClick = onFavoriteClick,
|
||||
onShareClick = onShareClick
|
||||
onShareClick = onShareClick,
|
||||
onAvatarClick = onAvatarClick
|
||||
)
|
||||
VideoHeader.invoke()
|
||||
if (moment != null && VideoBottom != null) {
|
||||
@@ -228,12 +243,17 @@ fun VideoPlayer(
|
||||
pauseIconVisibleState: MutableState<Boolean>,
|
||||
onLikeClick: ((MomentEntity) -> Unit)? = null,
|
||||
onCommentClick: ((MomentEntity) -> Unit)? = null,
|
||||
onCommentAdded: ((MomentEntity) -> Unit)? = null,
|
||||
onFavoriteClick: ((MomentEntity) -> Unit)? = null,
|
||||
onShareClick: ((MomentEntity) -> Unit)? = null,
|
||||
onAvatarClick: ((MomentEntity) -> Unit)? = null,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val configuration = androidx.compose.ui.platform.LocalConfiguration.current
|
||||
val screenHeight = configuration.screenHeightDp.dp
|
||||
val sheetHeight = screenHeight * 0.7f // 屏幕的一大半高度
|
||||
var showCommentModal by remember { mutableStateOf(false) }
|
||||
var sheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
@@ -371,42 +391,51 @@ fun VideoPlayer(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (moment != null) {
|
||||
UserAvatar(avatarUrl = moment.avatar)
|
||||
// 使用 key 确保状态变化时重新组合
|
||||
androidx.compose.runtime.key(moment.id, moment.isFavorite) {
|
||||
UserAvatar(
|
||||
avatarUrl = moment.avatar,
|
||||
onClick = { onAvatarClick?.invoke(moment) }
|
||||
)
|
||||
VideoBtn(
|
||||
icon = R.drawable.rider_pro_video_like,
|
||||
text = formatCount(moment.likeCount)
|
||||
) {
|
||||
moment?.let { onLikeClick?.invoke(it) }
|
||||
}
|
||||
icon = if (moment.liked) R.drawable.rider_pro_moment_liked else R.drawable.rider_pro_moment_like,
|
||||
text = formatCount(moment.likeCount),
|
||||
isActive = moment.liked,
|
||||
onClick = { onLikeClick?.invoke(moment) }
|
||||
)
|
||||
VideoBtn(
|
||||
icon = R.drawable.rider_pro_video_comment,
|
||||
text = formatCount(moment.commentCount)
|
||||
) {
|
||||
moment?.let {
|
||||
icon = R.mipmap.icon_comment,
|
||||
text = formatCount(moment.commentCount),
|
||||
onClick = {
|
||||
showCommentModal = true
|
||||
onCommentClick?.invoke(it)
|
||||
}
|
||||
onCommentClick?.invoke(moment)
|
||||
}
|
||||
)
|
||||
VideoBtn(
|
||||
icon = R.drawable.rider_pro_video_favor,
|
||||
text = formatCount(moment.favoriteCount)
|
||||
) {
|
||||
moment?.let { onFavoriteClick?.invoke(it) }
|
||||
}
|
||||
icon = if (moment.isFavorite) R.mipmap.icon_variant_2 else R.mipmap.icon_collect,
|
||||
text = formatCount(moment.favoriteCount),
|
||||
isActive = false, // 收藏后不使用红色滤镜,保持图标原本颜色
|
||||
keepOriginalColor = moment.isFavorite, // 收藏后保持原始颜色
|
||||
onClick = { onFavoriteClick?.invoke(moment) }
|
||||
)
|
||||
VideoBtn(
|
||||
icon = R.drawable.rider_pro_video_share,
|
||||
text = formatCount(moment.shareCount)
|
||||
) {
|
||||
moment?.let { onShareClick?.invoke(it) }
|
||||
icon = R.mipmap.icon_share,
|
||||
text = formatCount(moment.shareCount),
|
||||
onClick = { onShareClick?.invoke(moment) }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
UserAvatar()
|
||||
VideoBtn(icon = R.drawable.rider_pro_video_like, text = "0")
|
||||
VideoBtn(icon = R.drawable.rider_pro_video_comment, text = "0") {
|
||||
VideoBtn(icon = R.drawable.rider_pro_moment_like, text = "0")
|
||||
VideoBtn(
|
||||
icon = R.mipmap.icon_comment,
|
||||
text = "0",
|
||||
onClick = {
|
||||
showCommentModal = true
|
||||
}
|
||||
VideoBtn(icon = R.drawable.rider_pro_video_favor, text = "0")
|
||||
VideoBtn(icon = R.drawable.rider_pro_video_share, text = "0")
|
||||
)
|
||||
VideoBtn(icon = R.mipmap.icon_collect, text = "0")
|
||||
VideoBtn(icon = R.mipmap.icon_share, text = "0")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,26 +494,44 @@ fun VideoPlayer(
|
||||
}
|
||||
|
||||
if (showCommentModal && moment != null) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { showCommentModal = false },
|
||||
containerColor = Color.White,
|
||||
sheetState = sheetState
|
||||
containerColor = AppColors.background,
|
||||
sheetState = sheetState,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(sheetHeight)
|
||||
) {
|
||||
CommentModalContent(postId = moment.id) {
|
||||
|
||||
CommentModalContent(
|
||||
postId = moment.id,
|
||||
commentCount = moment.commentCount,
|
||||
onCommentAdded = {
|
||||
onCommentAdded?.invoke(moment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UserAvatar(avatarUrl: String? = null) {
|
||||
fun UserAvatar(
|
||||
avatarUrl: String? = null,
|
||||
onClick: (() -> Unit)? = null
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 16.dp)
|
||||
.size(40.dp)
|
||||
.border(width = 3.dp, color = Color.White, shape = RoundedCornerShape(40.dp))
|
||||
.clip(RoundedCornerShape(40.dp))
|
||||
.then(
|
||||
if (onClick != null) {
|
||||
Modifier.noRippleClickable { onClick() }
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
) {
|
||||
if (avatarUrl != null && avatarUrl.isNotEmpty()) {
|
||||
CustomAsyncImage(
|
||||
@@ -512,19 +559,31 @@ private fun formatCount(count: Int): String {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun VideoBtn(@DrawableRes icon: Int, text: String, onClick: (() -> Unit)? = null) {
|
||||
fun VideoBtn(
|
||||
@DrawableRes icon: Int,
|
||||
text: String,
|
||||
onClick: (() -> Unit)? = null,
|
||||
isActive: Boolean = false,
|
||||
keepOriginalColor: Boolean = false // 是否保持原始颜色(不应用白色滤镜)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 16.dp)
|
||||
.clickable {
|
||||
.noRippleClickable {
|
||||
onClick?.invoke()
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.size(36.dp),
|
||||
modifier = Modifier.size(30.dp),
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = ""
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.FillBounds, // 填满容器,让图标看起来更大
|
||||
colorFilter = when {
|
||||
isActive -> ColorFilter.tint(ActiveIconColor)
|
||||
keepOriginalColor -> null // 保持原始颜色
|
||||
else -> ColorFilter.tint(Color.White) // 未激活状态时图标为白色
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = text,
|
||||
|
||||
BIN
app/src/main/res/mipmap-hdpi/ts_dsp_z_wxz_btn.png
Normal file
|
After Width: | Height: | Size: 970 B |
BIN
app/src/main/res/mipmap-hdpi/ts_dsp_z_xz_btn.png
Normal file
|
After Width: | Height: | Size: 423 B |
BIN
app/src/main/res/mipmap-mdpi/ts_dsp_z_wxz_btn.png
Normal file
|
After Width: | Height: | Size: 657 B |
BIN
app/src/main/res/mipmap-mdpi/ts_dsp_z_xz_btn.png
Normal file
|
After Width: | Height: | Size: 333 B |
BIN
app/src/main/res/mipmap-xhdpi/ts_dsp_z_wxz_btn.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ts_dsp_z_xz_btn.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
app/src/main/res/mipmap-xxhdpi/ts_dsp_z_wxz_btn.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ts_dsp_z_xz_btn.png
Normal file
|
After Width: | Height: | Size: 647 B |
BIN
app/src/main/res/mipmap-xxxhdpi/ts_dsp_z_wxz_btn.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ts_dsp_z_xz_btn.png
Normal file
|
After Width: | Height: | Size: 805 B |