Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/start composable #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
Expand Down
4 changes: 3 additions & 1 deletion starview/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ android {

defaultConfig {
minSdk 21
targetSdk 33
targetSdk 34

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
Expand Down Expand Up @@ -48,6 +48,8 @@ dependencies {
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:1.6.0-alpha04"
implementation "androidx.compose.ui:ui-tooling-preview:1.6.0-alpha04"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
Expand Down
189 changes: 189 additions & 0 deletions starview/src/main/java/com/developerpaul123/starview/StarComposable.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package com.developerpaul123.starview

import android.graphics.CornerPathEffect
import android.graphics.RectF
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.PaintingStyle
import androidx.compose.ui.graphics.asComposePath
import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.graphics.toComposePathEffect
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.developerpaul123.starview.common.FillDirection
import com.developerpaul123.starview.engine.StarEngine

/**
* Copyright Paul 2023
* Part of the StarView project
*/
@Composable
fun Star(
points: Int,
outlineColor: Color,
fillColor: Color,
backgroundColor: Color,
fillPercent: Float,
cornerRadius: Float,
outlineThickness: Float,
fillDirection: FillDirection
) {
val effect = CornerPathEffect(cornerRadius).toComposePathEffect()
val fillPaint = remember {
Paint().apply {
pathEffect = effect
color = fillColor
style = PaintingStyle.Fill
}
}

val outlinePaint = remember {
Paint().apply {
pathEffect = effect
color = outlineColor
style = PaintingStyle.Stroke
strokeWidth = outlineThickness
}
}

val backgroundPaint = remember {
Paint().apply {
pathEffect = effect
color = backgroundColor
style = PaintingStyle.Fill
}
}

Box(modifier = Modifier.fillMaxSize()) {
Canvas(
modifier = Modifier
.fillMaxSize()
.defaultMinSize(100.dp, 100.dp),
onDraw = {
val width = size.width
val height = size.height
// get the path
val graphicsPath =
StarEngine.computeStarPath(
points,
width.toInt(),
height.toInt()
)
val bounds = RectF()
graphicsPath.computeBounds(bounds, true)

val path = graphicsPath.asComposePath()

with(drawContext.canvas) {
// draw background
drawPath(
path,
backgroundPaint
)

// determine clipping based on fill direction
val left: Float
val right: Float
val top: Float
val bottom: Float
when (fillDirection) {
FillDirection.LeftToRight -> {
left = 0f
right = bounds.width() * fillPercent
top = 0f
bottom = bounds.height()
}

FillDirection.RightToLeft -> {
left = width * (1 - fillPercent)
right = width
top = 0f
bottom = height
}

FillDirection.TopToBottom -> {
left = 0f
right = width
top = 0f
bottom = height * fillPercent
}

FillDirection.BottomToTop -> {
left = 0f
right = bounds.width()
top = height * (1 - fillPercent)
bottom = height
}

}
clipRect(left, top, right, bottom) {
drawPath(
path,
fillPaint
)
}

// draw the outline
drawPath(path, outlinePaint)
}
}
)
}
}

@Composable
@Preview
private fun StarPreview() {
LazyVerticalGrid(
columns = GridCells.Adaptive(100.dp),
modifier = Modifier.fillMaxSize(),
// content padding
contentPadding = PaddingValues(
start = 8.dp,
top = 16.dp,
end = 8.dp,
bottom = 8.dp
),
content = {
items(8) { point ->
Star(
point + 3,
outlineColor = Color(252, 212, 52),
fillColor = Color(252, 182, 52),
backgroundColor = Color.Transparent,
0.5f,
80f,
10f,
fillDirection = FillDirection.LeftToRight
)
}
}
)
}

@Composable
@Preview
private fun SimpleStar() {
Star(
5,
outlineColor = Color(252, 212, 52),
fillColor = Color(252, 182, 52),
backgroundColor = Color.Transparent,
0.5f,
80f,
20f,
fillDirection = FillDirection.BottomToTop
)
}
10 changes: 2 additions & 8 deletions starview/src/main/java/com/developerpaul123/starview/StarView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.core.math.MathUtils
import com.developerpaul123.starview.common.FillDirection
import com.developerpaul123.starview.engine.StarEngine

/**
* Copyright Paul 2021
* Copyright Paul 2021-23
* Part of the StarView project
*/
class StarView @JvmOverloads constructor(
Expand All @@ -17,13 +18,6 @@ class StarView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : View(context, attributeSet, defStyleAttr) {

enum class FillDirection {
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop
}

/**
* @brief Fill color of the star
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.developerpaul123.starview.common

/**
* Copyright Paul 2023
* Part of the StarView project
*/
enum class FillDirection {
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
package com.developerpaul123.starview.engine

import android.graphics.Path
import android.graphics.PointF
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin

/**
* Copyright Paul 2021
* Copyright Paul 2021-23
* Part of the StarView project
*
* This class computes the paths that are drawn as stars in the views and composable views.
*/
class StarEngine {
companion object {
fun computeStarPath(
private fun computeStarPoints(
numberOfPoints: Int,
width: Int,
height: Int,
innerToOuterRadiusRatio: Float = 1 / 3f
): Path {
innerToOuterRadiusRatio: Float
): List<PointF> {

val radius = (width / 2) * 0.95
val path = Path()
val dim = if (width > 0 && height > 0) minOf(width, height) else width
val radius = (dim / 2) * 0.95
val halfPi = PI / 2
val centerX = width / 2f
val centerY = height / 2f
val numberOfVertices = 2 * numberOfPoints
val radianSpacing = (2f * PI) / numberOfVertices

val points = mutableListOf<PointF>()
for (i in 0 until numberOfVertices + 1) {
val degreesInRad = i * radianSpacing
var radiusModifier = 1f
Expand All @@ -35,13 +39,30 @@ class StarEngine {

val x = centerX + (radius * radiusModifier) * cos(degreesInRad + 3 * halfPi)
val y = centerY + (radius * radiusModifier) * sin(degreesInRad + 3 * halfPi)
if (i == 0) {
path.moveTo(x.toFloat(), y.toFloat())
continue
}
path.lineTo(x.toFloat(), y.toFloat())
points.add(PointF(x.toFloat(), y.toFloat()))

}
return points
}

fun computeStarPath(
numberOfPoints: Int,
width: Int,
height: Int,
innerToOuterRadiusRatio: Float = 1 / 3f
): Path {

val path = Path()
val points = computeStarPoints(numberOfPoints, width, height, innerToOuterRadiusRatio)
var isFirst = true
points.forEach { point ->
if (isFirst) {
path.moveTo(point.x, point.y)
isFirst = false
} else {
path.lineTo(point.x, point.y)
}
}
path.close()
return path
}
Expand Down