Skip to content

Commit 99970d9

Browse files
refactor: create gradient interface
1 parent 8c1a25d commit 99970d9

File tree

4 files changed

+76
-135
lines changed

4 files changed

+76
-135
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/BackgroundImageLayer.kt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,22 @@ import com.facebook.react.bridge.ReadableMap
1414

1515
public class BackgroundImageLayer(gradientMap: ReadableMap?, context: Context) {
1616
private val gradient: Gradient? =
17-
if (gradientMap != null) {
18-
try {
19-
Gradient(gradientMap, context)
20-
} catch (e: IllegalArgumentException) {
21-
// Gracefully reject invalid styles
22-
null
17+
if (gradientMap != null) {
18+
val typeString = gradientMap.getString("type")
19+
try {
20+
when (typeString) {
21+
"linearGradient" -> LinearGradient(gradientMap, context)
22+
"radialGradient" -> RadialGradient(gradientMap, context)
23+
else -> null
2324
}
24-
} else {
25+
} catch (e: IllegalArgumentException) {
26+
// Gracefully reject invalid styles
2527
null
2628
}
29+
} else {
30+
null
31+
}
2732

28-
public fun getShader(bounds: Rect): Shader? = gradient?.getShader(bounds)
33+
public fun getShader(bounds: Rect): Shader? =
34+
gradient?.getShader(bounds.width().toFloat(), bounds.height().toFloat())
2935
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/Gradient.kt

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,73 +7,8 @@
77

88
package com.facebook.react.uimanager.style
99

10-
import android.content.Context
11-
import android.graphics.Rect
1210
import android.graphics.Shader
13-
import com.facebook.react.bridge.Arguments
14-
import com.facebook.react.bridge.ReadableMap
15-
import com.facebook.react.bridge.ReadableType
1611

17-
internal class Gradient(gradient: ReadableMap?, context: Context) {
18-
private enum class GradientType {
19-
LINEAR_GRADIENT,
20-
RADIAL_GRADIENT
21-
}
22-
23-
private val type: GradientType
24-
private val linearGradient: LinearGradient?
25-
private val radialGradient: RadialGradient?
26-
27-
init {
28-
gradient ?: throw IllegalArgumentException("Gradient cannot be null")
29-
30-
val typeString = gradient.getString("type")
31-
type =
32-
when (typeString) {
33-
"linearGradient" -> GradientType.LINEAR_GRADIENT
34-
"radialGradient" -> GradientType.RADIAL_GRADIENT
35-
else -> throw IllegalArgumentException("Unsupported gradient type: $typeString")
36-
}
37-
38-
val colorStops =
39-
gradient.getArray("colorStops")
40-
?: throw IllegalArgumentException("Invalid colorStops array")
41-
when (type) {
42-
GradientType.LINEAR_GRADIENT -> {
43-
val directionMap =
44-
gradient.getMap("direction")
45-
?: throw IllegalArgumentException("Gradient must have direction")
46-
linearGradient = LinearGradient(directionMap, colorStops, context)
47-
radialGradient = null
48-
}
49-
GradientType.RADIAL_GRADIENT -> {
50-
val shape = gradient.getString("shape") ?: "ellipse"
51-
val size = if (gradient.hasKey("size")) {
52-
if (gradient.getType("size") == ReadableType.String) {
53-
val sizeKeyword = gradient.getString("size") ?: "farthest-corner"
54-
val sizeMap = Arguments.createMap()
55-
sizeMap.putString("keyword", sizeKeyword)
56-
sizeMap
57-
} else {
58-
gradient.getMap("size")
59-
}
60-
} else {
61-
null
62-
}
63-
val positionMap = gradient.getMap("position")
64-
radialGradient = RadialGradient(shape, size, positionMap, colorStops, context)
65-
linearGradient = null
66-
}
67-
}
68-
}
69-
70-
fun getShader(bounds: Rect): Shader? {
71-
return when (type) {
72-
GradientType.LINEAR_GRADIENT ->
73-
linearGradient?.getShader(bounds.width().toFloat(), bounds.height().toFloat())
74-
75-
GradientType.RADIAL_GRADIENT ->
76-
radialGradient?.getShader(bounds.width().toFloat(), bounds.height().toFloat())
77-
}
78-
}
12+
public interface Gradient {
13+
public fun getShader(width: Float, height: Float): Shader?
7914
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/LinearGradient.kt

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import android.content.Context
1313
import android.graphics.LinearGradient as AndroidLinearGradient
1414
import android.graphics.Shader
1515
import com.facebook.react.bridge.ColorPropConverter
16-
import com.facebook.react.bridge.ReadableArray
1716
import com.facebook.react.bridge.ReadableMap
1817
import com.facebook.react.bridge.ReadableType
1918
import com.facebook.react.uimanager.LengthPercentage
@@ -22,10 +21,9 @@ import kotlin.math.sqrt
2221
import kotlin.math.tan
2322

2423
internal class LinearGradient(
25-
directionMap: ReadableMap,
26-
private val colorStopsArray: ReadableArray,
24+
gradientMap: ReadableMap,
2725
private val context: Context
28-
) {
26+
) : Gradient {
2927
private sealed class Direction {
3028
data class Angle(val value: Double) : Direction()
3129

@@ -39,31 +37,35 @@ internal class LinearGradient(
3937
data class Keyword(val value: Keywords) : Direction()
4038
}
4139

42-
private val direction: Direction =
43-
when (val type = directionMap.getString("type")) {
44-
"angle" -> {
45-
val angle = directionMap.getDouble("value")
46-
Direction.Angle(angle)
47-
}
48-
49-
"keyword" -> {
50-
val keyword =
51-
when (directionMap.getString("value")) {
52-
"to top right" -> Direction.Keywords.TO_TOP_RIGHT
53-
"to bottom right" -> Direction.Keywords.TO_BOTTOM_RIGHT
54-
"to top left" -> Direction.Keywords.TO_TOP_LEFT
55-
"to bottom left" -> Direction.Keywords.TO_BOTTOM_LEFT
56-
else ->
57-
throw IllegalArgumentException(
58-
"Invalid linear gradient direction keyword: ${directionMap.getString("value")}")
59-
}
60-
Direction.Keyword(keyword)
61-
}
62-
63-
else -> throw IllegalArgumentException("Invalid direction type: $type")
40+
private val direction: Direction = run {
41+
val directionMap =
42+
gradientMap.getMap("direction")
43+
?: throw IllegalArgumentException("Gradient must have direction")
44+
when (val type = directionMap.getString("type")) {
45+
"angle" -> {
46+
val angle = directionMap.getDouble("value")
47+
Direction.Angle(angle)
6448
}
65-
49+
"keyword" -> {
50+
val keyword =
51+
when (directionMap.getString("value")) {
52+
"to top right" -> Direction.Keywords.TO_TOP_RIGHT
53+
"to bottom right" -> Direction.Keywords.TO_BOTTOM_RIGHT
54+
"to top left" -> Direction.Keywords.TO_TOP_LEFT
55+
"to bottom left" -> Direction.Keywords.TO_BOTTOM_LEFT
56+
else ->
57+
throw IllegalArgumentException(
58+
"Invalid linear gradient direction keyword: ${directionMap.getString("value")}")
59+
}
60+
Direction.Keyword(keyword)
61+
}
62+
else -> throw IllegalArgumentException("Invalid direction type: $type")
63+
}
64+
}
6665
private val colorStops: ArrayList<ColorStop> = run {
66+
val colorStopsArray =
67+
gradientMap.getArray("colorStops")
68+
?: throw IllegalArgumentException("Invalid colorStops array")
6769
val stops = ArrayList<ColorStop>(colorStopsArray.size())
6870
for (i in 0 until colorStopsArray.size()) {
6971
val colorStop = colorStopsArray.getMap(i) ?: continue
@@ -85,7 +87,7 @@ internal class LinearGradient(
8587
stops
8688
}
8789

88-
fun getShader(width: Float, height: Float): Shader {
90+
override fun getShader(width: Float, height: Float): Shader {
8991
val angle =
9092
when (direction) {
9193
is Direction.Angle -> direction.value

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/RadialGradient.kt

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,9 @@ import kotlin.math.pow
2727
import kotlin.math.sqrt
2828

2929
internal class RadialGradient(
30-
shapeString: String,
31-
private val sizeMap: ReadableMap?,
32-
private val positionMap: ReadableMap?,
33-
private val colorStopsArray: ReadableArray,
30+
gradientMap: ReadableMap,
3431
private val context: Context
35-
) {
32+
) : Gradient {
3633
private enum class Shape {
3734
CIRCLE,
3835
ELLIPSE;
@@ -88,10 +85,14 @@ internal class RadialGradient(
8885
val bottom: LengthPercentage? = null
8986
)
9087

91-
private val shape: Shape = Shape.fromString(shapeString)
88+
private val shape: Shape = run {
89+
val shapeString = gradientMap.getString("shape") ?: throw IllegalArgumentException("Radial gradient must have shape")
90+
Shape.fromString(shapeString)
91+
}
9292
private val isCircle: Boolean = shape == Shape.CIRCLE
9393

9494
private val position: Position = run {
95+
val positionMap = gradientMap.getMap("position")
9596
val defaultPosition = Position(
9697
top = LengthPercentage(50f, LengthPercentageType.PERCENT),
9798
left = LengthPercentage(50f, LengthPercentageType.PERCENT)
@@ -130,33 +131,27 @@ internal class RadialGradient(
130131
}
131132

132133
private val size: GradientSize = run {
133-
if (sizeMap == null) {
134-
return@run GradientSize(
135-
GradientSize.SizeType.KEYWORD,
136-
SizeKeyword.FARTHEST_CORNER
137-
)
138-
}
139-
140-
if (sizeMap.hasKey("keyword")) {
141-
val keywordString = sizeMap.getString("keyword")
142-
val keyword = SizeKeyword.fromString(keywordString)
143-
return@run GradientSize(
144-
GradientSize.SizeType.KEYWORD,
145-
keyword
146-
)
147-
}
148-
149-
if (sizeMap.hasKey("x") && sizeMap.hasKey("y")) {
150-
val xDynamic = sizeMap.getDynamic("x")
151-
val yDynamic = sizeMap.getDynamic("y")
152-
val x = LengthPercentage.setFromDynamic(xDynamic)
153-
val y = LengthPercentage.setFromDynamic(yDynamic)
154-
155-
if (x != null && y != null) {
134+
if (gradientMap.hasKey("size")) {
135+
if (gradientMap.getType("size") == ReadableType.String) {
136+
val sizeKeyword = gradientMap.getString("size");
156137
return@run GradientSize(
157-
GradientSize.SizeType.DIMENSIONS,
158-
GradientSize.Dimensions(x, y)
138+
GradientSize.SizeType.KEYWORD,
139+
SizeKeyword.fromString(sizeKeyword)
159140
)
141+
} else if (gradientMap.getType("size") == ReadableType.Map) {
142+
val sizeMap = gradientMap.getMap("size")
143+
if (sizeMap != null) {
144+
if (sizeMap.hasKey("x") && sizeMap.hasKey("y")) {
145+
val x = LengthPercentage.setFromDynamic(sizeMap.getDynamic("x"))
146+
val y = LengthPercentage.setFromDynamic(sizeMap.getDynamic("y"))
147+
if (x != null && y != null) {
148+
return@run GradientSize(
149+
GradientSize.SizeType.DIMENSIONS,
150+
GradientSize.Dimensions(x, y)
151+
)
152+
}
153+
}
154+
}
160155
}
161156
}
162157

@@ -167,6 +162,9 @@ internal class RadialGradient(
167162
}
168163

169164
private val colorStops: ArrayList<ColorStop> = run {
165+
val colorStopsArray =
166+
gradientMap.getArray("colorStops")
167+
?: throw IllegalArgumentException("Invalid colorStops array")
170168
val stops = ArrayList<ColorStop>(colorStopsArray.size())
171169
for (i in 0 until colorStopsArray.size()) {
172170
val colorStop = colorStopsArray.getMap(i) ?: continue
@@ -189,7 +187,7 @@ internal class RadialGradient(
189187
stops
190188
}
191189

192-
fun getShader(width: Float, height: Float): Shader {
190+
override fun getShader(width: Float, height: Float): Shader {
193191
var centerX: Float = width / 2f
194192
var centerY: Float = height / 2f
195193

0 commit comments

Comments
 (0)