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" }