diff --git a/app/src/main/java/com/aiosman/ravenow/Colors.kt b/app/src/main/java/com/aiosman/ravenow/Colors.kt index f43c2d3..47f5f84 100644 --- a/app/src/main/java/com/aiosman/ravenow/Colors.kt +++ b/app/src/main/java/com/aiosman/ravenow/Colors.kt @@ -111,7 +111,7 @@ class DarkThemeColors : AppThemeData( chatActionColor = Color(0xFF3D3D3D), brandColorsColor = Color(0xffD80264), tabSelectedBackground = Color(0xffffffff), - tabUnselectedBackground = Color(0x2E7C7480), + tabUnselectedBackground = Color(0xFF1C1C1C), tabSelectedText = Color(0xff000000), tabUnselectedText = Color(0xffffffff), bubbleBackground = Color(0xff2d2c2e), diff --git a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt index 40ab759..0eb4c4d 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.ime @@ -157,6 +159,7 @@ fun CommentModalContent( } Column( modifier = Modifier + .fillMaxSize() ) { Box( modifier = Modifier @@ -196,12 +199,12 @@ fun CommentModalContent( Box( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp) .weight(1f) ) { LazyColumn( modifier = Modifier - .fillMaxWidth() + .fillMaxSize() + .padding(horizontal = 16.dp) ) { item { CommentContent( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/AnimatedFavouriteButton.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/AnimatedFavouriteButton.kt index 6d56ac2..513dea6 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/composables/AnimatedFavouriteButton.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/AnimatedFavouriteButton.kt @@ -64,6 +64,7 @@ fun AnimatedFavouriteIcon( modifier = modifier.graphicsLayer { rotationZ = animatableRotation.value }, + colorFilter = if (!isFavourite) ColorFilter.tint(AppColors.text) else null ) } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt index f44a5e0..05a026f 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt @@ -468,6 +468,7 @@ fun MomentOperateBtn(@DrawableRes icon: Int, count: String) { .size(width = 24.dp, height = 24.dp), painter = painterResource(id = icon), contentDescription = "", + colorFilter = ColorFilter.tint(AppColors.text) ) if (count.isNotEmpty()) { Text( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt index e3cd70b..60db5f6 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt @@ -269,7 +269,7 @@ fun IndexScreen() { ) { page -> when (page) { 0 -> Agent() - 1 -> Home() + 1 -> Home(isPageVisible = pagerState.currentPage == 1) 2 -> Add() 3 -> Notifications() 4 -> Profile() @@ -332,7 +332,9 @@ fun IndexScreen() { } @Composable -fun Home() { +fun Home( + isPageVisible: Boolean = true +) { val systemUiController = rememberSystemUiController() val context = LocalContext.current @@ -348,7 +350,7 @@ fun Home() { verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - MomentsList() + MomentsList(isPageVisible = isPageVisible) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt index dba3c1f..7dd5ecd 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt @@ -71,7 +71,9 @@ import com.aiosman.ravenow.ui.index.tabs.moment.tabs.shorts.ShortVideoScreen */ @OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) @Composable -fun MomentsList() { +fun MomentsList( + isPageVisible: Boolean = true +) { val AppColors = LocalAppTheme.current val navController = LocalNavController.current val navigationBarPaddings = @@ -437,7 +439,7 @@ fun MomentsList() { } 1 -> { // 短视频页面 - ShortVideoScreen() + ShortVideoScreen(isPageVisible = pagerState.currentPage == 1 && isPageVisible) } 2 -> { // 动态页面 - 暂时显示时间线内容 diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/dynamic/Dynamic.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/dynamic/Dynamic.kt index 04b2511..fb58cef 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/dynamic/Dynamic.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/dynamic/Dynamic.kt @@ -1,5 +1,6 @@ package com.aiosman.ravenow.ui.index.tabs.moment.tabs.dynamic +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -21,6 +22,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.aiosman.ravenow.GuestLoginCheckOut import com.aiosman.ravenow.GuestLoginCheckOutScene +import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.composables.MomentCard @@ -36,6 +38,7 @@ fun Dynamic() { val model = DynamicViewModel val moments = model.moments val navController = LocalNavController.current + val AppColors = LocalAppTheme.current val scope = rememberCoroutineScope() val state = rememberPullRefreshState(model.refreshing, onRefresh = { @@ -88,7 +91,7 @@ fun Dynamic() { Column( modifier = Modifier .fillMaxSize() - + .background(AppColors.background) ) { Box(Modifier.pullRefresh(state)) { LazyColumn( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/shorts/ShortVideoScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/shorts/ShortVideoScreen.kt index d4e1a47..2542863 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/shorts/ShortVideoScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/shorts/ShortVideoScreen.kt @@ -31,7 +31,9 @@ import kotlinx.coroutines.launch * 短视频页面 */ @Composable -fun ShortVideoScreen() { +fun ShortVideoScreen( + isPageVisible: Boolean = true +) { val viewModel = ShortVideoViewModel val allMoments = viewModel.moments val navController = LocalNavController.current @@ -187,7 +189,8 @@ fun ShortVideoScreen() { ) ) }, - onPageChanged = { idx -> currentIndex.value = idx } + onPageChanged = { idx -> currentIndex.value = idx }, + isPageVisible = isPageVisible ) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt index d129b0b..0f40a14 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt @@ -86,6 +86,7 @@ fun TimelineMomentsList() { Box( modifier = Modifier .fillMaxSize() + .background(AppColors.background) .padding(top = 188.dp), contentAlignment = Alignment.TopCenter ) { @@ -126,6 +127,7 @@ fun TimelineMomentsList() { Box( modifier = Modifier .fillMaxSize() + .background(AppColors.background) .padding(top = 188.dp), contentAlignment = Alignment.TopCenter ) { @@ -176,6 +178,7 @@ fun TimelineMomentsList() { Column( modifier = Modifier .fillMaxSize() + .background(AppColors.background) ) { Box(Modifier.pullRefresh(state)) { LazyColumn( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt index 3b412e6..d1cd9e6 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt @@ -76,12 +76,129 @@ import com.aiosman.ravenow.entity.MomentEntity import com.aiosman.ravenow.ui.comment.CommentModalContent import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.modifiers.noRippleClickable +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch // 激活状态的颜色(点赞/收藏时的红色) private val ActiveIconColor = Color(0xFFD80264) +/** + * 创建视频播放器视图 + */ +private fun createVideoPlayerView( + context: android.content.Context, + exoPlayer: ExoPlayer, + onViewCreated: (PlayerView) -> Unit +): FrameLayout { + return FrameLayout(context).apply { + setBackgroundColor(Color.Black.toArgb()) + layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + + val playerView = PlayerView(context).apply { + hideController() + useController = false + player = exoPlayer + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM + setShutterBackgroundColor(Color.Black.toArgb()) + setKeepContentOnPlayerReset(false) + + layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + Gravity.CENTER + ) + + // 布局完成后固定内容帧尺寸 - 使用更可靠的方法 + var layoutListener: android.view.ViewTreeObserver.OnGlobalLayoutListener? = null + layoutListener = object : android.view.ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + try { + val frame = findViewById(androidx.media3.ui.R.id.exo_content_frame) + if (frame != null && width > 0 && height > 0) { + // 确保内容帧的尺寸和缩放模式正确设置 + val layoutParams = FrameLayout.LayoutParams( + width, + height, + Gravity.CENTER + ) + frame.layoutParams = layoutParams + frame.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM) + // 强制重新布局 + frame.requestLayout() + } + } catch (e: Exception) { + // 忽略异常 + } + } + } + + // 使用 post 确保在布局完成后执行 + post { + viewTreeObserver.addOnGlobalLayoutListener(layoutListener) + // 延迟移除监听器,确保多次布局变化都能处理 + postDelayed({ + try { + layoutListener?.let { viewTreeObserver.removeOnGlobalLayoutListener(it) } + } catch (e: Exception) { + // 忽略异常 + } + }, 500) + } + } + + // 添加视频准备监听,确保视频准备就绪时也设置正确的缩放 + exoPlayer.addListener(object : Player.Listener { + override fun onVideoSizeChanged(videoSize: androidx.media3.common.VideoSize) { + playerView.post { + try { + val frame = playerView.findViewById(androidx.media3.ui.R.id.exo_content_frame) + if (frame != null && playerView.width > 0 && playerView.height > 0) { + frame.layoutParams = FrameLayout.LayoutParams( + playerView.width, + playerView.height, + Gravity.CENTER + ) + frame.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM) + frame.requestLayout() + } + } catch (e: Exception) { + // 忽略异常 + } + } + } + }) + + onViewCreated(playerView) + addView(playerView) + } +} + +/** + * 处理视频点击事件(播放/暂停) + */ +private fun handleVideoClick( + pauseIconVisibleState: MutableState, + exoPlayer: ExoPlayer, + scope: CoroutineScope +) { + scope.launch { + if (exoPlayer.isPlaying) { + // 正在播放:暂停 + exoPlayer.pause() + pauseIconVisibleState.value = true + } else { + // 已暂停:恢复播放 + exoPlayer.playWhenReady = true + exoPlayer.play() + pauseIconVisibleState.value = false + } + } +} + @Composable fun ShortViewCompose( videoItemsUrl: List = emptyList(), @@ -95,7 +212,8 @@ fun ShortViewCompose( onFavoriteClick: ((MomentEntity) -> Unit)? = null, onShareClick: ((MomentEntity) -> Unit)? = null, onAvatarClick: ((MomentEntity) -> Unit)? = null, - onPageChanged: ((Int) -> Unit)? = null + onPageChanged: ((Int) -> Unit)? = null, + isPageVisible: Boolean = true ) { // 优先使用 videoMoments,如果没有则使用 videoItemsUrl val items = if (videoMoments.isNotEmpty()) { @@ -144,35 +262,40 @@ fun ShortViewCompose( .clip(RectangleShape), state = pagerState, orientation = Orientation.Vertical, - offscreenLimit = 1 + offscreenLimit = 1 // 只预加载相邻页面,减少内存占用 ) { - pauseIconVisibleState.value = false - val currentMoment = if (videoMoments.isNotEmpty() && page < videoMoments.size) { - videoMoments[page] - } else { - null + // 使用 key 确保每个页面独立,避免状态混乱 + androidx.compose.runtime.key(page) { + pauseIconVisibleState.value = false + val currentMoment = if (videoMoments.isNotEmpty() && page < videoMoments.size) { + videoMoments[page] + } else { + null + } + + // 同步页码到外部(用于返回时恢复进度) + LaunchedEffect(pagerState.currentPage) { + onPageChanged?.invoke(pagerState.currentPage) + } + + SingleVideoItemContent( + videoUrl = items[page], + moment = currentMoment, + pagerState = pagerState, + pager = page, + initialLayout = initialLayout, + pauseIconVisibleState = pauseIconVisibleState, + VideoHeader = videoHeader, + VideoBottom = videoBottom, + onLikeClick = onLikeClick, + onCommentClick = onCommentClick, + onCommentAdded = onCommentAdded, + onFavoriteClick = onFavoriteClick, + onShareClick = onShareClick, + onAvatarClick = onAvatarClick, + isPageVisible = isPageVisible + ) } - - // 同步页码到外部(用于返回时恢复进度) - LaunchedEffect(pagerState.currentPage) { - onPageChanged?.invoke(pagerState.currentPage) - } - SingleVideoItemContent( - videoUrl = items[page], - moment = currentMoment, - pagerState = pagerState, - pager = page, - initialLayout = initialLayout, - pauseIconVisibleState = pauseIconVisibleState, - VideoHeader = videoHeader, - VideoBottom = videoBottom, - onLikeClick = onLikeClick, - onCommentClick = onCommentClick, - onCommentAdded = onCommentAdded, - onFavoriteClick = onFavoriteClick, - onShareClick = onShareClick, - onAvatarClick = onAvatarClick - ) } LaunchedEffect(clickItemPosition) { @@ -197,7 +320,8 @@ private fun SingleVideoItemContent( onCommentAdded: ((MomentEntity) -> Unit)? = null, onFavoriteClick: ((MomentEntity) -> Unit)? = null, onShareClick: ((MomentEntity) -> Unit)? = null, - onAvatarClick: ((MomentEntity) -> Unit)? = null + onAvatarClick: ((MomentEntity) -> Unit)? = null, + isPageVisible: Boolean = true ) { Box( modifier = Modifier @@ -215,7 +339,8 @@ private fun SingleVideoItemContent( onCommentAdded = onCommentAdded, onFavoriteClick = onFavoriteClick, onShareClick = onShareClick, - onAvatarClick = onAvatarClick + onAvatarClick = onAvatarClick, + isPageVisible = isPageVisible ) VideoHeader.invoke() if (moment != null && VideoBottom != null) { @@ -247,95 +372,89 @@ fun VideoPlayer( onFavoriteClick: ((MomentEntity) -> Unit)? = null, onShareClick: ((MomentEntity) -> Unit)? = null, onAvatarClick: ((MomentEntity) -> Unit)? = null, + isPageVisible: Boolean = true ) { 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 // 屏幕的一大半高度 + val sheetHeight = screenHeight * 0.7f // 屏幕的70%高度 var showCommentModal by remember { mutableStateOf(false) } var sheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true ) - val exoPlayer = remember { - ExoPlayer.Builder(context) - .build() - .apply { - // 创建带有认证头的 HttpDataSource.Factory - val httpDataSourceFactory = DefaultHttpDataSource.Factory() - .setUserAgent(Util.getUserAgent(context, context.packageName)) - .setDefaultRequestProperties( - mapOf( - "Authorization" to "Bearer ${com.aiosman.ravenow.AppStore.token ?: ""}", - "DEVICE-OS" to "Android" - ) + + // 确保弹窗从下往上展开 + LaunchedEffect(showCommentModal) { + if (showCommentModal) { + sheetState.expand() + } else { + sheetState.hide() + } + } + // 使用 key 确保每个视频的 ExoPlayer 完全独立,避免状态残留 + val exoPlayer = remember(videoUrl) { + ExoPlayer.Builder(context).build().apply { + // 创建带有认证头的数据源 + val httpDataSourceFactory = DefaultHttpDataSource.Factory() + .setUserAgent(Util.getUserAgent(context, context.packageName)) + .setDefaultRequestProperties( + mapOf( + "Authorization" to "Bearer ${com.aiosman.ravenow.AppStore.token ?: ""}", + "DEVICE-OS" to "Android" ) - - // 创建 DataSource.Factory,使用自定义的 HttpDataSource.Factory - val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory( - context, - httpDataSourceFactory ) - val source = ProgressiveMediaSource.Factory(dataSourceFactory) - .createMediaSource(MediaItem.fromUri(Uri.parse(videoUrl))) - - this.prepare(source) - } + + val dataSourceFactory = DefaultDataSourceFactory(context, httpDataSourceFactory) + val source = ProgressiveMediaSource.Factory(dataSourceFactory) + .createMediaSource(MediaItem.fromUri(Uri.parse(videoUrl))) + + prepare(source) + videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING + repeatMode = Player.REPEAT_MODE_ONE + } } - if (pager == pagerState.currentPage) { - exoPlayer.playWhenReady = true - exoPlayer.play() - } else { - exoPlayer.pause() + + // 根据页面状态控制播放 + LaunchedEffect(pager, pagerState.currentPage, isPageVisible) { + val isCurrentPage = pager == pagerState.currentPage && isPageVisible + if (isCurrentPage) { + // 当前页面且页面可见:恢复播放 + exoPlayer.playWhenReady = true + exoPlayer.play() + pauseIconVisibleState.value = false + } else { + // 非当前页面或页面不可见:立即暂停并停止准备播放 + exoPlayer.playWhenReady = false + exoPlayer.pause() + pauseIconVisibleState.value = false + } } - exoPlayer.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT - exoPlayer.repeatMode = Player.REPEAT_MODE_ONE - // player box + // 视频播放器容器 - 确保每个视频页面都被正确裁剪 Box( modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.TopCenter + .fillMaxSize() + .clip(RectangleShape) ) { - var playerView by remember { mutableStateOf(null) } // Store reference to PlayerView + var playerView by remember { mutableStateOf(null) } - AndroidView( - factory = { context -> - // 创建一个 FrameLayout 作为容器 - FrameLayout(context).apply { - // 设置背景颜色为黑色,用于显示黑边 - setBackgroundColor(Color.Black.toArgb()) - - // 创建 PlayerView 并添加到 FrameLayout 中 - val view = PlayerView(context).apply { - hideController() - useController = false - player = exoPlayer - resizeMode = - AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT // 或 RESIZE_MODE_ZOOM - layoutParams = FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - Gravity.CENTER - ) + // 使用 key 强制每个视频的 PlayerView 完全独立,避免布局状态残留 + androidx.compose.runtime.key(videoUrl) { + AndroidView( + factory = { ctx -> + createVideoPlayerView(ctx, exoPlayer) { view -> + playerView = view } - addView(view) - } - }, - modifier = Modifier.noRippleClickable { - pauseIconVisibleState.value = true - exoPlayer.pause() - scope.launch { - delay(100) - if (exoPlayer.isPlaying) { - exoPlayer.pause() - } else { - pauseIconVisibleState.value = false - exoPlayer.play() + }, + modifier = Modifier + .fillMaxSize() + .clip(RectangleShape) + .noRippleClickable { + handleVideoClick(pauseIconVisibleState, exoPlayer, scope) } - } - } - ) + ) + } if (pauseIconVisibleState.value) { Icon( @@ -348,11 +467,16 @@ fun VideoPlayer( } // Release ExoPlayer when the videoUrl changes or the composable leaves composition + // 使用 key 后,DisposableEffect 会在 videoUrl 变化时自动触发 DisposableEffect(videoUrl) { onDispose { - exoPlayer.release() - playerView?.player = null - playerView = null // Release the reference to the PlayerView + try { + exoPlayer.release() + playerView?.player = null + playerView = null // Release the reference to the PlayerView + } catch (e: Exception) { + // 忽略释放时的异常 + } } } @@ -360,12 +484,16 @@ fun VideoPlayer( val observer = LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_PAUSE -> { - exoPlayer.pause() // 应用进入后台时暂停 + // 应用进入后台时暂停 + exoPlayer.playWhenReady = false + exoPlayer.pause() } Lifecycle.Event.ON_RESUME -> { + // 返回前台且为当前页面时恢复播放 if (pager == pagerState.currentPage) { - exoPlayer.play() // 返回前台且为当前页面时恢复播放 + exoPlayer.playWhenReady = true + exoPlayer.play() } } @@ -496,20 +624,29 @@ fun VideoPlayer( if (showCommentModal && moment != null) { val AppColors = LocalAppTheme.current ModalBottomSheet( - onDismissRequest = { showCommentModal = false }, + onDismissRequest = { + scope.launch { + sheetState.hide() + } + showCommentModal = false + }, containerColor = AppColors.background, sheetState = sheetState, - modifier = Modifier - .fillMaxWidth() - .height(sheetHeight) + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp) ) { - CommentModalContent( - postId = moment.id, - commentCount = moment.commentCount, - onCommentAdded = { - onCommentAdded?.invoke(moment) - } - ) + Box( + modifier = Modifier + .fillMaxWidth() + .height(sheetHeight) + ) { + CommentModalContent( + postId = moment.id, + commentCount = moment.commentCount, + onCommentAdded = { + onCommentAdded?.invoke(moment) + } + ) + } } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt b/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt index d3788f1..5661431 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt @@ -74,7 +74,7 @@ fun PointsBottomSheet( Column( modifier = Modifier .fillMaxWidth() - .fillMaxHeight(0.98f) + .fillMaxHeight(0.9f) .padding(horizontal = 16.dp, vertical = 8.dp) ) { // 头部 @@ -162,18 +162,21 @@ fun PointsBottomSheet( TabItem( text = stringResource(R.string.transaction_history), isSelected = tab == 0, - onClick = { tab = 0 } + onClick = { tab = 0 }, + modifier = Modifier.weight(1f) ) TabSpacer() TabItem( text = stringResource(R.string.how_to_earn), isSelected = tab == 1, - onClick = { tab = 1 } + onClick = { tab = 1 }, + modifier = Modifier.weight(1f) ) } Spacer(Modifier.height(8.dp)) + // 列表区域 if (tab == 0) { PointsHistoryList( items = PointsViewModel.logs, @@ -183,8 +186,6 @@ fun PointsBottomSheet( } else { HowToEarnList() } - - Spacer(Modifier.height(24.dp)) } } } @@ -210,7 +211,10 @@ private fun PointsHistoryList( ) { val AppColors = LocalAppTheme.current val numberFormat = remember { NumberFormat.getNumberInstance(Locale.getDefault()) } - LazyColumn { + + LazyColumn( + modifier = Modifier.fillMaxWidth() + ) { items(items) { item -> Row( modifier = Modifier @@ -260,6 +264,7 @@ private fun PointsHistoryList( @Composable private fun HowToEarnList() { val AppColors = LocalAppTheme.current + @Composable fun RowItem(title: String, desc: String, amount: String) { Row( @@ -288,13 +293,23 @@ private fun HowToEarnList() { } } - Column { - RowItem(stringResource(R.string.new_user_reward), stringResource(R.string.new_user_reward_desc), "+500") - RowItem(stringResource(R.string.daily_check_in), stringResource(R.string.daily_check_in_desc), "+10-50") - RowItem(stringResource(R.string.invite_friends), stringResource(R.string.invite_friends_desc), "+100") - RowItem(stringResource(R.string.complete_tasks), stringResource(R.string.complete_tasks_desc), "+20-200") - RowItem(stringResource(R.string.recharge_pai_coin), stringResource(R.string.recharge_pai_coin_desc), ">") + LazyColumn( + modifier = Modifier.fillMaxWidth() + ) { + item { + RowItem(stringResource(R.string.new_user_reward), stringResource(R.string.new_user_reward_desc), "+500") + } + item { + RowItem(stringResource(R.string.daily_check_in), stringResource(R.string.daily_check_in_desc), "+10-50") + } + item { + RowItem(stringResource(R.string.invite_friends), stringResource(R.string.invite_friends_desc), "+100") + } + item { + RowItem(stringResource(R.string.complete_tasks), stringResource(R.string.complete_tasks_desc), "+20-200") + } + item { + RowItem(stringResource(R.string.recharge_pai_coin), stringResource(R.string.recharge_pai_coin_desc), ">") + } } } - -