diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b7e6dc3..2c46bc7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -46,6 +46,7 @@ coil = "2.7.0"
reorderable = "2.4.0-alpha02"
media3Session = "1.4.1"
media3ExoplayerDash = "1.4.1"
+adaptiveAndroid = "1.0.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -83,6 +84,7 @@ coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coi
reorderable = { group = "sh.calvin.reorderable", name = "reorderable", version.ref = "reorderable" }
androidx-media3-session = { group = "androidx.media3", name = "media3-session", version.ref = "media3Session" }
androidx-media3-exoplayer-dash = { group = "androidx.media3", name = "media3-exoplayer-dash", version.ref = "media3ExoplayerDash" }
+androidx-adaptive-android = { group = "androidx.compose.material3.adaptive", name = "adaptive-android", version.ref = "adaptiveAndroid" }
diff --git a/new-player/build.gradle.kts b/new-player/build.gradle.kts
index e73a7a5..c8403ac 100644
--- a/new-player/build.gradle.kts
+++ b/new-player/build.gradle.kts
@@ -70,6 +70,7 @@ dependencies {
implementation(libs.reorderable)
implementation(libs.androidx.media3.session)
implementation(libs.androidx.media3.exoplayer.dash)
+ implementation(libs.androidx.adaptive.android)
ksp(libs.hilt.android.compiler)
ksp(libs.androidx.hilt.compiler)
diff --git a/new-player/src/main/AndroidManifest.xml b/new-player/src/main/AndroidManifest.xml
index f04e26a..9722b13 100644
--- a/new-player/src/main/AndroidManifest.xml
+++ b/new-player/src/main/AndroidManifest.xml
@@ -4,7 +4,8 @@
-
+
- Box(
- modifier = Modifier
- .fillMaxSize()
- .padding(innerPadding)
- ) {
- Column(
- modifier = Modifier
- .fillMaxSize()
- ) {
- Column(
- modifier = Modifier
- .fillMaxSize()
- .padding(20.dp)
- .weight(1f),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- Box(
- modifier = Modifier
- .fillMaxSize()
- .weight(1f)
- )
- Box {
- Card(
- elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
- ) {
- Thumbnail(
- modifier = Modifier.fillMaxWidth(),
- thumbnail = uiState.currentlyPlaying?.mediaMetadata?.artworkUri,
- contentDescription = stringResource(
- id = R.string.stream_thumbnail
- ),
- )
- }
- }
- Box(
- modifier = Modifier
- .fillMaxSize()
- .weight(1f)
- )
- Text(
- text = uiState.currentlyPlaying?.mediaMetadata?.title.toString(),
- overflow = TextOverflow.Ellipsis,
- maxLines = 1,
- fontSize = 6.em
- )
- Text(
- text = uiState.currentlyPlaying?.mediaMetadata?.artist.toString(),
- overflow = TextOverflow.Ellipsis,
- maxLines = 1,
- fontSize = 4.em
- )
-
- Box(
- modifier = Modifier
- .fillMaxSize()
- .weight(0.2f)
- )
-
- NewPlayerSeeker(viewModel = viewModel, uiState = uiState)
-
- Row() {
- Text(
- getTimeStringFromMs(
- uiState.playbackPositionInMs,
- getLocale() ?: locale
- )
- )
- Box(modifier = Modifier.fillMaxWidth().weight(1f))
- Text(
- getTimeStringFromMs(
- uiState.durationInMs,
- getLocale() ?: locale
- )
- )
- }
-
- Box(
- modifier = Modifier
- .fillMaxSize()
- .weight(0.2f)
- )
- AudioPlaybackController(viewModel = viewModel, uiState = uiState)
- Box(
- modifier = Modifier
- .fillMaxSize()
- .weight(0.2f)
- )
- }
- AudioBottomUI(viewModel, uiState)
- Box(
- modifier = Modifier
- .fillMaxSize()
- .weight(0.025f)
- )
- }
+ if (isLandScape) {
+ LandscapeLayout(
+ viewModel = viewModel,
+ uiState = uiState,
+ innerPadding = innerPadding
+ )
+ } else {
+ PortraitLayout(
+ viewModel = viewModel,
+ uiState = uiState,
+ innerPadding = innerPadding
+ )
}
}
}
}
}
+@OptIn(UnstableApi::class)
+@Composable
+private fun LandscapeLayout(
+ modifier: Modifier = Modifier,
+ viewModel: NewPlayerViewModel,
+ uiState: NewPlayerUIState,
+ innerPadding: PaddingValues
+) {
+ Row(modifier = modifier
+ .fillMaxSize()
+ .padding(20.dp)) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(1f)
+ ) {
+ CoverArt(modifier = Modifier
+ .fillMaxSize()
+ .weight(0.9f), uiState = uiState)
+
+ TitleView(modifier = Modifier
+ .fillMaxSize()
+ .weight(0.1f), uiState = uiState)
+ }
+
+ Box(modifier = Modifier.width(20.dp))
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(1f)
+ ) {
+ Column(
+ verticalArrangement = Arrangement.SpaceAround,
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(1f)
+ ) {
+ ProgressUI(
+ viewModel = viewModel,
+ uiState = uiState
+ )
+ AudioPlaybackController(
+ viewModel = viewModel,
+ uiState = uiState
+ )
+ }
+ AudioBottomUI(viewModel, uiState)
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(0.025f)
+ )
+ }
+ }
+}
+
+@OptIn(UnstableApi::class)
+@Composable
+private fun PortraitLayout(
+ modifier: Modifier = Modifier,
+ viewModel: NewPlayerViewModel,
+ uiState: NewPlayerUIState,
+ innerPadding: PaddingValues
+) {
+ Box(
+ modifier = modifier
+ .fillMaxSize()
+ .padding(innerPadding)
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(20.dp)
+ .weight(1f),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(1f)
+ )
+ CoverArt(uiState = uiState)
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(0.3f)
+ )
+
+ TitleView(uiState = uiState)
+
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(0.6f)
+ )
+
+ ProgressUI(viewModel = viewModel, uiState = uiState)
+
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(0.2f)
+ )
+ AudioPlaybackController(viewModel = viewModel, uiState = uiState)
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(0.2f)
+ )
+ }
+ AudioBottomUI(viewModel, uiState)
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(0.025f)
+ )
+ }
+ }
+}
+
+@OptIn(UnstableApi::class)
+@Composable
+private fun ProgressUI(
+ modifier: Modifier = Modifier,
+ viewModel: NewPlayerViewModel,
+ uiState: NewPlayerUIState
+) {
+ val locale = getLocale()!!
+
+ Column(modifier = modifier) {
+ NewPlayerSeeker(viewModel = viewModel, uiState = uiState)
+ Row {
+ Text(
+ getTimeStringFromMs(
+ uiState.playbackPositionInMs,
+ getLocale() ?: locale
+ )
+ )
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(1f)
+ )
+ Text(
+ getTimeStringFromMs(
+ uiState.durationInMs,
+ getLocale() ?: locale
+ )
+ )
+ }
+ }
+}
+
+@OptIn(UnstableApi::class)
+@Composable
+private fun TitleView(modifier: Modifier = Modifier, uiState: NewPlayerUIState) {
+ Column(modifier = modifier) {
+ Text(
+ text = uiState.currentlyPlaying?.mediaMetadata?.title.toString(),
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ fontSize = 6.em
+ )
+ Text(
+ text = uiState.currentlyPlaying?.mediaMetadata?.artist.toString(),
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ fontSize = 4.em
+ )
+ }
+}
+
+@OptIn(UnstableApi::class)
+@Composable
+private fun CoverArt(modifier: Modifier = Modifier, uiState: NewPlayerUIState) {
+ Box {
+ Card(
+ elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
+ ) {
+ Thumbnail(
+ modifier = Modifier.fillMaxWidth(),
+ thumbnail = uiState.currentlyPlaying?.mediaMetadata?.artworkUri,
+ contentDescription = stringResource(
+ id = R.string.stream_thumbnail
+ ),
+ )
+ }
+ }
+}
+
@OptIn(UnstableApi::class)
@Preview(device = "id:pixel_6", showSystemUi = true)
@Composable
-fun AudioPlayerUIPreview() {
+fun AudioPlayerUIPortraitPreview() {
VideoPlayerTheme {
AudioPlayerUI(
viewModel = NewPlayerViewModelDummy(),
- uiState = NewPlayerUIState.DUMMY.copy(uiMode = UIModeState.FULLSCREEN_AUDIO)
+ uiState = NewPlayerUIState.DUMMY.copy(uiMode = UIModeState.FULLSCREEN_AUDIO),
+ isLandScape = false
+ )
+ }
+}
+
+@OptIn(UnstableApi::class)
+@Preview(device = "spec:parent=pixel_6,orientation=landscape", showSystemUi = true)
+@Composable
+fun AudioPlayerUILandscapePreview() {
+ VideoPlayerTheme {
+ AudioPlayerUI(
+ viewModel = NewPlayerViewModelDummy(),
+ uiState = NewPlayerUIState.DUMMY.copy(uiMode = UIModeState.FULLSCREEN_AUDIO),
+ isLandScape = true
)
}
}
\ No newline at end of file
diff --git a/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt b/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt
index f3286e5..6fb8da3 100644
--- a/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt
+++ b/new-player/src/main/java/net/newpipe/newplayer/ui/theme/Color.kt
@@ -104,7 +104,7 @@ fun VideoPlayerControllerUIPreviewEmbeddedColorPreview() {
@OptIn(UnstableApi::class)
@Preview(device = "id:pixel_6")
@Composable
-fun AudioPlayerUIPreviewEmbeddedColorPreview() {
+fun AudioPlayerUIColorPreview() {
VideoPlayerTheme {
PreviewBackgroundSurface {
AudioPlayerUI(
@@ -119,6 +119,7 @@ fun AudioPlayerUIPreviewEmbeddedColorPreview() {
bufferedPercentage = 0.4f,
fastSeekSeconds = 10,
),
+ isLandScape = false
)
}
}
diff --git a/test-app/src/main/res/values/test_streams.xml b/test-app/src/main/res/values/test_streams.xml
index 5866be7..dc31d68 100644
--- a/test-app/src/main/res/values/test_streams.xml
+++ b/test-app/src/main/res/values/test_streams.xml
@@ -33,7 +33,6 @@
- 1200000
- 1800000
- 2400000
- - 3600000
3116