From 698e9776afe09d2f63701f1716d3158591fd13d2 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Mon, 23 Sep 2024 20:16:05 +0200 Subject: [PATCH] make audioplayer landscape layout be halfway usable --- gradle/libs.versions.toml | 2 + new-player/build.gradle.kts | 1 + new-player/src/main/AndroidManifest.xml | 3 +- .../net/newpipe/newplayer/ui/NewPlayerUI.kt | 5 +- .../ui/audioplayer/AudioPlaybackController.kt | 58 +-- .../newplayer/ui/audioplayer/AudioPlayerUI.kt | 331 ++++++++++++------ .../net/newpipe/newplayer/ui/theme/Color.kt | 3 +- test-app/src/main/res/values/test_streams.xml | 1 - 8 files changed, 278 insertions(+), 126 deletions(-) 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