@craft-native/android 0.0.207 → 0.0.209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -578,6 +578,11 @@ internal class CraftNativeChrome(context: Context, private val tabs: List<CraftN
|
|
|
578
578
|
private val largeTitleView = TextView(context)
|
|
579
579
|
private val buttons = LinearLayout(context)
|
|
580
580
|
private val tabBar = LinearLayout(context)
|
|
581
|
+
private val tabRow = LinearLayout(context)
|
|
582
|
+
private val accessory = FrameLayout(context)
|
|
583
|
+
private val accessoryIcon = ImageView(context)
|
|
584
|
+
private val accessoryBadge = TextView(context)
|
|
585
|
+
private var accessorySpec: JSONObject? = null
|
|
581
586
|
private val tabViews = mutableListOf<Pair<TextView, TextView>>()
|
|
582
587
|
private val tabIconText = mutableMapOf<String, String>()
|
|
583
588
|
private val tabImageURLs = mutableMapOf<String, String>()
|
|
@@ -596,6 +601,7 @@ internal class CraftNativeChrome(context: Context, private val tabs: List<CraftN
|
|
|
596
601
|
var onBack: (() -> Unit)? = null
|
|
597
602
|
var onButton: ((String) -> Unit)? = null
|
|
598
603
|
var onTab: ((Int) -> Unit)? = null
|
|
604
|
+
var onAccessory: ((String) -> Unit)? = null
|
|
599
605
|
var onTabSwipeStart: ((Float, Float, Float) -> Boolean)? = null
|
|
600
606
|
var onTabSwipeMove: ((Float) -> Unit)? = null
|
|
601
607
|
var onTabSwipeEnd: ((Float, Boolean) -> Unit)? = null
|
|
@@ -660,8 +666,22 @@ internal class CraftNativeChrome(context: Context, private val tabs: List<CraftN
|
|
|
660
666
|
tabBar.addView(cell, LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f))
|
|
661
667
|
tabViews.add(icon to label)
|
|
662
668
|
}
|
|
663
|
-
|
|
664
|
-
|
|
669
|
+
tabRow.orientation = HORIZONTAL
|
|
670
|
+
tabRow.gravity = Gravity.CENTER_VERTICAL
|
|
671
|
+
tabRow.setPadding(dp(12), dp(4), dp(12), dp(4))
|
|
672
|
+
tabRow.addView(tabBar, LayoutParams(0, dp(64), 1f))
|
|
673
|
+
accessory.addView(accessoryIcon, FrameLayout.LayoutParams(dp(26), dp(26), Gravity.CENTER))
|
|
674
|
+
accessoryBadge.textSize = 10f
|
|
675
|
+
accessoryBadge.gravity = Gravity.CENTER
|
|
676
|
+
accessoryBadge.setTextColor(Color.WHITE)
|
|
677
|
+
accessoryBadge.setPadding(dp(4), 0, dp(4), 0)
|
|
678
|
+
accessoryBadge.background = GradientDrawable().apply { setColor(Color.RED); cornerRadius = dp(9).toFloat() }
|
|
679
|
+
accessory.addView(accessoryBadge, FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dp(18), Gravity.TOP or Gravity.END))
|
|
680
|
+
accessory.setOnClickListener { accessorySpec?.optString("path")?.let { onAccessory?.invoke(it) } }
|
|
681
|
+
accessory.visibility = View.GONE
|
|
682
|
+
tabRow.addView(accessory, LayoutParams(dp(64), dp(64)).apply { marginStart = dp(8) })
|
|
683
|
+
addView(tabRow, LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(72)))
|
|
684
|
+
tabRow.visibility = if (tabs.isEmpty()) View.GONE else View.VISIBLE
|
|
665
685
|
refreshColors()
|
|
666
686
|
}
|
|
667
687
|
|
|
@@ -671,7 +691,7 @@ internal class CraftNativeChrome(context: Context, private val tabs: List<CraftN
|
|
|
671
691
|
val overHorizontalScroll = onTabSwipeShouldDefer?.invoke(event.x, event.y) == true
|
|
672
692
|
horizontalScrollDeferred = overHorizontalScroll
|
|
673
693
|
if (overHorizontalScroll) parent?.requestDisallowInterceptTouchEvent(true)
|
|
674
|
-
swipeTracking = tabs.size > 1 && tabSwipeEnabled && !overHorizontalScroll &&
|
|
694
|
+
swipeTracking = tabs.size > 1 && tabSwipeEnabled && !overHorizontalScroll && tabRow.visibility == View.VISIBLE && event.y < tabRow.top
|
|
675
695
|
swipeIntercepted = false
|
|
676
696
|
swipeDownX = event.x
|
|
677
697
|
swipeDownY = event.y
|
|
@@ -742,7 +762,17 @@ internal class CraftNativeChrome(context: Context, private val tabs: List<CraftN
|
|
|
742
762
|
buttons.addView(navButton(button))
|
|
743
763
|
}
|
|
744
764
|
val tabBarHidden = options.optBoolean("tabBarHidden", false) || depth > 0 && options.optBoolean("tabBarHiddenWhenPushed", false)
|
|
745
|
-
|
|
765
|
+
tabRow.visibility = if (tabs.isEmpty() || tabBarHidden) View.GONE else View.VISIBLE
|
|
766
|
+
accessorySpec = options.optJSONObject("tabAccessory")?.takeIf {
|
|
767
|
+
val path = it.optString("path")
|
|
768
|
+
path.startsWith("/") && !path.startsWith("//") && it.has("title")
|
|
769
|
+
}
|
|
770
|
+
accessory.visibility = if (accessorySpec == null) View.GONE else View.VISIBLE
|
|
771
|
+
accessorySpec?.let {
|
|
772
|
+
accessory.contentDescription = it.optString("accessibilityLabel").ifBlank { it.optString("title") } + it.optString("badge").takeIf { badge -> badge.isNotBlank() && badge != "null" }?.let { badge -> ", $badge" }.orEmpty()
|
|
773
|
+
accessoryBadge.text = it.optString("badge").takeUnless { badge -> badge == "null" }.orEmpty().take(8)
|
|
774
|
+
accessoryBadge.visibility = if (accessoryBadge.text.isEmpty()) View.GONE else View.VISIBLE
|
|
775
|
+
}
|
|
746
776
|
tabSwipeEnabled = options.optBoolean("tabSwipeEnabled", true)
|
|
747
777
|
refreshColors()
|
|
748
778
|
}
|
|
@@ -801,13 +831,10 @@ internal class CraftNativeChrome(context: Context, private val tabs: List<CraftN
|
|
|
801
831
|
titleView.setTextColor(text)
|
|
802
832
|
largeTitleView.setTextColor(text)
|
|
803
833
|
backButton.imageTintList = ColorStateList.valueOf(accent)
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
divider,
|
|
809
|
-
GradientDrawable().apply { setColor(if (dark) Color.parseColor("#121212") else Color.parseColor("#F9F9F9")) },
|
|
810
|
-
)).apply { setLayerInset(1, 0, maxOf(1, (density / 2).toInt()), 0, 0) }
|
|
834
|
+
val surface = if (dark) Color.parseColor("#1C1C1E") else Color.parseColor("#F9F9F9")
|
|
835
|
+
tabBar.background = GradientDrawable().apply { setColor(surface); cornerRadius = dp(32).toFloat() }
|
|
836
|
+
accessory.background = GradientDrawable().apply { setColor(surface); cornerRadius = dp(32).toFloat() }
|
|
837
|
+
accessorySpec?.let { accessoryIcon.setImageDrawable(CraftNativeIcons.drawable(context, null, it.optString("symbol"), text)) }
|
|
811
838
|
tabViews.forEachIndexed { index, (icon, label) ->
|
|
812
839
|
val color = if (index == selectedTab) accent else muted
|
|
813
840
|
val number = tabIconText[tabs[index].id]
|
|
@@ -256,16 +256,9 @@ private data class CraftNativeLayoutStyle(
|
|
|
256
256
|
aspectRatio = decimal("aspectRatio")?.takeIf { it.isFinite() && it > 0.0 },
|
|
257
257
|
minWidth = length("minWidth"), maxWidth = length("maxWidth"),
|
|
258
258
|
minHeight = length("minHeight"), maxHeight = length("maxHeight"),
|
|
259
|
-
position = raw.opt("position")
|
|
260
|
-
?.takeUnless { it == JSONObject.NULL }
|
|
261
|
-
?.toString()
|
|
262
|
-
?.takeIf { it.isNotBlank() }
|
|
263
|
-
?: "relative",
|
|
259
|
+
position = craftNativeOptionalString(raw.opt("position")) ?: "relative",
|
|
264
260
|
top = number("top"), right = number("right"), bottom = number("bottom"), left = number("left"),
|
|
265
|
-
alignSelf = raw.opt("alignSelf")
|
|
266
|
-
?.takeUnless { it == JSONObject.NULL }
|
|
267
|
-
?.toString()
|
|
268
|
-
?.takeIf { it.isNotBlank() && it != "auto" },
|
|
261
|
+
alignSelf = craftNativeOptionalString(raw.opt("alignSelf"))?.takeUnless { it == "auto" },
|
|
269
262
|
flexGrow = decimal("flexGrow") ?: flex?.coerceAtLeast(0.0) ?: 0.0,
|
|
270
263
|
flexShrink = decimal("flexShrink") ?: flex?.let { if (it != 0.0) 1.0 else 0.0 },
|
|
271
264
|
flexBasis = length("flexBasis")
|
|
@@ -383,11 +376,8 @@ private class CraftNativeSvgView(context: Context) : View(context) {
|
|
|
383
376
|
fun merge(node: JSONObject): SvgPaint {
|
|
384
377
|
val props = node.optJSONObject("props") ?: JSONObject()
|
|
385
378
|
val style = node.optJSONObject("style") ?: JSONObject()
|
|
386
|
-
fun value(name: String): String? =
|
|
387
|
-
|
|
388
|
-
props.has(name) && !props.isNull(name) -> props.optString(name)
|
|
389
|
-
else -> null
|
|
390
|
-
}
|
|
379
|
+
fun value(name: String): String? = craftNativeOptionalString(style.opt(name))
|
|
380
|
+
?: craftNativeOptionalString(props.opt(name))
|
|
391
381
|
fun raw(name: String): Any? = when {
|
|
392
382
|
style.has(name) && !style.isNull(name) -> style.opt(name)
|
|
393
383
|
props.has(name) && !props.isNull(name) -> props.opt(name)
|
|
@@ -486,7 +476,7 @@ private class CraftNativeSvgView(context: Context) : View(context) {
|
|
|
486
476
|
for (index in 0 until children.length()) {
|
|
487
477
|
val node = children.optJSONObject(index) ?: continue
|
|
488
478
|
val style = node.optJSONObject("style") ?: JSONObject()
|
|
489
|
-
if (style.
|
|
479
|
+
if (craftNativeOptionalString(style.opt("display")) == "none") continue
|
|
490
480
|
val paint = inherited.merge(node)
|
|
491
481
|
when (node.optString("type")) {
|
|
492
482
|
"G" -> drawNodes(canvas, node.optJSONArray("children") ?: JSONArray(), paint)
|
|
@@ -582,7 +572,7 @@ private class CraftNativeSvgView(context: Context) : View(context) {
|
|
|
582
572
|
}
|
|
583
573
|
var x = craftNativeNumber(props.opt("x"))?.toFloat()?.takeIf { it.isFinite() } ?: 0f
|
|
584
574
|
val y = craftNativeNumber(props.opt("y"))?.toFloat()?.takeIf { it.isFinite() } ?: 0f
|
|
585
|
-
when (props.
|
|
575
|
+
when (craftNativeOptionalString(props.opt("textAnchor"))) {
|
|
586
576
|
"middle" -> x -= paint.measureText(text) / 2f
|
|
587
577
|
"end" -> x -= paint.measureText(text)
|
|
588
578
|
}
|
|
@@ -1027,14 +1017,15 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1027
1017
|
}
|
|
1028
1018
|
|
|
1029
1019
|
fun configure(style: JSONObject, density: Float) {
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1020
|
+
val flexDirection = craftNativeOptionalString(style.opt("flexDirection")).orEmpty()
|
|
1021
|
+
orientation = if (flexDirection in setOf("row", "row-reverse")) HORIZONTAL else VERTICAL
|
|
1022
|
+
reverse = flexDirection.endsWith("-reverse")
|
|
1023
|
+
val flexWrap = craftNativeOptionalString(style.opt("flexWrap")).orEmpty()
|
|
1024
|
+
wrap = flexWrap == "wrap" || flexWrap == "wrap-reverse" || craftNativeBoolean(style.opt("flexWrap"))
|
|
1034
1025
|
wrapReverse = flexWrap == "wrap-reverse"
|
|
1035
|
-
alignItems = style.
|
|
1036
|
-
alignContent = style.
|
|
1037
|
-
justifyContent = style.
|
|
1026
|
+
alignItems = craftNativeOptionalString(style.opt("alignItems")) ?: "stretch"
|
|
1027
|
+
alignContent = craftNativeOptionalString(style.opt("alignContent")) ?: "flex-start"
|
|
1028
|
+
justifyContent = craftNativeOptionalString(style.opt("justifyContent")) ?: "flex-start"
|
|
1038
1029
|
fun spacing(name: String, fallback: Float): Float {
|
|
1039
1030
|
val value = craftNativeNumber(style.opt(name)) ?: Double.NaN
|
|
1040
1031
|
val pixels = value * density
|
|
@@ -1044,7 +1035,7 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1044
1035
|
val gap = spacing("gap", 0f)
|
|
1045
1036
|
rowGap = spacing("rowGap", gap)
|
|
1046
1037
|
columnGap = spacing("columnGap", gap)
|
|
1047
|
-
grid = style.
|
|
1038
|
+
grid = craftNativeOptionalString(style.opt("display")) == "grid"
|
|
1048
1039
|
gridColumns = craftNativeGridColumnCount(
|
|
1049
1040
|
if (style.has("gridTemplateColumns")) style.opt("gridTemplateColumns") else style.opt("gridColumns")
|
|
1050
1041
|
)
|
|
@@ -2095,7 +2086,7 @@ private class CraftNativeKeyboardAvoidingView(context: Context) : FrameLayout(co
|
|
|
2095
2086
|
}
|
|
2096
2087
|
|
|
2097
2088
|
fun configure(props: JSONObject, style: JSONObject, density: Float) {
|
|
2098
|
-
behavior = props.
|
|
2089
|
+
behavior = craftNativeOptionalString(props.opt("behavior"))?.takeIf { it in setOf("height", "position", "padding") } ?: "padding"
|
|
2099
2090
|
val authoredOffset = craftNativeFiniteDouble(props, "keyboardVerticalOffset", 0.0)
|
|
2100
2091
|
val pixelOffset = (authoredOffset * density.toDouble()).takeIf { it.isFinite() } ?: 0.0
|
|
2101
2092
|
keyboardVerticalOffset = pixelOffset.roundToInt()
|
|
@@ -3958,6 +3949,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
3958
3949
|
val bars = CraftNativeChrome(this, routes.tabs)
|
|
3959
3950
|
bars.layoutParams = FrameLayout.LayoutParams(-1, -1)
|
|
3960
3951
|
bars.onBack = { onBackPressedDispatcherCompat() }
|
|
3952
|
+
bars.onAccessory = { path -> navigateOpen(path) }
|
|
3961
3953
|
bars.onButton = { id -> visibleScreen?.takeIf { it.active }?.let { send(it, "NAV_BUTTON", JSONObject().put("id", id)) } }
|
|
3962
3954
|
bars.onTab = { index ->
|
|
3963
3955
|
haptic()
|
|
@@ -4945,7 +4937,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
4945
4937
|
"Text" -> ((previous as? TextView)?.takeUnless { it is Button || it is EditText } ?: TextView(this)).apply {
|
|
4946
4938
|
includeFontPadding = false
|
|
4947
4939
|
maxLines = craftNativeInt(props.opt("numberOfLines"), 0).takeIf { it > 0 } ?: Int.MAX_VALUE
|
|
4948
|
-
ellipsize = when (props.
|
|
4940
|
+
ellipsize = when (craftNativeOptionalString(props.opt("ellipsizeMode"))) {
|
|
4949
4941
|
"head" -> TextUtils.TruncateAt.START
|
|
4950
4942
|
"middle" -> TextUtils.TruncateAt.MIDDLE
|
|
4951
4943
|
"tail" -> TextUtils.TruncateAt.END
|
|
@@ -5248,7 +5240,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5248
5240
|
// from the previous hidden state when it patches props.
|
|
5249
5241
|
craftNativeBoolean(props.opt("visible"))
|
|
5250
5242
|
} else {
|
|
5251
|
-
style.has("display") && style.
|
|
5243
|
+
style.has("display") && craftNativeOptionalString(style.opt("display")) != "none"
|
|
5252
5244
|
}
|
|
5253
5245
|
val wasVisible = screen.modalVisibility[this]
|
|
5254
5246
|
screen.modalVisibility[this] = visible
|
|
@@ -5480,7 +5472,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5480
5472
|
drawing = node
|
|
5481
5473
|
}
|
|
5482
5474
|
"ScrollView", "SectionList" -> (previous as? CraftNativeScrollView ?: CraftNativeScrollView(this)).apply {
|
|
5483
|
-
val horizontal = craftNativeBoolean(props.opt("horizontal")) || style.
|
|
5475
|
+
val horizontal = craftNativeBoolean(props.opt("horizontal")) || craftNativeOptionalString(style.opt("flexDirection")) in setOf("row", "row-reverse")
|
|
5484
5476
|
setHorizontal(horizontal)
|
|
5485
5477
|
setNativeNestedScrollingEnabled(true)
|
|
5486
5478
|
setScrollIndicators(
|
|
@@ -5488,7 +5480,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5488
5480
|
craftNativeBoolean(props.opt("showsHorizontalScrollIndicator"), true),
|
|
5489
5481
|
)
|
|
5490
5482
|
setScrollEnabled(craftNativeBoolean(props.opt("scrollEnabled"), true))
|
|
5491
|
-
setKeyboardShouldPersistTaps(props.
|
|
5483
|
+
setKeyboardShouldPersistTaps(craftNativeOptionalString(props.opt("keyboardShouldPersistTaps")) ?: "never")
|
|
5492
5484
|
setBounces(craftNativeBoolean(props.opt("bounces"), true))
|
|
5493
5485
|
setAlwaysBounce(
|
|
5494
5486
|
craftNativeBoolean(props.opt("alwaysBounceVertical"), !horizontal),
|
|
@@ -5550,7 +5542,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5550
5542
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject()))
|
|
5551
5543
|
}
|
|
5552
5544
|
},
|
|
5553
|
-
keyboardDismissMode = props.
|
|
5545
|
+
keyboardDismissMode = craftNativeOptionalString(props.opt("keyboardDismissMode")).orEmpty(),
|
|
5554
5546
|
dismissKeyboard = {
|
|
5555
5547
|
(getSystemService(INPUT_METHOD_SERVICE) as? android.view.inputmethod.InputMethodManager)
|
|
5556
5548
|
?.hideSoftInputFromWindow(nativeScroll.windowToken, 0)
|
|
@@ -5587,9 +5579,9 @@ class MainActivity : AppCompatActivity() {
|
|
|
5587
5579
|
{ send(screen, "EVENT", JSONObject().put("handlerName", handler).put("nativeEvent", JSONObject())) }
|
|
5588
5580
|
}, craftNativeBoolean(propRefresh.opt("refreshing"), craftNativeBoolean(props.opt("refreshing"))))
|
|
5589
5581
|
setRefreshAppearance(propRefresh, refreshTintFallback(screen))
|
|
5590
|
-
nativeList.setKeyboardShouldPersistTaps(props.
|
|
5582
|
+
nativeList.setKeyboardShouldPersistTaps(craftNativeOptionalString(props.opt("keyboardShouldPersistTaps")) ?: "never")
|
|
5591
5583
|
nativeList.setContentContainerStyle(props.optJSONObject("contentContainerStyle"), resources.displayMetrics.density)
|
|
5592
|
-
nativeList.setKeyboardDismissMode(props.
|
|
5584
|
+
nativeList.setKeyboardDismissMode(craftNativeOptionalString(props.opt("keyboardDismissMode")).orEmpty()) {
|
|
5593
5585
|
(getSystemService(INPUT_METHOD_SERVICE) as? android.view.inputmethod.InputMethodManager)
|
|
5594
5586
|
?.hideSoftInputFromWindow(windowToken, 0)
|
|
5595
5587
|
}
|
|
@@ -5598,6 +5590,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5598
5590
|
"View", "SafeAreaView" -> (previous as? CraftNativeFlexLayout ?: CraftNativeFlexLayout(this)).apply {
|
|
5599
5591
|
configureContainer(this, style)
|
|
5600
5592
|
if (type == "SafeAreaView") setSafeAreaEdges(props.optJSONArray("edges"))
|
|
5593
|
+
else setWindowSafeInsets(0, 0, 0, 0)
|
|
5601
5594
|
reconcileChildren(screen, this, children, identity, next, style, previousControls)
|
|
5602
5595
|
}
|
|
5603
5596
|
"KeyboardAvoidingView" -> (previous as? CraftNativeKeyboardAvoidingView ?: CraftNativeKeyboardAvoidingView(this)).apply {
|
|
@@ -5744,7 +5737,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5744
5737
|
if (type == "ActivityIndicator") {
|
|
5745
5738
|
val animating = craftNativeBoolean(props.opt("animating"), true)
|
|
5746
5739
|
val hidesWhenStopped = craftNativeBoolean(props.opt("hidesWhenStopped"), true)
|
|
5747
|
-
control.visibility = if (style.
|
|
5740
|
+
control.visibility = if (craftNativeOptionalString(style.opt("display")) == "none" || (!animating && hidesWhenStopped)) {
|
|
5748
5741
|
View.GONE
|
|
5749
5742
|
} else {
|
|
5750
5743
|
View.VISIBLE
|
|
@@ -5865,7 +5858,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5865
5858
|
layout.setChildStyle(childView, child.optJSONObject("style") ?: JSONObject(), resources.displayMetrics.density)
|
|
5866
5859
|
}
|
|
5867
5860
|
}
|
|
5868
|
-
if (style.
|
|
5861
|
+
if (craftNativeOptionalString(style.opt("flexDirection"))?.endsWith("-reverse") == true) desired.reverse()
|
|
5869
5862
|
val desiredSet = desired.toSet()
|
|
5870
5863
|
for ((index, childView) in desired.withIndex()) {
|
|
5871
5864
|
if (layout.getChildAt(index) !== childView) {
|
|
@@ -5992,7 +5985,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5992
5985
|
}
|
|
5993
5986
|
applyTransform(view, style.optJSONArray("transform"))
|
|
5994
5987
|
if (view !is CraftNativeModalView) {
|
|
5995
|
-
view.visibility = if (style.
|
|
5988
|
+
view.visibility = if (craftNativeOptionalString(style.opt("display")) == "none") View.GONE else View.VISIBLE
|
|
5996
5989
|
}
|
|
5997
5990
|
view.elevation = dp(craftNativeNonNegativeDouble(style, "elevation", 0.0)).toFloat()
|
|
5998
5991
|
view.z = craftNativeFiniteFloat(style, "zIndex", 0f)
|
|
@@ -6001,13 +5994,13 @@ class MainActivity : AppCompatActivity() {
|
|
|
6001
5994
|
// background paints over the decoded picture (only rounded corners
|
|
6002
5995
|
// showed it). Keep the outline/borders, with a transparent fill.
|
|
6003
5996
|
val backgroundColor = if (view is CraftNativeVideoView) Color.TRANSPARENT
|
|
6004
|
-
else color(style.
|
|
5997
|
+
else color(craftNativeOptionalString(style.opt("backgroundColor")).orEmpty(), Color.TRANSPARENT)
|
|
6005
5998
|
val border = craftNativeNonNegativeDouble(style, "borderWidth", 0.0)
|
|
6006
5999
|
val radius = craftNativeNonNegativeDouble(style, "borderRadius", 0.0)
|
|
6007
|
-
val gradientDirection = style.
|
|
6008
|
-
val gradientFrom = style.
|
|
6009
|
-
val gradientVia = style.
|
|
6010
|
-
val gradientTo = style.
|
|
6000
|
+
val gradientDirection = craftNativeOptionalString(style.opt("gradientDirection"))
|
|
6001
|
+
val gradientFrom = craftNativeOptionalString(style.opt("gradientFrom"))
|
|
6002
|
+
val gradientVia = craftNativeOptionalString(style.opt("gradientVia"))
|
|
6003
|
+
val gradientTo = craftNativeOptionalString(style.opt("gradientTo"))
|
|
6011
6004
|
val gradientColors = if (gradientDirection != null && gradientFrom != null && gradientTo != null) {
|
|
6012
6005
|
listOfNotNull(
|
|
6013
6006
|
color(gradientFrom, Color.TRANSPARENT),
|
|
@@ -6025,7 +6018,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6025
6018
|
listOf(radius, radius)
|
|
6026
6019
|
}.toFloatArray()
|
|
6027
6020
|
val sideColors = listOf("borderTopColor", "borderRightColor", "borderBottomColor", "borderLeftColor")
|
|
6028
|
-
.map { color(style.
|
|
6021
|
+
.map { color(craftNativeOptionalString(style.opt(it)) ?: craftNativeOptionalString(style.opt("borderColor")).orEmpty(), Color.TRANSPARENT) }
|
|
6029
6022
|
.toIntArray()
|
|
6030
6023
|
val defaultBackground = if (defaultBackgrounds.containsKey(view)) {
|
|
6031
6024
|
defaultBackgrounds[view]
|
|
@@ -6039,7 +6032,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6039
6032
|
cornerRadii,
|
|
6040
6033
|
sideWidths,
|
|
6041
6034
|
sideColors,
|
|
6042
|
-
style.
|
|
6035
|
+
craftNativeOptionalString(style.opt("borderStyle"))?.takeIf { it == "dashed" || it == "dotted" },
|
|
6043
6036
|
gradientDirection,
|
|
6044
6037
|
gradientColors,
|
|
6045
6038
|
)
|
|
@@ -6051,8 +6044,8 @@ class MainActivity : AppCompatActivity() {
|
|
|
6051
6044
|
} else setColor(backgroundColor)
|
|
6052
6045
|
if (hasCornerRadii) setCornerRadii(cornerRadii) else cornerRadius = dp(radius).toFloat()
|
|
6053
6046
|
if (border > 0) {
|
|
6054
|
-
val borderColor = color(style.
|
|
6055
|
-
when (style.
|
|
6047
|
+
val borderColor = color(craftNativeOptionalString(style.opt("borderColor")).orEmpty(), Color.TRANSPARENT)
|
|
6048
|
+
when (craftNativeOptionalString(style.opt("borderStyle"))) {
|
|
6056
6049
|
"dashed" -> setStroke(dp(border), borderColor, dp(border * 3).toFloat(), dp(border * 2).toFloat())
|
|
6057
6050
|
"dotted" -> setStroke(dp(border), borderColor, dp(border).toFloat(), dp(border * 1.5).toFloat())
|
|
6058
6051
|
else -> setStroke(dp(border), borderColor)
|
|
@@ -6065,13 +6058,14 @@ class MainActivity : AppCompatActivity() {
|
|
|
6065
6058
|
// and the web.
|
|
6066
6059
|
null
|
|
6067
6060
|
} else defaultBackground
|
|
6068
|
-
|
|
6069
|
-
|
|
6061
|
+
val overflow = craftNativeOptionalString(style.opt("overflow"))
|
|
6062
|
+
view.clipToOutline = overflow == "hidden"
|
|
6063
|
+
if (view is ViewGroup) view.clipChildren = overflow == "hidden"
|
|
6070
6064
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P &&
|
|
6071
6065
|
(style.has("shadowColor") || style.has("shadowOpacity") || style.has("shadowRadius"))
|
|
6072
6066
|
) {
|
|
6073
6067
|
val shadowOpacity = craftNativeFiniteFloat(style, "shadowOpacity", 1f).coerceIn(0f, 1f)
|
|
6074
|
-
val shadow = color(style.
|
|
6068
|
+
val shadow = color(craftNativeOptionalString(style.opt("shadowColor")).orEmpty(), Color.BLACK)
|
|
6075
6069
|
val alphaShadow = Color.argb((Color.alpha(shadow) * shadowOpacity).roundToInt(), Color.red(shadow), Color.green(shadow), Color.blue(shadow))
|
|
6076
6070
|
view.outlineAmbientShadowColor = alphaShadow
|
|
6077
6071
|
view.outlineSpotShadowColor = alphaShadow
|
|
@@ -6169,7 +6163,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6169
6163
|
}
|
|
6170
6164
|
|
|
6171
6165
|
private fun configureText(view: TextView, value: String, style: JSONObject) {
|
|
6172
|
-
view.text = when (style.
|
|
6166
|
+
view.text = when (craftNativeOptionalString(style.opt("textTransform"))) {
|
|
6173
6167
|
"uppercase" -> value.uppercase()
|
|
6174
6168
|
"lowercase" -> value.lowercase()
|
|
6175
6169
|
"capitalize" -> value.split(' ').joinToString(" ") { word -> word.replaceFirstChar(Char::uppercase) }
|
|
@@ -6279,7 +6273,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6279
6273
|
}
|
|
6280
6274
|
|
|
6281
6275
|
private fun configureTextStyle(view: TextView, style: JSONObject) {
|
|
6282
|
-
view.setTextColor(color(style.
|
|
6276
|
+
view.setTextColor(color(craftNativeOptionalString(style.opt("color")).orEmpty(), defaultTextColor))
|
|
6283
6277
|
view.setTextSize(TypedValue.COMPLEX_UNIT_SP, craftNativeFiniteFloat(style, "fontSize", 16f))
|
|
6284
6278
|
val fontWeight = style.opt("fontWeight") as? String
|
|
6285
6279
|
val weight = when (fontWeight) {
|
|
@@ -6287,13 +6281,14 @@ class MainActivity : AppCompatActivity() {
|
|
|
6287
6281
|
"100", "200", "300", "400", "500", "600", "700", "800", "900" -> style.optInt("fontWeight")
|
|
6288
6282
|
else -> 400
|
|
6289
6283
|
}
|
|
6290
|
-
val italic = style.
|
|
6291
|
-
val family = style.
|
|
6284
|
+
val italic = craftNativeOptionalString(style.opt("fontStyle")) == "italic"
|
|
6285
|
+
val family = craftNativeOptionalString(style.opt("fontFamily"))?.takeIf { it.isNotBlank() }
|
|
6292
6286
|
view.typeface = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
6293
6287
|
Typeface.create(Typeface.create(family, Typeface.NORMAL), weight, italic)
|
|
6294
6288
|
} else Typeface.create(family, (if (weight >= 600) Typeface.BOLD else Typeface.NORMAL) or
|
|
6295
6289
|
(if (italic) Typeface.ITALIC else Typeface.NORMAL))
|
|
6296
|
-
|
|
6290
|
+
val textAlign = craftNativeOptionalString(style.opt("textAlign"))
|
|
6291
|
+
view.textAlignment = when (textAlign) {
|
|
6297
6292
|
"left" -> View.TEXT_ALIGNMENT_TEXT_START
|
|
6298
6293
|
"right" -> View.TEXT_ALIGNMENT_TEXT_END
|
|
6299
6294
|
"center" -> View.TEXT_ALIGNMENT_CENTER
|
|
@@ -6301,7 +6296,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6301
6296
|
else -> View.TEXT_ALIGNMENT_INHERIT
|
|
6302
6297
|
}
|
|
6303
6298
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
6304
|
-
view.justificationMode = if (
|
|
6299
|
+
view.justificationMode = if (textAlign == "justify") {
|
|
6305
6300
|
Layout.JUSTIFICATION_MODE_INTER_WORD
|
|
6306
6301
|
} else {
|
|
6307
6302
|
Layout.JUSTIFICATION_MODE_NONE
|
|
@@ -6315,7 +6310,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6315
6310
|
craftNativeFiniteDouble(style, "lineHeight", Double.NaN).takeIf { it.isFinite() }?.let { dp(it) - view.textSize } ?: 0f,
|
|
6316
6311
|
1f
|
|
6317
6312
|
)
|
|
6318
|
-
val shadowColor = style.
|
|
6313
|
+
val shadowColor = craftNativeOptionalString(style.opt("textShadowColor"))?.takeIf { it.isNotBlank() }
|
|
6319
6314
|
if (shadowColor == null) {
|
|
6320
6315
|
view.paint.clearShadowLayer()
|
|
6321
6316
|
} else {
|
|
@@ -6332,16 +6327,16 @@ class MainActivity : AppCompatActivity() {
|
|
|
6332
6327
|
}
|
|
6333
6328
|
|
|
6334
6329
|
private fun applyTextDecoration(view: TextView, style: JSONObject) {
|
|
6335
|
-
val line = style.
|
|
6330
|
+
val line = craftNativeOptionalString(style.opt("textDecorationLine")).orEmpty()
|
|
6336
6331
|
if (view is EditText) {
|
|
6337
6332
|
// A field's own text, spanned in place: replacing it would move
|
|
6338
6333
|
// the caret to the start and tell the screen the text changed.
|
|
6339
6334
|
val editable = view.text ?: return
|
|
6340
6335
|
editable.getSpans(0, editable.length, CraftTextDecorationSpan::class.java).forEach(editable::removeSpan)
|
|
6341
6336
|
if (line.isBlank() || line == "none" || editable.isEmpty()) return
|
|
6342
|
-
val fieldColor = style.
|
|
6337
|
+
val fieldColor = craftNativeOptionalString(style.opt("textDecorationColor"))?.takeIf { it.isNotBlank() }?.let { color(it, Color.TRANSPARENT) }
|
|
6343
6338
|
editable.setSpan(
|
|
6344
|
-
CraftTextDecorationSpan(line, style.
|
|
6339
|
+
CraftTextDecorationSpan(line, craftNativeOptionalString(style.opt("textDecorationStyle")).orEmpty().ifBlank { "solid" }, fieldColor),
|
|
6345
6340
|
0,
|
|
6346
6341
|
editable.length,
|
|
6347
6342
|
Spannable.SPAN_INCLUSIVE_INCLUSIVE,
|
|
@@ -6353,14 +6348,14 @@ class MainActivity : AppCompatActivity() {
|
|
|
6353
6348
|
if (view.text is Spannable) view.text = text
|
|
6354
6349
|
return
|
|
6355
6350
|
}
|
|
6356
|
-
val decorationColor = style.
|
|
6351
|
+
val decorationColor = craftNativeOptionalString(style.opt("textDecorationColor")).orEmpty()
|
|
6357
6352
|
.takeIf { it.isNotBlank() }
|
|
6358
6353
|
?.let { color(it, Color.TRANSPARENT) }
|
|
6359
6354
|
val decorated = SpannableString(text)
|
|
6360
6355
|
decorated.setSpan(
|
|
6361
6356
|
CraftTextDecorationSpan(
|
|
6362
6357
|
line,
|
|
6363
|
-
style.
|
|
6358
|
+
craftNativeOptionalString(style.opt("textDecorationStyle")).orEmpty().ifBlank { "solid" },
|
|
6364
6359
|
decorationColor,
|
|
6365
6360
|
),
|
|
6366
6361
|
0,
|
|
@@ -6568,8 +6563,16 @@ class MainActivity : AppCompatActivity() {
|
|
|
6568
6563
|
info.roleDescription = role.takeIf { it !in setOf("view", "text", "textinput", "scrollview") }
|
|
6569
6564
|
info.hintText = host.tooltipText
|
|
6570
6565
|
info.isEnabled = host.isEnabled && !disabled
|
|
6571
|
-
|
|
6572
|
-
|
|
6566
|
+
// Keep the native widget state when no accessibilityState was
|
|
6567
|
+
// authored. Overwriting it with the strict false fallback
|
|
6568
|
+
// made a checked Switch/CheckBox announce as unchecked unless
|
|
6569
|
+
// the screen redundantly mirrored its value into metadata.
|
|
6570
|
+
if (state?.has("selected") == true) {
|
|
6571
|
+
info.isSelected = craftNativeBoolean(state.opt("selected"))
|
|
6572
|
+
}
|
|
6573
|
+
if (state?.has("checked") == true) {
|
|
6574
|
+
info.isChecked = craftNativeBoolean(state.opt("checked"))
|
|
6575
|
+
}
|
|
6573
6576
|
}
|
|
6574
6577
|
})
|
|
6575
6578
|
ViewCompat.setImportantForAccessibility(
|