Tweak player UI

This commit is contained in:
vfsfitvnm 2022-07-27 17:11:35 +02:00
parent 4ec94589ca
commit f5a0c2fe09
4 changed files with 129 additions and 168 deletions

View file

@ -28,7 +28,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@ -50,8 +49,6 @@ import kotlinx.coroutines.launch
fun BottomSheet( fun BottomSheet(
state: BottomSheetState, state: BottomSheetState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
peekHeight: Dp = 0.dp,
elevation: Dp = 8.dp,
onDismiss: (() -> Unit)? = null, onDismiss: (() -> Unit)? = null,
collapsedContent: @Composable BoxScope.() -> Unit, collapsedContent: @Composable BoxScope.() -> Unit,
content: @Composable BoxScope.() -> Unit content: @Composable BoxScope.() -> Unit
@ -59,12 +56,11 @@ fun BottomSheet(
Box( Box(
modifier = modifier modifier = modifier
.offset { .offset {
val y = (state.expandedBound - state.value + peekHeight) val y = (state.expandedBound - state.value)
.roundToPx() .roundToPx()
.coerceAtLeast(0) .coerceAtLeast(0)
IntOffset(x = 0, y = y) IntOffset(x = 0, y = y)
} }
.shadow(elevation = elevation)
.pointerInput(state) { .pointerInput(state) {
var initialValue = 0.dp var initialValue = 0.dp
val velocityTracker = VelocityTracker() val velocityTracker = VelocityTracker()

View file

@ -8,6 +8,7 @@ data class ColorPalette(
val background: Color, val background: Color,
val elevatedBackground: Color, val elevatedBackground: Color,
val lightBackground: Color, val lightBackground: Color,
val backgroundContainer: Color,
val text: Color, val text: Color,
val textSecondary: Color, val textSecondary: Color,
val textDisabled: Color, val textDisabled: Color,
@ -32,6 +33,7 @@ val DarkColorPalette = ColorPalette(
background = Color(0xff16171d), background = Color(0xff16171d),
lightBackground = Color(0xff1f2029), lightBackground = Color(0xff1f2029),
elevatedBackground = Color(0xff1f2029), elevatedBackground = Color(0xff1f2029),
backgroundContainer = Color(0xff2b2d3b),
text = Color(0xffe1e1e2), text = Color(0xffe1e1e2),
textSecondary = Color(0xffa3a4a6), textSecondary = Color(0xffa3a4a6),
textDisabled = Color(0xff6f6f73), textDisabled = Color(0xff6f6f73),
@ -44,7 +46,6 @@ val DarkColorPalette = ColorPalette(
orange = Color(0xffe9a033), orange = Color(0xffe9a033),
magenta = Color(0xffbb4da4), magenta = Color(0xffbb4da4),
cyan = Color(0xFF4DA5BB), cyan = Color(0xFF4DA5BB),
primaryContainer = Color(0xff4046bf), primaryContainer = Color(0xff4046bf),
onPrimaryContainer = Color.White, onPrimaryContainer = Color.White,
iconOnPrimaryContainer = Color.White, iconOnPrimaryContainer = Color.White,
@ -55,12 +56,14 @@ val BlackColorPalette = DarkColorPalette.copy(
background = Color.Black, background = Color.Black,
lightBackground = Color(0xff0d0d12), lightBackground = Color(0xff0d0d12),
elevatedBackground = Color(0xff0d0d12), elevatedBackground = Color(0xff0d0d12),
backgroundContainer = Color(0xff0d0d12)
) )
val LightColorPalette = ColorPalette( val LightColorPalette = ColorPalette(
background = Color(0xfffdfdfe), background = Color(0xfffdfdfe),
lightBackground = Color(0xFFf8f8fc), lightBackground = Color(0xFFf8f8fc),
elevatedBackground = Color(0xfffdfdfe), elevatedBackground = Color(0xfffdfdfe),
backgroundContainer = Color(0xffeaeaf5),
lightGray = Color(0xfff8f8f8), lightGray = Color(0xfff8f8f8),
gray = Color(0xFFE5E5E5), gray = Color(0xFFE5E5E5),
darkGray = Color(0xFF838383), darkGray = Color(0xFF838383),
@ -73,12 +76,8 @@ val LightColorPalette = ColorPalette(
orange = Color(0xffe8730e), orange = Color(0xffe8730e),
magenta = Color(0xffbb4da4), magenta = Color(0xffbb4da4),
cyan = Color(0xFF4DBBB2), cyan = Color(0xFF4DBBB2),
primaryContainer = Color(0xff4046bf), primaryContainer = Color(0xff4046bf),
onPrimaryContainer = Color.White, onPrimaryContainer = Color.White,
iconOnPrimaryContainer = Color.White, iconOnPrimaryContainer = Color.White,
// primaryContainer = Color(0xffecedf9),
// onPrimaryContainer = Color(0xff121212),
// iconOnPrimaryContainer = Color(0xff2e30b8),
isDark = false isDark = false
) )

View file

@ -3,7 +3,6 @@ package it.vfsfitvnm.vimusic.ui.views
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -20,94 +19,32 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
@Composable @Composable
fun PlayerBottomSheet( fun PlayerBottomSheet(
layoutState: BottomSheetState, layoutState: BottomSheetState,
isShowingLyrics: Boolean,
onShowLyrics: () -> Unit,
isShowingStatsForNerds: Boolean,
onShowStatsForNerds: () -> Unit,
onShowMenu: () -> Unit,
onGlobalRouteEmitted: () -> Unit, onGlobalRouteEmitted: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit,
) { ) {
val (colorPalette) = LocalAppearance.current val (colorPalette) = LocalAppearance.current
BottomSheet( BottomSheet(
state = layoutState, state = layoutState,
elevation = 16.dp,
modifier = modifier, modifier = modifier,
collapsedContent = { collapsedContent = {
Row( Box(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxSize()
.background(colorPalette.background) .background(colorPalette.background)
.fillMaxSize()
) { ) {
Row(
modifier = Modifier
.padding(horizontal = 8.dp)
) {
Spacer(
modifier = Modifier
.padding(all = 8.dp)
.size(20.dp)
)
Spacer(
modifier = Modifier
.padding(all = 8.dp)
.size(20.dp)
)
Spacer(
modifier = Modifier
.padding(all = 8.dp)
.size(20.dp)
)
}
Image( Image(
painter = painterResource(R.drawable.chevron_up), painter = painterResource(R.drawable.chevron_up),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text), colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier modifier = Modifier
.align(Alignment.Center)
.padding(all = 8.dp) .padding(all = 8.dp)
.size(18.dp) .size(18.dp)
) )
Row( content()
modifier = Modifier
.padding(horizontal = 8.dp)
) {
Image(
painter = painterResource(R.drawable.text),
contentDescription = null,
colorFilter = ColorFilter.tint(if (isShowingLyrics) colorPalette.text else colorPalette.textDisabled),
modifier = Modifier
.clickable(onClick = onShowLyrics)
.padding(all = 8.dp)
.size(20.dp)
)
Image(
painter = painterResource(R.drawable.information),
contentDescription = null,
colorFilter = ColorFilter.tint(if (isShowingStatsForNerds) colorPalette.text else colorPalette.textDisabled),
modifier = Modifier
.clickable(onClick = onShowStatsForNerds)
.padding(all = 8.dp)
.size(20.dp)
)
Image(
painter = painterResource(R.drawable.ellipsis_horizontal),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.clickable(onClick = onShowMenu)
.padding(all = 8.dp)
.size(20.dp)
)
}
} }
} }
) { ) {

View file

@ -14,6 +14,7 @@ import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
@ -38,7 +39,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicText import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@ -162,10 +162,7 @@ fun PlayerView(
drawLine( drawLine(
color = colorPalette.text, color = colorPalette.text,
start = Offset( start = Offset(x = offset, y = 1.dp.toPx()),
x = offset,
y = 1.dp.toPx()
),
end = Offset( end = Offset(
x = ((size.width - offset) * progress) + offset, x = ((size.width - offset) * progress) + offset,
y = 1.dp.toPx() y = 1.dp.toPx()
@ -201,31 +198,26 @@ fun PlayerView(
) )
} }
if (shouldBePlaying) { Box(
Image( modifier = Modifier
painter = painterResource(R.drawable.pause), .clickable {
contentDescription = null, if (shouldBePlaying) {
colorFilter = ColorFilter.tint(colorPalette.text), binder.player.pause()
modifier = Modifier } else {
.clickable(onClick = binder.player::pause)
.padding(vertical = 8.dp)
.padding(horizontal = 16.dp)
.size(22.dp)
)
} else {
Image(
painter = painterResource(R.drawable.play),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.clickable {
if (binder.player.playbackState == Player.STATE_IDLE) { if (binder.player.playbackState == Player.STATE_IDLE) {
binder.player.prepare() binder.player.prepare()
} }
binder.player.play() binder.player.play()
} }
.padding(vertical = 8.dp) }
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) {
Image(
painter = painterResource(if (shouldBePlaying) R.drawable.pause else R.drawable.play),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.align(Alignment.Center)
.size(22.dp) .size(22.dp)
) )
} }
@ -316,70 +308,105 @@ fun PlayerView(
PlayerBottomSheet( PlayerBottomSheet(
layoutState = rememberBottomSheetState(64.dp, layoutState.expandedBound), layoutState = rememberBottomSheetState(64.dp, layoutState.expandedBound),
isShowingLyrics = isShowingLyrics, onGlobalRouteEmitted = layoutState::collapseSoft,
onShowLyrics = { content = {
isShowingStatsForNerds = false Row(
isShowingLyrics = !isShowingLyrics verticalAlignment = Alignment.CenterVertically,
}, horizontalArrangement = Arrangement.End,
isShowingStatsForNerds = isShowingStatsForNerds, modifier = Modifier
onShowStatsForNerds = { .align(Alignment.BottomEnd)
isShowingLyrics = false .padding(horizontal = 8.dp)
isShowingStatsForNerds = !isShowingStatsForNerds .fillMaxHeight()
}, ) {
onShowMenu = { Image(
menuState.display { painter = painterResource(R.drawable.text),
val resultRegistryOwner = LocalActivityResultRegistryOwner.current contentDescription = null,
colorFilter = ColorFilter.tint(if (isShowingLyrics) colorPalette.text else colorPalette.textDisabled),
modifier = Modifier
.clickable {
isShowingStatsForNerds = false
isShowingLyrics = !isShowingLyrics
}
.padding(all = 8.dp)
.size(20.dp)
)
BaseMediaItemMenu( Image(
mediaItem = mediaItem, painter = painterResource(R.drawable.information),
onStartRadio = { contentDescription = null,
binder.stopRadio() colorFilter = ColorFilter.tint(if (isShowingStatsForNerds) colorPalette.text else colorPalette.textDisabled),
binder.player.seamlessPlay(mediaItem) modifier = Modifier
binder.setupRadio( .clickable {
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId) isShowingLyrics = false
) isShowingStatsForNerds = !isShowingStatsForNerds
}, }
onGoToEqualizer = { .padding(all = 8.dp)
val intent = .size(20.dp)
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply { )
putExtra(
AudioEffect.EXTRA_AUDIO_SESSION, Image(
binder.player.audioSessionId painter = painterResource(R.drawable.ellipsis_horizontal),
) contentDescription = null,
putExtra( colorFilter = ColorFilter.tint(colorPalette.text),
AudioEffect.EXTRA_PACKAGE_NAME, modifier = Modifier
context.packageName .clickable {
) menuState.display {
putExtra( val resultRegistryOwner = LocalActivityResultRegistryOwner.current
AudioEffect.EXTRA_CONTENT_TYPE,
AudioEffect.CONTENT_TYPE_MUSIC BaseMediaItemMenu(
mediaItem = mediaItem,
onStartRadio = {
binder.stopRadio()
binder.player.seamlessPlay(mediaItem)
binder.setupRadio(
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
)
},
onGoToEqualizer = {
val intent =
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
putExtra(
AudioEffect.EXTRA_AUDIO_SESSION,
binder.player.audioSessionId
)
putExtra(
AudioEffect.EXTRA_PACKAGE_NAME,
context.packageName
)
putExtra(
AudioEffect.EXTRA_CONTENT_TYPE,
AudioEffect.CONTENT_TYPE_MUSIC
)
}
if (intent.resolveActivity(context.packageManager) != null) {
val contract =
ActivityResultContracts.StartActivityForResult()
resultRegistryOwner?.activityResultRegistry
?.register("", contract) {}
?.launch(intent)
} else {
Toast
.makeText(
context,
"No equalizer app found!",
Toast.LENGTH_SHORT
)
.show()
}
},
onSetSleepTimer = {},
onDismiss = menuState::hide,
onGlobalRouteEmitted = layoutState::collapseSoft,
) )
} }
if (intent.resolveActivity(context.packageManager) != null) {
val contract =
ActivityResultContracts.StartActivityForResult()
resultRegistryOwner?.activityResultRegistry
?.register("", contract) {}
?.launch(intent)
} else {
Toast
.makeText(
context,
"No equalizer app found!",
Toast.LENGTH_SHORT
)
.show()
} }
}, .padding(all = 8.dp)
onSetSleepTimer = {}, .size(20.dp)
onDismiss = menuState::hide,
onGlobalRouteEmitted = layoutState::collapseSoft,
) )
} }
}, },
onGlobalRouteEmitted = layoutState::collapseSoft,
modifier = Modifier modifier = Modifier
.align(Alignment.BottomCenter) .align(Alignment.BottomCenter)
) )
@ -900,6 +927,8 @@ private fun Controls(
Database.likedAt(mediaItem.mediaId).distinctUntilChanged() Database.likedAt(mediaItem.mediaId).distinctUntilChanged()
}.collectAsState(initial = null, context = Dispatchers.IO) }.collectAsState(initial = null, context = Dispatchers.IO)
val playPauseRoundness by animateDpAsState(if (shouldBePlaying) 32.dp else 16.dp)
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier modifier = modifier
@ -949,7 +978,7 @@ private fun Controls(
scrubbingPosition = null scrubbingPosition = null
}, },
color = colorPalette.text, color = colorPalette.text,
backgroundColor = colorPalette.textDisabled, backgroundColor = colorPalette.backgroundContainer,
shape = RoundedCornerShape(8.dp) shape = RoundedCornerShape(8.dp)
) )
@ -981,7 +1010,6 @@ private fun Controls(
} }
} }
Spacer( Spacer(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
@ -1009,7 +1037,7 @@ private fun Controls(
} }
} }
.weight(1f) .weight(1f)
.size(28.dp) .size(24.dp)
) )
Image( Image(
@ -1019,7 +1047,7 @@ private fun Controls(
modifier = Modifier modifier = Modifier
.clickable(onClick = binder.player::seekToPrevious) .clickable(onClick = binder.player::seekToPrevious)
.weight(1f) .weight(1f)
.size(28.dp) .size(24.dp)
) )
Spacer( Spacer(
@ -1029,6 +1057,7 @@ private fun Controls(
Box( Box(
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(playPauseRoundness))
.clickable { .clickable {
if (shouldBePlaying) { if (shouldBePlaying) {
binder.player.pause() binder.player.pause()
@ -1039,13 +1068,13 @@ private fun Controls(
binder.player.play() binder.player.play()
} }
} }
.background(color = colorPalette.text, shape = CircleShape) .background(color = colorPalette.backgroundContainer)
.size(64.dp) .size(64.dp)
) { ) {
Image( Image(
painter = painterResource(if (shouldBePlaying) R.drawable.pause else R.drawable.play), painter = painterResource(if (shouldBePlaying) R.drawable.pause else R.drawable.play),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.background), colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier modifier = Modifier
.align(Alignment.Center) .align(Alignment.Center)
.size(28.dp) .size(28.dp)
@ -1064,7 +1093,7 @@ private fun Controls(
modifier = Modifier modifier = Modifier
.clickable(onClick = binder.player::seekToNext) .clickable(onClick = binder.player::seekToNext)
.weight(1f) .weight(1f)
.size(28.dp) .size(24.dp)
) )
Image( Image(
@ -1093,7 +1122,7 @@ private fun Controls(
} }
} }
.weight(1f) .weight(1f)
.size(28.dp) .size(24.dp)
) )
} }