Add isNew ribbon

This commit is contained in:
Thomas Andres Gomez 2023-03-27 14:09:01 +02:00
parent 8be1ecc0a7
commit 74fed885d0
8 changed files with 190 additions and 124 deletions

View file

@ -1,33 +1,32 @@
package com.pixelized.biblib.ui.screen.home.common.item package com.pixelized.biblib.ui.screen.home.common.item
import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Card import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.ui.Alignment import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pixelized.biblib.R import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.default import com.pixelized.biblib.utils.extention.default
import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
@Stable @Stable
data class LargeBookThumbnailUio( data class LargeBookThumbnailUio(
val id: Int, val id: Int,
val title: String,
val author: String,
val date: String?,
val isNew: Boolean, val isNew: Boolean,
val cover: String, val cover: String,
) )
@ -64,98 +63,52 @@ private fun LargeBookThumbnailContent(
thumbnail: LargeBookThumbnailUio, thumbnail: LargeBookThumbnailUio,
onClick: (LargeBookThumbnailUio) -> Unit = default<LargeBookThumbnailUio>(), onClick: (LargeBookThumbnailUio) -> Unit = default<LargeBookThumbnailUio>(),
) { ) {
Column( GlideImage(
modifier = modifier.clickable { thumbnail.let(onClick) } modifier = Modifier
) { .clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge)
GlideImage( .fillMaxWidth()
modifier = Modifier .aspectRatio(64f / 102f)
.clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge) .isNew { thumbnail.isNew }
.fillMaxWidth() .clickable { thumbnail.let(onClick) },
.aspectRatio(64f / 102f), previewPlaceholder = R.drawable.ic_fondatoin_cover,
previewPlaceholder = R.drawable.ic_fondatoin_cover, imageModel = thumbnail.cover,
imageModel = thumbnail.cover, )
)
Text(
modifier = Modifier
.padding(top = MaterialTheme.bibLib.dimen.dp4)
.padding(horizontal = MaterialTheme.bibLib.dimen.dp8),
style = MaterialTheme.typography.body1,
color = MaterialTheme.bibLib.colors.typography.medium,
text = thumbnail.title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
modifier = Modifier.padding(horizontal = MaterialTheme.bibLib.dimen.dp8),
style = MaterialTheme.typography.caption,
color = MaterialTheme.bibLib.colors.typography.easy,
text = thumbnail.author
)
Text(
modifier = Modifier
.align(alignment = Alignment.End)
.padding(horizontal = MaterialTheme.bibLib.dimen.dp8)
.padding(bottom = MaterialTheme.bibLib.dimen.dp8),
style = MaterialTheme.typography.caption,
color = MaterialTheme.bibLib.colors.typography.easy,
text = thumbnail.date ?: ""
)
}
} }
@Composable @Composable
private fun LargeBookThumbnailPlaceHolder( private fun LargeBookThumbnailPlaceHolder(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Column(modifier = modifier) { Box(
Box( modifier = Modifier
modifier = Modifier .fillMaxWidth()
.fillMaxWidth() .aspectRatio(64f / 102f)
.aspectRatio(64f / 102f) .background(
.background( color = MaterialTheme.bibLib.colors.placeHolder,
color = MaterialTheme.bibLib.colors.placeHolder, shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge,
shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge, ),
), )
) }
Box( @SuppressLint("ComposableModifierFactory")
modifier = Modifier @Composable
.padding(top = MaterialTheme.bibLib.dimen.dp4) private fun Modifier.isNew(
.padding(horizontal = MaterialTheme.bibLib.dimen.dp8) isNew: () -> Boolean,
.size(width = 80.dp, height = 12.dp) ) = if (isNew()) {
.background( val theme = MaterialTheme.bibLib
color = MaterialTheme.bibLib.colors.placeHolder, val label: String = stringResource(id = R.string.list_is_new)
shape = CircleShape, val color: Color = Color.Red
), val style: TextStyle = remember {
) theme.typography.base.caption.copy(color = Color.White)
Box(
modifier = Modifier
.padding(top = MaterialTheme.bibLib.dimen.dp4)
.padding(horizontal = MaterialTheme.bibLib.dimen.dp8)
.size(width = 60.dp, height = 12.dp)
.background(
color = MaterialTheme.bibLib.colors.placeHolder,
shape = CircleShape,
),
)
Box(
modifier = Modifier
.align(alignment = Alignment.End)
.padding(top = MaterialTheme.bibLib.dimen.dp4)
.padding(horizontal = MaterialTheme.bibLib.dimen.dp8)
.padding(bottom = MaterialTheme.bibLib.dimen.dp8)
.size(width = 40.dp, height = 12.dp)
.background(
color = MaterialTheme.bibLib.colors.placeHolder,
shape = CircleShape,
),
)
} }
drawDiagonalLabel(
text = label,
color = color,
style = style,
labelTextRatio = 4f,
)
} else {
this
} }
@Composable @Composable
@ -167,10 +120,7 @@ private fun LargeBookThumbnailPreview() {
modifier = Modifier.width(168.dp), modifier = Modifier.width(168.dp),
thumbnail = LargeBookThumbnailUio( thumbnail = LargeBookThumbnailUio(
id = 0, id = 0,
title = "Foundation", isNew = true,
author = "Asimov",
date = "February 1951",
isNew = false,
cover = "", cover = "",
), ),
) )

View file

@ -1,5 +1,6 @@
package com.pixelized.biblib.ui.screen.home.common.item package com.pixelized.biblib.ui.screen.home.common.item
import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -13,17 +14,23 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension import androidx.constraintlayout.compose.Dimension
import com.pixelized.biblib.R import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.default import com.pixelized.biblib.utils.extention.default
import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
@Stable @Stable
@ -82,7 +89,8 @@ private fun MicroBookThumbnailContent(
start.linkTo(parent.start) start.linkTo(parent.start)
} }
.clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverSmall) .clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverSmall)
.size(size = MaterialTheme.bibLib.dimen.thumbnail.micro), .size(size = MaterialTheme.bibLib.dimen.thumbnail.micro)
.isNew { thumbnail.isNew },
previewPlaceholder = R.drawable.ic_fondation_thumbnail, previewPlaceholder = R.drawable.ic_fondation_thumbnail,
imageModel = thumbnail.cover, imageModel = thumbnail.cover,
) )
@ -191,6 +199,30 @@ private fun MicroBookThumbnailPlaceHolder(
} }
} }
@SuppressLint("ComposableModifierFactory")
@Composable
private fun Modifier.isNew(
isNew: () -> Boolean,
) = if (isNew()) {
val theme = MaterialTheme.bibLib
val label: String = stringResource(id = R.string.list_is_new)
val color: Color = Color.Red
val style: TextStyle = remember {
theme.typography.base.caption.copy(
color = Color.White,
fontSize = 8.sp,
)
}
drawDiagonalLabel(
text = label,
color = color,
style = style,
labelTextRatio = 2f,
)
} else {
this
}
@Composable @Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@ -203,7 +235,7 @@ private fun MicroBookThumbnailPreview() {
title = "Foundation", title = "Foundation",
author = "Asimov", author = "Asimov",
series = "Foundation - 1", series = "Foundation - 1",
isNew = false, isNew = true,
) )
) )
} }

View file

@ -1,5 +1,6 @@
package com.pixelized.biblib.ui.screen.home.common.item package com.pixelized.biblib.ui.screen.home.common.item
import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -10,9 +11,13 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -22,6 +27,7 @@ import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.default import com.pixelized.biblib.utils.extention.default
import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
@Stable @Stable
@ -81,7 +87,8 @@ private fun SmallBookThumbnailContent(
start.linkTo(parent.start) start.linkTo(parent.start)
} }
.clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverSmall) .clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverSmall)
.size(size = MaterialTheme.bibLib.dimen.thumbnail.cover), .size(size = MaterialTheme.bibLib.dimen.thumbnail.cover)
.isNew { thumbnail.isNew },
previewPlaceholder = R.drawable.ic_fondation_thumbnail, previewPlaceholder = R.drawable.ic_fondation_thumbnail,
imageModel = thumbnail.cover, imageModel = thumbnail.cover,
) )
@ -228,6 +235,27 @@ private fun SmallBookThumbnailPlaceHolder(
} }
} }
@SuppressLint("ComposableModifierFactory")
@Composable
private fun Modifier.isNew(
isNew: () -> Boolean,
) = if (isNew()) {
val theme = MaterialTheme.bibLib
val label: String = stringResource(id = R.string.list_is_new)
val color: Color = Color.Red
val style: TextStyle = remember {
theme.typography.base.caption.copy(color = Color.White)
}
drawDiagonalLabel(
text = label,
color = color,
style = style,
labelTextRatio = 2f,
)
} else {
this
}
@Composable @Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@ -240,7 +268,7 @@ private fun SmallBookThumbnailPreview() {
title = "Foundation", title = "Foundation",
author = "Asimov", author = "Asimov",
date = "1951", date = "1951",
isNew = false, isNew = true,
cover = "", cover = "",
) )
) )

View file

@ -84,57 +84,36 @@ fun largeBookThumbnailPreviewResources(): LazyPagingItems<LargeBookThumbnailUio>
val thumbnails = listOf( val thumbnails = listOf(
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 112, id = 112,
title = "Prélude à Fondation",
author = "Asimov",
date = "1988",
isNew = false, isNew = false,
cover = "", cover = "",
), ),
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 78, id = 78,
title = "L'Aube de Fondation",
author = "Asimov",
date = "1993",
isNew = false, isNew = false,
cover = "", cover = "",
), ),
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 90, id = 90,
title = "Fondation",
author = "Asimov",
date = "1951",
isNew = false, isNew = false,
cover = "", cover = "",
), ),
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 184, id = 184,
title = "Fondation et Empire",
author = "Asimov",
date = "1952",
isNew = false, isNew = false,
cover = "", cover = "",
), ),
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 185, id = 185,
title = "Seconde Fondation",
author = "Asimov",
date = "1953",
isNew = false, isNew = false,
cover = "", cover = "",
), ),
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 119, id = 119,
title = "Fondation foudroyée",
author = "Asimov",
date = "1982",
isNew = false, isNew = false,
cover = "", cover = "",
), ),
LargeBookThumbnailUio( LargeBookThumbnailUio(
id = 163, id = 163,
title = "Terre et Fondation",
author = "Asimov",
date = "1986",
isNew = false, isNew = false,
cover = "", cover = "",
), ),

View file

@ -3,9 +3,10 @@ package com.pixelized.biblib.ui.theme.typography
import androidx.compose.material.Typography import androidx.compose.material.Typography
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import java.time.format.TextStyle
@Stable @Stable
@Immutable @Immutable
data class BibLibTypography( data class BibLibTypography(
val base: Typography = Typography() val base: Typography = Typography(),
) )

View file

@ -44,9 +44,6 @@ fun Book.toLargeBookThumbnailUio(
@CoverUrl coverBaseUrl: String = IBibLibClient.COVER_URL @CoverUrl coverBaseUrl: String = IBibLibClient.COVER_URL
) = LargeBookThumbnailUio( ) = LargeBookThumbnailUio(
id = id, id = id,
title = title,
author = author.joinToString { it.name },
date = releaseDate.longDate(),
isNew = isNew, isNew = isNew,
cover = "${coverBaseUrl}/$id.jpg", cover = "${coverBaseUrl}/$id.jpg",
) )

View file

@ -0,0 +1,77 @@
package com.pixelized.biblib.utils.extention.modifier
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.withTransform
import androidx.compose.ui.text.*
import kotlin.math.sqrt
@OptIn(ExperimentalTextApi::class)
fun Modifier.drawDiagonalLabel(
text: String,
color: Color,
style: TextStyle,
labelTextRatio: Float,
) = clipToBounds().composed(
factory = {
val textMeasurer = rememberTextMeasurer()
val textLayoutResult: TextLayoutResult = remember {
textMeasurer.measure(text = AnnotatedString(text), style = style)
}
drawWithContent {
val canvasWidth = size.width
val textSize = textLayoutResult.size
val textWidth = textSize.width
val textHeight = textSize.height
val rectWidth = textWidth * labelTextRatio * 1.1f
val rect = Rect(
offset = Offset(canvasWidth - rectWidth, 0f),
size = Size(rectWidth, textHeight.toFloat())
)
val sqrt = sqrt(rectWidth / 2f)
val translatePos = sqrt * sqrt
drawContent()
withTransform(
transformBlock = {
rotate(
degrees = 45f,
pivot = Offset(
canvasWidth - rectWidth / 2,
translatePos
)
)
},
drawBlock = {
drawRect(
color = color,
topLeft = rect.topLeft,
size = rect.size
)
drawText(
textMeasurer = textMeasurer,
text = text,
style = style,
topLeft = Offset(
rect.left + (rectWidth - textWidth) / 2f,
rect.top + (rect.bottom - textHeight) / 2f
)
)
}
)
}
}
)

View file

@ -55,6 +55,8 @@
<string name="authentication_password">Password</string> <string name="authentication_password">Password</string>
<string name="authentication_credential_remember">Remember my credential</string> <string name="authentication_credential_remember">Remember my credential</string>
<string name="list_is_new" translatable="false">New</string>
<string name="detail_rating">Rating</string> <string name="detail_rating">Rating</string>
<string name="detail_language">Language</string> <string name="detail_language">Language</string>
<string name="detail_release">Release</string> <string name="detail_release">Release</string>