Skip to content

Commit

Permalink
减少视频页部分不必要的 recomposition, 简化代码
Browse files Browse the repository at this point in the history
  • Loading branch information
Him188 committed Apr 17, 2024
1 parent ca3167c commit 326296d
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 75 deletions.
91 changes: 44 additions & 47 deletions app/shared/pages/episode-play/common/EpisodePage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package me.him188.ani.app.ui.subject.episode

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
Expand Down Expand Up @@ -75,69 +74,67 @@ fun EpisodePage(

@Composable
fun EpisodePageContent(
viewModel: EpisodeViewModel,
vm: EpisodeViewModel,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current

// 处理当用户点击返回键时, 如果是全屏, 则退出全屏
val navigator = LocalNavigator.current
BackHandler {
viewModel.playerState.pause()
vm.playerState.pause()
navigator.navigator.goBack()
}

BackHandler(enabled = viewModel.isFullscreen) {
BackHandler(enabled = vm.isFullscreen) {
context.setRequestFullScreen(false)
viewModel.isFullscreen = false
vm.isFullscreen = false
}

ScreenOnEffect()

AutoPauseEffect(viewModel)
AutoPauseEffect(vm)


Column(modifier.then(if (viewModel.isFullscreen) Modifier.fillMaxSize() else Modifier.navigationBarsPadding())) {
Column(modifier.then(if (vm.isFullscreen) Modifier.fillMaxSize() else Modifier.navigationBarsPadding())) {
// 视频
val selected by viewModel.mediaSelected.collectAsStateWithLifecycle(false)
val danmakuConfig = viewModel.danmaku.config.collectAsStateWithLifecycle(DanmakuConfig.Default).value
Box(
Modifier.fillMaxWidth().background(Color.Black)
.then(if (viewModel.isFullscreen) Modifier.fillMaxSize() else Modifier.statusBarsPadding())
) {
val danmakuEnabled by viewModel.danmaku.enabled.collectAsStateWithLifecycle(false)
EpisodeVideo(
{ selected },
title = {
val episode = viewModel.episodePresentation
val subject = viewModel.subjectPresentation
EpisodePlayerTitle(
episode.sort,
episode.title,
subject.title,
modifier.placeholder(episode.isPlaceholder || subject.isPlaceholder)
)
},
viewModel.playerState,
danmakuConfig = { danmakuConfig },
danmakuHostState = remember(viewModel) { viewModel.danmaku.danmakuHostState },
onClickFullScreen = {
if (viewModel.isFullscreen) {
context.setRequestFullScreen(false)
viewModel.isFullscreen = false
} else {
viewModel.isFullscreen = true
context.setRequestFullScreen(true)
}
},
danmakuEnabled = { danmakuEnabled },
setDanmakuEnabled = { viewModel.launchInBackground { danmaku.setEnabled(it) } },
onSendDanmaku = {},
isFullscreen = viewModel.isFullscreen,
)
}

if (viewModel.isFullscreen) {
val selected by vm.mediaSelected.collectAsStateWithLifecycle(false)
val danmakuConfig by vm.danmaku.config.collectAsStateWithLifecycle(DanmakuConfig.Default)

val danmakuEnabled by vm.danmaku.enabled.collectAsStateWithLifecycle(false)
EpisodeVideo(
vm.playerState,
expanded = vm.isFullscreen,
title = {
val episode = vm.episodePresentation
val subject = vm.subjectPresentation
EpisodePlayerTitle(
episode.sort,
episode.title,
subject.title,
modifier.placeholder(episode.isPlaceholder || subject.isPlaceholder)
)
},
danmakuHostState = vm.danmaku.danmakuHostState,
videoSourceSelected = { selected },
danmakuConfig = { danmakuConfig },
onClickFullScreen = {
if (vm.isFullscreen) {
context.setRequestFullScreen(false)
vm.isFullscreen = false
} else {
vm.isFullscreen = true
context.setRequestFullScreen(true)
}
},
danmakuEnabled = { danmakuEnabled },
setDanmakuEnabled = { vm.launchInBackground { danmaku.setEnabled(it) } },
onSendDanmaku = {},
modifier = Modifier.fillMaxWidth().background(Color.Black)
.then(if (vm.isFullscreen) Modifier.fillMaxSize() else Modifier.statusBarsPadding())
)

if (vm.isFullscreen) {
return@Column
}

Expand Down Expand Up @@ -172,7 +169,7 @@ fun EpisodePageContent(
HorizontalPager(state = pagerState, Modifier.fillMaxSize()) { index ->

when (index) {
0 -> EpisodeDetails(viewModel, LocalSnackbar.current, Modifier.fillMaxSize())
0 -> EpisodeDetails(vm, LocalSnackbar.current, Modifier.fillMaxSize())
// 1 -> {
// CommentColumn(commentViewModel, Modifier.fillMaxSize())
// }
Expand Down
29 changes: 14 additions & 15 deletions app/shared/pages/episode-play/common/EpisodeVideo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.map
import me.him188.ani.app.platform.AniBuildConfig
import me.him188.ani.app.platform.isInLandscapeMode
import me.him188.ani.app.tools.rememberUiMonoTasker
import me.him188.ani.app.ui.foundation.LocalIsPreviewing
import me.him188.ani.app.ui.foundation.rememberViewModel
Expand Down Expand Up @@ -60,30 +59,31 @@ import moe.tlaster.precompose.flow.collectAsStateWithLifecycle
*/
@Composable
internal fun EpisodeVideo(
videoSourceSelected: () -> Boolean,
title: @Composable () -> Unit,
playerState: PlayerState,
danmakuConfig: () -> DanmakuConfig,
expanded: Boolean,
title: @Composable () -> Unit,
danmakuHostState: DanmakuHostState,
videoSourceSelected: () -> Boolean,
danmakuConfig: () -> DanmakuConfig,
onClickFullScreen: () -> Unit,
danmakuEnabled: () -> Boolean,
setDanmakuEnabled: (enabled: Boolean) -> Unit,
onSendDanmaku: (text: String) -> Unit,
modifier: Modifier = Modifier,
isFullscreen: Boolean = isInLandscapeMode(),
) {
// Don't rememberSavable. 刻意让每次切换都是隐藏的
var controllerVisible by remember { mutableStateOf(false) }
var isLocked by remember { mutableStateOf(false) }
var showSettings by remember { mutableStateOf(false) }

VideoScaffold(
expanded = expanded,
modifier = modifier,
controllersVisible = controllerVisible,
gestureLocked = isLocked,
controllersVisible = { controllerVisible },
gestureLocked = { isLocked },
topBar = {
EpisodeVideoTopBar(
title = if (isFullscreen) {
title = if (expanded) {
{ title() }
} else {
null
Expand All @@ -98,7 +98,7 @@ internal fun EpisodeVideo(
} else {
// Save the status bar height to offset the video player
var statusBarHeight by rememberSaveable { mutableStateOf(0) }
if (!isFullscreen) {
if (!expanded) {
val insets = WindowInsets.systemBars
val density = LocalDensity.current
SideEffect {
Expand All @@ -110,7 +110,7 @@ internal fun EpisodeVideo(
playerState,
Modifier
.offset(
x = if (isFullscreen) with(LocalDensity.current) {
x = if (expanded) with(LocalDensity.current) {
-statusBarHeight.toDp() / 2
} else 0.dp,
y = 0.dp
Expand Down Expand Up @@ -169,7 +169,7 @@ internal fun EpisodeVideo(
}
},
rhsBar = {
if (isFullscreen) {
if (expanded) {
GestureLock(isLocked = isLocked, onClick = { isLocked = !isLocked })
}
},
Expand Down Expand Up @@ -224,11 +224,11 @@ internal fun EpisodeVideo(
{ playerState.setPlaybackSpeed(it) },
)
PlayerControllerDefaults.FullscreenIcon(
isFullscreen,
expanded,
onClickFullscreen = onClickFullScreen,
)
},
expanded = isFullscreen,
expanded = expanded,
)
},
rhsSheet = {
Expand All @@ -241,7 +241,6 @@ internal fun EpisodeVideo(
)
}
}
},
isFullscreen = isFullscreen
}
)
}
6 changes: 3 additions & 3 deletions app/shared/video-player/android/ui/VideoScaffold.android.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ private fun PreviewVideoScaffoldImpl(
var isLocked by remember { mutableStateOf(false) }

VideoScaffold(
expanded = true,
modifier = Modifier,
controllersVisible = controllerVisible,
gestureLocked = isLocked,
controllersVisible = { controllerVisible },
gestureLocked = { isLocked },
topBar = {
EpisodeVideoTopBar(
title = {
Expand Down Expand Up @@ -193,6 +194,5 @@ private fun PreviewVideoScaffoldImpl(
Modifier.fillMaxWidth(),
)
},
isFullscreen = true,
)
}
24 changes: 14 additions & 10 deletions app/shared/video-player/common/ui/VideoScaffold.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import me.him188.ani.app.platform.isInLandscapeMode
import me.him188.ani.app.ui.theme.aniDarkColorTheme
import me.him188.ani.app.ui.theme.slightlyWeaken
import me.him188.ani.app.videoplayer.ui.guesture.VideoGestureHost
Expand All @@ -56,13 +57,14 @@ import me.him188.ani.app.videoplayer.ui.top.PlayerTopBar
* @param floatingMessage 悬浮消息, 例如正在缓冲. 将会对齐到中央
* @param rhsBar 右侧控制栏, 锁定手势等.
* @param bottomBar [PlayerControllerBar]
* @param isFullscreen 当前是否处于全屏模式. 全屏时此框架会 [Modifier.fillMaxSize], 否则会限制为一个 16:9 的框.
* @param expanded 当前是否处于全屏模式. 全屏时此框架会 [Modifier.fillMaxSize], 否则会限制为一个 16:9 的框.
*/
@Composable
fun VideoScaffold(
expanded: Boolean,
modifier: Modifier = Modifier,
controllersVisible: Boolean = true,
gestureLocked: Boolean = false,
controllersVisible: () -> Boolean = { true },
gestureLocked: () -> Boolean = { false },
topBar: @Composable RowScope.() -> Unit = {},
/**
* @see VideoPlayer
Expand All @@ -74,16 +76,18 @@ fun VideoScaffold(
rhsBar: @Composable ColumnScope.() -> Unit = {},
bottomBar: @Composable RowScope.() -> Unit = {},
rhsSheet: @Composable () -> Unit = {},
isFullscreen: Boolean = isInLandscapeMode(),
) {
val controllersVisibleState by derivedStateOf(controllersVisible)
val gestureLockedState by derivedStateOf(gestureLocked) // delayed access to minimize recomposition

BoxWithConstraints(
modifier.then(if (isFullscreen) Modifier.fillMaxHeight() else Modifier.fillMaxWidth()),
modifier.then(if (expanded) Modifier.fillMaxHeight() else Modifier.fillMaxWidth()),
contentAlignment = Alignment.Center
) { // 16:9 box
Box(
Modifier
.then(
if (isFullscreen) {
if (expanded) {
Modifier.fillMaxSize()
} else {
Modifier.fillMaxWidth().height(maxWidth * 9 / 16) // 16:9 box
Expand Down Expand Up @@ -114,7 +118,7 @@ fun VideoScaffold(
Column(Modifier.fillMaxSize().background(Color.Transparent)) {
// 顶部控制栏: 返回键, 标题, 设置
AnimatedVisibility(
visible = controllersVisible && !gestureLocked,
visible = controllersVisibleState && !gestureLockedState,
enter = fadeIn(),
exit = fadeOut(),
) {
Expand Down Expand Up @@ -150,7 +154,7 @@ fun VideoScaffold(

// 底部控制栏: 播放/暂停, 进度条, 切换全屏
AnimatedVisibility(
visible = controllersVisible && !gestureLocked,
visible = controllersVisibleState && !gestureLockedState,
enter = fadeIn(),
exit = fadeOut(),
) {
Expand Down Expand Up @@ -183,7 +187,7 @@ fun VideoScaffold(
Box(Modifier.weight(1f, fill = true).fillMaxWidth()) {
Column(Modifier.padding(end = 16.dp).align(Alignment.CenterEnd)) {
AnimatedVisibility(
visible = controllersVisible,
visible = controllersVisibleState,
enter = fadeIn(),
exit = fadeOut(),
) {
Expand Down

0 comments on commit 326296d

Please sign in to comment.