From 0f3c1d6670dfd2327a4f6679bf7acc55f11b04d0 Mon Sep 17 00:00:00 2001 From: Shreyas Patil Date: Thu, 9 Jan 2025 16:43:35 +0530 Subject: [PATCH 1/3] Feat: Dropdown songs card for Artist --- .../brainzplayer/BrainzPlayerScreen.kt | 15 +++- .../overview/ArtistsOverviewScreen.kt | 79 ++++++++++++++++--- 2 files changed, 83 insertions(+), 11 deletions(-) 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 03716d8be..82927814c 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 @@ -301,10 +301,21 @@ fun BrainzPlayerHomeScreen( ) }, onAddToNewPlaylist = { - artist -> + artist -> }, onAddToExistingPlaylist = { - artist -> + artist -> + }, + onSongClick = { + song -> + brainzPlayerViewModel.changePlayable( + listOf(song), + PlayableType.SONG, + song.mediaID, + 0, + 0L + ) + brainzPlayerViewModel.playOrToggleSong(song, true) } ) 3 -> AlbumsOverViewScreen(albums = albums, onPlayIconClick = { diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt index 3a886e6b4..5bf19f29f 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt @@ -1,8 +1,11 @@ package org.listenbrainz.android.ui.screens.brainzplayer.overview import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState @@ -21,8 +24,11 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import org.listenbrainz.android.R import org.listenbrainz.android.model.Artist +import org.listenbrainz.android.model.Song +import org.listenbrainz.android.model.feed.FeedListenArtist import org.listenbrainz.android.ui.components.BrainzPlayerDropDownMenu import org.listenbrainz.android.ui.components.BrainzPlayerListenCard +import org.listenbrainz.android.ui.components.ListenCardSmall import org.listenbrainz.android.ui.theme.ListenBrainzTheme @Composable @@ -33,11 +39,14 @@ fun ArtistsOverviewScreen( onAddToQueue : (Artist) -> Unit, onAddToExistingPlaylist : (Artist) -> Unit, onAddToNewPlaylist : (Artist) -> Unit, + onSongClick: (Song) -> Unit ) { val artistsStarting: MutableMap> = mutableMapOf() var dropdownState by remember { mutableStateOf(Pair(-1,-1)) } + var expandedArtist by remember { mutableStateOf(null) } + for (i in 0..25) { artistsStarting['A' + i] = mutableListOf() } @@ -68,15 +77,67 @@ fun ArtistsOverviewScreen( ) for (j in 1..artistsStarting[startingLetter]!!.size) { var coverArt: String? = null - val artist = artistsStarting[startingLetter]!![j-1] - if (artistsStarting[startingLetter]!![j - 1].albums.isNotEmpty()) - coverArt = artistsStarting[startingLetter]!![j - 1].albums[0].albumArt - BrainzPlayerListenCard(title = artistsStarting[startingLetter]!![j - 1].name, subTitle = when (artistsStarting[startingLetter]!![j - 1].songs.size) { - 1 -> "1 track" - else -> "${artistsStarting[startingLetter]!![j - 1].songs.size} tracks" - }, coverArtUrl = coverArt, errorAlbumArt = R.drawable.ic_artist, onPlayIconClick = { - onPlayClick(artistsStarting[startingLetter]!![j-1]) - }, modifier = Modifier.padding(start = 10.dp, end = 10.dp), dropDown = { BrainzPlayerDropDownMenu(onAddToNewPlaylist = {onAddToNewPlaylist(artist)}, onAddToExistingPlaylist = {onAddToExistingPlaylist(artist)},onAddToQueue = {onAddToQueue(artist)}, onPlayNext = {onPlayNext(artist)},expanded = dropdownState == Pair(i,j-1), onDismiss = {dropdownState = Pair(-1,-1)})}, onDropdownIconClick = {dropdownState = Pair(i,j-1)}, dropDownState = dropdownState == Pair(i,j-1)) + val artist = artistsStarting[startingLetter]!![j - 1] + if (artist.albums.isNotEmpty()) + coverArt = artist.albums[0].albumArt + Column { + BrainzPlayerListenCard( + title = artist.name, + subTitle = when (artist.songs.size) { + 1 -> "1 track" + else -> "${artist.songs.size} tracks" + }, + coverArtUrl = coverArt, + errorAlbumArt = R.drawable.ic_artist, + onPlayIconClick = { + onPlayClick(artist) + }, + modifier = Modifier + .padding(start = 10.dp, end = 10.dp) + .clickable { + expandedArtist = + if (expandedArtist == artist) null else artist + }, + dropDown = { + BrainzPlayerDropDownMenu( + onAddToNewPlaylist = { onAddToNewPlaylist(artist) }, + onAddToExistingPlaylist = { onAddToExistingPlaylist(artist) }, + onAddToQueue = { onAddToQueue(artist) }, + onPlayNext = { onPlayNext(artist) }, + expanded = dropdownState == Pair(i, j - 1), + onDismiss = { dropdownState = Pair(-1, -1) } + ) + }, + onDropdownIconClick = { dropdownState = Pair(i, j - 1) }, + dropDownState = dropdownState == Pair(i, j - 1) + ) + if (expandedArtist == artist) { + Row(modifier = Modifier.fillMaxWidth()) { + Spacer(modifier = Modifier.weight(0.5f)) + Column( + modifier = Modifier + .weight(3.5f) + .padding(horizontal = ListenBrainzTheme.paddings.horizontal) + ) { + artist.songs.forEach { song -> + ListenCardSmall( + modifier = Modifier + .padding(vertical = 6.dp) + .fillMaxWidth(), + trackName = song.title, + artists = listOf(FeedListenArtist(song.artist, null, "")), + coverArtUrl = song.albumArt, + errorAlbumArt = R.drawable.ic_erroralbumart, + goToArtistPage = {} + ) { + onSongClick(song) + } + } + } + } + } + + } Spacer(modifier = Modifier.height(10.dp)) } } From ed965661f0bcea9aee8f795fc5d44f5a9af21075 Mon Sep 17 00:00:00 2001 From: Shreyas Patil Date: Thu, 9 Jan 2025 22:56:04 +0530 Subject: [PATCH 2/3] Feat: Dropdown songs card for Albums --- .../brainzplayer/BrainzPlayerScreen.kt | 70 +++++++++++-------- .../overview/AlbumsOverviewScreen.kt | 70 ++++++++++++++++--- 2 files changed, 103 insertions(+), 37 deletions(-) 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 82927814c..dc18315db 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 @@ -16,6 +16,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.material3.ElevatedSuggestionChip import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SuggestionChipDefaults +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState @@ -134,7 +135,7 @@ fun BrainzPlayerHomeScreen( shape = ListenBrainzTheme.shapes.chips, elevation = SuggestionChipDefaults.elevatedSuggestionChipElevation(elevation = 4.dp), label = { - androidx.compose.material3.Text( + Text( text = when (position) { 0 -> "Overview" 1 -> "Recent" @@ -318,33 +319,46 @@ fun BrainzPlayerHomeScreen( brainzPlayerViewModel.playOrToggleSong(song, true) } ) - 3 -> AlbumsOverViewScreen(albums = albums, onPlayIconClick = { - album -> - val albumSongs = albumSongsMap[album]!! - brainzPlayerViewModel.changePlayable( - albumSongs.sortedBy { it.trackNumber }, - PlayableType.ALBUM, - album.albumId, - albumSongs - .sortedBy { it.trackNumber } - .indexOf (albumSongs[0]), - 0L - ) - brainzPlayerViewModel.playOrToggleSong(albumSongs[0],true) - - - }) - 4 -> SongsOverviewScreen(songs = songs, onPlayIconClick = { - song , newPlayables -> - brainzPlayerViewModel.changePlayable( - newPlayables, - PlayableType.ALL_SONGS, - song.mediaID, - newPlayables.sortedBy { it.discNumber }.indexOf(song), - 0L - ) - brainzPlayerViewModel.playOrToggleSong(song,true) - }) + 3 -> AlbumsOverViewScreen( + albums = albums, + onPlayIconClick = { album -> + val albumSongs = albumSongsMap[album]!! + brainzPlayerViewModel.changePlayable( + albumSongs.sortedBy { it.trackNumber }, + PlayableType.ALBUM, + album.albumId, + albumSongs + .sortedBy { it.trackNumber } + .indexOf(albumSongs[0]), + 0L + ) + brainzPlayerViewModel.playOrToggleSong(albumSongs[0], true) + }, + onSongClick = { song -> + brainzPlayerViewModel.changePlayable( + listOf(song), + PlayableType.SONG, + song.mediaID, + 0, + 0L + ) + brainzPlayerViewModel.playOrToggleSong(song, true) + }, + albumSongsMap = albumSongsMap + ) + 4 -> SongsOverviewScreen( + songs = songs, + onPlayIconClick = { song , newPlayables -> + brainzPlayerViewModel.changePlayable( + newPlayables, + PlayableType.ALL_SONGS, + song.mediaID, + newPlayables.sortedBy { it.discNumber }.indexOf(song), + 0L + ) + brainzPlayerViewModel.playOrToggleSong(song,true) + } + ) } } } \ No newline at end of file diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt index 977a3a9e4..582b1c534 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt @@ -1,14 +1,21 @@ package org.listenbrainz.android.ui.screens.brainzplayer.overview import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth 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.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font @@ -17,15 +24,22 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import org.listenbrainz.android.R import org.listenbrainz.android.model.Album +import org.listenbrainz.android.model.Song +import org.listenbrainz.android.model.feed.FeedListenArtist import org.listenbrainz.android.ui.components.BrainzPlayerListenCard +import org.listenbrainz.android.ui.components.ListenCardSmall import org.listenbrainz.android.ui.theme.ListenBrainzTheme @Composable fun AlbumsOverViewScreen( albums : List, - onPlayIconClick: (Album) -> Unit + albumSongsMap: Map>, + onPlayIconClick: (Album) -> Unit, + onSongClick: (Song) -> Unit ) { val albumsStarting: MutableMap> = mutableMapOf() + var expandedAlbum by remember { mutableStateOf(null) } + for (i in 0..25) { albumsStarting['A' + i] = mutableListOf() } @@ -54,14 +68,52 @@ fun AlbumsOverViewScreen( ) for (j in 1..albumsStarting[startingLetter]!!.size) { val coverArt = albumsStarting[startingLetter]!![j - 1].albumArt - BrainzPlayerListenCard(title = albumsStarting[startingLetter]!![j - 1].title, subTitle = albumsStarting[startingLetter]!![j - 1].artist, coverArtUrl = coverArt, errorAlbumArt = R.drawable.ic_erroralbumart, modifier = Modifier.padding( - start = 10.dp, - end = 10.dp, - top = 3.dp, - bottom = 3.dp - ), onPlayIconClick = { - onPlayIconClick(albumsStarting[startingLetter]!![j-1]) - }) + val album = albumsStarting[startingLetter]!![j - 1] + BrainzPlayerListenCard( + title = album.title, + subTitle = album.artist, + coverArtUrl = coverArt, + errorAlbumArt = R.drawable.ic_erroralbumart, + modifier = Modifier + .padding( + start = 10.dp, + end = 10.dp, + top = 3.dp, + bottom = 3.dp + ) + .clickable { + expandedAlbum = if (expandedAlbum == album) null else album + }, + onPlayIconClick = { + onPlayIconClick(album) + } + ) + if (expandedAlbum == album) { + val albumSongs = albumSongsMap[album]!!.sortedBy { it.trackNumber } + Row(modifier = Modifier.fillMaxWidth()) { + Spacer(modifier = Modifier.weight(0.5f)) + Column( + modifier = Modifier + .weight(3.5f) + .padding(horizontal = ListenBrainzTheme.paddings.horizontal) + ) { + albumSongs.forEach { song -> + ListenCardSmall( + modifier = Modifier + .padding(vertical = 6.dp) + .fillMaxWidth(), + trackName = song.title, + artists = listOf(FeedListenArtist(song.artist, null, "")), + coverArtUrl = song.albumArt, + errorAlbumArt = R.drawable.ic_erroralbumart, + goToArtistPage = {} + ) { + onSongClick(song) + } + } + } + } + } Spacer(modifier = Modifier.height(10.dp)) } } From 02b9c3665c793ecbf1855f8d75b0e8fdc10bfa0d Mon Sep 17 00:00:00 2001 From: Shreyas Patil Date: Thu, 9 Jan 2025 23:03:08 +0530 Subject: [PATCH 3/3] Added animation for dropdown --- .../brainzplayer/overview/AlbumsOverviewScreen.kt | 11 ++++++++++- .../brainzplayer/overview/ArtistsOverviewScreen.kt | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt index 582b1c534..548763933 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/AlbumsOverviewScreen.kt @@ -1,5 +1,10 @@ package org.listenbrainz.android.ui.screens.brainzplayer.overview +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -88,7 +93,11 @@ fun AlbumsOverViewScreen( onPlayIconClick(album) } ) - if (expandedAlbum == album) { + AnimatedVisibility( + visible = expandedAlbum == album, + enter = fadeIn() + expandVertically(), + exit = fadeOut() + shrinkVertically() + ) { val albumSongs = albumSongsMap[album]!!.sortedBy { it.trackNumber } Row(modifier = Modifier.fillMaxWidth()) { Spacer(modifier = Modifier.weight(0.5f)) diff --git a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt index 5bf19f29f..bad3d81da 100644 --- a/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt +++ b/app/src/main/java/org/listenbrainz/android/ui/screens/brainzplayer/overview/ArtistsOverviewScreen.kt @@ -1,5 +1,10 @@ package org.listenbrainz.android.ui.screens.brainzplayer.overview +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -111,7 +116,11 @@ fun ArtistsOverviewScreen( onDropdownIconClick = { dropdownState = Pair(i, j - 1) }, dropDownState = dropdownState == Pair(i, j - 1) ) - if (expandedArtist == artist) { + AnimatedVisibility( + visible = expandedArtist == artist, + enter = fadeIn() + expandVertically(), + exit = fadeOut() + shrinkVertically() + ) { Row(modifier = Modifier.fillMaxWidth()) { Spacer(modifier = Modifier.weight(0.5f)) Column(