mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-12 00:32:26 +01:00
With the player beside the map, like, shuffle, repeat and lyrics move into the nav bar
The nav bar's pill carries them while the player is docked, with its dock button in the same place to close it, so the player itself is just the cover, the song and play/skip. The player's own close button, which sat over the corner of the cover, is gone.
This commit is contained in:
1 parent
fa33e7c650
commit
4aeaaee875
3 files changed
+50
-24
No files matched your search
@@ -275,31 +275,15 @@ private fun DockedPlayer(now: NowPlaying, modifier: Modifier) {
|
||||
// Sized from the column's width rather than fixed: fixed sizes filled a narrow
|
||||
// column edge to edge, so the buttons sat squeezed against each other. Each row
|
||||
// keeps a clear gap between buttons, and none grows past a comfortable size.
|
||||
// Like, shuffle, repeat and lyrics are in the nav bar's pill while the player is
|
||||
// here (NavNowPlaying), which leaves the cover more room.
|
||||
BoxWithConstraints(Modifier.fillMaxWidth()) {
|
||||
val w = maxWidth
|
||||
// Two skips, play at 1.25 times a skip, and two gaps of at least 20dp.
|
||||
val skip = ((w - 40.dp) / 3.25f).coerceIn(36.dp, 48.dp)
|
||||
// Four buttons and three gaps of at least 12dp.
|
||||
val mode = ((w - 36.dp) / 4).coerceIn(34.dp, 42.dp)
|
||||
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
TransportRow(now, media, skip = skip, modifier = Modifier.fillMaxWidth())
|
||||
Spacer(Modifier.height(10.dp))
|
||||
PlayModeRow(now, media, size = mode, modifier = Modifier.fillMaxWidth()) {
|
||||
GsIconButton(
|
||||
ImageVector.vectorResource(R.drawable.lyrics_24), stringResource(R.string.storage_lyrics), navigator::showSideLyrics,
|
||||
size = mode, iconSize = mode * 0.52f,
|
||||
)
|
||||
}
|
||||
}
|
||||
val skip = ((maxWidth - 40.dp) / 3.25f).coerceIn(36.dp, 48.dp)
|
||||
TransportRow(now, media, skip = skip, modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp))
|
||||
}
|
||||
}
|
||||
// Round like the player's other buttons, and tucked into the card's corner so it
|
||||
// covers as little of the cover as it can.
|
||||
GsIconButton(
|
||||
Icons.Filled.Close, stringResource(R.string.home_back_nav), navigator::closeSidePanel,
|
||||
Modifier.align(Alignment.TopEnd).offset(x = 6.dp, y = (-6).dp), size = 32.dp, iconSize = 18.dp,
|
||||
shape = CircleShape,
|
||||
)
|
||||
// No close button here: the nav bar's dock button closes the player (NavNowPlaying).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,8 +556,13 @@ private fun NavNowPlaying(navigator: CarNavigator, selected: Boolean, modifier:
|
||||
val phase by media.phase.collectAsState()
|
||||
val now by media.now.collectAsState()
|
||||
if (phase != CarMedia.Phase.READY || !now.isActive) return
|
||||
// Docked beside the map, the player is already on screen - the pill steps aside for it.
|
||||
if (navigator.sidePanel == SidePanel.CONTROLS && navigator.current == CarScreen.Home) return
|
||||
// Docked beside the map, the player is already on screen, so the pill carries what the
|
||||
// player leaves out - like, shuffle, repeat and lyrics - and its dock button, filled in, in
|
||||
// the same place: tapped again, it closes the player.
|
||||
if (navigator.sidePanel == SidePanel.CONTROLS && navigator.current == CarScreen.Home) {
|
||||
DockedPill(navigator, now, selected, modifier)
|
||||
return
|
||||
}
|
||||
// The media screen is the full player already; the pill would only repeat its controls.
|
||||
if (navigator.current == CarScreen.Media) return
|
||||
val context = LocalContext.current
|
||||
@@ -670,6 +675,42 @@ private fun NavNowPlaying(navigator: CarNavigator, selected: Boolean, modifier:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The pill while the player is docked: like, shuffle, repeat and lyrics, then the dock button,
|
||||
* shown open, which closes it. Sits on the player's side of the bar, under the player.
|
||||
*/
|
||||
@Composable
|
||||
private fun DockedPill(navigator: CarNavigator, now: app.seb3thehacker.gearslip.media.NowPlaying, selected: Boolean, modifier: Modifier) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
val playerLeft by CarSettings.playerLeft.collectAsState()
|
||||
Box(modifier.fillMaxWidth(), contentAlignment = if (playerLeft) Alignment.CenterStart else Alignment.CenterEnd) {
|
||||
Surface(
|
||||
modifier = Modifier.height(44.dp),
|
||||
shape = RoundedCornerShape(14.dp),
|
||||
color = if (selected) scheme.primaryContainer else scheme.secondaryContainer,
|
||||
contentColor = if (selected) scheme.onPrimaryContainer else scheme.onSecondaryContainer,
|
||||
) {
|
||||
PlayModeRow(
|
||||
now, CarServices.media, size = 36.dp,
|
||||
modifier = Modifier.fillMaxHeight().padding(horizontal = 4.dp),
|
||||
arrangement = Arrangement.spacedBy(6.dp),
|
||||
) {
|
||||
GsIconButton(
|
||||
androidx.compose.ui.graphics.vector.ImageVector.vectorResource(R.drawable.lyrics_24),
|
||||
stringResource(R.string.storage_lyrics), navigator::showSideLyrics,
|
||||
size = 36.dp, iconSize = 20.dp,
|
||||
)
|
||||
GsIconButton(
|
||||
if (playerLeft) MediaIcons.DockLeftOpen else MediaIcons.DockRightOpen,
|
||||
stringResource(R.string.navbar_close_panel),
|
||||
navigator::togglePlayerDock,
|
||||
size = 36.dp, iconSize = 22.dp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A filled lightning bolt, next to the battery percentage instead of the word "charging" - the
|
||||
* core Material icon set this project ships (no extended pack, to keep the app small) has no
|
||||
|
||||
@@ -130,6 +130,7 @@ internal fun PlayModeRow(
|
||||
size: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
maxOther: Int = 0,
|
||||
arrangement: Arrangement.Horizontal = Arrangement.SpaceEvenly,
|
||||
trailing: @Composable RowScope.() -> Unit = {},
|
||||
) {
|
||||
val modes by media.modes.collectAsState()
|
||||
@@ -139,7 +140,7 @@ internal fun PlayModeRow(
|
||||
val shuffleOn = shuffleKnown && modes.shuffle != PlaybackStateCompat.SHUFFLE_MODE_NONE
|
||||
val repeatOn = repeatKnown && modes.repeat != PlaybackStateCompat.REPEAT_MODE_NONE
|
||||
val icon = size * 0.52f
|
||||
Row(modifier, horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(modifier, horizontalArrangement = arrangement, verticalAlignment = Alignment.CenterVertically) {
|
||||
// An app's own like, shuffle or repeat button shows whether it's on only through its icon,
|
||||
// so that icon is drawn, as Android Auto does, and lit when its name says it's on.
|
||||
// Gearslip's own stand in for apps that report a heart rating or shuffle and repeat modes.
|
||||
|
||||
Reference in new issue
Block a user