diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/Badge.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/Badge.kt deleted file mode 100644 index 0e6d10d..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/Badge.kt +++ /dev/null @@ -1,22 +0,0 @@ -package it.vfsfitvnm.vimusic.ui.components - -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp - -fun Modifier.badge(color: Color, isDisplayed: Boolean = true, radius: Dp = 4.dp) = - if (isDisplayed) { - drawWithContent { - drawContent() - drawCircle( - color = color, - center = Offset(x = size.width, y = 0.dp.toPx()), - radius = radius.toPx() - ) - } - } else { - this - } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/ChunkyChipGroup.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/ChunkyChipGroup.kt deleted file mode 100644 index 9eafc96..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/ChunkyChipGroup.kt +++ /dev/null @@ -1,50 +0,0 @@ -package it.vfsfitvnm.vimusic.ui.components - -import androidx.compose.foundation.horizontalScroll -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.dp - -@Composable -fun ChipGroup( - items: List>, - value: T, - selectedBackgroundColor: Color, - unselectedBackgroundColor: Color, - selectedTextStyle: TextStyle, - unselectedTextStyle: TextStyle, - modifier: Modifier = Modifier, - shape: Shape = RoundedCornerShape(16.dp), - onValueChanged: (T) -> Unit -) { - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - modifier = Modifier - .horizontalScroll(rememberScrollState()) - .then(modifier) - ) { - items.forEach { chipItem -> - ChunkyButton( - text = chipItem.text, - textStyle = if (chipItem.value == value) selectedTextStyle else unselectedTextStyle, - backgroundColor = if (chipItem.value == value) selectedBackgroundColor else unselectedBackgroundColor, - shape = shape, - onClick = { - onValueChanged(chipItem.value) - } - ) - } - } -} - -data class ChipItem( - val text: String, - val value: T -) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TopAppBar.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TopAppBar.kt deleted file mode 100644 index 238d304..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TopAppBar.kt +++ /dev/null @@ -1,23 +0,0 @@ -package it.vfsfitvnm.vimusic.ui.components - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier - -@Composable -inline fun TopAppBar( - modifier: Modifier = Modifier, - content: @Composable RowScope.() -> Unit -) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - modifier = modifier - .fillMaxWidth(), - content = content - ) -} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/LoadingOrError.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/LoadingOrError.kt deleted file mode 100644 index d81efa8..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/LoadingOrError.kt +++ /dev/null @@ -1,41 +0,0 @@ -package it.vfsfitvnm.vimusic.ui.components.themed - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import com.valentinilk.shimmer.shimmer -import it.vfsfitvnm.vimusic.R - -@Composable -fun LoadingOrError( - errorMessage: String? = null, - onRetry: (() -> Unit)? = null, - horizontalAlignment: Alignment.Horizontal = Alignment.Start, - loadingContent: @Composable ColumnScope.() -> Unit -) { - Box { - Column( - horizontalAlignment = horizontalAlignment, - modifier = Modifier - .alpha(if (errorMessage == null) 1f else 0f) - .shimmer(), - content = loadingContent - ) - - errorMessage?.let { - TextCard( - icon = R.drawable.alert_circle, - onClick = onRetry, - modifier = Modifier - .align(Alignment.Center) - ) { - Title(text = onRetry?.let { "Tap to retry" } ?: "Error") - Text(text = "An error has occurred:\n$errorMessage") - } - } - } -} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/TextCard.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/TextCard.kt deleted file mode 100644 index d87311a..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/TextCard.kt +++ /dev/null @@ -1,113 +0,0 @@ -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.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.text.BasicText -import androidx.compose.material.ripple.rememberRipple -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance -import it.vfsfitvnm.vimusic.utils.align -import it.vfsfitvnm.vimusic.utils.secondary -import it.vfsfitvnm.vimusic.utils.semiBold - -@Composable -fun TextCard( - modifier: Modifier = Modifier, - @DrawableRes icon: Int? = null, - iconColor: ColorFilter? = null, - onClick: (() -> Unit)? = null, - content: @Composable TextCardScope.() -> Unit, -) { - val (colorPalette) = LocalAppearance.current - - Column( - modifier = modifier - .padding(horizontal = 16.dp, vertical = 16.dp) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple(bounded = true), - enabled = onClick != null, - onClick = onClick ?: {} - ) - .background(colorPalette.background1) - .padding(horizontal = 16.dp, vertical = 16.dp) - ) { - icon?.let { - Image( - painter = painterResource(icon), - contentDescription = null, - colorFilter = iconColor ?: ColorFilter.tint(Color.Red), - modifier = Modifier - .padding(bottom = 16.dp) - .size(24.dp) - ) - } - - (icon?.let { IconTextCardScopeImpl } ?: TextCardScopeImpl).content() - } -} - -interface TextCardScope { - @Composable - fun Title(text: String) - - @Composable - fun Text(text: String) -} - -private object TextCardScopeImpl : TextCardScope { - @Composable - override fun Title(text: String) { - val (_, typography) = LocalAppearance.current - BasicText( - text = text, - style = typography.xxs.semiBold, - ) - } - - @Composable - override fun Text(text: String) { - val (_, typography) = LocalAppearance.current - BasicText( - text = text, - style = typography.xxs.secondary.align(TextAlign.Justify), - ) - } -} - -private object IconTextCardScopeImpl : TextCardScope { - @Composable - override fun Title(text: String) { - val (_, typography) = LocalAppearance.current - BasicText( - text = text, - style = typography.xxs.semiBold, - modifier = Modifier - .padding(horizontal = 16.dp) - ) - } - - @Composable - override fun Text(text: String) { - val (_, typography) = LocalAppearance.current - BasicText( - text = text, - style = typography.xxs.secondary, - modifier = Modifier - .padding(horizontal = 16.dp) - ) - } -} 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 0f41d76..21a8215 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 @@ -299,7 +299,7 @@ fun AlbumOverview( .fillMaxSize() ) { BasicText( - text = "An error has occurred.\nTap to retry", + text = "An error has occurred.", style = typography.s.medium.secondary.center, modifier = Modifier .align(Alignment.Center) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt index ca61383..d9bf3e0 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/artist/ArtistScreen.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -32,7 +31,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveableStateHolder 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.geometry.center import androidx.compose.ui.graphics.ColorFilter @@ -50,17 +48,12 @@ import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.models.Artist import it.vfsfitvnm.vimusic.models.DetailedSong import it.vfsfitvnm.vimusic.query -import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu -import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold -import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder -import it.vfsfitvnm.vimusic.ui.screens.album.AlbumOverview import it.vfsfitvnm.vimusic.ui.screens.globalRoutes import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.px -import it.vfsfitvnm.vimusic.ui.styling.shimmer import it.vfsfitvnm.vimusic.ui.views.SongItem import it.vfsfitvnm.vimusic.utils.asMediaItem import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex @@ -73,7 +66,6 @@ import it.vfsfitvnm.youtubemusic.YouTube import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking @@ -147,21 +139,7 @@ fun ArtistScreen2(browseId: String) { .fillMaxSize() ) { item { - TopAppBar( - modifier = Modifier - .height(52.dp) - ) { - Image( - painter = painterResource(R.drawable.chevron_back), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.text), - modifier = Modifier - .clickable(onClick = pop) - .padding(vertical = 8.dp) - .padding(horizontal = 16.dp) - .size(24.dp) - ) - } + } item { @@ -234,17 +212,17 @@ fun ArtistScreen2(browseId: String) { ) } } ?: artistResult?.exceptionOrNull()?.let { throwable -> - LoadingOrError( - errorMessage = throwable.javaClass.canonicalName, - onRetry = { - query { - runBlocking { - Database.artist(browseId).first()?.let(Database::update) - } - } - } - ) - } ?: LoadingOrError() +// LoadingOrError( +// errorMessage = throwable.javaClass.canonicalName, +// onRetry = { +// query { +// runBlocking { +// Database.artist(browseId).first()?.let(Database::update) +// } +// } +// } +// ) + } } item("songs") { @@ -367,39 +345,6 @@ fun ArtistScreen2(browseId: String) { } } -@Composable -private fun LoadingOrError( - errorMessage: String? = null, - onRetry: (() -> Unit)? = null -) { - val (colorPalette) = LocalAppearance.current - - LoadingOrError( - errorMessage = errorMessage, - onRetry = onRetry, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Spacer( - modifier = Modifier - .background(color = colorPalette.shimmer, shape = CircleShape) - .size(Dimensions.thumbnails.artist) - ) - - TextPlaceholder( - modifier = Modifier - .alpha(0.9f) - .padding(vertical = 8.dp, horizontal = 16.dp) - ) - - repeat(3) { - TextPlaceholder( - modifier = Modifier - .alpha(0.8f) - .padding(horizontal = 16.dp) - ) - } - } -} private suspend fun fetchArtist(browseId: String): Result? { return YouTube.artist(browseId) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt index 9c039c7..5cf6c1d 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt @@ -2,27 +2,32 @@ package it.vfsfitvnm.vimusic.ui.screens.searchresult import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect 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.alpha import androidx.compose.ui.input.pointer.pointerInput import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues -import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.savers.ListSaver import it.vfsfitvnm.vimusic.savers.StringResultSaver import it.vfsfitvnm.vimusic.ui.components.themed.Header -import it.vfsfitvnm.vimusic.ui.components.themed.TextCard -import it.vfsfitvnm.vimusic.ui.views.SearchResultLoadingOrError +import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance +import it.vfsfitvnm.vimusic.utils.center +import it.vfsfitvnm.vimusic.utils.medium import it.vfsfitvnm.vimusic.utils.produceSaveableRelaunchableOneShotState +import it.vfsfitvnm.vimusic.utils.secondary import it.vfsfitvnm.youtubemusic.YouTube import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -37,6 +42,8 @@ inline fun SearchResult( crossinline itemContent: @Composable LazyItemScope.(T) -> Unit, noinline itemShimmer: @Composable BoxScope.() -> Unit, ) { + val (_, typography) = LocalAppearance.current + var items by rememberSaveable(query, filter, stateSaver = stateSaver) { mutableStateOf(listOf()) } @@ -93,28 +100,54 @@ inline fun SearchResult( SideEffect(fetch) } } - } ?: continuationResult?.exceptionOrNull()?.let { throwable -> + } ?: continuationResult?.exceptionOrNull()?.let { item { - SearchResultLoadingOrError( - errorMessage = throwable.javaClass.canonicalName, - onRetry = fetch, - shimmerContent = {} - ) + Box( + modifier = Modifier + .pointerInput(Unit) { + detectTapGestures { + fetch() + } + } + .fillMaxSize() + ) { + BasicText( + text = "An error has occurred.\nTap to retry", + style = typography.s.medium.secondary.center, + modifier = Modifier + .align(Alignment.Center) + ) + } } } ?: continuationResult?.let { if (items.isEmpty()) { item { - TextCard(icon = R.drawable.sad) { - Title(text = "No results found") - Text(text = "Please try a different query or category.") + Box( + modifier = Modifier + .pointerInput(Unit) { + detectTapGestures { + fetch() + } + } + .fillMaxSize() + ) { + BasicText( + text = "No results found.\nPlease try a different query or category", + style = typography.s.medium.secondary.center, + modifier = Modifier + .align(Alignment.Center) + ) } } } } ?: item(key = "loading") { - SearchResultLoadingOrError( - itemCount = if (items.isEmpty()) 8 else 3, - shimmerContent = itemShimmer - ) + repeat(if (items.isEmpty()) 8 else 3) { index -> + Box( + modifier = Modifier + .alpha(1f - index * 0.125f), + content = itemShimmer + ) + } } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt index f6f2126..d62ad6c 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/YouTubeItems.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -22,7 +21,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember 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.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow @@ -30,7 +28,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import it.vfsfitvnm.vimusic.ui.components.LocalMenuState -import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder import it.vfsfitvnm.vimusic.ui.styling.Dimensions @@ -458,42 +455,3 @@ fun ArtistItemShimmer( } } } - -@Composable -fun SearchResultLoadingOrError( - itemCount: Int = 0, - errorMessage: String? = null, - onRetry: (() -> Unit)? = null, - shimmerContent: @Composable BoxScope.() -> Unit, -) { - LoadingOrError( - errorMessage = errorMessage, - onRetry = onRetry, - horizontalAlignment = Alignment.CenterHorizontally - ) { - repeat(itemCount) { index -> - Box( - modifier = Modifier - .alpha(1f - index * 0.125f), - content = shimmerContent - ) -// if (isLoadingArtists) { -// SmallArtistItemShimmer( -// thumbnailSizeDp = Dimensions.thumbnails.song, -// modifier = Modifier -// .alpha(1f - index * 0.125f) -// .fillMaxWidth() -// .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) -// ) -// } else { -// SmallSongItemShimmer( -// thumbnailSizeDp = Dimensions.thumbnails.song, -// modifier = Modifier -// .alpha(1f - index * 0.125f) -// .fillMaxWidth() -// .padding(vertical = Dimensions.itemsVerticalPadding, horizontal = 16.dp) -// ) -// } - } - } -}