roughly layout AudioPlayerView
This commit is contained in:
parent
df26c3c094
commit
a222a7c9a0
|
@ -23,8 +23,11 @@ package net.newpipe.newplayer.ui.audioplayer;
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
@ -39,11 +42,13 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import net.newpipe.newplayer.R
|
import net.newpipe.newplayer.R
|
||||||
import net.newpipe.newplayer.model.NewPlayerUIState
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.common.RepeatModeButton
|
import net.newpipe.newplayer.ui.common.RepeatModeButton
|
||||||
import net.newpipe.newplayer.ui.common.ShuffleModeButton
|
import net.newpipe.newplayer.ui.common.ShuffleModeButton
|
||||||
|
|
||||||
|
@ -56,48 +61,58 @@ fun AudioPlaybackController(viewModel: NewPlayerViewModel, uiState: NewPlayerUIS
|
||||||
|
|
||||||
Box(modifier = Modifier.size(80.dp), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.size(80.dp), contentAlignment = Alignment.Center) {
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
uiState.currentPlaylistItemIndex != 0,
|
uiState.currentPlaylistItemIndex != 0,
|
||||||
enter = fadeIn(animationSpec = tween(400)),
|
enter = fadeIn(animationSpec = tween(400)),
|
||||||
exit = fadeOut(animationSpec = tween(400))
|
exit = fadeOut(animationSpec = tween(400))
|
||||||
|
|
||||||
) {
|
) {
|
||||||
IconButton(
|
Button(
|
||||||
onClick = viewModel::toggleShuffle
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.aspectRatio(1f),
|
||||||
|
onClick = {},
|
||||||
|
colors = lightAudioControlButtonColorScheme()
|
||||||
) {
|
) {
|
||||||
Icon(
|
Image(
|
||||||
imageVector = Icons.Filled.SkipPrevious,
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentDescription = stringResource(R.string.widget_description_previous_stream)
|
imageVector = Icons.Filled.SkipPrevious,
|
||||||
|
contentDescription = stringResource(R.string.widget_description_previous_stream)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.size(80.dp),
|
modifier = Modifier.size(80.dp),
|
||||||
onClick = if (uiState.playing) viewModel::pause else viewModel::play,
|
onClick = if (uiState.playing) viewModel::pause else viewModel::play,
|
||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = if (uiState.playing) Icons.Filled.Pause else Icons.Filled.PlayArrow,
|
imageVector = if (uiState.playing) Icons.Filled.Pause else Icons.Filled.PlayArrow,
|
||||||
contentDescription = stringResource(
|
contentDescription = stringResource(
|
||||||
if (uiState.playing) R.string.widget_description_pause
|
if (uiState.playing) R.string.widget_description_pause
|
||||||
else R.string.widget_description_play
|
else R.string.widget_description_play
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(modifier = Modifier.size(80.dp), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.size(80.dp), contentAlignment = Alignment.Center) {
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
uiState.currentPlaylistItemIndex < uiState.playList.size - 1,
|
uiState.currentPlaylistItemIndex < uiState.playList.size - 1,
|
||||||
enter = fadeIn(animationSpec = tween(400)),
|
enter = fadeIn(animationSpec = tween(400)),
|
||||||
exit = fadeOut(animationSpec = tween(400))
|
exit = fadeOut(animationSpec = tween(400))
|
||||||
) {
|
) {
|
||||||
IconButton(
|
Button(
|
||||||
onClick = viewModel::toggleShuffle
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.aspectRatio(1f),
|
||||||
|
onClick = {},
|
||||||
|
colors = lightAudioControlButtonColorScheme()
|
||||||
) {
|
) {
|
||||||
Icon(
|
Image(
|
||||||
imageVector = Icons.Filled.SkipNext,
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentDescription = stringResource(R.string.widget_description_next_stream)
|
imageVector = Icons.Filled.SkipNext,
|
||||||
|
contentDescription = stringResource(R.string.widget_description_next_stream)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,3 +121,13 @@ fun AudioPlaybackController(viewModel: NewPlayerViewModel, uiState: NewPlayerUIS
|
||||||
RepeatModeButton(viewModel = viewModel, uiState = uiState)
|
RepeatModeButton(viewModel = viewModel, uiState = uiState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
|
@Preview(device = "id:pixel_6")
|
||||||
|
@Composable
|
||||||
|
fun AudioPlayerControllerPreview() {
|
||||||
|
// VideoPlayerTheme {
|
||||||
|
AudioPlaybackController(viewModel = NewPlayerViewModelDummy(), uiState = NewPlayerUIState.DUMMY)
|
||||||
|
// }
|
||||||
|
}
|
|
@ -22,14 +22,70 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.ui.audioplayer
|
package net.newpipe.newplayer.ui.audioplayer
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.List
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.MenuBook
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import net.newpipe.newplayer.R
|
||||||
|
import net.newpipe.newplayer.model.EmbeddedUiConfig
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
|
||||||
|
@androidx.annotation.OptIn(UnstableApi::class)
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AudioPlayerTopBar(modifier: Modifier = Modifier) {
|
fun AudioPlayerTopBar(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
viewModel: NewPlayerViewModel,
|
||||||
|
uiState: NewPlayerUIState
|
||||||
|
) {
|
||||||
|
val embeddedUiConfig =
|
||||||
|
if (LocalContext.current is Activity)
|
||||||
|
getEmbeddedUiConfig(activity = LocalContext.current as Activity)
|
||||||
|
else EmbeddedUiConfig.DUMMY
|
||||||
TopAppBar(modifier = modifier,
|
TopAppBar(modifier = modifier,
|
||||||
title = { })
|
title = { }, actions = {
|
||||||
|
AnimatedVisibility(visible = uiState.chapters.isNotEmpty()) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
viewModel.openStreamSelection(
|
||||||
|
selectChapter = true,
|
||||||
|
embeddedUiConfig
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.MenuBook,
|
||||||
|
contentDescription = stringResource(R.string.widget_description_chapter_selection)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimatedVisibility(visible = 1 < uiState.playList.size) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
viewModel.openStreamSelection(
|
||||||
|
selectChapter = false,
|
||||||
|
embeddedUiConfig
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.List,
|
||||||
|
contentDescription = stringResource(R.string.widget_descriptoin_playlist_item_selection)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
|
@ -22,29 +22,15 @@
|
||||||
package net.newpipe.newplayer.ui.audioplayer
|
package net.newpipe.newplayer.ui.audioplayer
|
||||||
|
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.animation.fadeIn
|
|
||||||
import androidx.compose.animation.fadeOut
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Pause
|
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
|
||||||
import androidx.compose.material.icons.filled.Shuffle
|
|
||||||
import androidx.compose.material.icons.filled.ShuffleOn
|
|
||||||
import androidx.compose.material.icons.filled.SkipNext
|
|
||||||
import androidx.compose.material.icons.filled.SkipPrevious
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
@ -61,11 +47,15 @@ import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModel
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
import net.newpipe.newplayer.ui.common.NewPlayerSeeker
|
import net.newpipe.newplayer.ui.common.NewPlayerSeeker
|
||||||
import net.newpipe.newplayer.ui.common.RepeatModeButton
|
|
||||||
import net.newpipe.newplayer.ui.common.ShuffleModeButton
|
|
||||||
import net.newpipe.newplayer.utils.Thumbnail
|
import net.newpipe.newplayer.utils.Thumbnail
|
||||||
import net.newpipe.newplayer.utils.getInsets
|
import net.newpipe.newplayer.utils.getInsets
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun lightAudioControlButtonColorScheme() = ButtonDefaults.buttonColors().copy(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
|
@ -73,7 +63,7 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
Scaffold(modifier = Modifier
|
Scaffold(modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(insets),
|
.windowInsetsPadding(insets),
|
||||||
topBar = { AudioPlayerTopBar() }) { innerPadding ->
|
topBar = { AudioPlayerTopBar(viewModel = viewModel, uiState = uiState) }) { innerPadding ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
@ -82,35 +72,58 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(20.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
) {
|
||||||
Card(
|
Column(
|
||||||
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(20.dp)
|
||||||
|
.weight(1f),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Thumbnail(
|
Box(modifier = Modifier
|
||||||
thumbnail = uiState.currentlyPlaying?.mediaMetadata?.artworkUri,
|
.fillMaxSize()
|
||||||
contentDescription = stringResource(
|
.weight(1f))
|
||||||
id = R.string.stream_thumbnail
|
Box {
|
||||||
),
|
Card(
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
|
||||||
|
) {
|
||||||
|
Thumbnail(
|
||||||
|
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)
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.weight(0.2f))
|
||||||
|
AudioPlaybackController(viewModel = viewModel, uiState = uiState)
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.weight(0.2f))
|
||||||
}
|
}
|
||||||
Text(
|
AudioBottomUI(viewModel, uiState)
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
NewPlayerSeeker(viewModel = viewModel, uiState = uiState)
|
|
||||||
|
|
||||||
AudioPlaybackController(viewModel = viewModel, uiState = uiState)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +132,7 @@ fun AudioPlayerUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "id:pixel_6")
|
@Preview(device = "id:pixel_6")
|
||||||
@Composable
|
@Composable
|
||||||
fun AudioPlayerUIPreviewEmbedded() {
|
fun AudioPlayerUIPreview() {
|
||||||
// VideoPlayerTheme {
|
// VideoPlayerTheme {
|
||||||
AudioPlayerUI(viewModel = NewPlayerViewModelDummy(), uiState = NewPlayerUIState.DUMMY)
|
AudioPlayerUI(viewModel = NewPlayerViewModelDummy(), uiState = NewPlayerUIState.DUMMY)
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/* NewPlayer
|
||||||
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
|
*
|
||||||
|
* Copyright (C) NewPipe e.V. 2024 <code(at)newpipe-ev.de>
|
||||||
|
*
|
||||||
|
* NewPlayer is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPlayer is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPlayer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package net.newpipe.newplayer.ui.audioplayer
|
||||||
|
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.Notes
|
||||||
|
import androidx.compose.material.icons.filled.Language
|
||||||
|
import androidx.compose.material.icons.filled.LiveTv
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
import androidx.compose.material.icons.filled.PictureInPicture
|
||||||
|
import androidx.compose.material.icons.filled.Share
|
||||||
|
import androidx.compose.material.icons.filled.Speed
|
||||||
|
import androidx.compose.material.icons.filled.Translate
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonColors
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import net.newpipe.newplayer.R
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerUIState
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerViewModel
|
||||||
|
import net.newpipe.newplayer.model.NewPlayerViewModelDummy
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
@Composable
|
||||||
|
fun AudioBottomUI(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
|
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f), horizontalArrangement = Arrangement.SpaceAround
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = { /*TODO*/ },
|
||||||
|
colors = lightAudioControlButtonColorScheme()
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.Notes,
|
||||||
|
contentDescription = stringResource(
|
||||||
|
id = R.string.details_view_button_description
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Button(onClick = { /*TODO*/ }, colors = lightAudioControlButtonColorScheme()) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.LiveTv,
|
||||||
|
contentDescription = stringResource(
|
||||||
|
id = R.string.fullscreen_button_description
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Button(onClick = { /*TODO*/ }, colors = lightAudioControlButtonColorScheme()) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.PictureInPicture,
|
||||||
|
contentDescription = stringResource(
|
||||||
|
id = R.string.pip_button_description
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Menu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Menu() {
|
||||||
|
var showMenu: Boolean by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Box {
|
||||||
|
IconButton(onClick = {
|
||||||
|
showMenu = true
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.MoreVert,
|
||||||
|
contentDescription = stringResource(R.string.menu_item_more_settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
|
||||||
|
DropdownMenuItem(text = { Text(stringResource(R.string.menu_item_playback_speed)) },
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Speed,
|
||||||
|
contentDescription = stringResource(R.string.menu_item_playback_speed)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = { /*TODO*/ showMenu = false })
|
||||||
|
DropdownMenuItem(text = { Text(stringResource(R.string.menu_item_language)) },
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Translate,
|
||||||
|
contentDescription = stringResource(R.string.menu_item_language)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = { /*TODO*/ showMenu = false })
|
||||||
|
DropdownMenuItem(text = { Text(stringResource(R.string.menu_item_share_timestamp)) },
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Share,
|
||||||
|
contentDescription = stringResource(R.string.menu_item_share_timestamp)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = { /*TODO*/ showMenu = false })
|
||||||
|
DropdownMenuItem(text = { Text(stringResource(R.string.menu_item_open_in_browser)) },
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Language,
|
||||||
|
contentDescription = stringResource(R.string.menu_item_open_in_browser)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = { /*TODO*/ showMenu = false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
@Preview(device = "id:pixel_6")
|
||||||
|
@Composable
|
||||||
|
fun AudioBottomUIPreview() {
|
||||||
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
AudioBottomUI(viewModel = NewPlayerViewModelDummy(), uiState = NewPlayerUIState.DUMMY)
|
||||||
|
}
|
||||||
|
}
|
|
@ -144,6 +144,7 @@ fun DropDownMenu(viewModel: NewPlayerViewModel, uiState: NewPlayerUIState) {
|
||||||
// Preview
|
// Preview
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Preview(device = "spec:width=1080px,height=1080px,dpi=440,orientation=landscape")
|
@Preview(device = "spec:width=1080px,height=1080px,dpi=440,orientation=landscape")
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoPlayerControllerDropDownPreview() {
|
fun VideoPlayerControllerDropDownPreview() {
|
||||||
|
|
|
@ -57,6 +57,7 @@ import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
||||||
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
import net.newpipe.newplayer.ui.theme.video_player_onSurface
|
||||||
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
import net.newpipe.newplayer.utils.getEmbeddedUiConfig
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun TopUI(
|
fun TopUI(
|
||||||
modifier: Modifier, viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
modifier: Modifier, viewModel: NewPlayerViewModel, uiState: NewPlayerUIState
|
||||||
|
|
|
@ -28,8 +28,9 @@
|
||||||
<string name="menu_item_fit_screen">Fit screen</string>
|
<string name="menu_item_fit_screen">Fit screen</string>
|
||||||
<string name="menu_item_sub_titles">Subtitles</string>
|
<string name="menu_item_sub_titles">Subtitles</string>
|
||||||
<string name="menu_item_language">Language</string>
|
<string name="menu_item_language">Language</string>
|
||||||
|
<string name="menu_item_playback_speed">Playback speed</string>
|
||||||
<string name="widget_description_previous_stream">Previous stream</string>
|
<string name="widget_description_previous_stream">Previous stream</string>
|
||||||
<string name="widget_description_next_stream">Previous stream</string>
|
<string name="widget_description_next_stream">Next stream</string>
|
||||||
<string name="widget_description_play">Play</string>
|
<string name="widget_description_play">Play</string>
|
||||||
<string name="widget_description_pause">Pause</string>
|
<string name="widget_description_pause">Pause</string>
|
||||||
<string name="widget_description_toggle_fullscreen">Toggle fullscreen</string>
|
<string name="widget_description_toggle_fullscreen">Toggle fullscreen</string>
|
||||||
|
@ -54,4 +55,7 @@
|
||||||
<string name="store_playlist">Save current playlist</string>
|
<string name="store_playlist">Save current playlist</string>
|
||||||
<string name="close">Close</string>
|
<string name="close">Close</string>
|
||||||
<string name="stream_thumbnail">Stream Thumbnail</string>
|
<string name="stream_thumbnail">Stream Thumbnail</string>
|
||||||
|
<string name="details_view_button_description">Switch to details view</string>
|
||||||
|
<string name="fullscreen_button_description">Switch to fullscreen video mode</string>
|
||||||
|
<string name="pip_button_description">Switch to picture in picture mode</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue