Skip to content

Commit

Permalink
Merge pull request #520 from GautamCoder4019k/dynamic_player_background
Browse files Browse the repository at this point in the history
feat: Made the player screen background dynamic
  • Loading branch information
07jasjeet authored Jan 11, 2025
2 parents 99791fc + 89a669f commit d44ae75
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 54 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
36 changes: 25 additions & 11 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,8 +28,10 @@ import org.listenbrainz.android.ui.theme.ListenBrainzTheme

@Composable
fun TopBar(
modifier: Modifier = Modifier,
navController: NavController = rememberNavController(),
searchBarState: SearchBarState,
backgroundColor: Color = Color.Transparent,
context: Context = LocalContext.current,
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
Expand All @@ -42,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 = Color.Transparent,
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 @@ -82,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 @@ -63,10 +63,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
Expand All @@ -82,21 +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 @@ -106,6 +104,7 @@ import kotlin.math.max
@ExperimentalMaterialApi
@Composable
fun BrainzPlayerBackDropScreen(
modifier: Modifier = Modifier,
backdropScaffoldState: BackdropScaffoldState,
brainzPlayerViewModel: BrainzPlayerViewModel = viewModel(),
paddingValues: PaddingValues,
Expand All @@ -118,25 +117,35 @@ fun BrainzPlayerBackDropScreen(
mutableFloatStateOf(0F)
}
val repeatMode by brainzPlayerViewModel.repeatMode.collectAsStateWithLifecycle()
val context = LocalContext.current
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.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()
}
},
frontLayerBackgroundColor = MaterialTheme.colorScheme.background,
backLayerContent = backLayerContent,
frontLayerBackgroundColor = defaultBackgroundColor,
appBar = {},
persistentAppBar = false,
frontLayerContent = {
Expand All @@ -149,7 +158,14 @@ fun BrainzPlayerBackDropScreen(
currentlyPlayingSong = currentlyPlayingSong,
isShuffled = isShuffled,
repeatMode = repeatMode,
backdropScaffoldState = backdropScaffoldState
backdropScaffoldState = backdropScaffoldState,
backgroundBrush = Brush.verticalGradient(
colors = listOf(
brainzPlayerViewModel.playerBackGroundColor,
defaultBackgroundColor
)
),
dynamicBackground = brainzPlayerViewModel.playerBackGroundColor
)
val songList = brainzPlayerViewModel.mediaItem.collectAsState().value.data ?: listOf()
SongViewPager(
Expand All @@ -172,6 +188,8 @@ fun PlayerScreen(
isShuffled: Boolean,
repeatMode: RepeatMode,
backdropScaffoldState: BackdropScaffoldState,
backgroundBrush: Brush,
dynamicBackground: Color = MaterialTheme.colorScheme.background
) {
val coroutineScope = rememberCoroutineScope()
val playlistViewModel = hiltViewModel<PlaylistViewModel>()
Expand All @@ -189,17 +207,17 @@ fun PlayerScreen(
println("Playlist is empty")
}

if(backdropScaffoldState.isConcealed){
if (backdropScaffoldState.isConcealed) {
BackHandler {
coroutineScope.launch {
backdropScaffoldState.reveal()
}
}
}
LazyColumn {
LazyColumn(modifier = Modifier.background(brush = backgroundBrush)) {
item {
songList.data?.let {
AlbumArtViewPager(currentlyPlayingSong, pagerState)
AlbumArtViewPager(currentlyPlayingSong, pagerState, dynamicBackground)
}
}
item {
Expand Down Expand Up @@ -539,12 +557,15 @@ fun PlayerScreen(

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AlbumArtViewPager(currentlyPlayingSong: Song, pagerState: PagerState) {
fun AlbumArtViewPager(
currentlyPlayingSong: Song,
pagerState: PagerState,
dynamicBackground: Color
) {
HorizontalPager(
state = pagerState,
modifier = Modifier
.fillMaxWidth()
.background(ListenBrainzTheme.colorScheme.background),
) { page ->
Column(
Modifier
Expand All @@ -556,7 +577,7 @@ fun AlbumArtViewPager(currentlyPlayingSong: Song, pagerState: PagerState) {
.padding(top = 20.dp)
.width(300.dp)
.clip(RoundedCornerShape(20.dp))
.background(MaterialTheme.colorScheme.background)
.background(dynamicBackground)
.graphicsLayer {
// Calculate the absolute offset for the current page from the
// scroll position. We use the absolute value which allows us to mirror
Expand All @@ -583,7 +604,7 @@ fun AlbumArtViewPager(currentlyPlayingSong: Song, pagerState: PagerState) {
) {
AsyncImage(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.background(dynamicBackground)
.fillMaxSize()
.padding()
.clip(shape = RoundedCornerShape(20.dp))
Expand All @@ -607,7 +628,8 @@ fun AlbumArtViewPager(currentlyPlayingSong: Song, pagerState: PagerState) {
fun AlbumArtViewPagerPreview() {
AlbumArtViewPager(
currentlyPlayingSong = Song.preview(),
pagerState = rememberPagerState { 3 }
pagerState = rememberPagerState { 3 },
dynamicBackground = MaterialTheme.colorScheme.background
)
}

Expand Down
Loading

0 comments on commit d44ae75

Please sign in to comment.