remove FullScreen Activity
This commit is contained in:
parent
be54682b93
commit
b111b77e04
|
@ -45,6 +45,9 @@ class VideoPlayerView : FrameLayout {
|
||||||
get() = videoPlayerFragment.minLayoutRatio
|
get() = videoPlayerFragment.minLayoutRatio
|
||||||
set(value) {videoPlayerFragment.minLayoutRatio = value}
|
set(value) {videoPlayerFragment.minLayoutRatio = value}
|
||||||
|
|
||||||
|
var fullScreenToggleListener: FullScreenToggleListener?
|
||||||
|
set(value) {videoPlayerFragment.fullScreenToggleListener = value}
|
||||||
|
get() = videoPlayerFragment.fullScreenToggleListener
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -66,4 +69,8 @@ class VideoPlayerView : FrameLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FullScreenToggleListener {
|
||||||
|
fun fullscreenToggle(turnOn: Boolean)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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<net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl>()
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -36,6 +36,7 @@ import androidx.fragment.app.viewModels
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import net.newpipe.newplayer.NewPlayer
|
import net.newpipe.newplayer.NewPlayer
|
||||||
import net.newpipe.newplayer.R
|
import net.newpipe.newplayer.R
|
||||||
|
import net.newpipe.newplayer.VideoPlayerView
|
||||||
import net.newpipe.newplayer.internal.model.VideoPlayerViewModel
|
import net.newpipe.newplayer.internal.model.VideoPlayerViewModel
|
||||||
import net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl
|
import net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl
|
||||||
import net.newpipe.newplayer.internal.ui.VideoPlayerUI
|
import net.newpipe.newplayer.internal.ui.VideoPlayerUI
|
||||||
|
@ -50,6 +51,8 @@ class VideoPlayerFragment() : Fragment() {
|
||||||
private var currentVideoRatio = 0F
|
private var currentVideoRatio = 0F
|
||||||
private lateinit var composeView: ComposeView
|
private lateinit var composeView: ComposeView
|
||||||
|
|
||||||
|
var fullScreenToggleListener: VideoPlayerView.FullScreenToggleListener? = null
|
||||||
|
|
||||||
var minLayoutRatio = 4F / 3F
|
var minLayoutRatio = 4F / 3F
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value <= 0 && maxLayoutRatio < minLayoutRatio)
|
if (value <= 0 && maxLayoutRatio < minLayoutRatio)
|
||||||
|
@ -100,7 +103,10 @@ class VideoPlayerFragment() : Fragment() {
|
||||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||||
setContent {
|
setContent {
|
||||||
VideoPlayerTheme {
|
VideoPlayerTheme {
|
||||||
VideoPlayerUI(viewModel = viewModel)
|
VideoPlayerUI(viewModel = viewModel,
|
||||||
|
{fullscreenOn ->
|
||||||
|
fullScreenToggleListener?.fullscreenToggle(fullscreenOn)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,6 @@ interface VideoPlayerViewModel {
|
||||||
val player: Player?
|
val player: Player?
|
||||||
val uiState: StateFlow<VideoPlayerUIState>
|
val uiState: StateFlow<VideoPlayerUIState>
|
||||||
var listener: Listener?
|
var listener: Listener?
|
||||||
val events: SharedFlow<Events>?
|
|
||||||
|
|
||||||
fun initUIState(instanceState: Bundle)
|
fun initUIState(instanceState: Bundle)
|
||||||
fun play()
|
fun play()
|
||||||
|
@ -93,12 +92,10 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
|
|
||||||
// private
|
// private
|
||||||
private val mutableUiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
|
private val mutableUiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
|
||||||
private val mutableEvent = MutableSharedFlow<VideoPlayerViewModel.Events>()
|
|
||||||
private var current_video_size = VideoSize.DEFAULT
|
private var current_video_size = VideoSize.DEFAULT
|
||||||
|
|
||||||
//interface
|
//interface
|
||||||
override val uiState = mutableUiState.asStateFlow()
|
override val uiState = mutableUiState.asStateFlow()
|
||||||
override val events: SharedFlow<VideoPlayerViewModel.Events> = mutableEvent
|
|
||||||
override var listener: VideoPlayerViewModel.Listener? = null
|
override var listener: VideoPlayerViewModel.Listener? = null
|
||||||
|
|
||||||
override val player:Player?
|
override val player:Player?
|
||||||
|
@ -106,6 +103,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
installExoPlayer()
|
installExoPlayer()
|
||||||
|
println("gurken reinit ViewModel")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installExoPlayer() {
|
private fun installExoPlayer() {
|
||||||
|
@ -180,15 +178,14 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun switchToEmbeddedView() {
|
override fun switchToEmbeddedView() {
|
||||||
viewModelScope.launch {
|
mutableUiState.update {
|
||||||
mutableEvent.emit(VideoPlayerViewModel.Events.SwitchToEmbeddedView)
|
it.copy(fullscreen = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun switchToFullscreen() {
|
override fun switchToFullscreen() {
|
||||||
|
mutableUiState.update {
|
||||||
viewModelScope.launch {
|
it.copy(fullscreen = true)
|
||||||
mutableEvent.emit(VideoPlayerViewModel.Events.SwitchToFullscreen)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +195,7 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
override val player: Player? = null
|
override val player: Player? = null
|
||||||
override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
|
override val uiState = MutableStateFlow(VideoPlayerUIState.DEFAULT)
|
||||||
override var listener: VideoPlayerViewModel.Listener? = null
|
override var listener: VideoPlayerViewModel.Listener? = null
|
||||||
override val events: SharedFlow<VideoPlayerViewModel.Events>? = null
|
|
||||||
|
|
||||||
override fun initUIState(instanceState: Bundle) {
|
override fun initUIState(instanceState: Bundle) {
|
||||||
println("dummy impl")
|
println("dummy impl")
|
||||||
|
|
|
@ -22,6 +22,7 @@ package net.newpipe.newplayer.internal.ui
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
|
@ -46,17 +47,16 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
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.VideoPlayerViewModel
|
||||||
import net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl
|
import net.newpipe.newplayer.internal.model.VideoPlayerViewModelImpl
|
||||||
import net.newpipe.newplayer.internal.ui.theme.VideoPlayerTheme
|
import net.newpipe.newplayer.internal.ui.theme.VideoPlayerTheme
|
||||||
|
import net.newpipe.newplayer.internal.utils.LockScreenOrientation
|
||||||
import net.newpipe.newplayer.internal.utils.findActivity
|
import net.newpipe.newplayer.internal.utils.findActivity
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerUI(
|
fun VideoPlayerUI(
|
||||||
viewModel: VideoPlayerViewModel,
|
viewModel: VideoPlayerViewModel,
|
||||||
|
fullscreenToggled: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
|
|
||||||
|
@ -67,6 +67,8 @@ fun VideoPlayerUI(
|
||||||
val activity = LocalContext.current.findActivity()
|
val activity = LocalContext.current.findActivity()
|
||||||
|
|
||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
|
|
||||||
|
// Prepare stuff for the SurfaceView to which the video will be rendered
|
||||||
DisposableEffect(lifecycleOwner) {
|
DisposableEffect(lifecycleOwner) {
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
lifecycle = 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 =
|
val fullscreenLauncher =
|
||||||
|
@ -90,20 +96,20 @@ fun VideoPlayerUI(
|
||||||
viewModel.initUIState(result.data?.extras!!)
|
viewModel.initUIState(result.data?.extras!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(key1 = Unit) {
|
LaunchedEffect(key1 = uiState.fullscreen) {
|
||||||
viewModel.events?.collectLatest { event ->
|
println("gurken launch fullscreen: ${uiState.fullscreen}")
|
||||||
when (event) {
|
}
|
||||||
VideoPlayerViewModel.Events.SwitchToEmbeddedView -> {
|
|
||||||
closeFullscreen(viewModel, activity!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoPlayerViewModel.Events.SwitchToFullscreen -> {
|
// Set Screen Rotation
|
||||||
openFullscreen(viewModel, activity!!, fullscreenLauncher)
|
if(uiState.fullscreen) {
|
||||||
}
|
if(uiState.contentRatio < 1) {
|
||||||
}
|
LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
|
||||||
|
} else {
|
||||||
|
LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set UI
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = Color.Black
|
color = Color.Black
|
||||||
|
@ -124,8 +130,6 @@ fun VideoPlayerUI(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
val isPlaying = viewModel.player?.isPlaying ?: false
|
|
||||||
|
|
||||||
VideoPlayerControllerUI(
|
VideoPlayerControllerUI(
|
||||||
isPlaying = uiState.playing,
|
isPlaying = uiState.playing,
|
||||||
fullscreen = uiState.fullscreen,
|
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<Intent, ActivityResult>
|
|
||||||
) {
|
|
||||||
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")
|
@Preview(device = "spec:width=1080px,height=700px,dpi=440,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun PlayerUIPreviewEmbeded() {
|
fun PlayerUIPreviewEmbeded() {
|
||||||
VideoPlayerTheme {
|
VideoPlayerTheme {
|
||||||
VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy)
|
VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy, {})
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,9 +23,14 @@ package net.newpipe.newplayer.internal.utils
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
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.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import net.newpipe.newplayer.internal.model.VIDEOPLAYER_UI_STATE
|
||||||
|
import net.newpipe.newplayer.internal.model.VideoPlayerViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LockScreenOrientation(orientation: Int) {
|
fun LockScreenOrientation(orientation: Int) {
|
||||||
|
|
|
@ -43,16 +43,47 @@ class MainActivity : AppCompatActivity() {
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
val video_view = findViewById<VideoPlayerView>(R.id.new_player_video_view)
|
val video_view = findViewById<VideoPlayerView>(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.playWhenReady = true
|
||||||
newPlayer.setStream(getString(R.string.ccc_chromebooks_video))
|
newPlayer.setStream(getString(R.string.ccc_chromebooks_video))
|
||||||
|
|
||||||
//TODO: This is a dirty hack. Fix this later on
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
if (getResources().configuration.orientation != Configuration.ORIENTATION_LANDSCAPE) {
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
v.setPadding(
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
systemBars.left,
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
systemBars.top,
|
||||||
insets
|
systemBars.right,
|
||||||
}
|
systemBars.bottom
|
||||||
|
)
|
||||||
|
insets
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,15 +28,40 @@
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<LinearLayout
|
||||||
android:id="@+id/player_frament_view"
|
android:id="@+id/player_column"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBaseline_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/hw_view"
|
||||||
|
app:layout_constraintHorizontal_weight="1"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
app:layout_constraintBottom_toTopOf="parent"
|
|
||||||
android:name="net.newpipe.newplayer.internal.VideoPlayerFragment"
|
<net.newpipe.newplayer.VideoPlayerView
|
||||||
/>
|
android:id="@+id/new_player_video_view"
|
||||||
|
android:name="net.newpipe.newplayer.VideoPlayerFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="50dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/hw_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Hello World!"
|
||||||
|
app:layout_constraintHorizontal_weight="1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/player_column"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue