From 8bed5b701d0919cc12862d182d9086d7a714e191 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Mon, 22 Jul 2024 20:13:27 +0200 Subject: [PATCH] onVideoSizeChanged is not cought anymore --- gradle/libs.versions.toml | 11 +- new-player/build.gradle.kts | 1 + .../newplayer/model/VideoPlayerViewModel.kt | 105 +++++++++--------- .../newpipe/newplayer/ui/ContentFitMode.kt | 8 ++ .../ui/VideoPlayerLoadingPlaceholder.kt | 12 +- .../net/newpipe/newplayer/ui/VideoPlayerUI.kt | 84 +++++++------- .../net/newpipe/newplayer/utils/VideoSize.kt | 3 + .../newpipe/newplayer/testapp/MainActivity.kt | 1 - 8 files changed, 120 insertions(+), 105 deletions(-) create mode 100644 new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdaeb62..6293d9d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ # along with NewPlayer. If not, see . [versions] -agp = "8.5.0" +agp = "8.5.1" kotlin = "2.0.20-Beta2" coreKtx = "1.13.1" junit = "4.13.2" @@ -31,7 +31,7 @@ constraintlayout = "2.1.4" material3 = "1.2.1" uiTooling = "1.6.8" materialIconsExtendedAndroid = "1.7.0-beta05" -media3Ui = "1.4.0-beta01" +media3 = "1.3.1" hiltAndroid = "2.51.1" hiltCompiler = "1.2.0" hiltNavigationCompose = "1.2.0" @@ -39,7 +39,6 @@ lifecycleViewmodelCompose = "2.8.3" kspVersion = "2.0.20-Beta2-1.0.23" fragmentKtx = "1.8.1" lifecycleRuntimeKtx = "2.8.3" -composeBom = "2024.06.01" kotlinParcelize = "2.0.20-Beta2" newplayer = "master-SNAPSHOT" @@ -56,8 +55,9 @@ androidx-activity-compose = { group = "androidx.activity", name = "activity-comp androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiTooling" } androidx-material-icons-extended-android = { group = "androidx.compose.material", name = "material-icons-extended-android", version.ref = "materialIconsExtendedAndroid" } -androidx-media3-exoplayer = { group = "androidx.media3", name = "media3-exoplayer", version.ref = "media3Ui" } -androidx-media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3Ui" } +androidx-media3-exoplayer = { group = "androidx.media3", name = "media3-exoplayer", version.ref = "media3" } +androidx-media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3" } +androidx-media3-common = { group = "androidx.media3", name = "media3-common", version.ref = "media3" } hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hiltAndroid" } androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltCompiler" } androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" } @@ -75,6 +75,7 @@ androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit newplayer = { group = "com.github.theScrabi.NewPlayer", name = "new-player", version.ref = "newplayer" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/new-player/build.gradle.kts b/new-player/build.gradle.kts index 1aa941e..263fa04 100644 --- a/new-player/build.gradle.kts +++ b/new-player/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.hilt.navigation.compose) + implementation(libs.androidx.media3.common) ksp(libs.hilt.android.compiler) ksp(libs.androidx.hilt.compiler) 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 eb828c5..453c824 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,6 +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 val VIDEOPLAYER_UI_STATE = "video_player_ui_state" @@ -47,19 +48,19 @@ private const val TAG = "VideoPlayerViewModel" data class VideoPlayerUIState( val playing: Boolean, var fullscreen: Boolean, - var uiVissible: Boolean, - var contentRatio: Float, - var minContentRatio: Float, - var maxContentRatio: Float + var uiVisible: Boolean, + val contentRatio: Float, + val uiRatio: Float, + val contentFitMode: ContentFitMode ) : Parcelable { companion object { val DEFAULT = VideoPlayerUIState( playing = false, fullscreen = false, - uiVissible = false, + uiVisible = false, contentRatio = 0F, - minContentRatio = 4F / 3F, - maxContentRatio = 16F / 9F + uiRatio = 16F / 9F, + contentFitMode = ContentFitMode.FIT_INSIDE ) } } @@ -68,7 +69,6 @@ interface VideoPlayerViewModel { var newPlayer: NewPlayer? val player: Player? val uiState: StateFlow - var listener: Listener? var minContentRatio: Float var maxContentRatio: Float @@ -79,15 +79,6 @@ interface VideoPlayerViewModel { fun nextStream() fun switchToFullscreen() fun switchToEmbeddedView() - - interface Listener { - fun requestUpdateLayoutRatio(ratio: Float) - } - - sealed class Events { - object SwitchToFullscreen : Events() - object SwitchToEmbeddedView : Events() - } } @HiltViewModel @@ -98,7 +89,6 @@ class VideoPlayerViewModelImpl @Inject constructor( // private private val mutableUiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) - private var current_video_size = VideoSize.DEFAULT //interface override var newPlayer: NewPlayer? = null @@ -108,75 +98,71 @@ class VideoPlayerViewModelImpl @Inject constructor( } override val uiState = mutableUiState.asStateFlow() - override var listener: VideoPlayerViewModel.Listener? = null override val player: Player? get() = newPlayer?.player - override var minContentRatio: Float + override var minContentRatio: Float = 4F / 3F set(value) { - if (value <= 0 || mutableUiState.value.maxContentRatio < value) + if (value <= 0 || maxContentRatio < value) Log.e( TAG, "Ignoring maxContentRatio: It must not be 0 or less and it may not be bigger then mmaxContentRatio. It was Set to: $value" ) - else - mutableUiState.update { it.copy(minContentRatio = value) } + else { + field = value + mutableUiState.update { it.copy(uiRatio = getUiRatio()) } + } } - get() = mutableUiState.value.minContentRatio - override var maxContentRatio: Float - get() = mutableUiState.value.maxContentRatio + + override var maxContentRatio: Float = 16F / 9F set(value) { - if (value <= 0 || value < mutableUiState.value.minContentRatio) + if (value <= 0 || value < minContentRatio) Log.e( TAG, "Ignoring maxContentRatio: It must not be 0 or less and it may not be smaller then minContentRatio. It was Set to: $value" ) - else - mutableUiState.update { it.copy(maxContentRatio = value) } + else { + field = value + mutableUiState.update { it.copy(uiRatio = getUiRatio()) } + } } private fun installExoPlayer() { player?.let { player -> - Log.i(TAG, "Install player") + Log.d(TAG, "Install player: ${player.videoSize.width}") + player.addListener(object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { super.onIsPlayingChanged(isPlaying) - + Log.d(TAG, "Playing state changed. Is Playing: $isPlaying") + Log.d(TAG, "Gurken: ${VideoSize.fromMedia3VideoSize(player.videoSize)}") mutableUiState.update { it.copy(playing = isPlaying) } } - // We need to updated the layout of our player view if the video ratio changes - // However, this should be done differently depending on weather we are in - // embedded or fullscreen view. - // If we are in embedded view, we tell the mother layout (only ConstraintLayout supported!) - // to change the ratio of the whole player view. - // If we are in fullscreen we only want to change the ratio of the SurfaceView - override fun onVideoSizeChanged(media3VideoSize: androidx.media3.common.VideoSize) { - super.onVideoSizeChanged(media3VideoSize) - - val videoSize = VideoSize.fromMedia3VideoSize(media3VideoSize) - - if (current_video_size != videoSize) { - val newRatio = videoSize.getRatio() - if (current_video_size.getRatio() != newRatio) { - mutableUiState.update { - it.copy(contentRatio = newRatio) - } - if (!mutableUiState.value.fullscreen) { - listener?.requestUpdateLayoutRatio(newRatio) - } - } - current_video_size = videoSize - } + override fun onVideoSizeChanged(videoSize: androidx.media3.common.VideoSize) { + super.onVideoSizeChanged(videoSize) + println("gurken aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + updateContentRatio(VideoSize.fromMedia3VideoSize(videoSize)) } }) } } + fun updateContentRatio(videoSize: VideoSize) { + val newRatio = videoSize.getRatio() + Log.d(TAG, "Update Content ratio: $newRatio") + mutableUiState.update { + it.copy( + contentRatio = newRatio, + uiRatio = getUiRatio() + ) + } + } + override fun onCleared() { super.onCleared() Log.d(TAG, "viewmodel cleared") @@ -226,12 +212,21 @@ class VideoPlayerViewModelImpl @Inject constructor( } } + private fun getUiRatio() = + player?.let { player -> + val videoRatio = VideoSize.fromMedia3VideoSize(player.videoSize).getRatio() + return if (videoRatio.isNaN()) + minContentRatio + else + videoRatio.coerceIn(minContentRatio, maxContentRatio) + } ?: minContentRatio + + companion object { val dummy = object : VideoPlayerViewModel { override var newPlayer: NewPlayer? = null override val player: Player? = null override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) - override var listener: VideoPlayerViewModel.Listener? = null override var minContentRatio = 4F / 3F override var maxContentRatio = 16F / 9F diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt new file mode 100644 index 0000000..585bb92 --- /dev/null +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/ContentFitMode.kt @@ -0,0 +1,8 @@ +package net.newpipe.newplayer.ui + + +enum class ContentFitMode { + FILL, + FIT_INSIDE, + ZOOM +} diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerLoadingPlaceholder.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerLoadingPlaceholder.kt index bd60582..1af153b 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerLoadingPlaceholder.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/ui/VideoPlayerLoadingPlaceholder.kt @@ -17,13 +17,17 @@ import androidx.compose.ui.unit.dp import net.newpipe.newplayer.ui.theme.VideoPlayerTheme @Composable -fun VideoPlayerLoadingPlaceholder(aspectRatio:Float = 3F/1F) { +fun VideoPlayerLoadingPlaceholder(aspectRatio: Float = 3F / 1F) { Surface( - modifier = Modifier.fillMaxWidth().aspectRatio(aspectRatio), + modifier = Modifier + .fillMaxWidth() + .aspectRatio(aspectRatio), color = Color.Black ) { - Box { - CircularProgressIndicator(modifier = Modifier.width(64.dp).align((Alignment.Center))) + Box(contentAlignment = Alignment.Center) { + CircularProgressIndicator(modifier = Modifier + .width(64.dp) + .align((Alignment.Center))) } } } 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 aa29e91..881eb21 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 @@ -23,9 +23,9 @@ package net.newpipe.newplayer.ui import android.content.pm.ActivityInfo import android.view.SurfaceView import androidx.activity.compose.BackHandler -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Box 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.material3.Surface @@ -37,9 +37,9 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.viewinterop.AndroidView @@ -49,7 +49,6 @@ import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.ui.theme.VideoPlayerTheme import net.newpipe.newplayer.utils.LockScreenOrientation -import net.newpipe.newplayer.utils.findActivity @Composable fun VideoPlayerUI( @@ -57,8 +56,8 @@ fun VideoPlayerUI( ) { if (viewModel == null) { VideoPlayerLoadingPlaceholder() - } else if (viewModel.player == null) { - VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.maxContentRatio) + } else if (viewModel.player == null || viewModel.uiState.collectAsState().value.contentRatio == 0.0F) { + VideoPlayerLoadingPlaceholder(viewModel.uiState.collectAsState().value.uiRatio) } else { val uiState by viewModel.uiState.collectAsState() @@ -88,14 +87,6 @@ fun VideoPlayerUI( } } - val fullscreenLauncher = - rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult() - ) { result -> - println("gurken returned for result") - viewModel.initUIState(result.data?.extras!!) - } - LaunchedEffect(key1 = uiState.fullscreen) { println("gurken launch fullscreen: ${uiState.fullscreen}") } @@ -110,41 +101,54 @@ fun VideoPlayerUI( } // Set UI - val aspectRatio = - uiState.contentRatio.coerceIn(uiState.minContentRatio, uiState.maxContentRatio) - Surface( modifier = Modifier .fillMaxWidth() - .aspectRatio(aspectRatio), + .aspectRatio(uiState.uiRatio), color = Color.Black ) { - AndroidView( - modifier = Modifier.fillMaxSize(), - factory = { context -> - SurfaceView(context).also { view -> - viewModel.player?.setVideoSurfaceView(view) - } - }, update = { view -> - when (lifecycle) { - Lifecycle.Event.ON_RESUME -> { + Box(contentAlignment = Alignment.Center){ + AndroidView( + modifier = Modifier.also { modifier -> + when (uiState.contentFitMode) { + ContentFitMode.FILL -> modifier.fillMaxSize() + ContentFitMode.FIT_INSIDE -> if (uiState.contentRatio < uiState.uiRatio) { + modifier.fillMaxHeight().aspectRatio(uiState.contentRatio) + } else if (uiState.uiRatio < uiState.contentRatio) { + modifier.fillMaxWidth().aspectRatio(uiState.contentRatio) + } + ContentFitMode.ZOOM -> if(uiState.uiRatio < uiState.contentRatio) { + modifier.fillMaxHeight().aspectRatio(uiState.contentRatio) + } else if (uiState.contentRatio < uiState.uiRatio) { + modifier.fillMaxWidth().aspectRatio(uiState.contentRatio) + } + } + }, + factory = { context -> + SurfaceView(context).also { view -> viewModel.player?.setVideoSurfaceView(view) } + }, update = { view -> + when (lifecycle) { + Lifecycle.Event.ON_RESUME -> { + viewModel.player?.setVideoSurfaceView(view) + } - else -> Unit - } - }) + else -> Unit + } + }) - VideoPlayerControllerUI( - isPlaying = uiState.playing, - fullscreen = uiState.fullscreen, - play = viewModel::play, - pause = viewModel::pause, - prevStream = viewModel::prevStream, - nextStream = viewModel::nextStream, - switchToFullscreen = viewModel::switchToFullscreen, - switchToEmbeddedView = viewModel::switchToEmbeddedView - ) + VideoPlayerControllerUI( + isPlaying = uiState.playing, + fullscreen = uiState.fullscreen, + play = viewModel::play, + pause = viewModel::pause, + prevStream = viewModel::prevStream, + nextStream = viewModel::nextStream, + switchToFullscreen = viewModel::switchToFullscreen, + switchToEmbeddedView = viewModel::switchToEmbeddedView + ) + } } } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/utils/VideoSize.kt b/new-player/src/main/java/net/newpipe/newplayer/utils/VideoSize.kt index 8f4c3f8..3a7ddd2 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/utils/VideoSize.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/utils/VideoSize.kt @@ -20,6 +20,9 @@ data class VideoSize( fun getRatio() = (width * pixelWidthHeightRatio) / height + override fun toString() = + "VideoSize(width = $width, height = $height, pixelRatio = $pixelWidthHeightRatio, ratio = ${getRatio()})" + companion object { val DEFAULT = VideoSize(0, 0, 1F) 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 a1487ff..4e907f9 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 @@ -98,6 +98,5 @@ class MainActivity : AppCompatActivity() { ) insets } - } } \ No newline at end of file