From dc8d382afe88bf983f959831aeec09e8f529fef0 Mon Sep 17 00:00:00 2001 From: rahul31124 Date: Fri, 31 Jan 2025 17:06:57 +0530 Subject: [PATCH 1/2] Fixed-Lag-In-SongsOverviewScreen --- .../overview/SongsOverviewScreen.kt | 153 ++++++++++-------- 1 file changed, 88 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt index 9e1141fb..ef9ab633 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt @@ -3,12 +3,14 @@ package org.listenbrainz.android.ui.screens.brainzplayer.overview import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.getValue @@ -21,8 +23,9 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.listenbrainz.android.R -import org.listenbrainz.android.model.Artist import org.listenbrainz.android.model.Song import org.listenbrainz.android.ui.components.BrainzPlayerDropDownMenu import org.listenbrainz.android.ui.components.ListenCardSmall @@ -34,77 +37,97 @@ import org.listenbrainz.android.viewmodel.BrainzPlayerViewModel fun SongsOverviewScreen( songs: List, onPlayIconClick: (Song, List) -> Unit, - onPlayNext : (Song) -> Unit, - onAddToQueue : (Song) -> Unit, - onAddToExistingPlaylist : (Song) -> Unit, - onAddToNewPlaylist : (Song) -> Unit, + onPlayNext: (Song) -> Unit, + onAddToQueue: (Song) -> Unit, + onAddToExistingPlaylist: (Song) -> Unit, + onAddToNewPlaylist: (Song) -> Unit, ) { - val songsStarting = remember(songs.size) { - val songsStarting = mutableMapOf>() - for (i in 0..25) { - songsStarting['A' + i] = mutableListOf() - } - for (i in 1..songs.size) { - songsStarting[songs[i - 1].title[0]]?.add(songs[i-1]) - } - songsStarting - } + val songsStarting = remember { mutableStateOf>>(emptyMap()) } - val viewModel: BrainzPlayerViewModel = hiltViewModel() - val currentlyPlayingSong = viewModel.currentlyPlayingSong.collectAsStateWithLifecycle().value.toSong + LaunchedEffect(songs) { + withContext(Dispatchers.Default) { + val groupedSongs = mutableMapOf>() + for (i in 0..25) { + groupedSongs['A' + i] = mutableListOf() + } - Column(modifier = Modifier.verticalScroll(rememberScrollState())) { - for (i in 0..25) { - val startingLetter = ('A' + i) - if (songsStarting[startingLetter]!!.isNotEmpty()) { - Column( - modifier = Modifier.background( - brush = ListenBrainzTheme.colorScheme.gradientBrush - ).padding(top = 15.dp, bottom = 15.dp) - ) { - Text( - startingLetter.toString(), - modifier = Modifier.padding(start = 10.dp, top = 10.dp, bottom = 5.dp), - style = TextStyle( - color = ListenBrainzTheme.colorScheme.lbSignature, - fontSize = 20.sp, - fontFamily = FontFamily(Font(R.font.roboto_bold)), - ) - ) - for (j in 1..songsStarting[startingLetter]!!.size) { - val song = songsStarting[startingLetter]!![j-1] - val coverArt = songsStarting[startingLetter]!![j - 1].albumArt + songs.forEach { song -> + val firstChar = song.title.firstOrNull()?.uppercaseChar() ?: '#' + groupedSongs[firstChar]?.add(song) + } - var showDropdown by remember { mutableStateOf(false) } + withContext(Dispatchers.IO) { + songsStarting.value = groupedSongs + } + } + } - ListenCardSmall( - modifier = Modifier.padding(start = 10.dp, end = 10.dp), - trackName = songsStarting[startingLetter]!![j - 1].title, - artist = songsStarting[startingLetter]!![j - 1].artist, - coverArtUrl = coverArt, - errorAlbumArt = R.drawable.ic_erroralbumart, - onClick = { onPlayIconClick(song, songsStarting[startingLetter]!!) }, - onDropdownIconClick = { - showDropdown = !showDropdown - }, - goToArtistPage = { }, - isPlaying = song.mediaID == currentlyPlayingSong.mediaID, - dropDown = { - BrainzPlayerDropDownMenu( - onAddToNewPlaylist = {onAddToNewPlaylist(song)}, - onAddToExistingPlaylist = {onAddToExistingPlaylist(song)}, - onAddToQueue = {onAddToQueue(song)}, - onPlayNext = {onPlayNext(song)}, - expanded = showDropdown, - onDismiss = { showDropdown = false }, - ) - } + val viewModel: BrainzPlayerViewModel = hiltViewModel() + val currentlyPlayingSong = + viewModel.currentlyPlayingSong.collectAsStateWithLifecycle().value.toSong + LazyColumn( + modifier = Modifier + .fillMaxSize() + .background(brush = ListenBrainzTheme.colorScheme.gradientBrush) + ) { + songsStarting.value.forEach { (startingLetter, songList) -> + if (songList.isNotEmpty()) { + item { + Column( + modifier = Modifier.padding(top = 15.dp, bottom = 15.dp) + ) { + Text( + startingLetter.toString(), + modifier = Modifier.padding(start = 10.dp, top = 10.dp, bottom = 5.dp), + style = TextStyle( + color = ListenBrainzTheme.colorScheme.lbSignature, + fontSize = 20.sp, + fontFamily = FontFamily(Font(R.font.roboto_bold)), + ) ) - Spacer(modifier = Modifier.height(10.dp)) } } + + items(songList) { song -> + val coverArt = song.albumArt + var showDropdown by remember { mutableStateOf(false) } + ListenCardSmall( + modifier = Modifier.padding(start = 10.dp, end = 10.dp), + trackName = song.title, + artist = song.artist, + coverArtUrl = coverArt, + errorAlbumArt = R.drawable.ic_erroralbumart, + onClick = { + onPlayIconClick(song, songList) + }, + onDropdownIconClick = { + showDropdown = !showDropdown + }, + goToArtistPage = { }, + isPlaying = song.mediaID == currentlyPlayingSong.mediaID, + dropDown = { + BrainzPlayerDropDownMenu( + onAddToNewPlaylist = { + onAddToNewPlaylist(song) + }, + onAddToExistingPlaylist = { + onAddToExistingPlaylist(song) + }, + onAddToQueue = { + onAddToQueue(song) + }, + onPlayNext = { + onPlayNext(song) + }, + expanded = showDropdown, + onDismiss = { showDropdown = false } + ) + } + ) + Spacer(modifier = Modifier.height(10.dp)) + } } } } -} \ No newline at end of file +} From ca5316965fe156aad644d1d0d397d4e8994900cd Mon Sep 17 00:00:00 2001 From: Jasjeet Singh <98077881+07jasjeet@users.noreply.github.com> Date: Sat, 1 Feb 2025 13:00:00 +0530 Subject: [PATCH 2/2] Add empty state --- .../overview/SongsOverviewScreen.kt | 148 +++++++++++------- 1 file changed, 89 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt index ef9ab633..e0b26709 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/SongsOverviewScreen.kt @@ -1,6 +1,11 @@ package org.listenbrainz.android.ui.screens.brainzplayer.overview +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -11,10 +16,12 @@ import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font @@ -42,7 +49,6 @@ fun SongsOverviewScreen( onAddToExistingPlaylist: (Song) -> Unit, onAddToNewPlaylist: (Song) -> Unit, ) { - val songsStarting = remember { mutableStateOf>>(emptyMap()) } LaunchedEffect(songs) { @@ -57,77 +63,101 @@ fun SongsOverviewScreen( groupedSongs[firstChar]?.add(song) } - withContext(Dispatchers.IO) { - songsStarting.value = groupedSongs - } + songsStarting.value = groupedSongs } } val viewModel: BrainzPlayerViewModel = hiltViewModel() val currentlyPlayingSong = viewModel.currentlyPlayingSong.collectAsStateWithLifecycle().value.toSong - LazyColumn( - modifier = Modifier - .fillMaxSize() - .background(brush = ListenBrainzTheme.colorScheme.gradientBrush) - ) { - songsStarting.value.forEach { (startingLetter, songList) -> - if (songList.isNotEmpty()) { - item { - Column( - modifier = Modifier.padding(top = 15.dp, bottom = 15.dp) - ) { - Text( - startingLetter.toString(), - modifier = Modifier.padding(start = 10.dp, top = 10.dp, bottom = 5.dp), - style = TextStyle( - color = ListenBrainzTheme.colorScheme.lbSignature, - fontSize = 20.sp, - fontFamily = FontFamily(Font(R.font.roboto_bold)), - ) - ) - } - } - items(songList) { song -> - val coverArt = song.albumArt - var showDropdown by remember { mutableStateOf(false) } - ListenCardSmall( - modifier = Modifier.padding(start = 10.dp, end = 10.dp), - trackName = song.title, - artist = song.artist, - coverArtUrl = coverArt, - errorAlbumArt = R.drawable.ic_erroralbumart, - onClick = { - onPlayIconClick(song, songList) - }, - onDropdownIconClick = { - showDropdown = !showDropdown - }, - goToArtistPage = { }, - isPlaying = song.mediaID == currentlyPlayingSong.mediaID, - dropDown = { - BrainzPlayerDropDownMenu( - onAddToNewPlaylist = { - onAddToNewPlaylist(song) - }, - onAddToExistingPlaylist = { - onAddToExistingPlaylist(song) - }, - onAddToQueue = { - onAddToQueue(song) + val areSongsLoaded by remember { + derivedStateOf { + songsStarting.value.isNotEmpty() + } + } + + AnimatedContent( + modifier = Modifier.fillMaxSize(), + targetState = areSongsLoaded, + transitionSpec = { fadeIn() togetherWith fadeOut() } + ) { areSongsLoaded -> + if (areSongsLoaded) { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .background(brush = ListenBrainzTheme.colorScheme.gradientBrush) + ) { + songsStarting.value.forEach { (startingLetter, songList) -> + if (songList.isNotEmpty()) { + item { + Column( + modifier = Modifier.padding(top = 15.dp, bottom = 15.dp) + ) { + Text( + startingLetter.toString(), + modifier = Modifier.padding(start = 10.dp, top = 10.dp, bottom = 5.dp), + style = TextStyle( + color = ListenBrainzTheme.colorScheme.lbSignature, + fontSize = 20.sp, + fontFamily = FontFamily(Font(R.font.roboto_bold)), + ) + ) + } + } + + items(songList) { song -> + val coverArt = song.albumArt + var showDropdown by remember { mutableStateOf(false) } + ListenCardSmall( + modifier = Modifier.padding(start = 10.dp, end = 10.dp), + trackName = song.title, + artist = song.artist, + coverArtUrl = coverArt, + errorAlbumArt = R.drawable.ic_erroralbumart, + onClick = { + onPlayIconClick(song, songList) }, - onPlayNext = { - onPlayNext(song) + onDropdownIconClick = { + showDropdown = !showDropdown }, - expanded = showDropdown, - onDismiss = { showDropdown = false } + goToArtistPage = { }, + isPlaying = song.mediaID == currentlyPlayingSong.mediaID, + dropDown = { + BrainzPlayerDropDownMenu( + onAddToNewPlaylist = { + onAddToNewPlaylist(song) + }, + onAddToExistingPlaylist = { + onAddToExistingPlaylist(song) + }, + onAddToQueue = { + onAddToQueue(song) + }, + onPlayNext = { + onPlayNext(song) + }, + expanded = showDropdown, + onDismiss = { showDropdown = false } + ) + } ) + Spacer(modifier = Modifier.height(10.dp)) } - ) - Spacer(modifier = Modifier.height(10.dp)) + } } } + } else { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text( + modifier = Modifier.padding(12.dp), + text = "Loading songs...", + color = ListenBrainzTheme.colorScheme.text + ) + } } } }