onVideoSizeChanged is not cought anymore
This commit is contained in:
parent
4089de7272
commit
8bed5b701d
|
@ -18,7 +18,7 @@
|
|||
# along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
[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" }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<VideoPlayerUIState>
|
||||
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
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package net.newpipe.newplayer.ui
|
||||
|
||||
|
||||
enum class ContentFitMode {
|
||||
FILL,
|
||||
FIT_INSIDE,
|
||||
ZOOM
|
||||
}
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -98,6 +98,5 @@ class MainActivity : AppCompatActivity() {
|
|||
)
|
||||
insets
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue