diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0aa0a03a..16016441 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -136,6 +136,7 @@ dependencies { implementation(libs.androidx.work.runtime.ktx) implementation(libs.androidx.paging.runtime) implementation(libs.androidx.paging.compose) + implementation(libs.androidx.palette.ktx) //Room DB implementation(libs.androidx.room.runtime) diff --git a/app/src/main/java/org/listenbrainz/android/ui/components/SeekBar.kt b/app/src/main/java/org/listenbrainz/android/ui/components/SeekBar.kt index 03b76c92..4eda2546 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/components/SeekBar.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/components/SeekBar.kt @@ -1,11 +1,24 @@ package org.listenbrainz.android.ui.components import androidx.annotation.FloatRange +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.material.Slider import androidx.compose.material.SliderDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.res.colorResource +import androidx.compose.ui.semantics.ProgressBarRangeInfo +import androidx.compose.ui.semantics.progressBarRangeInfo +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp import org.listenbrainz.android.R @Composable @@ -25,6 +38,61 @@ fun SeekBar( thumbColor = colorResource(id = R.color.app_bg), activeTrackColor = colorResource(id = R.color.bp_color_primary) ) - ) -} \ No newline at end of file +} + +@Composable +fun CustomSeekBar( + modifier: Modifier = Modifier, + @FloatRange(from = 0.0, to = 1.0) + progress: Float, + onValueChange: (Float) -> Unit, + remainingProgressColor: Color = Color.Transparent +) { + val range = 0f..1f + + Box( + modifier = modifier + .fillMaxWidth() + .semantics(mergeDescendants = true) { + progressBarRangeInfo = ProgressBarRangeInfo(progress, range) + } + .pointerInput(Unit) { + detectDragGestures( + onDragStart = { offset -> + val width = size.width.toFloat() + val newProgress = (offset.x / width).coerceIn(range) + onValueChange(newProgress) + }, + onDrag = { change, _ -> + val width = size.width.toFloat() + val newProgress = (change.position.x / width).coerceIn(range) + onValueChange(newProgress) + } + ) + } + .pointerInput(Unit) { + detectTapGestures { offset -> + val width = size.width.toFloat() + val newProgress = (offset.x / width).coerceIn(range) + onValueChange(newProgress) + } + } + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(4.dp) + .graphicsLayer { + alpha = 0.2f + } + .background(remainingProgressColor) + ) + Box( + modifier = Modifier + .fillMaxWidth(progress) + .height(4.dp) + .background(colorResource(id = R.color.bp_color_primary)) + ) + } +} diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerBackDropScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerBackDropScreen.kt index e9612c85..16545cdd 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerBackDropScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerBackDropScreen.kt @@ -67,6 +67,7 @@ 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.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -76,6 +77,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.util.lerp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage import kotlinx.coroutines.launch @@ -86,6 +88,7 @@ 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 @@ -108,16 +111,16 @@ fun BrainzPlayerBackDropScreen( paddingValues: PaddingValues, backLayerContent: @Composable () -> Unit ) { - val isShuffled by brainzPlayerViewModel.isShuffled.collectAsState() + val isShuffled by brainzPlayerViewModel.isShuffled.collectAsStateWithLifecycle() val currentlyPlayingSong = - brainzPlayerViewModel.currentlyPlayingSong.collectAsState().value.toSong + brainzPlayerViewModel.currentlyPlayingSong.collectAsStateWithLifecycle().value.toSong var maxDelta by rememberSaveable { mutableFloatStateOf(0F) } - val repeatMode by brainzPlayerViewModel.repeatMode.collectAsState() + val repeatMode by brainzPlayerViewModel.repeatMode.collectAsStateWithLifecycle() - /** 56.dp is default bottom navigation height. 80.dp is our mini player's height. */ - val headerHeight by animateDpAsState(targetValue = if (currentlyPlayingSong.title == "null" && currentlyPlayingSong.artist == "null") 56.dp else 136.dp) + /** 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 BackdropScaffold( @@ -125,7 +128,7 @@ fun BrainzPlayerBackDropScreen( frontLayerShape = RectangleShape, backLayerBackgroundColor = MaterialTheme.colorScheme.background, frontLayerScrimColor = Color.Unspecified, - headerHeight = if (isPlaying) headerHeight else 56.dp, // 136.dp is optimal header height. + headerHeight = headerHeight, // 126.dp is optimal header height. peekHeight = 0.dp, scaffoldState = backdropScaffoldState, backLayerContent = { @@ -257,14 +260,17 @@ fun PlayerScreen( item { Box { val progress by brainzPlayerViewModel.progress.collectAsState() - SeekBar( + CustomSeekBar( modifier = Modifier .height(10.dp) .fillMaxWidth(0.98F) .padding(horizontal = 20.dp), progress = progress, - onValueChange = brainzPlayerViewModel::onSeek, - onValueChanged = brainzPlayerViewModel::onSeeked + onValueChange = { newProgress -> + brainzPlayerViewModel.onSeek(newProgress) + brainzPlayerViewModel.onSeeked() + }, + remainingProgressColor = colorResource(id = R.color.bp_color_primary) ) } Row( @@ -457,8 +463,7 @@ fun PlayerScreen( ) { index, song -> val isChecked = checkedSongs.contains(song) BoxWithConstraints { - val maxWidth = - (maxWidth - 70.dp) + val maxWidth = (this@BoxWithConstraints.maxWidth - 70.dp) Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, @@ -530,14 +535,6 @@ fun PlayerScreen( Spacer(modifier = Modifier.height(56.dp)) } } - - // TODO: fix this - val cache = App.context?.let { CacheService(it, RECENTLY_PLAYED_KEY) } - cache?.saveData(currentlyPlayingSong, Song::class.java) - val data = cache?.getData(Song::class.java) - if (data != null) { - recentlyPlayed.items = data.filter { it.title != "null" }.toList().reversed() - } } @OptIn(ExperimentalFoundationApi::class) @@ -624,3 +621,4 @@ fun BrainzPlayerBackDropScreenPreview() { ) {} } + diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerScreen.kt index d0bef744..03716d8b 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/BrainzPlayerScreen.kt @@ -80,8 +80,7 @@ fun BrainzPlayerScreen() { topAlbums.add(Album()) Column( - modifier = Modifier - .fillMaxSize() + modifier = Modifier.fillMaxSize() ) { Navigation(albums = albums, previewAlbums = topAlbums, artists = artists, previewArtists = topArtists, playlists, songsPlayedToday, songsPlayedThisWeek ,topRecents ,songs, albumSongsMap) } @@ -108,7 +107,8 @@ fun BrainzPlayerHomeScreen( brainzPlayerViewModel.currentlyPlayingSong.collectAsState().value.toSong val isPlaying = brainzPlayerViewModel.isPlaying Column { - Row(modifier = Modifier + Row( + modifier = Modifier .fillMaxWidth() .horizontalScroll(rememberScrollState()) .background( @@ -118,7 +118,8 @@ fun BrainzPlayerHomeScreen( Color.Transparent ) ) - )) { + ) + ) { Spacer(modifier = Modifier.width(ListenBrainzTheme.paddings.chipsHorizontal / 2)) repeat(5) { position -> ElevatedSuggestionChip( diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/OverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/OverviewScreen.kt index 2dd16a61..d3d1b732 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/OverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/OverviewScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -33,34 +34,52 @@ import org.listenbrainz.android.ui.theme.ListenBrainzTheme import org.listenbrainz.android.viewmodel.BrainzPlayerViewModel @Composable -fun OverviewScreen ( +fun OverviewScreen( songsPlayedToday: List, goToRecentScreen: () -> Unit, goToArtistScreen: () -> Unit, goToAlbumScreen: () -> Unit, recentlyPlayedSongs: List, brainzPlayerViewModel: BrainzPlayerViewModel = hiltViewModel(), - artists : List, + artists: List, albums: List ) { - Column (modifier = Modifier.verticalScroll(rememberScrollState())) { - RecentlyPlayedOverview(recentlyPlayedSongs = recentlyPlayedSongs, goToRecentScreen = goToRecentScreen ,brainzPlayerViewModel = brainzPlayerViewModel) - ArtistsOverview(artists = artists, goToArtistScreen = goToArtistScreen) - AlbumsOverview(albums = albums, goToAlbumScreen = goToAlbumScreen) + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + ) { + RecentlyPlayedOverview( + modifier = Modifier.fillMaxWidth(), + recentlyPlayedSongs = recentlyPlayedSongs, + goToRecentScreen = goToRecentScreen, + brainzPlayerViewModel = brainzPlayerViewModel + ) + ArtistsOverview( + modifier = Modifier.fillMaxWidth(), + artists = artists, + goToArtistScreen = goToArtistScreen + ) + AlbumsOverview( + modifier = Modifier.fillMaxWidth(), + albums = albums, + goToAlbumScreen = goToAlbumScreen + ) } - - } @Composable private fun RecentlyPlayedOverview( + modifier: Modifier = Modifier, recentlyPlayedSongs: List, - brainzPlayerViewModel : BrainzPlayerViewModel, - goToRecentScreen : () -> Unit + brainzPlayerViewModel: BrainzPlayerViewModel, + goToRecentScreen: () -> Unit ) { - Column(modifier = Modifier.background( - brush = ListenBrainzTheme.colorScheme.gradientBrush - ).padding(top = 15.dp, bottom = 15.dp)) { + Column( + modifier = modifier + .background(brush = ListenBrainzTheme.colorScheme.gradientBrush) + .padding(top = 15.dp, bottom = 15.dp) + ) { Text( "Recently Played", style = TextStyle( fontSize = 24.sp, @@ -101,7 +120,9 @@ private fun RecentlyPlayedOverview( } ) { Column( - modifier = Modifier.fillMaxSize().background(ListenBrainzTheme.colorScheme.placeHolderColor) + modifier = Modifier + .fillMaxSize() + .background(ListenBrainzTheme.colorScheme.placeHolderColor) .padding(start = 5.dp, bottom = 20.dp), verticalArrangement = Arrangement.Bottom ) { @@ -120,12 +141,17 @@ private fun RecentlyPlayedOverview( @Composable private fun ArtistsOverview( - artists : List, - goToArtistScreen : () -> Unit + modifier: Modifier = Modifier, + artists: List, + goToArtistScreen: () -> Unit ) { - Column(modifier = Modifier.background( - brush = ListenBrainzTheme.colorScheme.gradientBrush - ).padding(top = 15.dp, bottom = 15.dp)) { + Column( + modifier = modifier + .background( + brush = ListenBrainzTheme.colorScheme.gradientBrush + ) + .padding(top = 15.dp, bottom = 15.dp) + ) { Text( "Artists", style = TextStyle( fontSize = 24.sp, @@ -156,7 +182,9 @@ private fun ArtistsOverview( } ) { Column( - modifier = Modifier.fillMaxSize().background(ListenBrainzTheme.colorScheme.placeHolderColor) + modifier = Modifier + .fillMaxSize() + .background(ListenBrainzTheme.colorScheme.placeHolderColor) .padding(start = 5.dp, bottom = 20.dp), verticalArrangement = Arrangement.Bottom ) { @@ -168,7 +196,6 @@ private fun ArtistsOverview( } } } - } } } @@ -176,30 +203,35 @@ private fun ArtistsOverview( @Composable private fun AlbumsOverview( + modifier: Modifier = Modifier, albums: List, goToAlbumScreen: () -> Unit -){ - Column(modifier = Modifier.background( - brush = ListenBrainzTheme.colorScheme.gradientBrush - ).padding(top = 15.dp, bottom = 15.dp)){ - Text("Albums" , style = TextStyle( - fontSize = 24.sp, - fontWeight = FontWeight.Bold, - color = ListenBrainzTheme.colorScheme.lbSignature - ) , modifier = Modifier.padding(start = 17.dp)) +) { + Column( + modifier = modifier + .background(brush = ListenBrainzTheme.colorScheme.gradientBrush) + .padding(top = 15.dp, bottom = 15.dp) + ) { + Text( + "Albums", style = TextStyle( + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + color = ListenBrainzTheme.colorScheme.lbSignature + ), modifier = Modifier.padding(start = 17.dp) + ) LazyRow( modifier = Modifier - .height(250.dp)){ - items(items = albums) { - album -> - if(album.title != ""){ - BrainzPlayerActivityCards(icon = album.albumArt, + .height(250.dp) + ) { + items(items = albums) { album -> + if (album.title != "") { + BrainzPlayerActivityCards( + icon = album.albumArt, errorIcon = R.drawable.ic_album, title = album.artist, subtitle = album.title, ) - } - else{ + } else { Box( modifier = Modifier .padding(10.dp) @@ -208,13 +240,22 @@ private fun AlbumsOverview( .clickable { goToAlbumScreen() } - ){ - Column (modifier = Modifier.fillMaxSize().background(ListenBrainzTheme.colorScheme.placeHolderColor).padding(start = 5.dp , bottom = 20.dp) , verticalArrangement = Arrangement.Bottom) { - Text(" All \n Albums" , style = TextStyle(fontSize = 20.sp) , color = ListenBrainzTheme.colorScheme.lbSignature) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .background(ListenBrainzTheme.colorScheme.placeHolderColor) + .padding(start = 5.dp, bottom = 20.dp), + verticalArrangement = Arrangement.Bottom + ) { + Text( + " All \n Albums", + style = TextStyle(fontSize = 20.sp), + color = ListenBrainzTheme.colorScheme.lbSignature + ) } } } - } } } diff --git a/app/src/main/java/org/listenbrainz/android/util/SongViewPager.kt b/app/src/main/java/org/listenbrainz/android/util/SongViewPager.kt index 610e524b..bc1e25d0 100644 --- a/app/src/main/java/org/listenbrainz/android/util/SongViewPager.kt +++ b/app/src/main/java/org/listenbrainz/android/util/SongViewPager.kt @@ -1,5 +1,7 @@ package org.listenbrainz.android.util +import android.graphics.drawable.BitmapDrawable +import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -29,14 +31,23 @@ import androidx.compose.material.icons.rounded.SkipPrevious import androidx.compose.material.rememberBackdropScaffoldState import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -44,13 +55,18 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.palette.graphics.Palette +import coil.ImageLoader import coil.compose.AsyncImage +import coil.request.ImageRequest +import coil.request.SuccessResult import kotlinx.coroutines.launch import org.listenbrainz.android.R import org.listenbrainz.android.model.Song +import org.listenbrainz.android.ui.components.CustomSeekBar 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.viewmodel.BrainzPlayerViewModel @OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) @@ -62,12 +78,28 @@ fun SongViewPager( songList: List, viewModel: BrainzPlayerViewModel = hiltViewModel() ) { + if (songList.isEmpty()) + return + val coroutineScope = rememberCoroutineScope() - val pagerState: PagerState = rememberPagerState { songList.size } - - HorizontalPager(state = pagerState, modifier = modifier - .fillMaxWidth() - .background(MaterialTheme.colorScheme.tertiaryContainer) + val pagerState: PagerState = rememberPagerState( + initialPage = songList + .indexOfFirst { it.mediaID == currentlyPlayingSong.mediaID } + .takeIf { it != -1 } ?: 0 + ) { songList.size } + + LaunchedEffect(pagerState.settledPage) { + val newSong = songList[pagerState.settledPage] + if (currentlyPlayingSong.mediaID != 0L && newSong != currentlyPlayingSong) { + viewModel.playOrToggleSong(newSong) + } + } + + HorizontalPager( + state = pagerState, + modifier = modifier + .fillMaxWidth() + .dynamicBackgroundFromAlbumArt(currentlyPlayingSong.albumArt) ) { Column( modifier = Modifier @@ -83,17 +115,18 @@ fun SongViewPager( ) { Box { val progress by viewModel.progress.collectAsState() - SeekBar( + CustomSeekBar( modifier = Modifier .height(10.dp) - .fillMaxWidth() - .padding(top = 12.dp, start = 5.dp, end = 5.dp), + .fillMaxWidth(), progress = progress, - onValueChange = viewModel::onSeek, - onValueChanged = viewModel::onSeeked + onValueChange = { newProgress -> + viewModel.onSeek(newProgress) + viewModel.onSeeked() + } ) } - Spacer(modifier = Modifier.height(14.dp)) + Spacer(modifier = Modifier.height(4.dp)) Box( modifier = Modifier .fillMaxWidth() @@ -143,28 +176,23 @@ fun SongViewPager( } viewModel.skipToPreviousSong() }, - tint = MaterialTheme.colorScheme.onTertiary + tint = MaterialTheme.colorScheme.onSurface ) - Box( - modifier = Modifier - .size(35.dp) - .clip(CircleShape) - .background(MaterialTheme.colorScheme.onTertiary) - ) { - PlayPauseIcon( - playIcon, - viewModel, - Modifier.size(35.dp), - tint = MaterialTheme.colorScheme.tertiaryContainer - ) - } + + PlayPauseIcon( + playIcon, + viewModel, + Modifier.size(35.dp), + tint = MaterialTheme.colorScheme.onSurface + ) + Icon( imageVector = Icons.Rounded.SkipNext, contentDescription = "", Modifier .size(35.dp) .clickable { viewModel.skipToNextSong() }, - tint = MaterialTheme.colorScheme.onTertiary + tint = MaterialTheme.colorScheme.onSurface ) } Text( @@ -184,7 +212,50 @@ fun SongViewPager( } } } - // TODO("Fix View Pager changing pages") + } +} + +@Composable +fun Modifier.dynamicBackgroundFromAlbumArt( + albumArtUrl: String?, + defaultColor: Color = ListenBrainzTheme.colorScheme.level1, + dullnessFactor: Float = 0.6f +) = composed { + val context = LocalContext.current + var backgroundColor by remember { mutableStateOf(defaultColor) } + val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor) + + LaunchedEffect(albumArtUrl) { + albumArtUrl?.let { url -> + val loader = ImageLoader(context) + val request = ImageRequest.Builder(context) + .data(url) + .allowHardware(false) + .build() + val result = loader.execute(request) + val bitmap = (result as? SuccessResult)?.drawable?.let { drawable -> + (drawable as? BitmapDrawable)?.bitmap + } + + bitmap?.let { + Palette.from(it).generate { palette -> + val dominantColor = palette?.getDominantColor(defaultColor.toArgb()) + val color = Color(dominantColor ?: defaultColor.toArgb()) + + backgroundColor = color.copy( + red = color.red * dullnessFactor + (1 - dullnessFactor) * 0.5f, + green = color.green * dullnessFactor + (1 - dullnessFactor) * 0.5f, + blue = color.blue * dullnessFactor + (1 - dullnessFactor) * 0.5f + ) + } + } ?: run { + backgroundColor = defaultColor + } + } + } + + Modifier.drawBehind { + drawRect(color = animatedBackgroundColor, size = size) } } @@ -197,4 +268,4 @@ fun SongViewPagerPreview() { currentlyPlayingSong = Song.preview(), backdropScaffoldState = rememberBackdropScaffoldState(initialValue = BackdropValue.Revealed) ) -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c288b96e..6ac4d556 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,6 +48,7 @@ loggerAndroid = "1.0.0" compileSdk = "35" targetSdk = "35" minSdk = "22" +paletteKtx = "1.0.0" [libraries] androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } @@ -141,6 +142,7 @@ androidx-test-espresso-intents = { module = "androidx.test.espresso:espresso-int vico-compose = { module = "com.patrykandpatrick.vico:compose", version.ref = "vicoCompose" } compose-ratingbar = { module = "com.github.a914-gowtham:compose-ratingbar", version.ref = "composeRatingbar" } logger-android = { module = "com.github.akshaaatt:Logger-Android", version.ref = "loggerAndroid" } +androidx-palette-ktx = { group = "androidx.palette", name = "palette-ktx", version.ref = "paletteKtx" } [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }