diff --git a/new-player/src/main/java/net/newpipe/newplayer/VideoPlayerView.kt b/new-player/src/main/java/net/newpipe/newplayer/VideoPlayerView.kt index 1b89922..25e2dd7 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/VideoPlayerView.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/VideoPlayerView.kt @@ -45,6 +45,9 @@ class VideoPlayerView : FrameLayout { get() = videoPlayerFragment.minLayoutRatio set(value) {videoPlayerFragment.minLayoutRatio = value} + var fullScreenToggleListener: FullScreenToggleListener? + set(value) {videoPlayerFragment.fullScreenToggleListener = value} + get() = videoPlayerFragment.fullScreenToggleListener @JvmOverloads constructor( @@ -66,4 +69,8 @@ class VideoPlayerView : FrameLayout { } } } + + interface FullScreenToggleListener { + fun fullscreenToggle(turnOn: Boolean) + } } \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerActivity.kt b/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerActivity.kt deleted file mode 100644 index f2e4af3..0000000 --- a/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerActivity.kt +++ /dev/null @@ -1,27 +0,0 @@ -package net.newpipe.newplayer.internal - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.activity.viewModels -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class VideoPlayerActivity : ComponentActivity() { - - private val viewModel: net.newpipe.newplayer.internal.model.VideoPlayerViewModel by viewModels() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - viewModel.initUIState(intent.extras!!) - - enableEdgeToEdge() - setContent { - net.newpipe.newplayer.internal.ui.theme.VideoPlayerTheme { - net.newpipe.newplayer.internal.ui.VideoPlayerUI(viewModel = viewModel) - } - } - } -} \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerFragment.kt b/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerFragment.kt index 43ba76d..c338da1 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerFragment.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/internal/VideoPlayerFragment.kt @@ -36,6 +36,7 @@ import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint import net.newpipe.newplayer.NewPlayer import net.newpipe.newplayer.R +import net.newpipe.newplayer.VideoPlayerView import net.newpipe.newplayer.internal.model.VideoPlayerViewModel import net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.internal.ui.VideoPlayerUI @@ -50,6 +51,8 @@ class VideoPlayerFragment() : Fragment() { private var currentVideoRatio = 0F private lateinit var composeView: ComposeView + var fullScreenToggleListener: VideoPlayerView.FullScreenToggleListener? = null + var minLayoutRatio = 4F / 3F set(value) { if (value <= 0 && maxLayoutRatio < minLayoutRatio) @@ -100,7 +103,10 @@ class VideoPlayerFragment() : Fragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { VideoPlayerTheme { - VideoPlayerUI(viewModel = viewModel) + VideoPlayerUI(viewModel = viewModel, + {fullscreenOn -> + fullScreenToggleListener?.fullscreenToggle(fullscreenOn) + }) } } } diff --git a/new-player/src/main/java/net/newpipe/newplayer/internal/model/VideoPlayerViewModel.kt b/new-player/src/main/java/net/newpipe/newplayer/internal/model/VideoPlayerViewModel.kt index bfc6349..0077b46 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/internal/model/VideoPlayerViewModel.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/internal/model/VideoPlayerViewModel.kt @@ -63,7 +63,6 @@ interface VideoPlayerViewModel { val player: Player? val uiState: StateFlow var listener: Listener? - val events: SharedFlow? fun initUIState(instanceState: Bundle) fun play() @@ -93,12 +92,10 @@ class VideoPlayerViewModelImpl @Inject constructor( // private private val mutableUiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) - private val mutableEvent = MutableSharedFlow() private var current_video_size = VideoSize.DEFAULT //interface override val uiState = mutableUiState.asStateFlow() - override val events: SharedFlow = mutableEvent override var listener: VideoPlayerViewModel.Listener? = null override val player:Player? @@ -106,6 +103,7 @@ class VideoPlayerViewModelImpl @Inject constructor( init { installExoPlayer() + println("gurken reinit ViewModel") } private fun installExoPlayer() { @@ -180,15 +178,14 @@ class VideoPlayerViewModelImpl @Inject constructor( } override fun switchToEmbeddedView() { - viewModelScope.launch { - mutableEvent.emit(VideoPlayerViewModel.Events.SwitchToEmbeddedView) + mutableUiState.update { + it.copy(fullscreen = false) } } override fun switchToFullscreen() { - - viewModelScope.launch { - mutableEvent.emit(VideoPlayerViewModel.Events.SwitchToFullscreen) + mutableUiState.update { + it.copy(fullscreen = true) } } @@ -198,7 +195,7 @@ class VideoPlayerViewModelImpl @Inject constructor( override val player: Player? = null override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT) override var listener: VideoPlayerViewModel.Listener? = null - override val events: SharedFlow? = null + override fun initUIState(instanceState: Bundle) { println("dummy impl") diff --git a/new-player/src/main/java/net/newpipe/newplayer/internal/ui/VideoPlayerUI.kt b/new-player/src/main/java/net/newpipe/newplayer/internal/ui/VideoPlayerUI.kt index 2b5e299..fc79f1b 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/internal/ui/VideoPlayerUI.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/internal/ui/VideoPlayerUI.kt @@ -22,6 +22,7 @@ package net.newpipe.newplayer.internal.ui import android.app.Activity import android.content.Intent +import android.content.pm.ActivityInfo import android.view.SurfaceView import androidx.activity.compose.BackHandler import androidx.activity.compose.ManagedActivityResultLauncher @@ -46,17 +47,16 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver -import kotlinx.coroutines.flow.collectLatest -import net.newpipe.newplayer.internal.VideoPlayerActivity -import net.newpipe.newplayer.internal.model.VIDEOPLAYER_UI_STATE import net.newpipe.newplayer.internal.model.VideoPlayerViewModel import net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.internal.ui.theme.VideoPlayerTheme +import net.newpipe.newplayer.internal.utils.LockScreenOrientation import net.newpipe.newplayer.internal.utils.findActivity @Composable fun VideoPlayerUI( viewModel: VideoPlayerViewModel, + fullscreenToggled: (Boolean) -> Unit ) { val uiState by viewModel.uiState.collectAsState() @@ -67,6 +67,8 @@ fun VideoPlayerUI( val activity = LocalContext.current.findActivity() val lifecycleOwner = LocalLifecycleOwner.current + + // Prepare stuff for the SurfaceView to which the video will be rendered DisposableEffect(lifecycleOwner) { val observer = LifecycleEventObserver { _, event -> lifecycle = event @@ -78,8 +80,12 @@ fun VideoPlayerUI( } } - BackHandler { - closeFullscreen(viewModel, activity!!) + + // Handle Fullscreen/Embedded view transition + if(uiState.fullscreen) { + BackHandler { + //closeFullscreen(viewModel, activity!!) + } } val fullscreenLauncher = @@ -90,20 +96,20 @@ fun VideoPlayerUI( viewModel.initUIState(result.data?.extras!!) } - LaunchedEffect(key1 = Unit) { - viewModel.events?.collectLatest { event -> - when (event) { - VideoPlayerViewModel.Events.SwitchToEmbeddedView -> { - closeFullscreen(viewModel, activity!!) - } + LaunchedEffect(key1 = uiState.fullscreen) { + println("gurken launch fullscreen: ${uiState.fullscreen}") + } - VideoPlayerViewModel.Events.SwitchToFullscreen -> { - openFullscreen(viewModel, activity!!, fullscreenLauncher) - } - } + // Set Screen Rotation + if(uiState.fullscreen) { + if(uiState.contentRatio < 1) { + LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + } else { + LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) } } + // Set UI Surface( modifier = Modifier.fillMaxSize(), color = Color.Black @@ -124,8 +130,6 @@ fun VideoPlayerUI( } }) - val isPlaying = viewModel.player?.isPlaying ?: false - VideoPlayerControllerUI( isPlaying = uiState.playing, fullscreen = uiState.fullscreen, @@ -139,32 +143,10 @@ fun VideoPlayerUI( } } -fun closeFullscreen(viewModel: VideoPlayerViewModel, activity: Activity) { - val return_fullscreen_intent = Intent() - var uiState = viewModel.uiState.value - uiState.fullscreen = false - return_fullscreen_intent.putExtra(VIDEOPLAYER_UI_STATE, uiState) - activity.setResult(0, return_fullscreen_intent) - activity.finish() -} - -fun openFullscreen( - viewModel: VideoPlayerViewModel, - activity: Activity, - fullscreenLauncher: ManagedActivityResultLauncher -) { - val fullscreen_activity_intent = - Intent(activity!!.findActivity(), VideoPlayerActivity::class.java) - var uiState = viewModel.uiState.value - uiState.fullscreen = true - fullscreen_activity_intent.putExtra(VIDEOPLAYER_UI_STATE, uiState) - fullscreenLauncher.launch(fullscreen_activity_intent) -} - @Preview(device = "spec:width=1080px,height=700px,dpi=440,orientation=landscape") @Composable fun PlayerUIPreviewEmbeded() { VideoPlayerTheme { - VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy) + VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy, {}) } } \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/internal/utils/utils.kt b/new-player/src/main/java/net/newpipe/newplayer/internal/utils/utils.kt index bc4f1fc..920971c 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/internal/utils/utils.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/internal/utils/utils.kt @@ -23,9 +23,14 @@ package net.newpipe.newplayer.internal.utils import android.app.Activity import android.content.Context import android.content.ContextWrapper +import android.content.Intent +import androidx.activity.compose.ManagedActivityResultLauncher +import androidx.activity.result.ActivityResult import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.platform.LocalContext +import net.newpipe.newplayer.internal.model.VIDEOPLAYER_UI_STATE +import net.newpipe.newplayer.internal.model.VideoPlayerViewModel @Composable fun LockScreenOrientation(orientation: Int) { 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 35987d5..2f6b2c9 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 @@ -43,16 +43,47 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) val video_view = findViewById(R.id.new_player_video_view) + + video_view.fullScreenToggleListener = object : VideoPlayerView.FullScreenToggleListener { + override fun fullscreenToggle(turnOn: Boolean) { + if (turnOn) { + println("gurken blub") + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + v.setPadding( + 0, 0, 0, 0 + ) + insets + } + + } else { + println("gurken blab") + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding( + systemBars.left, + systemBars.top, + systemBars.right, + systemBars.bottom + ) + insets + } + + } + } + } + newPlayer.playWhenReady = true newPlayer.setStream(getString(R.string.ccc_chromebooks_video)) - //TODO: This is a dirty hack. Fix this later on - if (getResources().configuration.orientation != Configuration.ORIENTATION_LANDSCAPE) { - ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> - val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) - v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) - insets - } + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding( + systemBars.left, + systemBars.top, + systemBars.right, + systemBars.bottom + ) + insets } } diff --git a/test-app/src/main/res/layout-land/activity_main.xml b/test-app/src/main/res/layout-land/activity_main.xml index b4d97aa..0c37970 100644 --- a/test-app/src/main/res/layout-land/activity_main.xml +++ b/test-app/src/main/res/layout-land/activity_main.xml @@ -28,15 +28,40 @@ tools:context=".MainActivity"> - + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + \ No newline at end of file