Skip to content

Commit f3b2be8

Browse files
add shape selection
1 parent ae51aa1 commit f3b2be8

File tree

6 files changed

+160
-29
lines changed

6 files changed

+160
-29
lines changed

app/src/main/java/com/smarttoolfactory/composecropper/preferences/CropPropertySelection.kt

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import androidx.compose.runtime.remember
88
import androidx.compose.ui.Modifier
99
import androidx.compose.ui.unit.dp
1010
import androidx.compose.ui.unit.sp
11-
import com.smarttoolfactory.cropper.model.AspectRatio
12-
import com.smarttoolfactory.cropper.model.AspectRatioModel
13-
import com.smarttoolfactory.cropper.model.aspectRatios
11+
import com.smarttoolfactory.cropper.model.*
1412
import com.smarttoolfactory.cropper.settings.CropProperties
1513
import com.smarttoolfactory.cropper.settings.CropType
1614
import kotlin.math.roundToInt
@@ -26,7 +24,7 @@ internal fun CropPropertySelectionMenu(
2624
val aspectRatio = cropProperties.aspectRatio
2725
val handleSize = cropProperties.handleSize
2826
val contentScale = cropProperties.contentScale
29-
val shape = cropProperties.shape
27+
val cropShape = cropProperties.cropShape
3028

3129
Title("Crop Type")
3230
CropTypeDialogSelection(
@@ -55,6 +53,16 @@ internal fun CropPropertySelectionMenu(
5553
}
5654
)
5755

56+
Title("Shape")
57+
ShapeSelection(
58+
cropShape = cropShape,
59+
onCropShapeChange = {
60+
onCropPropertiesChange(
61+
cropProperties.copy(cropShape = it)
62+
)
63+
}
64+
)
65+
5866
// Handle size and overlay size applies only to Dynamic crop
5967
if (cropType == CropType.Dynamic) {
6068
Title("Handle Size")
@@ -134,7 +142,7 @@ internal fun CropGestureSelectionMenu(
134142
@Composable
135143
internal fun AspectRatioSelection(
136144
aspectRatio: AspectRatio,
137-
onAspectRatioChange: (AspectRatioModel) -> Unit
145+
onAspectRatioChange: (CropAspectRatio) -> Unit
138146
) {
139147

140148
val initialSelectedIndex = remember {
@@ -151,6 +159,26 @@ internal fun AspectRatioSelection(
151159
}
152160
}
153161

162+
@Composable
163+
internal fun ShapeSelection(
164+
cropShape: CropShape,
165+
onCropShapeChange: (CropShape) -> Unit
166+
) {
167+
168+
val initialSelectedIndex = remember {
169+
val shapes = shapes
170+
val currentModel = shapes.first { it == cropShape }
171+
shapes.indexOf(currentModel)
172+
}
173+
174+
AnimatedShapeSelection(
175+
modifier = Modifier.fillMaxWidth(),
176+
initialSelectedIndex = initialSelectedIndex
177+
) {
178+
onCropShapeChange(it)
179+
}
180+
}
181+
154182
@Composable
155183
internal fun FlingEnableSelection(
156184
flingEnabled: Boolean,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.smarttoolfactory.composecropper.preferences
2+
3+
import androidx.compose.foundation.layout.padding
4+
import androidx.compose.foundation.layout.width
5+
import androidx.compose.runtime.*
6+
import androidx.compose.ui.Modifier
7+
import androidx.compose.ui.graphics.graphicsLayer
8+
import androidx.compose.ui.unit.Dp
9+
import androidx.compose.ui.unit.dp
10+
import com.smarttoolfactory.animatedlist.AnimatedInfiniteLazyRow
11+
import com.smarttoolfactory.animatedlist.model.AnimationProgress
12+
import com.smarttoolfactory.cropper.model.CropShape
13+
import com.smarttoolfactory.cropper.model.shapes
14+
import com.smarttoolfactory.cropper.widget.ShapeSelectionCard
15+
16+
@Composable
17+
fun AnimatedShapeSelection(
18+
modifier: Modifier = Modifier,
19+
initialSelectedIndex: Int = 2,
20+
onCropShapeChange: (CropShape) -> Unit
21+
) {
22+
23+
var currentIndex by remember { mutableStateOf(initialSelectedIndex) }
24+
25+
AnimatedInfiniteLazyRow(
26+
modifier = modifier.padding(horizontal = 10.dp),
27+
items = shapes,
28+
inactiveItemPercent = 80,
29+
initialFirstVisibleIndex = initialSelectedIndex - 2
30+
) { animationProgress: AnimationProgress, index: Int, item: CropShape, width: Dp ->
31+
32+
val scale = animationProgress.scale
33+
val color = animationProgress.color
34+
val selectedLocalIndex = animationProgress.itemIndex
35+
36+
ShapeSelectionCard(modifier = Modifier
37+
.graphicsLayer {
38+
scaleX = scale
39+
scaleY = scale
40+
}
41+
.width(width),
42+
color = color,
43+
cropShape = item
44+
)
45+
46+
if (currentIndex != selectedLocalIndex) {
47+
currentIndex = selectedLocalIndex
48+
onCropShapeChange(shapes[selectedLocalIndex])
49+
}
50+
}
51+
}

cropper/src/main/java/com/smarttoolfactory/cropper/model/ShapeModel.kt renamed to cropper/src/main/java/com/smarttoolfactory/cropper/model/CropShape.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import androidx.compose.ui.graphics.Shape
88
* for setting overlay in state and UI
99
*/
1010
@Immutable
11-
open class ShapeModel(
11+
open class CropShape(
1212
open val title: String,
1313
open val shape: Shape,
14-
)
14+
val editable:Boolean = false,
15+
val shapeType: ShapeType = ShapeType.Rect
16+
)
17+
18+
enum class ShapeType {
19+
Rect, RoundedRect, CutCorner, Oval, Polygon, Custom
20+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.smarttoolfactory.cropper.model
2+
3+
import androidx.compose.foundation.shape.CircleShape
4+
import androidx.compose.foundation.shape.CutCornerShape
5+
import androidx.compose.foundation.shape.RoundedCornerShape
6+
import androidx.compose.ui.graphics.RectangleShape
7+
import com.smarttoolfactory.cropper.util.createPolygonShape
8+
9+
val shapes = listOf(
10+
CropShape(
11+
title = "Rect",
12+
shape = RectangleShape,
13+
shapeType = ShapeType.Rect
14+
),
15+
CropShape(
16+
title = "Rounded",
17+
shape = RoundedCornerShape(10),
18+
editable = true,
19+
shapeType = ShapeType.RoundedRect
20+
),
21+
CropShape(
22+
title = "CutCorner",
23+
shape = CutCornerShape(10),
24+
editable = true,
25+
shapeType = ShapeType.CutCorner),
26+
CropShape(
27+
title = "Oval",
28+
shape = CircleShape,
29+
editable = true,
30+
shapeType = ShapeType.Oval
31+
),
32+
CropShape(
33+
title = "Polygon",
34+
shape = createPolygonShape(6),
35+
editable = true,
36+
shapeType = ShapeType.Polygon
37+
)
38+
)

cropper/src/main/java/com/smarttoolfactory/cropper/settings/CropDefaults.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ package com.smarttoolfactory.cropper.settings
33
import androidx.compose.runtime.Immutable
44
import androidx.compose.ui.Modifier
55
import androidx.compose.ui.graphics.Color
6-
import androidx.compose.ui.graphics.RectangleShape
7-
import androidx.compose.ui.graphics.Shape
86
import androidx.compose.ui.layout.ContentScale
97
import androidx.compose.ui.unit.Dp
108
import androidx.compose.ui.unit.dp
119
import com.smarttoolfactory.cropper.ImageCropper
1210
import com.smarttoolfactory.cropper.crop
1311
import com.smarttoolfactory.cropper.model.AspectRatio
12+
import com.smarttoolfactory.cropper.model.CropShape
13+
import com.smarttoolfactory.cropper.model.aspectRatios
14+
import com.smarttoolfactory.cropper.model.shapes
1415
import com.smarttoolfactory.cropper.state.CropState
1516

1617
/**
@@ -22,24 +23,24 @@ object CropDefaults {
2223
cropType: CropType = CropType.Dynamic,
2324
handleSize: Dp = 20.dp,
2425
maxZoom: Float = 10f,
25-
aspectRatio: AspectRatio = AspectRatio.Unspecified,
26+
aspectRatio: AspectRatio = aspectRatios[2].aspectRatio,
2627
contentScale: ContentScale = ContentScale.Fit,
27-
shape: Shape = RectangleShape,
28-
fling: Boolean = true,
29-
zoomable: Boolean = true,
28+
shape: CropShape = shapes[0],
3029
pannable: Boolean = true,
30+
fling: Boolean = false,
31+
zoomable: Boolean = true,
3132
rotatable: Boolean = false
3233
): CropProperties {
3334
return CropProperties(
3435
cropType = cropType,
3536
handleSize = handleSize,
3637
contentScale = contentScale,
37-
shape = shape,
38+
cropShape = shape,
3839
maxZoom = maxZoom,
3940
aspectRatio = aspectRatio,
41+
pannable = pannable,
4042
fling = fling,
4143
zoomable = zoomable,
42-
pannable = pannable,
4344
rotatable = rotatable
4445
)
4546
}
@@ -72,9 +73,9 @@ data class CropProperties internal constructor(
7273
val handleSize: Dp,
7374
val aspectRatio: AspectRatio,
7475
val contentScale: ContentScale,
75-
val shape: Shape,
76-
val fling: Boolean,
76+
val cropShape: CropShape,
7777
val pannable: Boolean,
78+
val fling: Boolean,
7879
val rotatable: Boolean,
7980
val zoomable: Boolean,
8081
val maxZoom: Float,

cropper/src/main/java/com/smarttoolfactory/cropper/widget/ShapeSelection.kt renamed to cropper/src/main/java/com/smarttoolfactory/cropper/widget/ShapeSelectionCard.kt

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ import androidx.compose.ui.graphics.drawscope.Stroke
1515
import androidx.compose.ui.graphics.drawscope.translate
1616
import androidx.compose.ui.platform.LocalDensity
1717
import androidx.compose.ui.platform.LocalLayoutDirection
18+
import androidx.compose.ui.unit.TextUnit
1819
import androidx.compose.ui.unit.dp
1920
import androidx.compose.ui.unit.sp
20-
import com.smarttoolfactory.cropper.model.AspectRatioModel
21-
import com.smarttoolfactory.cropper.model.ShapeModel
21+
import com.smarttoolfactory.cropper.model.CropShape
2222

2323

2424
@Composable
25-
fun ShapeSelection(
25+
fun ShapeSelectionCard(
2626
modifier: Modifier = Modifier,
2727
color: Color,
28-
shapeModel: ShapeModel
28+
fontSize:TextUnit = 12.sp,
29+
cropShape: CropShape
2930
) {
3031
Box(
3132
modifier = modifier
@@ -41,7 +42,7 @@ fun ShapeSelection(
4142
.aspectRatio(1f)
4243
.drawWithContent {
4344

44-
val outline = shapeModel.shape.createOutline(
45+
val outline = cropShape.shape.createOutline(
4546
size = size,
4647
layoutDirection = layoutDirection,
4748
density = density
@@ -64,16 +65,21 @@ fun ShapeSelection(
6465
}
6566
}
6667
)
67-
Text(text = shapeModel.title, color = color, fontSize = 14.sp)
68+
if(cropShape.title.isNotEmpty()){
69+
Text(text = cropShape.title, color = color, fontSize = fontSize)
70+
}
6871
}
6972
}
7073
}
7174

7275
@Composable
73-
fun ShapeSelection(
76+
fun ShapeSelectionCard(
7477
modifier: Modifier = Modifier,
7578
isSelected: Boolean,
76-
aspectRatioModel: AspectRatioModel
79+
activeColor: Color = Color.Red,
80+
inactiveColor: Color = Color.LightGray,
81+
fontSize:TextUnit = 14.sp,
82+
cropShape: CropShape
7783
) {
7884
Box(
7985
modifier = modifier
@@ -84,14 +90,14 @@ fun ShapeSelection(
8490
Column(horizontalAlignment = Alignment.CenterHorizontally) {
8591
val density = LocalDensity.current
8692
val layoutDirection = LocalLayoutDirection.current
87-
val color = if (isSelected) Color.Cyan else Color.LightGray
93+
val color = if (isSelected) activeColor else inactiveColor
8894
Box(modifier = Modifier
8995
.fillMaxWidth()
9096
.padding(4.dp)
9197
.aspectRatio(1f)
9298
.drawWithContent {
9399

94-
val outline = aspectRatioModel.shape.createOutline(
100+
val outline = cropShape.shape.createOutline(
95101
size = size,
96102
layoutDirection = layoutDirection,
97103
density = density
@@ -114,7 +120,8 @@ fun ShapeSelection(
114120
}
115121
}
116122
)
117-
Text(text = aspectRatioModel.title, color = color, fontSize = 14.sp)
118-
}
123+
if(cropShape.title.isNotEmpty()){
124+
Text(text = cropShape.title, color = color, fontSize = fontSize)
125+
} }
119126
}
120127
}

0 commit comments

Comments
 (0)