Add TextCard component

This commit is contained in:
vfsfitvnm 2022-06-29 21:33:35 +02:00
parent 53190a39f7
commit fd41e78625
4 changed files with 137 additions and 94 deletions

View file

@ -0,0 +1,110 @@
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.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.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
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 = LocalColorPalette.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.lightBackground)
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
icon?.let {
Image(
painter = painterResource(icon),
contentDescription = null,
colorFilter = iconColor ?: ColorFilter.tint(colorPalette.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) {
BasicText(
text = text,
style = LocalTypography.current.xxs.semiBold,
)
}
@Composable
override fun Text(text: String) {
BasicText(
text = text,
style = LocalTypography.current.xxs.secondary.align(TextAlign.Justify),
)
}
}
private object IconTextCardScopeImpl : TextCardScope {
@Composable
override fun Title(text: String) {
BasicText(
text = text,
style = LocalTypography.current.xxs.semiBold,
modifier = Modifier
.padding(horizontal = 16.dp)
)
}
@Composable
override fun Text(text: String) {
BasicText(
text = text,
style = LocalTypography.current.xxs.secondary,
modifier = Modifier
.padding(horizontal = 16.dp)
)
}
}

View file

@ -4,14 +4,12 @@ import androidx.compose.animation.ExperimentalAnimationApi
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.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.BasicText
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -24,7 +22,6 @@ import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import coil.compose.AsyncImage
@ -38,6 +35,7 @@ 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.TextCard
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
@ -154,7 +152,11 @@ fun ArtistScreen(
.clickable {
query {
runBlocking {
Database.artist(browseId).first()?.copy(shufflePlaylistId = null)?.let(Database::update)
Database
.artist(browseId)
.first()
?.copy(shufflePlaylistId = null)
?.let(Database::update)
}
}
}
@ -292,22 +294,9 @@ fun ArtistScreen(
artistResult?.getOrNull()?.info?.let { description ->
item {
Column(
modifier = Modifier
.padding(top = 32.dp)
.padding(horizontal = 16.dp, vertical = 16.dp)
.background(colorPalette.lightBackground)
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
BasicText(
text = "Information",
style = typography.xxs.semiBold
)
BasicText(
text = description,
style = typography.xxs.secondary.align(TextAlign.Justify)
)
TextCard {
Title(text = "Information")
Text(text = description)
}
}
}
@ -321,7 +310,6 @@ private fun LoadingOrError(
errorMessage: String? = null,
onRetry: (() -> Unit)? = null
) {
val typography = LocalTypography.current
val colorPalette = LocalColorPalette.current
Box {
@ -353,41 +341,14 @@ private fun LoadingOrError(
}
errorMessage?.let {
Column(
TextCard(
icon = R.drawable.alert_circle,
onClick = onRetry,
modifier = Modifier
.align(Alignment.Center)
.padding(horizontal = 16.dp, vertical = 16.dp)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(bounded = true),
enabled = onRetry != null,
onClick = onRetry ?: {}
)
.background(colorPalette.lightBackground)
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
Image(
painter = painterResource(R.drawable.alert_circle),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.red),
modifier = Modifier
.padding(bottom = 16.dp)
.size(24.dp)
)
BasicText(
text = onRetry?.let { "Tap to retry" } ?: "Error",
style = typography.xxs.semiBold,
modifier = Modifier
.padding(horizontal = 16.dp)
)
BasicText(
text = "An error has occurred:\n$errorMessage",
style = typography.xxs.secondary,
modifier = Modifier
.padding(horizontal = 16.dp)
)
Title(text = onRetry?.let { "Tap to retry" } ?: "Error")
Text(text = "An error has occurred:\n$errorMessage")
}
}
}

View file

@ -25,6 +25,7 @@ import it.vfsfitvnm.vimusic.*
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.PlaylistOrAlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
@ -194,7 +195,6 @@ fun BackupAndRestoreScreen() {
)
}
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
@ -231,53 +231,19 @@ fun BackupAndRestoreScreen() {
}
}
Column(
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 16.dp)
.background(colorPalette.lightBackground)
.padding(horizontal = 16.dp, vertical = 16.dp)
TextCard(
icon = R.drawable.alert_circle,
) {
Image(
painter = painterResource(R.drawable.alert_circle),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.red),
modifier = Modifier
.padding(bottom = 16.dp)
.size(24.dp)
)
//
BasicText(
text = "Backup",
style = typography.xxs.semiBold,
modifier = Modifier
.padding(horizontal = 16.dp)
)
BasicText(
text = "The backup consists in exporting the application database to your device storage.\nThis means playlists, song history, favorites songs will exported.\nThis operation excludes personal preferences such as the theme mode and everything you can set in the Settings page.",
style = typography.xxs.secondary,
modifier = Modifier
.padding(horizontal = 16.dp)
)
Title(text = "Backup")
Text(text = "The backup consists in exporting the application database to your device storage.\nThis means playlists, song history, favorites songs will exported.\nThis operation excludes personal preferences such as the theme mode and everything you can set in the Settings page.")
Spacer(
modifier = Modifier
.height(32.dp)
)
BasicText(
text = "Restore",
style = typography.xxs.semiBold,
modifier = Modifier
.padding(horizontal = 16.dp)
)
BasicText(
text = "The restore replaces the existing application database with the selected - previously exported - one.\nThis means every currently existing data will be wiped: THE TWO DATABASES WON'T BE MERGED.\nIt is recommended to restore the database immediately after the application is installed on a new device.",
style = typography.xxs.secondary,
modifier = Modifier
.padding(horizontal = 16.dp)
)
Title(text = "Restore")
Text(text = "The restore replaces the existing application database with the selected - previously exported - one.\nThis means every currently existing data will be wiped: THE TWO DATABASES WON'T BE MERGED.\nIt is recommended to restore the database immediately after the application is installed on a new device.")
}
}
}

View file

@ -19,6 +19,7 @@ import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.SeekBar
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
@ -224,6 +225,11 @@ fun OtherSettingsScreen() {
text = "${Formatter.formatShortFileSize(context, diskCacheSize)} (${diskCacheSize * 100 / preferences.exoPlayerDiskCacheMaxSizeBytes.coerceAtLeast(1)}%)",
)
}
TextCard(icon = R.drawable.alert_circle) {
Title(text = "Cache strategy")
Text(text = "The cache follows the LRU (Least Recently Used) strategy: when it runs out of space, the resources that haven't been accessed for the longest time are cleared to accommodate the new resource.")
}
}
}
}