Add TextCard component
This commit is contained in:
parent
53190a39f7
commit
fd41e78625
4 changed files with 137 additions and 94 deletions
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue