Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package io.github.lyxnx.compose.pine
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
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.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import compose.icons.TablerIcons
import compose.icons.tablericons.Filled
import compose.icons.tablericons.Outline
import compose.icons.tablericons.filled.Heart
import compose.icons.tablericons.filled.Star
import compose.icons.tablericons.outline.Heart
import compose.icons.tablericons.outline.Star
import io.github.lyxnx.compose.ui.drawWithLayer
import io.github.lyxnx.compose.ui.ifTrue
/**
* Represents the rating bar type
*/
public enum class RatingType {
Star, Heart
}
/**
* A Pine Theme rating input component
*
* @param modifier modifier to apply the the rating display
* @param rating the current rating to display. This can be fractional, for example, 4.5 and a [maxRating] of 5 will show 4 full stars and a half star being shown
* @param ratingType type of rating to use
* @param colors color to apply to the rating icons
* @param spacing spacing between each rating icon
* @param maxRating the maximum rating value
* @param itemSize the size of each item
* @param onRatingSelected action to perform when a rating item is selected. The received value corresponds to the
* rating value, not the index of selected item
*/
@Composable
public fun RatingDisplay(
modifier: Modifier = Modifier,
rating: Float = 0f,
ratingType: RatingType = RatingType.Star,
colors: RatingColors = RatingDefaults.starColors(),
spacing: Dp = RatingDefaults.ItemSpacing,
maxRating: Int = RatingDefaults.MaxRating,
itemSize: DpSize = RatingDefaults.ItemSize,
onRatingSelected: ((Int) -> Unit)? = null
) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(spacing),
verticalAlignment = Alignment.CenterVertically
) {
repeat(maxRating) { i ->
RatingDisplayItem(
type = ratingType,
colors = colors,
onClick = {
onRatingSelected!!.invoke(i + 1)
}.takeIf { onRatingSelected != null },
fraction = (rating - i).coerceIn(0f, 1f),
modifier = Modifier.size(itemSize)
)
}
}
}
/**
* A Pine Theme rating display item. This is used by a [RatingDisplay] but can also be used on its own
*
* @param type the type of rating item to display
*/
@Suppress("NAME_SHADOWING")
@Composable
public fun RatingDisplayItem(
modifier: Modifier = Modifier,
fraction: Float = 0f,
type: RatingType = RatingType.Star,
colors: RatingColors = RatingDefaults.starColors(),
size: DpSize = RatingDefaults.ItemSize,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
onClick: (() -> Unit)? = null
) {
val isPressed by interactionSource.collectIsPressedAsState()
val color by colors.iconColor(isPressed)
val fraction = remember(fraction) { fraction.coerceIn(0f, 1f) }
val image =
rememberVectorPainter(if (type == RatingType.Star) TablerIcons.Outline.Star else TablerIcons.Outline.Heart)
val imageFilled =
rememberVectorPainter(if (type == RatingType.Star) TablerIcons.Filled.Star else TablerIcons.Filled.Heart)
Canvas(
modifier
.ifTrue(onClick != null) {
clickable(
interactionSource = interactionSource,
onClick = onClick!!,
indication = LocalIndication.current
)
}
.size(size)
) {
val size = this.size
with(image) {
draw(
size = Size(size.width, size.height),
colorFilter = ColorFilter.tint(color)
)
}
drawWithLayer {
with(imageFilled) {
draw(
size = Size(size.width, size.height),
colorFilter = ColorFilter.tint(color)
)
}
drawRect(
color = Color.Transparent,
topLeft = Offset(size.width * fraction, 0f),
// the fraction is how much of the star we want visible, so 1 - fraction is the width to cover up
size = Size(size.width * (1f - fraction), size.height),
blendMode = BlendMode.SrcIn
)
}
}
}