Skip to content

Commit

Permalink
Merge pull request #19 from stoyan-vuchev/3.0.0/corner-based-shape
Browse files Browse the repository at this point in the history
Breaking change: SquircleBasedShape is now derived from CornerBasedShape instead of Shape.
  • Loading branch information
stoyan-vuchev authored Nov 24, 2024
2 parents c0dd97f + 52c8d5b commit 5b83c2c
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 420 deletions.
218 changes: 36 additions & 182 deletions .idea/workspace.xml

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

* [Why Squircle?](#why-squircle)
* [Requirements](#requirements)
* [Supported Platforms](#supported-platforms)
* [Gradle Kotlin DSL Setup (For Multiplatform projects).](#gradle-kotlin-dsl-setup-for-multiplatform-projects)
* [Gradle Kotlin DSL Setup (For Android-only projects).](#gradle-kotlin-dsl-setup-for-android-only-projects)
* [Gradle Groovy Setup (For Android-only projects).](#gradle-groovy-setup-for-android-only-projects)
Expand All @@ -34,7 +35,6 @@
---

## Requirements
<br/>

##### Base requirements (For Multiplatform projects):

Expand All @@ -43,8 +43,6 @@

<br/>

---

##### Base requirements (For Android-only projects):

- Kotlin version - `2.0.21`
Expand All @@ -56,6 +54,19 @@

---

## Supported Platforms

##### List of currently supported platforms:

- Android
- iOS
- Desktop (JVM)
- Web (WasmJS)

<br/>

---

## Gradle Kotlin DSL Setup (For Multiplatform projects).

##### Step 1
Expand Down
34 changes: 23 additions & 11 deletions composeApp/src/commonMain/kotlin/App.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Shapes
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
Expand All @@ -14,27 +15,38 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import sv.lib.squircleshape.CornerSmoothing
import sv.lib.squircleshape.SquircleShape
import kotlin.math.roundToInt
import kotlin.random.Random

@Composable
fun App() {

var aspectRatio by remember { mutableFloatStateOf(1f) }
var cornerRadius by remember { mutableIntStateOf(100) }
var cornerSmoothing by remember { mutableFloatStateOf(CornerSmoothing.Medium) }
val state by rememberUpdatedState(
PreviewScreenState(
aspectRatio = aspectRatio,
cornerRadius = cornerRadius,
cornerSmoothing = cornerSmoothing
)
)

val shapes by rememberUpdatedState(
Shapes(
large = SquircleShape(
percent = state.cornerRadius,
cornerSmoothing = state.cornerSmoothing
)
)
)

MaterialTheme(
shapes = shapes,
colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme(),
content = {

var aspectRatio by remember { mutableFloatStateOf(1f) }
var cornerRadius by remember { mutableIntStateOf(100) }
var cornerSmoothing by remember { mutableFloatStateOf(CornerSmoothing.Medium) }
val state by rememberUpdatedState(
PreviewScreenState(
aspectRatio = aspectRatio,
cornerRadius = cornerRadius,
cornerSmoothing = cornerSmoothing
)
)

val scope = rememberCoroutineScope()
val onUiAction = remember<(PreviewScreenUiAction) -> Unit> {
{ uiAction ->
Expand Down
33 changes: 15 additions & 18 deletions composeApp/src/commonMain/kotlin/PreviewScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
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.platform.LocalDensity
import androidx.compose.ui.unit.dp
import sv.lib.squircleshape.SquircleShape
import sv.lib.squircleshape.drawSquircle

@Composable
Expand Down Expand Up @@ -54,6 +54,8 @@ fun PreviewScreen(
) {

val color = MaterialTheme.colorScheme.primary
val shape = MaterialTheme.shapes.large
val density = LocalDensity.current

Canvas(
modifier = Modifier
Expand All @@ -63,18 +65,19 @@ fun PreviewScreen(

val landscapeSquircleSize = this.size
val landscapeSquircleOffset = Offset.Zero
val landscapeSquircleCorner = (
landscapeSquircleSize.minDimension / 2f
) * (state.cornerRadius.toFloat() / 100f)
val shapeSize = Size(
width = landscapeSquircleSize.width / 2,
height = landscapeSquircleSize.height / 2
)

drawSquircle(
color = color,
topLeft = landscapeSquircleOffset,
size = landscapeSquircleSize,
topLeftCorner = landscapeSquircleCorner,
topRightCorner = landscapeSquircleCorner,
bottomLeftCorner = landscapeSquircleCorner,
bottomRightCorner = landscapeSquircleCorner,
topLeftCorner = shape.topStart.toPx(shapeSize, density),
topRightCorner = shape.topEnd.toPx(shapeSize, density),
bottomLeftCorner = shape.bottomStart.toPx(shapeSize, density),
bottomRightCorner = shape.bottomEnd.toPx(shapeSize, density),
cornerSmoothing = state.cornerSmoothing
)

Expand Down Expand Up @@ -119,6 +122,7 @@ fun PreviewScreen(
.padding(horizontal = 24.dp),
title = cornerRadiusSliderTitle,
value = cornerRadiusSliderValue,
valueRange = 0f..1f,
onValueChange = remember {
{ onUiAction(PreviewScreenUiAction.SetCornerRadius(it)) }
}
Expand Down Expand Up @@ -154,24 +158,17 @@ fun PreviewScreen(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {

val buttonShape by rememberUpdatedState(
SquircleShape(
percent = state.cornerRadius,
cornerSmoothing = state.cornerSmoothing
)
)

TextButton(
onClick = remember { { onUiAction(PreviewScreenUiAction.Reset) } },
modifier = Modifier.weight(1f),
shape = buttonShape,
shape = MaterialTheme.shapes.large,
content = { Text(text = "Reset") }
)

TextButton(
onClick = remember { { onUiAction(PreviewScreenUiAction.Random) } },
modifier = Modifier.weight(1f),
shape = buttonShape,
shape = MaterialTheme.shapes.large,
content = { Text(text = "Random") }
)

Expand Down
2 changes: 1 addition & 1 deletion library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ mavenPublishing {
coordinates(
groupId = "io.github.stoyan-vuchev",
artifactId = "squircle-shape",
version = "2.1.0"
version = "3.0.0"
)

pom {
Expand Down
122 changes: 13 additions & 109 deletions library/src/commonMain/kotlin/sv/lib/squircleshape/SquircleBasedShape.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@

package sv.lib.squircleshape

import androidx.compose.foundation.shape.CornerBasedShape
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Outline
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection

/**
*
* Base class for creating a Squircle based [Shape] defined by four corners and smoothing factor.
* Base class for creating a Squircle shape derived from a [CornerBasedShape]
* defined by four corners and a corner smoothing.
*
* @param topStart The top start corner radius defined as [CornerSize].
* @param topEnd The top end corner radius defined as [CornerSize].
Expand All @@ -40,107 +37,14 @@ import androidx.compose.ui.unit.LayoutDirection
*
**/
abstract class SquircleBasedShape(
val topStart: CornerSize,
val topEnd: CornerSize,
val bottomStart: CornerSize,
val bottomEnd: CornerSize,
topStart: CornerSize,
topEnd: CornerSize,
bottomStart: CornerSize,
bottomEnd: CornerSize,
val cornerSmoothing: Float
) : Shape {

final override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
): Outline {

var topStart = topStart.toPx(size, density)
var topEnd = topEnd.toPx(size, density)
var bottomEnd = bottomEnd.toPx(size, density)
var bottomStart = bottomStart.toPx(size, density)
val minDimension = size.minDimension

if (topStart + bottomStart > minDimension) {
val scale = minDimension / (topStart + bottomStart)
topStart *= scale
bottomStart *= scale
}

if (topEnd + bottomEnd > minDimension) {
val scale = minDimension / (topEnd + bottomEnd)
topEnd *= scale
bottomEnd *= scale
}

require(topStart >= 0.0f && topEnd >= 0.0f && bottomEnd >= 0.0f && bottomStart >= 0.0f) {
"Corner size in Px can't be negative(topStart = $topStart, topEnd = $topEnd, " +
"bottomEnd = $bottomEnd, bottomStart = $bottomStart)!"
}

return createOutline(
size = size,
topStart = topStart,
topEnd = topEnd,
bottomEnd = bottomEnd,
bottomStart = bottomStart,
cornerSmoothing = cornerSmoothing,
layoutDirection = layoutDirection
)

}

/**
*
* Creates [Outline] of this shape for the given [size].
*
* @param size the size of the shape boundary.
* @param topStart the resolved size of the top start corner
* @param topEnd the resolved size for the top end corner
* @param bottomEnd the resolved size for the bottom end corner
* @param bottomStart the resolved size for the bottom start corner
* @param cornerSmoothing the resolved smoothing factor for all corners
* @param layoutDirection the current layout direction.
*
*/
abstract fun createOutline(
size: Size,
topStart: Float,
topEnd: Float,
bottomEnd: Float,
bottomStart: Float,
cornerSmoothing: Float,
layoutDirection: LayoutDirection
): Outline

/**
*
* Creates a copy of this Shape with a new corner sizes.
*
* @param topStart a size of the top start corner
* @param topEnd a size of the top end corner
* @param bottomEnd a size of the bottom end corner
* @param bottomStart a size of the bottom start corner
* @param cornerSmoothing a factor for smoothing all corners
*
*/
abstract fun copy(
topStart: CornerSize = this.topStart,
topEnd: CornerSize = this.topEnd,
bottomEnd: CornerSize = this.bottomEnd,
bottomStart: CornerSize = this.bottomStart,
cornerSmoothing: Float = this.cornerSmoothing
): SquircleBasedShape

/**
*
* Creates a copy of this Shape with a new corner size.
*
* @param all a size to apply for all four corners
* @param cornerSmoothing a factor for smoothing all corners
*
*/
fun copy(
all: CornerSize,
cornerSmoothing: Float = this.cornerSmoothing
): SquircleBasedShape = copy(all, all, all, all, cornerSmoothing)

}
) : CornerBasedShape(
topStart = topStart,
topEnd = topEnd,
bottomStart = bottomStart,
bottomEnd = bottomEnd
)
Loading

0 comments on commit 5b83c2c

Please sign in to comment.