diff --git a/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/MediaViewScreen.kt b/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/MediaViewScreen.kt index cbd2a8047..073a2206c 100644 --- a/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/MediaViewScreen.kt +++ b/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/MediaViewScreen.kt @@ -71,6 +71,7 @@ import com.dot.gallery.feature_node.domain.use_case.MediaHandleUseCase import com.dot.gallery.feature_node.presentation.mediaview.components.MediaViewActions2 import com.dot.gallery.feature_node.presentation.mediaview.components.MediaViewAppBar import com.dot.gallery.feature_node.presentation.mediaview.components.MediaViewDetails +import com.dot.gallery.feature_node.presentation.mediaview.components.TrackVisibility import com.dot.gallery.feature_node.presentation.mediaview.components.media.MediaPreviewComponent import com.dot.gallery.feature_node.presentation.mediaview.components.video.VideoPlayerController import com.dot.gallery.feature_node.presentation.util.ViewScreenConstants.BOTTOM_BAR_HEIGHT @@ -226,124 +227,122 @@ fun MediaViewScreen( Column( modifier = Modifier.fillMaxWidth() ) { - var playWhenReady by rememberSaveable { mutableStateOf(false) } - LaunchedEffect(pagerState) { - snapshotFlow { pagerState.currentPage } - .collect { currentPage -> - playWhenReady = currentPage == index - } - } + var playWhenReady by remember { mutableStateOf(false) } val media by remember(index, mediaState) { derivedStateOf { mediaState.value.media.getOrNull(index) } } - - AnimatedVisibility( - visible = remember(media) { media != null }, - enter = enterAnimation, - exit = exitAnimation + TrackVisibility( + onVisibilityChanged = { isVisible -> + playWhenReady = isVisible + } ) { - MediaPreviewComponent( - media = media!!, - uiEnabled = showUI.value, - playWhenReady = playWhenReady, - onSwipeDown = { - windowInsetsController.toggleSystemBars(show = true) - navigateUp() - }, - onItemClick = { - if (sheetState.currentDetent == ImageOnly) { - showUI.value = !showUI.value - windowInsetsController.toggleSystemBars(showUI.value) + AnimatedVisibility( + visible = remember(media) { media != null }, + enter = enterAnimation, + exit = exitAnimation + ) { + MediaPreviewComponent( + media = media!!, + uiEnabled = showUI.value, + playWhenReady = playWhenReady, + onSwipeDown = { + windowInsetsController.toggleSystemBars(show = true) + navigateUp() + }, + onItemClick = { + if (sheetState.currentDetent == ImageOnly) { + showUI.value = !showUI.value + windowInsetsController.toggleSystemBars(showUI.value) + } } - } - ) { player, isPlaying, currentTime, totalTime, buffer, frameRate -> - Box( - modifier = Modifier.fillMaxSize() - ) { - val context = LocalContext.current - val width = - remember(context) { context.resources.displayMetrics.widthPixels } - Spacer( - modifier = Modifier - .fillMaxSize() - .graphicsLayer { - translationX = width / 1.5f - } - .align(Alignment.TopEnd) - .clip(CircleShape) - .combinedClickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - onDoubleClick = { - scope.launch { - currentTime.longValue += 10 * 1000 - player.seekTo(currentTime.longValue) - delay(100) - player.play() - } - }, - onClick = { - if (sheetState.currentDetent == ImageOnly) { - showUI.value = !showUI.value - windowInsetsController.toggleSystemBars( - showUI.value - ) - } + ) { player, isPlaying, currentTime, totalTime, buffer, frameRate -> + Box( + modifier = Modifier.fillMaxSize() + ) { + val context = LocalContext.current + val width = + remember(context) { context.resources.displayMetrics.widthPixels } + Spacer( + modifier = Modifier + .fillMaxSize() + .graphicsLayer { + translationX = width / 1.5f } - ) - ) - - Spacer( - modifier = Modifier - .fillMaxSize() - .graphicsLayer { - translationX = -width / 1.5f - } - .align(Alignment.TopStart) - .clip(CircleShape) - .combinedClickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - onDoubleClick = { - scope.launch { - currentTime.longValue -= 10 * 1000 - player.seekTo(currentTime.longValue) - delay(100) - player.play() + .align(Alignment.TopEnd) + .clip(CircleShape) + .combinedClickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onDoubleClick = { + scope.launch { + currentTime.longValue += 10 * 1000 + player.seekTo(currentTime.longValue) + delay(100) + player.play() + } + }, + onClick = { + if (sheetState.currentDetent == ImageOnly) { + showUI.value = !showUI.value + windowInsetsController.toggleSystemBars( + showUI.value + ) + } } - }, - onClick = { - if (sheetState.currentDetent == ImageOnly) { - showUI.value = !showUI.value - windowInsetsController.toggleSystemBars( - showUI.value - ) - } - } - ) - ) + ) + ) - androidx.compose.animation.AnimatedVisibility( - visible = showUI.value, - enter = enterAnimation(DEFAULT_TOP_BAR_ANIMATION_DURATION), - exit = exitAnimation(DEFAULT_TOP_BAR_ANIMATION_DURATION), - modifier = Modifier.fillMaxSize() - ) { - VideoPlayerController( - paddingValues = paddingValues, - player = player, - isPlaying = isPlaying, - currentTime = currentTime, - totalTime = totalTime, - buffer = buffer, - toggleRotate = toggleRotate, - frameRate = frameRate + Spacer( + modifier = Modifier + .fillMaxSize() + .graphicsLayer { + translationX = -width / 1.5f + } + .align(Alignment.TopStart) + .clip(CircleShape) + .combinedClickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onDoubleClick = { + scope.launch { + currentTime.longValue -= 10 * 1000 + player.seekTo(currentTime.longValue) + delay(100) + player.play() + } + }, + onClick = { + if (sheetState.currentDetent == ImageOnly) { + showUI.value = !showUI.value + windowInsetsController.toggleSystemBars( + showUI.value + ) + } + } + ) ) + + androidx.compose.animation.AnimatedVisibility( + visible = showUI.value, + enter = enterAnimation(DEFAULT_TOP_BAR_ANIMATION_DURATION), + exit = exitAnimation(DEFAULT_TOP_BAR_ANIMATION_DURATION), + modifier = Modifier.fillMaxSize() + ) { + VideoPlayerController( + paddingValues = paddingValues, + player = player, + isPlaying = isPlaying, + currentTime = currentTime, + totalTime = totalTime, + buffer = buffer, + toggleRotate = toggleRotate, + frameRate = frameRate + ) + } } } } } - } } MediaViewAppBar( diff --git a/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/TrackVisibility.kt b/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/TrackVisibility.kt new file mode 100644 index 000000000..8c24f7d6a --- /dev/null +++ b/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/TrackVisibility.kt @@ -0,0 +1,46 @@ +package com.dot.gallery.feature_node.presentation.mediaview.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.layout.layout +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.positionInWindow +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.IntSize + +@Composable +fun TrackVisibility( + modifier: Modifier = Modifier, + onVisibilityChanged: (Boolean) -> Unit, + content: @Composable () -> Unit +) { + var size by remember { mutableStateOf(IntSize.Zero) } + var position by remember { mutableStateOf(Offset.Zero) } + val density = LocalDensity.current + + Box( + modifier = modifier + .onGloballyPositioned { coordinates -> + size = coordinates.size + position = coordinates.positionInWindow() + } + .layout { measurable, constraints -> + val placeable = measurable.measure(constraints) + layout(placeable.width, placeable.height) { + val isVisible = position.x >= 0 && position.y >= 0 && + position.x + size.width <= with(density) { constraints.maxWidth.toDp().toPx() } && + position.y + size.height <= with(density) { constraints.maxHeight.toDp().toPx() } + onVisibilityChanged(isVisible) + placeable.place(0, 0) + } + } + ) { + content() + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/video/VideoPlayer.kt b/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/video/VideoPlayer.kt index d8477a3e3..6833ffb28 100644 --- a/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/video/VideoPlayer.kt +++ b/app/src/main/kotlin/com/dot/gallery/feature_node/presentation/mediaview/components/video/VideoPlayer.kt @@ -107,7 +107,7 @@ fun VideoPlayer( LaunchedEffect(showPlayer) { if (showPlayer) { delay(100) - exoPlayer?.playWhenReady = true + exoPlayer?.playWhenReady = isPlaying.value exoPlayer?.seekTo(currentTime.longValue) } } @@ -121,7 +121,7 @@ fun VideoPlayer( ) ), handleLifecycle = true, - autoPlay = true, + autoPlay = playWhenReady, usePlayerController = false, enablePip = false, handleAudioFocus = true,