diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt new file mode 100644 index 0000000..28524e3 --- /dev/null +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt @@ -0,0 +1,50 @@ +package it.vfsfitvnm.vimusic.ui.components.themed + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues +import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance + +@Composable +fun BoxScope.PrimaryButton( + onClick: () -> Unit, + @DrawableRes iconId: Int, + modifier: Modifier = Modifier, + isEnabled: Boolean = true, +) { + val (colorPalette) = LocalAppearance.current + + Box( + modifier = modifier + .align(Alignment.BottomEnd) + .padding(all = 16.dp) + .padding(LocalPlayerAwarePaddingValues.current) + .clip(RoundedCornerShape(16.dp)) + .clickable(enabled = isEnabled, onClick = onClick) + .background(colorPalette.background2) + .size(62.dp) + ) { + Image( + painter = painterResource(iconId), + contentDescription = null, + colorFilter = ColorFilter.tint(colorPalette.text), + modifier = Modifier + .align(Alignment.Center) + .size(20.dp) + ) + } +} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Scaffold.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Scaffold.kt index 362fa1c..11ffa02 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Scaffold.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Scaffold.kt @@ -1,6 +1,7 @@ package it.vfsfitvnm.vimusic.ui.components.themed import android.annotation.SuppressLint +import androidx.annotation.DrawableRes import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.AnimatedVisibilityScope @@ -13,6 +14,7 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -85,25 +87,10 @@ fun Scaffold( } primaryIconButtonId?.let { - Box( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(all = 16.dp) - .padding(LocalPlayerAwarePaddingValues.current) - .clip(RoundedCornerShape(16.dp)) - .clickable(onClick = onPrimaryIconButtonClick) - .background(colorPalette.background2) - .size(62.dp) - ) { - Image( - painter = painterResource(primaryIconButtonId), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.text), - modifier = Modifier - .align(Alignment.Center) - .size(20.dp) - ) - } + PrimaryButton( + iconId = primaryIconButtonId, + onClick = onPrimaryIconButtonClick + ) } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/album/AlbumOverview.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/album/AlbumOverview.kt index dc40c54..237359b 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/album/AlbumOverview.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/album/AlbumOverview.kt @@ -48,6 +48,7 @@ import it.vfsfitvnm.vimusic.savers.DetailedSongListSaver import it.vfsfitvnm.vimusic.ui.components.themed.Header import it.vfsfitvnm.vimusic.ui.components.themed.HeaderPlaceholder import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu +import it.vfsfitvnm.vimusic.ui.components.themed.PrimaryButton import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance @@ -266,32 +267,16 @@ fun AlbumOverview( } } - Box( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(all = 16.dp) - .padding(LocalPlayerAwarePaddingValues.current) - .clip(RoundedCornerShape(16.dp)) - .clickable(enabled = songs.isNotEmpty()) { - binder?.stopRadio() - binder?.player?.forcePlayFromBeginning( - songs - .shuffled() - .map(DetailedSong::asMediaItem) - ) - } - .background(colorPalette.background2) - .size(62.dp) - ) { - Image( - painter = painterResource(R.drawable.shuffle), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.text), - modifier = Modifier - .align(Alignment.Center) - .size(20.dp) - ) - } + PrimaryButton( + iconId = R.drawable.shuffle, + isEnabled = songs.isNotEmpty(), + onClick = { + binder?.stopRadio() + binder?.player?.forcePlayFromBeginning( + songs.shuffled().map(DetailedSong::asMediaItem) + ) + } + ) } ?: albumResult?.exceptionOrNull()?.let { Box( modifier = Modifier diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt index ba04073..95ba666 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistOverview.kt @@ -73,226 +73,4 @@ fun ArtistOverview( val (colorPalette, typography, thumbnailShape) = LocalAppearance.current val binder = LocalPlayerServiceBinder.current val context = LocalContext.current - -// BoxWithConstraints { -// val thumbnailSizeDp = maxWidth - Dimensions.verticalBarWidth -// val thumbnailSizePx = (thumbnailSizeDp - 32.dp).px -// -// viewModel.result?.getOrNull()?.let { albumWithSongs -> -// LazyColumn( -// contentPadding = LocalPlayerAwarePaddingValues.current, -// modifier = Modifier -// .background(colorPalette.background0) -// .fillMaxSize() -// ) { -// item( -// key = "header", -// contentType = 0 -// ) { -// Column { -// Header(title = albumWithSongs.album.title ?: "Unknown") { -// if (albumWithSongs.songs.isNotEmpty()) { -// BasicText( -// text = "Enqueue", -// style = typography.xxs.medium, -// modifier = Modifier -// .clip(RoundedCornerShape(16.dp)) -// .clickable { -// binder?.player?.enqueue( -// albumWithSongs.songs.map(DetailedSong::asMediaItem) -// ) -// } -// .background(colorPalette.background2) -// .padding(all = 8.dp) -// .padding(horizontal = 8.dp) -// ) -// } -// -// Spacer( -// modifier = Modifier -// .weight(1f) -// ) -// -// Image( -// painter = painterResource( -// if (albumWithSongs.album.bookmarkedAt == null) { -// R.drawable.bookmark_outline -// } else { -// R.drawable.bookmark -// } -// ), -// contentDescription = null, -// colorFilter = ColorFilter.tint(colorPalette.accent), -// modifier = Modifier -// .clickable { -// query { -// Database.update( -// albumWithSongs.album.copy( -// bookmarkedAt = if (albumWithSongs.album.bookmarkedAt == null) { -// System.currentTimeMillis() -// } else { -// null -// } -// ) -// ) -// } -// } -// .padding(all = 4.dp) -// .size(18.dp) -// ) -// -// Image( -// painter = painterResource(R.drawable.share_social), -// contentDescription = null, -// colorFilter = ColorFilter.tint(colorPalette.text), -// modifier = Modifier -// .clickable { -// albumWithSongs.album.shareUrl?.let { url -> -// val sendIntent = Intent().apply { -// action = Intent.ACTION_SEND -// type = "text/plain" -// putExtra(Intent.EXTRA_TEXT, url) -// } -// -// context.startActivity( -// Intent.createChooser( -// sendIntent, -// null -// ) -// ) -// } -// } -// .padding(all = 4.dp) -// .size(18.dp) -// ) -// } -// -// AsyncImage( -// model = albumWithSongs.album.thumbnailUrl?.thumbnail(thumbnailSizePx), -// contentDescription = null, -// modifier = Modifier -// .align(Alignment.CenterHorizontally) -// .padding(all = 16.dp) -// .clip(thumbnailShape) -// .size(thumbnailSizeDp) -// ) -// } -// } -// -// itemsIndexed( -// items = albumWithSongs.songs, -// key = { _, song -> song.id } -// ) { index, song -> -// SongItem( -// title = song.title, -// authors = song.artistsText ?: albumWithSongs.album.authorsText, -// durationText = song.durationText, -// onClick = { -// binder?.stopRadio() -// binder?.player?.forcePlayAtIndex( -// albumWithSongs.songs.map(DetailedSong::asMediaItem), -// index -// ) -// }, -// startContent = { -// BasicText( -// text = "${index + 1}", -// style = typography.s.semiBold.center.color(colorPalette.textDisabled), -// maxLines = 1, -// overflow = TextOverflow.Ellipsis, -// modifier = Modifier -// .width(Dimensions.thumbnails.song) -// ) -// }, -// menuContent = { -// NonQueuedMediaItemMenu(mediaItem = song.asMediaItem) -// } -// ) -// } -// } -// -// Box( -// modifier = Modifier -// .align(Alignment.BottomEnd) -// .padding(all = 16.dp) -// .padding(LocalPlayerAwarePaddingValues.current) -// .clip(RoundedCornerShape(16.dp)) -// .clickable(enabled = albumWithSongs.songs.isNotEmpty()) { -// binder?.stopRadio() -// binder?.player?.forcePlayFromBeginning( -// albumWithSongs.songs -// .shuffled() -// .map(DetailedSong::asMediaItem) -// ) -// } -// .background(colorPalette.background2) -// .size(62.dp) -// ) { -// Image( -// painter = painterResource(R.drawable.shuffle), -// contentDescription = null, -// colorFilter = ColorFilter.tint(colorPalette.text), -// modifier = Modifier -// .align(Alignment.Center) -// .size(20.dp) -// ) -// } -// } ?: viewModel.result?.exceptionOrNull()?.let { -// Box( -// modifier = Modifier -// .pointerInput(Unit) { -// detectTapGestures { -// viewModel.fetch(browseId) -// } -// } -// .align(Alignment.Center) -// .fillMaxSize() -// ) { -// BasicText( -// text = "An error has occurred.\nTap to retry", -// style = typography.s.medium.secondary.center, -// modifier = Modifier -// .align(Alignment.Center) -// ) -// } -// } ?: Column( -// modifier = Modifier -// .padding(LocalPlayerAwarePaddingValues.current) -// .shimmer() -// ) { -// HeaderPlaceholder() -// -// Spacer( -// modifier = Modifier -// .align(Alignment.CenterHorizontally) -// .padding(all = 16.dp) -// .clip(thumbnailShape) -// .size(thumbnailSizeDp) -// .background(colorPalette.shimmer) -// ) -// -// repeat(3) { index -> -// Row( -// verticalAlignment = Alignment.CenterVertically, -// horizontalArrangement = Arrangement.spacedBy(12.dp), -// modifier = Modifier -// .alpha(1f - index * 0.25f) -// .fillMaxWidth() -// .padding(horizontal = 16.dp, vertical = Dimensions.itemsVerticalPadding) -// .height(Dimensions.thumbnails.song) -// ) { -// Spacer( -// modifier = Modifier -// .background(color = colorPalette.shimmer, shape = thumbnailShape) -// .size(Dimensions.thumbnails.song) -// ) -// -// Column { -// TextPlaceholder() -// TextPlaceholder() -// } -// } -// } -// } -// } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/builtinplaylist/LocalPlaylistSongList.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/builtinplaylist/LocalPlaylistSongList.kt index 3d6c6c9..fa1f7dc 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/builtinplaylist/LocalPlaylistSongList.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/builtinplaylist/LocalPlaylistSongList.kt @@ -1,25 +1,20 @@ package it.vfsfitvnm.vimusic.ui.screens.builtinplaylist import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import it.vfsfitvnm.vimusic.Database import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues @@ -31,6 +26,7 @@ import it.vfsfitvnm.vimusic.savers.DetailedSongListSaver import it.vfsfitvnm.vimusic.ui.components.themed.Header import it.vfsfitvnm.vimusic.ui.components.themed.InFavoritesMediaItemMenu import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu +import it.vfsfitvnm.vimusic.ui.components.themed.PrimaryButton import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.px @@ -136,27 +132,15 @@ fun BuiltInPlaylistSongList(builtInPlaylist: BuiltInPlaylist) { } } - Box( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(all = 16.dp) - .padding(LocalPlayerAwarePaddingValues.current) - .clip(RoundedCornerShape(16.dp)) - .clickable(enabled = songs.isNotEmpty()) { - binder?.stopRadio() - binder?.player?.forcePlayFromBeginning(songs.shuffled().map(DetailedSong::asMediaItem)) - } - .background(colorPalette.background2) - .size(62.dp) - ) { - Image( - painter = painterResource(R.drawable.shuffle), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.text), - modifier = Modifier - .align(Alignment.Center) - .size(20.dp) - ) - } + PrimaryButton( + iconId = R.drawable.shuffle, + isEnabled = songs.isNotEmpty(), + onClick = { + binder?.stopRadio() + binder?.player?.forcePlayFromBeginning( + songs.shuffled().map(DetailedSong::asMediaItem) + ) + } + ) } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongList.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongList.kt index 5aaec96..7b12acc 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongList.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongList.kt @@ -19,7 +19,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.ColorFilter @@ -42,6 +41,7 @@ import it.vfsfitvnm.vimusic.transaction import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog import it.vfsfitvnm.vimusic.ui.components.themed.Header import it.vfsfitvnm.vimusic.ui.components.themed.InPlaylistMediaItemMenu +import it.vfsfitvnm.vimusic.ui.components.themed.PrimaryButton import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance @@ -267,32 +267,18 @@ fun LocalPlaylistSongList( } } - Box( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(all = 16.dp) - .padding(LocalPlayerAwarePaddingValues.current) - .clip(RoundedCornerShape(16.dp)) - .clickable(enabled = playlistWithSongs?.songs?.isNotEmpty() == true) { - playlistWithSongs?.songs - ?.shuffled() - ?.map(DetailedSong::asMediaItem) - ?.let { mediaItems -> - binder?.stopRadio() - binder?.player?.forcePlayFromBeginning(mediaItems) - } - } - .background(colorPalette.background2) - .size(62.dp) - ) { - Image( - painter = painterResource(R.drawable.shuffle), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.text), - modifier = Modifier - .align(Alignment.Center) - .size(20.dp) - ) - } + PrimaryButton( + iconId = R.drawable.shuffle, + isEnabled = playlistWithSongs?.songs?.isNotEmpty() == true, + onClick = { + playlistWithSongs?.songs + ?.shuffled() + ?.map(DetailedSong::asMediaItem) + ?.let { mediaItems -> + binder?.stopRadio() + binder?.player?.forcePlayFromBeginning(mediaItems) + } + } + ) } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/playlist/PlaylistSongList.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/playlist/PlaylistSongList.kt index 6c69858..fd69b95 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/playlist/PlaylistSongList.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/playlist/PlaylistSongList.kt @@ -46,6 +46,7 @@ import it.vfsfitvnm.vimusic.transaction import it.vfsfitvnm.vimusic.ui.components.themed.Header import it.vfsfitvnm.vimusic.ui.components.themed.HeaderPlaceholder import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu +import it.vfsfitvnm.vimusic.ui.components.themed.PrimaryButton import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance @@ -234,30 +235,16 @@ fun PlaylistSongList( } } - Box( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(all = 16.dp) - .padding(LocalPlayerAwarePaddingValues.current) - .clip(RoundedCornerShape(16.dp)) - .clickable(enabled = playlist.songs?.isNotEmpty() == true) { - playlist.songs?.map(YouTube.Item.Song::asMediaItem)?.let { mediaItems -> - binder?.stopRadio() - binder?.player?.forcePlayFromBeginning(mediaItems.shuffled()) - } + PrimaryButton( + iconId = R.drawable.shuffle, + isEnabled = playlist.songs?.isNotEmpty() == true, + onClick = { + playlist.songs?.map(YouTube.Item.Song::asMediaItem)?.let { mediaItems -> + binder?.stopRadio() + binder?.player?.forcePlayFromBeginning(mediaItems.shuffled()) } - .background(colorPalette.background2) - .size(62.dp) - ) { - Image( - painter = painterResource(R.drawable.shuffle), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.text), - modifier = Modifier - .align(Alignment.Center) - .size(20.dp) - ) - } + } + ) } ?: playlistResult?.exceptionOrNull()?.let { Box( modifier = Modifier