From 752b29c93acd8081c8cd0d2bb97fc119b02c2e27 Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Wed, 28 Sep 2022 15:43:42 +0200 Subject: [PATCH] Tweak code --- .../vimusic/ui/components/TabColumn.kt | 105 -------------- .../vimusic/ui/components/themed/Header.kt | 3 +- .../ui/components/themed/NavigationRail.kt | 134 ++++++++++++++++++ .../vimusic/ui/components/themed/Scaffold.kt | 11 +- .../ui/components/themed/VerticalBar.kt | 66 --------- .../vimusic/ui/screens/album/AlbumOverview.kt | 2 +- .../vimusic/ui/screens/home/HomeSongList.kt | 2 +- .../ui/screens/playlist/PlaylistSongList.kt | 2 +- .../vimusic/ui/screens/search/OnlineSearch.kt | 14 +- .../ui/screens/searchresult/SearchResult.kt | 19 ++- .../vimusic/ui/styling/Dimensions.kt | 4 +- 11 files changed, 173 insertions(+), 189 deletions(-) delete mode 100644 app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TabColumn.kt create mode 100644 app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/NavigationRail.kt delete mode 100644 app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/VerticalBar.kt diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TabColumn.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TabColumn.kt deleted file mode 100644 index 60170e8..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TabColumn.kt +++ /dev/null @@ -1,105 +0,0 @@ -package it.vfsfitvnm.vimusic.ui.components - -import androidx.compose.animation.animateColor -import androidx.compose.animation.core.animateFloat -import androidx.compose.animation.core.updateTransition -import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicText -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.ripple.rememberRipple -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.layout -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.dp - -@Composable -fun TabColumn( - tabIndex: Int, - onTabIndexChanged: (Int) -> Unit, - selectedTextColor: Color, - disabledTextColor: Color, - textStyle: TextStyle, - modifier: Modifier = Modifier, - content: @Composable (@Composable (Int, String, Int) -> Unit) -> Unit -) { - Column( - modifier = modifier - .verticalScroll(rememberScrollState()) - ) { - val transition = updateTransition(targetState = tabIndex, label = null) - - content { index, text, icon -> - val dothAlpha by transition.animateFloat(label = "") { - if (it == index) 1f else 0f - } - - val textColor by transition.animateColor(label = "") { - if (it == index) selectedTextColor else disabledTextColor - } - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clip(RoundedCornerShape(16.dp)) - .clickable( - indication = rememberRipple(bounded = true), - interactionSource = remember { MutableInteractionSource() }, - onClick = { onTabIndexChanged(index) } - ) - .padding(horizontal = 8.dp) - ) { - Image( - painter = painterResource(icon), - contentDescription = null, - colorFilter = ColorFilter.tint(selectedTextColor), - modifier = Modifier - .vertical() - .graphicsLayer { - alpha = dothAlpha - translationX = (1f - dothAlpha) * -48.dp.toPx() - rotationZ = -90f - } - .size(12.dp) - ) - - BasicText( - text = text, - style = textStyle.copy(color = textColor), - modifier = Modifier - .vertical() - .rotate(-90f) - .padding(horizontal = 16.dp) - ) - } - } - } -} - -fun Modifier.vertical() = - layout { measurable, constraints -> - val placeable = measurable.measure(constraints) - layout(placeable.height, placeable.width) { - placeable.place( - x = -(placeable.width / 2 - placeable.height / 2), - y = -(placeable.height / 2 - placeable.width / 2) - ) - } - } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Header.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Header.kt index c174126..0f4a05c 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Header.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/Header.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.shimmer import it.vfsfitvnm.vimusic.utils.medium @@ -55,7 +56,7 @@ fun Header( horizontalAlignment = Alignment.End, modifier = modifier .padding(horizontal = 16.dp) - .height(128.dp) + .height(Dimensions.headerHeight) .fillMaxWidth() ) { Spacer( diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/NavigationRail.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/NavigationRail.kt new file mode 100644 index 0000000..eb46bbf --- /dev/null +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/NavigationRail.kt @@ -0,0 +1,134 @@ +package it.vfsfitvnm.vimusic.ui.components.themed + +import androidx.compose.animation.animateColor +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.updateTransition +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicText +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.ripple.rememberRipple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.layout +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import it.vfsfitvnm.vimusic.ui.styling.Dimensions +import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance +import it.vfsfitvnm.vimusic.utils.semiBold + +@Composable +fun NavigationRail( + topIconButtonId: Int, + onTopIconButtonClick: () -> Unit, + tabIndex: Int, + onTabIndexChanged: (Int) -> Unit, + content: @Composable ColumnScope.(@Composable (Int, String, Int) -> Unit) -> Unit, + modifier: Modifier = Modifier +) { + val (colorPalette, typography) = LocalAppearance.current + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + ) { + Box( + contentAlignment = Alignment.TopCenter, + modifier = Modifier + .size(width = Dimensions.navigationRailWidth, height = Dimensions.headerHeight) + ) { + Image( + painter = painterResource(topIconButtonId), + contentDescription = null, + colorFilter = ColorFilter.tint(colorPalette.textSecondary), + modifier = Modifier + .offset(x = Dimensions.navigationRailIconOffset, y = 48.dp) + .clip(CircleShape) + .clickable(onClick = onTopIconButtonClick) + .padding(all = 12.dp) + .size(22.dp) + ) + } + + Column( + modifier = modifier + .verticalScroll(rememberScrollState()) + ) { + val transition = updateTransition(targetState = tabIndex, label = null) + + content { index, text, icon -> + val dothAlpha by transition.animateFloat(label = "") { + if (it == index) 1f else 0f + } + + val textColor by transition.animateColor(label = "") { + if (it == index) colorPalette.text else colorPalette.textDisabled + } + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clip(RoundedCornerShape(24.dp)) + .clickable( + indication = rememberRipple(bounded = true), + interactionSource = remember { MutableInteractionSource() }, + onClick = { onTabIndexChanged(index) } + ) + .padding(horizontal = 8.dp) + ) { + Image( + painter = painterResource(icon), + contentDescription = null, + colorFilter = ColorFilter.tint(colorPalette.text), + modifier = Modifier + .vertical() + .graphicsLayer { + alpha = dothAlpha + translationX = (1f - dothAlpha) * -48.dp.toPx() + rotationZ = -90f + } + .size(Dimensions.navigationRailIconOffset * 2) + ) + + BasicText( + text = text, + style = typography.xs.semiBold.copy(color = textColor), + modifier = Modifier + .vertical() + .rotate(-90f) + .padding(horizontal = 16.dp) + ) + } + } + } + } +} + +private fun Modifier.vertical() = + layout { measurable, constraints -> + val placeable = measurable.measure(constraints) + layout(placeable.height, placeable.width) { + placeable.place( + x = -(placeable.width / 2 - placeable.height / 2), + y = -(placeable.height / 2 - placeable.width / 2) + ) + } + } 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 8ef5ea0..29b46ea 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 @@ -13,6 +13,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.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -37,7 +38,7 @@ fun Scaffold( onTopIconButtonClick: () -> Unit, tabIndex: Int, onTabChanged: (Int) -> Unit, - tabColumnContent: @Composable (@Composable (Int, String, Int) -> Unit) -> Unit, + tabColumnContent: @Composable ColumnScope.(@Composable (Int, String, Int) -> Unit) -> Unit, primaryIconButtonId: Int? = null, onPrimaryIconButtonClick: () -> Unit = {}, modifier: Modifier = Modifier, @@ -54,14 +55,14 @@ fun Scaffold( modifier = modifier .fillMaxSize() ) { - VerticalBar( + NavigationRail( topIconButtonId = topIconButtonId, onTopIconButtonClick = onTopIconButtonClick, tabIndex = tabIndex, - onTabChanged = onTabChanged, - tabColumnContent = tabColumnContent, + onTabIndexChanged = onTabChanged, modifier = Modifier - .padding(LocalPlayerAwarePaddingValues.current) + .padding(LocalPlayerAwarePaddingValues.current), + content = tabColumnContent ) AnimatedContent( diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/VerticalBar.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/VerticalBar.kt deleted file mode 100644 index ef9e254..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/VerticalBar.kt +++ /dev/null @@ -1,66 +0,0 @@ -package it.vfsfitvnm.vimusic.ui.components.themed - -import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.CircleShape -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.ui.components.TabColumn -import it.vfsfitvnm.vimusic.ui.styling.Dimensions -import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance -import it.vfsfitvnm.vimusic.utils.semiBold - -@Composable -fun VerticalBar( - topIconButtonId: Int, - onTopIconButtonClick: () -> Unit, - tabIndex: Int, - onTabChanged: (Int) -> Unit, - tabColumnContent: @Composable (@Composable (Int, String, Int) -> Unit) -> Unit, - modifier: Modifier = Modifier -) { - val (colorPalette, typography) = LocalAppearance.current - - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = modifier - .padding(vertical = 16.dp) - ) { - Image( - painter = painterResource(topIconButtonId), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.textSecondary), - modifier = Modifier - .clip(CircleShape) - .clickable(onClick = onTopIconButtonClick) - .padding(all = 12.dp) - .size(22.dp) - ) - - Spacer( - modifier = Modifier - .width(Dimensions.verticalBarWidth) - .height(32.dp) - ) - - TabColumn( - tabIndex = tabIndex, - onTabIndexChanged = onTabChanged, - selectedTextColor = colorPalette.text, - disabledTextColor = colorPalette.textDisabled, - textStyle = typography.xs.semiBold, - content = tabColumnContent, - ) - } -} 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 21a8215..dc40c54 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 @@ -130,7 +130,7 @@ fun AlbumOverview( } BoxWithConstraints { - val thumbnailSizeDp = maxWidth - Dimensions.verticalBarWidth + val thumbnailSizeDp = maxWidth - Dimensions.navigationRailWidth val thumbnailSizePx = (thumbnailSizeDp - 32.dp).px albumResult?.getOrNull()?.let { album -> diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/HomeSongList.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/HomeSongList.kt index 9a1c867..142065a 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/HomeSongList.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/home/HomeSongList.kt @@ -210,7 +210,7 @@ fun HomeSongList() { ScrollToTop( lazyListState = lazyListState, modifier = Modifier - .offset(x = -Dimensions.verticalBarWidth) + .offset(x = Dimensions.navigationRailIconOffset - Dimensions.navigationRailWidth) .align(Alignment.BottomStart) ) } 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 b663834..6c69858 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 @@ -99,7 +99,7 @@ fun PlaylistSongList( } BoxWithConstraints { - val thumbnailSizeDp = maxWidth - Dimensions.verticalBarWidth + val thumbnailSizeDp = maxWidth - Dimensions.navigationRailWidth val thumbnailSizePx = (thumbnailSizeDp - 32.dp).px val songThumbnailSizeDp = Dimensions.thumbnails.song diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/search/OnlineSearch.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/search/OnlineSearch.kt index 382caff..274b2be 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/search/OnlineSearch.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/search/OnlineSearch.kt @@ -49,9 +49,9 @@ import it.vfsfitvnm.vimusic.query import it.vfsfitvnm.vimusic.savers.SearchQueryListSaver import it.vfsfitvnm.vimusic.savers.StringListResultSaver import it.vfsfitvnm.vimusic.ui.components.themed.Header -import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.utils.align +import it.vfsfitvnm.vimusic.utils.center import it.vfsfitvnm.vimusic.utils.medium import it.vfsfitvnm.vimusic.utils.produceSaveableOneShotState import it.vfsfitvnm.vimusic.utils.produceSaveableState @@ -320,7 +320,17 @@ fun OnlineSearch( } } ?: suggestionsResult?.exceptionOrNull()?.let { throwable -> item { - LoadingOrError(errorMessage = throwable.javaClass.canonicalName) {} + Box( + modifier = Modifier + .fillMaxSize() + ) { + BasicText( + 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/searchresult/SearchResult.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/searchresult/SearchResult.kt index 5cf6c1d..a291171 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 @@ -4,6 +4,7 @@ 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.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyItemScope @@ -19,6 +20,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.input.pointer.pointerInput +import com.valentinilk.shimmer.shimmer import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues import it.vfsfitvnm.vimusic.savers.ListSaver import it.vfsfitvnm.vimusic.savers.StringResultSaver @@ -141,12 +143,17 @@ inline fun SearchResult( } } } ?: item(key = "loading") { - repeat(if (items.isEmpty()) 8 else 3) { index -> - Box( - modifier = Modifier - .alpha(1f - index * 0.125f), - content = itemShimmer - ) + Column( + modifier = Modifier + .shimmer() + ) { + 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/styling/Dimensions.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/styling/Dimensions.kt index f503f5b..7f34514 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/styling/Dimensions.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/styling/Dimensions.kt @@ -10,7 +10,9 @@ import androidx.compose.ui.unit.dp object Dimensions { val itemsVerticalPadding = 8.dp - val verticalBarWidth = 64.dp + val navigationRailWidth = 64.dp + val navigationRailIconOffset = 6.dp + val headerHeight = 128.dp object thumbnails { val album = 128.dp