From 0d85401cdde14a4038119e330ac454bd3cb51435 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Wed, 17 Jul 2024 13:21:02 +0200 Subject: [PATCH] experimental fullscreen videoplayeractivity --- .idea/deploymentTargetSelector.xml | 8 +++++ app/build.gradle.kts | 17 +++++++++ app/src/main/AndroidManifest.xml | 27 ++++---------- .../newpipe/newplayer/VideoPlayerActivity.kt | 28 +++++++++++++++ .../newpipe/newplayer/VideoPlayerComponent.kt | 6 ++-- .../newpipe/newplayer/VideoPlayerFragment.kt | 2 +- .../newplayer/model/VideoPlayerViewModel.kt | 35 +++++++++---------- .../newplayer/ui/VideoPlayerControllerUI.kt | 15 ++++---- .../net/newpipe/newplayer/ui/VideoPlayerUI.kt | 31 ++++++++++++---- .../newpipe/newplayer/{ui => utils}/utils.kt | 3 +- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/themes.xml | 4 +++ gradle/libs.versions.toml | 9 +++++ 14 files changed, 131 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/net/newpipe/newplayer/VideoPlayerActivity.kt rename app/src/main/java/net/newpipe/newplayer/{ui => utils}/utils.kt (95%) diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index b268ef3..daec8bb 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,6 +4,14 @@ diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d893b08..381b96c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -46,6 +46,9 @@ android { versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } } buildTypes { @@ -64,6 +67,11 @@ android { kotlinOptions { jvmTarget = "1.8" } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } } @@ -83,6 +91,15 @@ dependencies { implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.foundation) implementation(libs.androidx.fragment.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) ksp(libs.hilt.android.compiler) ksp(libs.androidx.hilt.compiler) implementation(libs.androidx.hilt.navigation.compose) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0a45fa4..5cc8d32 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,27 +1,9 @@ - - + + + diff --git a/app/src/main/java/net/newpipe/newplayer/VideoPlayerActivity.kt b/app/src/main/java/net/newpipe/newplayer/VideoPlayerActivity.kt new file mode 100644 index 0000000..9e24488 --- /dev/null +++ b/app/src/main/java/net/newpipe/newplayer/VideoPlayerActivity.kt @@ -0,0 +1,28 @@ +package net.newpipe.newplayer + +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 +import net.newpipe.newplayer.model.VideoPlayerViewModel +import net.newpipe.newplayer.model.VideoPlayerViewModelImpl +import net.newpipe.newplayer.ui.VideoPlayerUI +import net.newpipe.newplayer.ui.theme.VideoPlayerTheme + +@AndroidEntryPoint +class VideoPlayerActivity : ComponentActivity() { + + private val viewModel: VideoPlayerViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + VideoPlayerTheme { + VideoPlayerUI(viewModel = viewModel, isFullscreen = true) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/newpipe/newplayer/VideoPlayerComponent.kt b/app/src/main/java/net/newpipe/newplayer/VideoPlayerComponent.kt index beaf4e8..e9af06f 100644 --- a/app/src/main/java/net/newpipe/newplayer/VideoPlayerComponent.kt +++ b/app/src/main/java/net/newpipe/newplayer/VideoPlayerComponent.kt @@ -28,12 +28,14 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.components.ViewModelComponent import dagger.hilt.android.scopes.ViewModelScoped +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton @Module -@InstallIn(ViewModelComponent::class) +@InstallIn(SingletonComponent::class) object VideoPlayerComponent { @Provides - @ViewModelScoped + @Singleton fun provideVideoPlayer(app: Application) : Player { return ExoPlayer.Builder(app).build() } diff --git a/app/src/main/java/net/newpipe/newplayer/VideoPlayerFragment.kt b/app/src/main/java/net/newpipe/newplayer/VideoPlayerFragment.kt index d495b59..89ac82c 100644 --- a/app/src/main/java/net/newpipe/newplayer/VideoPlayerFragment.kt +++ b/app/src/main/java/net/newpipe/newplayer/VideoPlayerFragment.kt @@ -80,7 +80,7 @@ class VideoPlayerFragment() : Fragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { VideoPlayerTheme { - VideoPlayerUI(viewModel) + VideoPlayerUI(viewModel = viewModel, isFullscreen = false) } } } diff --git a/app/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt b/app/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt index 307f1c9..7baa810 100644 --- a/app/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt +++ b/app/src/main/java/net/newpipe/newplayer/model/VideoPlayerViewModel.kt @@ -21,6 +21,7 @@ package net.newpipe.newplayer.model import android.app.Application +import android.content.Intent import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.SavedStateHandle import androidx.media3.common.MediaItem @@ -32,20 +33,15 @@ import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update +import net.newpipe.newplayer.VideoPlayerActivity import net.newpipe.newplayer.utils.VideoSize data class VideoPlayerUIState( - val playing: Boolean, - var fullscreen: Boolean, - var uiVissible: Boolean, - var contentRatio: Float + val playing: Boolean, var fullscreen: Boolean, var uiVissible: Boolean, var contentRatio: Float ) { companion object { val DEFAULT = VideoPlayerUIState( - playing = false, - fullscreen = false, - uiVissible = false, - 0F + playing = false, fullscreen = false, uiVissible = false, 0F ) } } @@ -88,7 +84,12 @@ class VideoPlayerViewModelImpl @Inject constructor( var current_video_size = VideoSize.DEFAULT init { - player.prepare() + + println("gurken $this") + + if (player.playbackState == Player.STATE_IDLE) { + player.prepare() + } player.addListener(object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { super.onIsPlayingChanged(isPlaying) @@ -109,13 +110,13 @@ class VideoPlayerViewModelImpl @Inject constructor( val videoSize = VideoSize.fromMedia3VideoSize(media3VideoSize) - if(current_video_size != videoSize) { + if (current_video_size != videoSize) { val newRatio = videoSize.getRatio() - if(current_video_size.getRatio() != newRatio) { + if (current_video_size.getRatio() != newRatio) { mutableUiState.update { it.copy(contentRatio = newRatio) } - if(!mutableUiState.value.fullscreen) { + if (!mutableUiState.value.fullscreen) { listener?.requestUpdateLayoutRatio(newRatio) } } @@ -125,17 +126,15 @@ class VideoPlayerViewModelImpl @Inject constructor( }) player.setMediaItem(MediaItem.fromUri(app.getString(R.string.ccc_6502_video))) - player.playWhenReady = true + //player.playWhenReady = true } override fun play() { - println("gurken Play") - player.play() + //player.play() } override fun pause() { - println("gurken pause") - player.pause() + //player.pause() } override fun prevStream() { @@ -156,7 +155,7 @@ class VideoPlayerViewModelImpl @Inject constructor( mutableUiState.update { it.copy(fullscreen = true) } - listener?.switchToFullscreen() + //listener?.switchToFullscreen() } override fun onCleared() { diff --git a/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt b/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt index e1bec00..ee289c7 100644 --- a/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt +++ b/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerControllerUI.kt @@ -82,11 +82,12 @@ import androidx.compose.ui.unit.sp import net.newpipe.newplayer.R import net.newpipe.newplayer.ui.theme.VideoPlayerTheme import net.newpipe.newplayer.ui.theme.video_player_onSurface +import net.newpipe.newplayer.utils.LockScreenOrientation @Composable fun VideoPlayerControllerUI( isPlaying: Boolean, - isFullscreen: Boolean, + fullscreen: Boolean, play: () -> Unit, pause: () -> Unit, prevStream: () -> Unit, @@ -98,7 +99,7 @@ fun VideoPlayerControllerUI( modifier = Modifier.fillMaxSize(), color = Color(0x75000000) ) { Box( - modifier = if (isFullscreen) { + modifier = if (fullscreen) { Modifier .background(Color.Transparent) .windowInsetsPadding(WindowInsets.systemBars) @@ -128,13 +129,13 @@ fun VideoPlayerControllerUI( .padding(start = 16.dp, end = 16.dp) .defaultMinSize(minHeight = 40.dp) .fillMaxWidth(), - isFullscreen = isFullscreen, + isFullscreen = fullscreen, switchToFullscreen, switchToEmbeddedView ) } } - if (isFullscreen) { + if (fullscreen) { BackHandler { switchToEmbeddedView() } @@ -404,7 +405,7 @@ fun VideoPlayerControllerUIPreviewEmbeded() { VideoPlayerTheme { PreviewBackgroundSurface { VideoPlayerControllerUI(isPlaying = false, - isFullscreen = false, + fullscreen = false, play = {}, pause = {}, prevStream = {}, @@ -421,7 +422,7 @@ fun VideoPlayerControllerUIPreviewLandscape() { VideoPlayerTheme { PreviewBackgroundSurface { VideoPlayerControllerUI(isPlaying = true, - isFullscreen = true, + fullscreen = true, play = {}, pause = {}, prevStream = {}, @@ -439,7 +440,7 @@ fun VideoPlayerControllerUIPreviewPortrait() { PreviewBackgroundSurface { VideoPlayerControllerUI( isPlaying = false, - isFullscreen = true, + fullscreen = true, play = {}, pause = {}, prevStream = {}, diff --git a/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt b/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt index 49badc9..29b8a30 100644 --- a/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt +++ b/app/src/main/java/net/newpipe/newplayer/ui/VideoPlayerUI.kt @@ -20,6 +20,7 @@ package net.newpipe.newplayer.ui +import android.content.Intent import android.view.SurfaceView import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Surface @@ -32,21 +33,23 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue 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 -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver +import net.newpipe.newplayer.VideoPlayerActivity import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModelImpl import net.newpipe.newplayer.ui.theme.VideoPlayerTheme +import net.newpipe.newplayer.utils.findActivity @Composable fun VideoPlayerUI( - viewModel: VideoPlayerViewModel + viewModel: VideoPlayerViewModel, + isFullscreen: Boolean ) { - val uiState by viewModel.uiState.collectAsState() var lifecycle by remember { @@ -65,6 +68,22 @@ fun VideoPlayerUI( } } + var fullscreen_requested by remember { + mutableStateOf(false) + } + + if(isFullscreen != uiState.fullscreen && !fullscreen_requested) { + fullscreen_requested = true + val current_acitivity = LocalContext.current.findActivity() + if(uiState.fullscreen) { + val fullscreen_acitivity_intent = Intent(current_acitivity, VideoPlayerActivity::class.java) + current_acitivity!!.startActivity(fullscreen_acitivity_intent) + } else { + current_acitivity!!.finish() + } + } + + Surface( modifier = Modifier.fillMaxSize(), color = Color.Black @@ -73,7 +92,7 @@ fun VideoPlayerUI( modifier = Modifier.fillMaxSize(), factory = { context -> SurfaceView(context).also { - viewModel.player?.setVideoSurfaceView(it) + //viewModel.player?.setVideoSurfaceView(it) } }, update = { when (lifecycle) { @@ -90,7 +109,7 @@ fun VideoPlayerUI( println("is Player playing: $isPlaying") VideoPlayerControllerUI( isPlaying = uiState.playing, - isFullscreen = uiState.fullscreen, + fullscreen = uiState.fullscreen, play = viewModel::play, pause = viewModel::pause, prevStream = viewModel::prevStream, @@ -105,6 +124,6 @@ fun VideoPlayerUI( @Composable fun PlayerUIPreviewEmbeded() { VideoPlayerTheme { - VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy) + VideoPlayerUI(viewModel = VideoPlayerViewModelImpl.dummy, isFullscreen = false) } } \ No newline at end of file diff --git a/app/src/main/java/net/newpipe/newplayer/ui/utils.kt b/app/src/main/java/net/newpipe/newplayer/utils/utils.kt similarity index 95% rename from app/src/main/java/net/newpipe/newplayer/ui/utils.kt rename to app/src/main/java/net/newpipe/newplayer/utils/utils.kt index 3fb58d4..b023625 100644 --- a/app/src/main/java/net/newpipe/newplayer/ui/utils.kt +++ b/app/src/main/java/net/newpipe/newplayer/utils/utils.kt @@ -18,7 +18,7 @@ * along with NewPlayer. If not, see . */ -package net.newpipe.newplayer.ui +package net.newpipe.newplayer.utils import android.app.Activity import android.content.Context @@ -26,7 +26,6 @@ import android.content.ContextWrapper import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.platform.LocalContext -import androidx.core.view.WindowCompat @Composable fun LockScreenOrientation(orientation: Int) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 53ed26d..2bd7235 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -36,7 +36,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - android:name="net.newpipe.newplayer.PlayerFragment" + android:name="net.newpipe.newplayer.VideoPlayerFragment" /> Toggle fullscreen Chapter selection Playlist item selection + VideoPlayerActivity \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index a1d11ba..1338bc0 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -26,4 +26,8 @@ \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 58eca62..213f039 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,8 @@ lifecycleViewmodelCompose = "2.8.3" kspVersion = "1.9.0-1.0.13" runtimeLivedata = "1.7.0-beta04" fragmentKtx = "1.8.1" +lifecycleRuntimeKtx = "2.8.3" +composeBom = "2024.04.01" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -62,6 +64,13 @@ hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-comp androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" } androidx-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "uiTooling" } androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }