Skip to content

Commit

Permalink
Improvements and bug fixes
Browse files Browse the repository at this point in the history
1. Add fallback swatches
2. Better animation for background
  • Loading branch information
07jasjeet committed Jan 11, 2025
1 parent c0d5653 commit 89a669f
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 77 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.listenbrainz.android.ui.navigation

import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.BackdropScaffoldState
Expand Down Expand Up @@ -31,6 +32,7 @@ import org.listenbrainz.android.ui.theme.ListenBrainzTheme
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun BottomNavigationBar(
modifier: Modifier = Modifier,
navController: NavController = rememberNavController(),
backdropScaffoldState: BackdropScaffoldState = rememberBackdropScaffoldState(initialValue = BackdropValue.Revealed),
scrollToTop: () -> Unit,
Expand All @@ -43,6 +45,7 @@ fun BottomNavigationBar(
AppNavigationItem.Profile
)
BottomNavigation(
modifier = modifier,
backgroundColor = ListenBrainzTheme.colorScheme.nav,
elevation = 0.dp
) {
Expand All @@ -52,6 +55,7 @@ fun BottomNavigationBar(
val currentDestination = navBackStackEntry?.destination
val selected = currentDestination?.route?.startsWith("${item.route}/") == true || currentDestination?.route == item.route
BottomNavigationItem(
modifier = Modifier.navigationBarsPadding(),
icon = {
Icon(
painterResource(id = selected
Expand Down
37 changes: 25 additions & 12 deletions app/src/main/java/org/listenbrainz/android/ui/navigation/TopBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.material.TopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
Expand All @@ -27,9 +28,10 @@ import org.listenbrainz.android.ui.theme.ListenBrainzTheme

@Composable
fun TopBar(
modifier: Modifier = Modifier,
navController: NavController = rememberNavController(),
searchBarState: SearchBarState,
backgroundColor: Color=Color.Transparent,
backgroundColor: Color = Color.Transparent,
context: Context = LocalContext.current,
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
Expand All @@ -43,32 +45,43 @@ fun TopBar(
AppNavigationItem.Settings.route -> AppNavigationItem.Settings.title
AppNavigationItem.About.route -> AppNavigationItem.About.title
"${AppNavigationItem.Artist.route}/{mbid}" -> AppNavigationItem.Artist.title
"${AppNavigationItem.Album.route}/{mbid}" -> AppNavigationItem.Album.title
"${AppNavigationItem.Album.route}/{mbid}" -> AppNavigationItem.Album.title
else -> ""
}
} ?: "ListenBrainz"

TopAppBar(
modifier = modifier,
title = { Text(text = title) },
navigationIcon = {
navigationIcon = {
IconButton(onClick = {
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://listenbrainz.org")))
context.startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("https://listenbrainz.org")
)
)
}) {
Icon(painterResource(id = R.drawable.ic_listenbrainz_logo_icon),
Icon(
painterResource(id = R.drawable.ic_listenbrainz_logo_icon),
"ListenBrainz",
tint = Color.Unspecified)
tint = Color.Unspecified
)
}
},
backgroundColor =backgroundColor,
backgroundColor = backgroundColor,
contentColor = MaterialTheme.colorScheme.onSurface,
elevation = 0.dp,
actions = {
IconButton(onClick = { searchBarState.activate() }) {
Icon(painterResource(id = R.drawable.ic_search), contentDescription = "Search users")
Icon(
painterResource(id = R.drawable.ic_search),
contentDescription = "Search users"
)
}

IconButton(onClick = {
if (navBackStackEntry?.destination?.route == AppNavigationItem.Settings.route){
if (navBackStackEntry?.destination?.route == AppNavigationItem.Settings.route) {
navController.popBackStack()
} else {
navController.navigate(AppNavigationItem.Settings.route) {
Expand All @@ -83,11 +96,11 @@ fun TopBar(
}
}
}) {
Icon(painterResource(id = R.drawable.ic_settings),"Settings")
Icon(painterResource(id = R.drawable.ic_settings), "Settings")
}
}
)

}

@Preview
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
Expand Down Expand Up @@ -85,22 +84,17 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import kotlinx.coroutines.launch
import org.listenbrainz.android.R
import org.listenbrainz.android.application.App
import org.listenbrainz.android.model.PlayableType
import org.listenbrainz.android.model.Playlist.Companion.recentlyPlayed
import org.listenbrainz.android.model.RepeatMode
import org.listenbrainz.android.model.Song
import org.listenbrainz.android.model.feed.FeedListenArtist
import org.listenbrainz.android.ui.components.CustomSeekBar
import org.listenbrainz.android.ui.components.ListenCardSmall
import org.listenbrainz.android.ui.components.PlayPauseIcon
import org.listenbrainz.android.ui.components.SeekBar
import org.listenbrainz.android.ui.screens.brainzplayer.ui.components.basicMarquee
import org.listenbrainz.android.ui.theme.ListenBrainzTheme
import org.listenbrainz.android.ui.theme.onScreenUiModeIsDark
import org.listenbrainz.android.util.BrainzPlayerExtensions.toSong
import org.listenbrainz.android.util.CacheService
import org.listenbrainz.android.util.Constants.RECENTLY_PLAYED_KEY
import org.listenbrainz.android.util.SongViewPager
import org.listenbrainz.android.viewmodel.BrainzPlayerViewModel
import org.listenbrainz.android.viewmodel.PlaylistViewModel
Expand All @@ -110,6 +104,7 @@ import kotlin.math.max
@ExperimentalMaterialApi
@Composable
fun BrainzPlayerBackDropScreen(
modifier: Modifier = Modifier,
backdropScaffoldState: BackdropScaffoldState,
brainzPlayerViewModel: BrainzPlayerViewModel = viewModel(),
paddingValues: PaddingValues,
Expand All @@ -123,33 +118,33 @@ fun BrainzPlayerBackDropScreen(
}
val repeatMode by brainzPlayerViewModel.repeatMode.collectAsStateWithLifecycle()
val context = LocalContext.current
val defaultBackgroundColor = MaterialTheme.colorScheme.background
val defaultBackgroundColor = ListenBrainzTheme.colorScheme.background
val isDarkThemeEnabled = onScreenUiModeIsDark()

/** 56.dp is default bottom navigation height. 70.dp is our mini player's height. */
val headerHeight by animateDpAsState(targetValue = if (currentlyPlayingSong.title == "null" && currentlyPlayingSong.artist == "null") 56.dp else 126.dp)
val isPlaying = brainzPlayerViewModel.isPlaying.collectAsState().value
/** 56.dp is default bottom navigation height */
val headerHeight by animateDpAsState(
targetValue = if (currentlyPlayingSong.title == "null" && currentlyPlayingSong.artist == "null")
56.dp
else
56.dp + ListenBrainzTheme.sizes.brainzPlayerPeekHeight
)
LaunchedEffect(currentlyPlayingSong, isDarkThemeEnabled) {
brainzPlayerViewModel.getBackGroundColorForPlayer(
brainzPlayerViewModel.updateBackgroundColorForPlayer(
currentlyPlayingSong.albumArt,
defaultBackgroundColor,
context,
isDarkThemeEnabled = isDarkThemeEnabled
)
}
BackdropScaffold(
modifier = Modifier.padding(top = paddingValues.calculateTopPadding()),
modifier = modifier.padding(top = paddingValues.calculateTopPadding()),
frontLayerShape = RectangleShape,
backLayerBackgroundColor = MaterialTheme.colorScheme.background,
backLayerBackgroundColor = Color.Transparent,
frontLayerScrimColor = Color.Unspecified,
headerHeight = headerHeight, // 126.dp is optimal header height.
peekHeight = 0.dp,
scaffoldState = backdropScaffoldState,
backLayerContent = {
Surface(modifier = Modifier.fillMaxSize(), color = Color.Transparent) {
backLayerContent()
}
},
backLayerContent = backLayerContent,
frontLayerBackgroundColor = defaultBackgroundColor,
appBar = {},
persistentAppBar = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.captionBar
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.BackdropValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Surface
import androidx.compose.material.rememberBackdropScaffoldState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
Expand All @@ -22,13 +26,16 @@ import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
Expand All @@ -52,6 +59,7 @@ import org.listenbrainz.android.ui.screens.search.rememberSearchBarState
import org.listenbrainz.android.ui.theme.ListenBrainzTheme
import org.listenbrainz.android.util.Utils.isServiceRunning
import org.listenbrainz.android.util.Utils.openAppSystemSettings
import org.listenbrainz.android.util.Utils.toPx
import org.listenbrainz.android.viewmodel.BrainzPlayerViewModel
import org.listenbrainz.android.viewmodel.DashBoardViewModel

Expand Down Expand Up @@ -164,16 +172,52 @@ class MainActivity : ComponentActivity() {
val currentDestination = navBackStackEntry?.destination
val username = dashBoardViewModel.username
val brainzPlayerViewModel: BrainzPlayerViewModel by viewModels()

val isBackdropInitialised by remember {
derivedStateOf {
val currentOffset = runCatching {
backdropScaffoldState.requireOffset()
}.getOrNull()

currentOffset != null
}
}

var maxOffset by remember {
mutableFloatStateOf(0f)
}

val playerHeight = ListenBrainzTheme.sizes.brainzPlayerPeekHeight.toPx()
LaunchedEffect(isBackdropInitialised) {
if (isBackdropInitialised) {
maxOffset = maxOf(maxOffset, backdropScaffoldState.requireOffset() - playerHeight)
println(maxOffset)
}
}

val desiredBackgroundColor by remember {
derivedStateOf {
brainzPlayerViewModel.playerBackGroundColor.copy(
alpha = runCatching {
1 - (backdropScaffoldState.requireOffset() / maxOffset).coerceIn(0f, 1f)
}.getOrElse { 0f }
)
}
}

Scaffold(
modifier = Modifier.safeDrawingPadding(),
modifier = Modifier
.fillMaxSize()
.background(ListenBrainzTheme.colorScheme.background)
.background(desiredBackgroundColor),
topBar = {
TopBar(
modifier = Modifier.statusBarsPadding(),
navController = navController,
searchBarState = when (currentDestination?.route) {
AppNavigationItem.BrainzPlayer.route -> brainzplayerSearchBarState
else -> searchBarState
},
backgroundColor = if (backdropScaffoldState.isConcealed) brainzPlayerViewModel.playerBackGroundColor else Color.Transparent
)
},
bottomBar = {
Expand All @@ -185,7 +229,10 @@ class MainActivity : ComponentActivity() {
)
},
snackbarHost = {
SnackbarHost(hostState = snackbarState) { snackbarData ->
SnackbarHost(
modifier = Modifier.safeDrawingPadding(),
hostState = snackbarState
) { snackbarData ->
Snackbar(
snackbarData = snackbarData,
containerColor = MaterialTheme.colorScheme.background,
Expand All @@ -195,14 +242,12 @@ class MainActivity : ComponentActivity() {
)
}
},
containerColor = MaterialTheme.colorScheme.background,
containerColor = Color.Transparent,
contentWindowInsets = WindowInsets.captionBar

) {

if (isGrantedPerms == PermissionStatus.GRANTED.name) {

BrainzPlayerBackDropScreen(
modifier = Modifier.navigationBarsPadding(),
backdropScaffoldState = backdropScaffoldState,
paddingValues = it,
brainzPlayerViewModel = brainzPlayerViewModel
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/org/listenbrainz/android/ui/theme/Theme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ val LocalPaddings = staticCompositionLocalOf { Paddings() }
data class Sizes(
val listenCardHeight: Dp = 60.dp,
val listenCardCorner: Dp = 8.dp,
val dropdownItem: Dp = 20.dp
val dropdownItem: Dp = 20.dp,
val brainzPlayerPeekHeight: Dp = 70.dp
)

val LocalSizes = staticCompositionLocalOf { Sizes() }
Expand Down Expand Up @@ -343,15 +344,13 @@ fun ListenBrainzTheme(
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
(view.context as Activity).window.statusBarColor = localColorScheme.background.toArgb()
val isDark = when (uiMode){
UiMode.DARK -> false
UiMode.LIGHT -> true
UiMode.FOLLOW_SYSTEM -> !systemTheme
}
systemUiController.statusBarDarkContentEnabled = isDark
systemUiController.navigationBarDarkContentEnabled = isDark
systemUiController.setNavigationBarColor(color = colorScheme.tertiaryContainer)
}
}

Expand Down
Loading

0 comments on commit 89a669f

Please sign in to comment.