diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 8bcdc35..df92f12 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,6 +4,14 @@ diff --git a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt index 90c5665..d61bac8 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt @@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.update import net.newpipe.newplayer.utils.VideoSize import kotlinx.parcelize.Parcelize import net.newpipe.newplayer.NewPlayer -import net.newpipe.newplayer.ui.ContentFitMode +import net.newpipe.newplayer.ui.ContentScale val VIDEOPLAYER_UI_STATE = "video_player_ui_state" @@ -51,7 +51,7 @@ data class VideoPlayerUIState( var uiVisible: Boolean, val contentRatio: Float, val uiRatio: Float, - val contentFitMode: ContentFitMode + val contentFitMode: ContentScale ) : Parcelable { companion object { val DEFAULT = VideoPlayerUIState( @@ -60,7 +60,7 @@ data class VideoPlayerUIState( uiVisible = false, contentRatio = 16 / 9F, uiRatio = 16F / 9F, - contentFitMode = ContentFitMode.FIT_INSIDE + contentFitMode = ContentScale.FIT_INSIDE ) } } @@ -71,6 +71,7 @@ interface VideoPlayerViewModel { val uiState: StateFlow var minContentRatio: Float var maxContentRatio: Float + var contentFitMode: ContentScale fun initUIState(instanceState: Bundle) fun play() @@ -129,6 +130,14 @@ class VideoPlayerViewModelImpl @Inject constructor( } } + override var contentFitMode: ContentScale + get() = mutableUiState.value.contentFitMode + set(value) { + mutableUiState.update { + it.copy(contentFitMode = value) + } + } + private fun installExoPlayer() { player?.let { player -> Log.d(TAG, "Install player: ${player.videoSize.width}") @@ -227,6 +236,7 @@ class VideoPlayerViewModelImpl @Inject constructor( override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) override var minContentRatio = 4F / 3F override var maxContentRatio = 16F / 9F + override var contentFitMode = ContentScale.FIT_INSIDE override fun initUIState(instanceState: Bundle) { println("dummy impl") diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/ContentScale.kt similarity index 63% rename from new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt rename to new-player/src/main/java/net/newpipe/newplayer/ui/ContentScale.kt index 585bb92..0d75852 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/ContentScale.kt @@ -1,8 +1,8 @@ package net.newpipe.newplayer.ui -enum class ContentFitMode { +enum class ContentScale { FILL, FIT_INSIDE, - ZOOM + CROP } diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt index 5dc169c..893a3f8 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt @@ -28,6 +28,8 @@ import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -45,6 +47,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver +import androidx.media3.common.Player import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.ui.theme.VideoPlayerTheme @@ -107,60 +110,13 @@ fun VideoPlayerUI( .aspectRatio(uiState.uiRatio), color = Color.Black ) { Box(contentAlignment = Alignment.Center) { - val viewBoxModifier = Modifier - when (uiState.contentFitMode) { - ContentFitMode.FILL -> { - println("fit mode fill") - viewBoxModifier.fillMaxSize() - } - - ContentFitMode.FIT_INSIDE -> { - println("fit mode fit inside:") - if (uiState.contentRatio < uiState.uiRatio) { - println("fit mode fill max height") - viewBoxModifier - .fillMaxHeight() - .aspectRatio(uiState.contentRatio) - } else if (uiState.uiRatio < uiState.contentRatio) { - println("fit mode fill max width") - viewBoxModifier - .fillMaxWidth() - .aspectRatio(uiState.contentRatio) - } - } - - ContentFitMode.ZOOM -> { - println("fit mode zoom:") - if (uiState.uiRatio < uiState.contentRatio) { - viewBoxModifier - .fillMaxHeight() - .aspectRatio(uiState.contentRatio) - } else if (uiState.contentRatio < uiState.uiRatio) { - viewBoxModifier - .fillMaxWidth() - .aspectRatio(uiState.contentRatio) - } - } - } - - Box(modifier = viewBoxModifier) { - AndroidView(factory = { context -> - SurfaceView(context).also { view -> - viewModel.player?.setVideoSurfaceView(view) - } - }, update = { view -> - when (lifecycle) { - Lifecycle.Event.ON_RESUME -> { - viewModel.player?.setVideoSurfaceView(view) - } - - else -> Unit - } - }) - Surface(color = Color.Green, modifier = Modifier.fillMaxSize()) { - - } - } + PlaySurface( + player = viewModel.player, + lifecycle = lifecycle, + fitMode = uiState.contentFitMode, + uiRatio = uiState.uiRatio, + contentRatio = uiState.contentRatio + ) } VideoPlayerControllerUI( isPlaying = uiState.playing, @@ -176,6 +132,50 @@ fun VideoPlayerUI( } } +@Composable +fun PlaySurface( + player: Player?, + lifecycle: Lifecycle.Event, + fitMode: ContentScale, + uiRatio: Float, + contentRatio: Float +) { + val viewBoxModifier = Modifier + viewBoxModifier + .fillMaxWidth() + .aspectRatio(16F / 9F) + + Box( + modifier = Modifier + .then( + when (fitMode) { + ContentScale.FILL -> Modifier.fillMaxSize() + ContentScale.FIT_INSIDE -> Modifier.aspectRatio(contentRatio) + ContentScale.CROP -> Modifier + .aspectRatio(contentRatio) + .wrapContentWidth(unbounded = true) + .fillMaxSize() + } + ) + ) { + + AndroidView(factory = { context -> + SurfaceView(context).also { view -> + player?.setVideoSurfaceView(view) + } + }, update = { view -> + when (lifecycle) { + Lifecycle.Event.ON_RESUME -> { + player?.setVideoSurfaceView(view) + } + + else -> Unit + } + }) + + } +} + @Preview(device = "spec:width=1080px,height=700px,dpi=440,orientation=landscape") @Composable diff --git a/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt b/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt index 4e907f9..ae2ea13 100644 --- a/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt +++ b/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt @@ -26,12 +26,12 @@ import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat -import androidx.lifecycle.viewmodel.compose.viewModel import dagger.hilt.android.AndroidEntryPoint import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.VideoPlayerView import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModelImpl +import net.newpipe.newplayer.ui.ContentScale import javax.inject.Inject @AndroidEntryPoint @@ -52,6 +52,7 @@ class MainActivity : AppCompatActivity() { videoPlayerViewModel.newPlayer = newPlayer videoPlayerViewModel.maxContentRatio = 4F/3F + videoPlayerViewModel.contentFitMode = ContentScale.FIT_INSIDE /* video_view.fullScreenToggleListener = object : VideoPlayerView.FullScreenToggleListener {