craft-native 0.0.395 → 0.0.396
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/dist/android/templates/CraftNativeFlatList.kt.template +7 -0
- package/dist/android/templates/CraftNativeMapGoogle.kt.template +3 -0
- package/dist/android/templates/CraftNativeMapLibre.kt.template +3 -0
- package/dist/android/templates/CraftNativeRefreshableFlatList.kt.template +9 -0
- package/dist/android/templates/MainActivityNative.kt.template +317 -20
- package/dist/cli.js +1 -1
- package/dist/components/index.d.ts +16 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/templates/CraftNativeFlatList.swift +4 -0
- package/dist/ios/templates/CraftNativeMutation.swift +27 -2
- package/dist/ios/templates/CraftNativeScreen.swift +292 -44
- package/dist/macos/templates/CraftNativeMutation.swift +27 -2
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package {{PACKAGE_NAME}}
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.view.MotionEvent
|
|
4
5
|
import android.view.View
|
|
5
6
|
import android.view.ViewGroup
|
|
6
7
|
import android.widget.FrameLayout
|
|
@@ -18,6 +19,9 @@ internal typealias CraftNativeRenderItem = (node: JSONObject, identity: String,
|
|
|
18
19
|
|
|
19
20
|
/** A stable-key RecyclerView host for stx native FlatList nodes. */
|
|
20
21
|
internal class CraftNativeFlatList(context: Context) : RecyclerView(context) {
|
|
22
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
23
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
24
|
+
|
|
21
25
|
private data class Item(
|
|
22
26
|
val identity: String,
|
|
23
27
|
val node: JSONObject,
|
|
@@ -227,11 +231,13 @@ internal class CraftNativeFlatList(context: Context) : RecyclerView(context) {
|
|
|
227
231
|
.map { it.second }
|
|
228
232
|
|
|
229
233
|
override fun onInterceptTouchEvent(event: android.view.MotionEvent): Boolean {
|
|
234
|
+
if (event.actionMasked != MotionEvent.ACTION_CANCEL && !CraftNativePointers.ownsTouch(this)) return false
|
|
230
235
|
if (!scrollEnabled) return false
|
|
231
236
|
return super.onInterceptTouchEvent(event)
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
override fun onTouchEvent(event: android.view.MotionEvent): Boolean {
|
|
240
|
+
if (event.actionMasked != MotionEvent.ACTION_CANCEL && !CraftNativePointers.ownsTouch(this)) return false
|
|
235
241
|
if (!scrollEnabled) return false
|
|
236
242
|
return super.onTouchEvent(event)
|
|
237
243
|
}
|
|
@@ -304,6 +310,7 @@ internal class CraftNativeFlatList(context: Context) : RecyclerView(context) {
|
|
|
304
310
|
}
|
|
305
311
|
var dismissed = false
|
|
306
312
|
setOnTouchListener { _, event ->
|
|
313
|
+
if (!CraftNativePointers.ownsTouch(this) && event.actionMasked != MotionEvent.ACTION_CANCEL) return@setOnTouchListener false
|
|
307
314
|
when (event.actionMasked) {
|
|
308
315
|
android.view.MotionEvent.ACTION_DOWN -> dismissed = false
|
|
309
316
|
android.view.MotionEvent.ACTION_MOVE -> if (!dismissed) {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** The Android host for the small, host-neutral native trail map contract. */
|
|
2
2
|
private class CraftNativeMapView(context: Context) : FrameLayout(context), OnMapReadyCallback {
|
|
3
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
4
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
5
|
+
|
|
3
6
|
private data class PolygonValue(val points: List<LatLng>, val fillColor: Int, val strokeColor: Int, val strokeWidth: Float)
|
|
4
7
|
private val mapView = MapView(context)
|
|
5
8
|
private val scaleView = LinearLayout(context).apply {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** A key-free native Android map. STX geometry never enters a WebView. */
|
|
2
2
|
internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMapReadyCallback {
|
|
3
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
4
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
5
|
+
|
|
3
6
|
private val mapView: MapView
|
|
4
7
|
private var map: MapLibreMap? = null
|
|
5
8
|
private var destroyed = false
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
package {{PACKAGE_NAME}}
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.view.MotionEvent
|
|
4
5
|
import org.json.JSONObject
|
|
5
6
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
6
7
|
|
|
7
8
|
/** Swipe-to-refresh host for a native FlatList. */
|
|
8
9
|
internal class CraftNativeRefreshableFlatList(context: Context) : SwipeRefreshLayout(context) {
|
|
10
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
11
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
12
|
+
|
|
13
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean =
|
|
14
|
+
CraftNativePointers.ownsTouch(this) && super.onInterceptTouchEvent(event)
|
|
15
|
+
override fun onTouchEvent(event: MotionEvent): Boolean =
|
|
16
|
+
(event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
17
|
+
|
|
9
18
|
val list = CraftNativeFlatList(context)
|
|
10
19
|
private var refreshHandler: (() -> Unit)? = null
|
|
11
20
|
|
|
@@ -366,6 +366,9 @@ private object CraftNativeSkewTransforms {
|
|
|
366
366
|
|
|
367
367
|
/** A DOM-free SVG surface for the geometry emitted by the shared STX native protocol. */
|
|
368
368
|
private class CraftNativeSvgView(context: Context) : View(context) {
|
|
369
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
370
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
371
|
+
|
|
369
372
|
var drawing: JSONObject = JSONObject()
|
|
370
373
|
set(value) {
|
|
371
374
|
field = value
|
|
@@ -972,8 +975,184 @@ internal class CraftNativeCelebration(private val view: View) {
|
|
|
972
975
|
}
|
|
973
976
|
}
|
|
974
977
|
|
|
978
|
+
/** Authored nodes are boundaries; native control implementation views are not. */
|
|
979
|
+
internal object CraftNativePointers {
|
|
980
|
+
private data class State(var mode: String? = null, var container: Boolean = false,
|
|
981
|
+
var active: Boolean = false, var cancelled: Boolean = false, var route: List<String> = emptyList())
|
|
982
|
+
private val states = java.util.WeakHashMap<View, State>()
|
|
983
|
+
|
|
984
|
+
fun configure(view: View, props: JSONObject, style: JSONObject, container: Boolean) {
|
|
985
|
+
val raw = if (props.has("pointerEvents") && !props.isNull("pointerEvents")) props.opt("pointerEvents") else style.opt("pointerEvents")
|
|
986
|
+
val state = states.getOrPut(view) { State() }
|
|
987
|
+
state.mode = (raw as? String)?.takeIf { it in setOf("auto", "none", "box-none", "box-only") } ?: "auto"
|
|
988
|
+
state.container = container
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
private fun route(view: View): List<String> {
|
|
992
|
+
val result = mutableListOf<String>()
|
|
993
|
+
var candidate: View? = view
|
|
994
|
+
while (candidate != null) {
|
|
995
|
+
states[candidate]?.mode?.let { result.add(it) }
|
|
996
|
+
candidate = candidate.parent as? View
|
|
997
|
+
}
|
|
998
|
+
return result
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
fun ownsTouch(view: View): Boolean = route(view).firstOrNull() !in setOf("none", "box-none")
|
|
1002
|
+
|
|
1003
|
+
fun dispatch(view: View, event: MotionEvent, native: (MotionEvent) -> Boolean): Boolean {
|
|
1004
|
+
val state = states.getOrPut(view) { State() }
|
|
1005
|
+
val route = route(view)
|
|
1006
|
+
if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
|
|
1007
|
+
state.active = false
|
|
1008
|
+
return native(event)
|
|
1009
|
+
}
|
|
1010
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
1011
|
+
state.active = false
|
|
1012
|
+
state.cancelled = false
|
|
1013
|
+
state.route = route
|
|
1014
|
+
} else if (state.active && state.route != route) {
|
|
1015
|
+
val cancel = MotionEvent.obtain(event)
|
|
1016
|
+
cancel.action = MotionEvent.ACTION_CANCEL
|
|
1017
|
+
try { native(cancel) } finally { cancel.recycle() }
|
|
1018
|
+
state.active = false
|
|
1019
|
+
state.cancelled = true
|
|
1020
|
+
}
|
|
1021
|
+
if (state.cancelled) return false
|
|
1022
|
+
if (state.mode == "box-only" && event.actionMasked == MotionEvent.ACTION_DOWN &&
|
|
1023
|
+
(event.x < 0 || event.x >= view.width || event.y < 0 || event.y >= view.height)) return false
|
|
1024
|
+
val ancestors = route.drop(1)
|
|
1025
|
+
if ("none" in route || "box-only" in ancestors || (state.mode == "box-none" && !state.container)) return false
|
|
1026
|
+
val handled = native(event) || (state.mode == "box-only" && state.container && view.isEnabled)
|
|
1027
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) state.active = handled
|
|
1028
|
+
if (event.actionMasked == MotionEvent.ACTION_UP) state.active = false
|
|
1029
|
+
return handled
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
internal class CraftNativePointerTextView(context: Context) : TextView(context) {
|
|
1034
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1035
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1036
|
+
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
internal class CraftNativePointerButton(context: Context) : Button(context) {
|
|
1040
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1041
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1042
|
+
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
internal class CraftNativePointerCheckBox(context: Context) : CheckBox(context) {
|
|
1046
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1047
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1048
|
+
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
internal class CraftNativePointerRadioGroup(context: Context) : android.widget.RadioGroup(context) {
|
|
1052
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1053
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
internal class CraftNativePointerSpinner(context: Context) : Spinner(context) {
|
|
1057
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1058
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1059
|
+
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
internal class CraftNativePointerSwitch(context: Context) : Switch(context) {
|
|
1063
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1064
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1065
|
+
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
internal class CraftNativePointerSeekBar(context: Context) : SeekBar(context) {
|
|
1069
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1070
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1071
|
+
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
internal class CraftNativePointerImageView(context: Context) : ImageView(context) {
|
|
1075
|
+
private var objectFit: String? = null
|
|
1076
|
+
private var objectX = 0.5f
|
|
1077
|
+
private var objectY = 0.5f
|
|
1078
|
+
|
|
1079
|
+
fun configureObjectGeometry(props: JSONObject, style: JSONObject) {
|
|
1080
|
+
fun value(name: String): Any? = props.opt(name)?.takeUnless { it == JSONObject.NULL }
|
|
1081
|
+
?: style.opt(name)?.takeUnless { it == JSONObject.NULL }
|
|
1082
|
+
val fit = value("objectFit")
|
|
1083
|
+
val position = value("objectPosition")
|
|
1084
|
+
objectFit = if (fit != null || position != null) (fit as? String)
|
|
1085
|
+
?.takeIf { it in setOf("fill", "contain", "cover", "none", "scale-down") } ?: "fill" else null
|
|
1086
|
+
val point = parsePosition(position)
|
|
1087
|
+
objectX = point.first; objectY = point.second
|
|
1088
|
+
cropToPadding = objectFit != null
|
|
1089
|
+
updateObjectGeometry()
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
private fun parsePosition(raw: Any?): Pair<Float, Float> {
|
|
1093
|
+
val center = 0.5f to 0.5f
|
|
1094
|
+
val text = (raw as? String)?.trim()?.lowercase() ?: return center
|
|
1095
|
+
var parts = text.split(Regex("\\s+"))
|
|
1096
|
+
if (parts.size !in 1..2) return center
|
|
1097
|
+
if (parts.size == 1) parts = if (parts[0] in setOf("top", "bottom")) listOf("center", parts[0]) else listOf(parts[0], "center")
|
|
1098
|
+
else if (parts[0] in setOf("top", "bottom") || parts[1] in setOf("left", "right")) parts = parts.reversed()
|
|
1099
|
+
fun fraction(part: String, low: String, high: String): Float? = when (part) {
|
|
1100
|
+
low -> 0f; high -> 1f; "center" -> 0.5f
|
|
1101
|
+
else -> if (part.endsWith("%")) part.dropLast(1).toFloatOrNull()?.takeIf { it.isFinite() }?.div(100f) else null
|
|
1102
|
+
}
|
|
1103
|
+
return (fraction(parts[0], "left", "right") ?: return center) to (fraction(parts[1], "top", "bottom") ?: return center)
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
override fun setImageDrawable(drawable: android.graphics.drawable.Drawable?) {
|
|
1107
|
+
super.setImageDrawable(drawable)
|
|
1108
|
+
updateObjectGeometry()
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
1112
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
1113
|
+
updateObjectGeometry()
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
1117
|
+
super.onLayout(changed, left, top, right, bottom)
|
|
1118
|
+
updateObjectGeometry()
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
private fun updateObjectGeometry() {
|
|
1122
|
+
val fit = objectFit ?: return
|
|
1123
|
+
val source = drawable ?: return
|
|
1124
|
+
val sw = source.intrinsicWidth.toFloat(); val sh = source.intrinsicHeight.toFloat()
|
|
1125
|
+
if (sw <= 0 || sh <= 0) return
|
|
1126
|
+
val w = (width - paddingLeft - paddingRight).coerceAtLeast(0).toFloat()
|
|
1127
|
+
val h = (height - paddingTop - paddingBottom).coerceAtLeast(0).toFloat()
|
|
1128
|
+
val contain = minOf(w / sw, h / sh)
|
|
1129
|
+
val scale = when (fit) {
|
|
1130
|
+
"cover" -> maxOf(w / sw, h / sh)
|
|
1131
|
+
"none" -> 1f
|
|
1132
|
+
"scale-down" -> minOf(1f, contain)
|
|
1133
|
+
else -> contain
|
|
1134
|
+
}
|
|
1135
|
+
val sx = if (fit == "fill") w / sw else scale
|
|
1136
|
+
val sy = if (fit == "fill") h / sh else scale
|
|
1137
|
+
scaleType = ScaleType.MATRIX
|
|
1138
|
+
imageMatrix = Matrix().apply {
|
|
1139
|
+
setScale(sx, sy)
|
|
1140
|
+
postTranslate((w - sw * sx) * objectX, (h - sh * sy) * objectY)
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1145
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
1146
|
+
|
|
1147
|
+
}
|
|
1148
|
+
|
|
975
1149
|
/** A deterministic flex-shaped container shared by normal views and scroll content. */
|
|
976
1150
|
internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
1151
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean =
|
|
1152
|
+
CraftNativePointers.ownsTouch(this) && super.onInterceptTouchEvent(event)
|
|
1153
|
+
override fun onTouchEvent(event: MotionEvent): Boolean =
|
|
1154
|
+
(event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
1155
|
+
|
|
977
1156
|
private var celebration: CraftNativeCelebration? = null
|
|
978
1157
|
fun configureCelebration(raw: JSONObject?, radius: Float) {
|
|
979
1158
|
if (raw != null && celebration == null) celebration = CraftNativeCelebration(this)
|
|
@@ -1012,10 +1191,76 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1012
1191
|
private var safeAreaPadding = intArrayOf(0, 0, 0, 0)
|
|
1013
1192
|
private var applyingPadding = false
|
|
1014
1193
|
private var safeAreaEdges = setOf("top", "right", "bottom", "left")
|
|
1194
|
+
private var overflowTouchTarget: View? = null
|
|
1195
|
+
|
|
1196
|
+
private fun childEvent(child: View, event: MotionEvent): MotionEvent = MotionEvent.obtain(event).also {
|
|
1197
|
+
it.offsetLocation((scrollX - child.left).toFloat(), (scrollY - child.top).toFloat())
|
|
1198
|
+
if (!child.matrix.isIdentity) {
|
|
1199
|
+
val inverse = android.graphics.Matrix()
|
|
1200
|
+
if (child.matrix.invert(inverse)) it.transform(inverse)
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
private fun overflowContains(group: ViewGroup, x: Float, y: Float): Boolean {
|
|
1205
|
+
if (group.clipChildren) return false
|
|
1206
|
+
for (index in group.childCount - 1 downTo 0) {
|
|
1207
|
+
val child = group.getChildAt(index)
|
|
1208
|
+
if (child.visibility != View.VISIBLE || child.alpha <= 0.01f) continue
|
|
1209
|
+
val point = floatArrayOf(x + group.scrollX - child.left, y + group.scrollY - child.top)
|
|
1210
|
+
val inverse = android.graphics.Matrix()
|
|
1211
|
+
if (!child.matrix.isIdentity && child.matrix.invert(inverse)) inverse.mapPoints(point)
|
|
1212
|
+
if (point[0] >= 0 && point[0] < child.width && point[1] >= 0 && point[1] < child.height) return true
|
|
1213
|
+
if (child is ViewGroup && overflowContains(child, point[0], point[1])) return true
|
|
1214
|
+
}
|
|
1215
|
+
return false
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// Android normally rejects a zero-height child's entire subtree before
|
|
1219
|
+
// dispatch, even when it draws outside that box. Only that overflow path
|
|
1220
|
+
// needs routing here; ordinary gestures stay in ViewGroup's dispatcher.
|
|
1221
|
+
private fun dispatchOverflow(event: MotionEvent): Boolean? {
|
|
1222
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
1223
|
+
overflowTouchTarget = null
|
|
1224
|
+
val children = (0 until childCount).map { getChildAt(it) }
|
|
1225
|
+
.filter { it.visibility == View.VISIBLE && it.alpha > 0.01f }
|
|
1226
|
+
.sortedBy { it.z }.reversed()
|
|
1227
|
+
val reachesOverflow = children.any { child ->
|
|
1228
|
+
val local = childEvent(child, event)
|
|
1229
|
+
try {
|
|
1230
|
+
child is ViewGroup && (local.x < 0 || local.x >= child.width || local.y < 0 || local.y >= child.height) &&
|
|
1231
|
+
overflowContains(child, local.x, local.y)
|
|
1232
|
+
} finally { local.recycle() }
|
|
1233
|
+
}
|
|
1234
|
+
if (!reachesOverflow) return null
|
|
1235
|
+
for (child in children) {
|
|
1236
|
+
val local = childEvent(child, event)
|
|
1237
|
+
try {
|
|
1238
|
+
val inside = local.x >= 0 && local.x < child.width && local.y >= 0 && local.y < child.height
|
|
1239
|
+
if ((inside || (child is ViewGroup && overflowContains(child, local.x, local.y))) && child.dispatchTouchEvent(local)) {
|
|
1240
|
+
overflowTouchTarget = child
|
|
1241
|
+
return true
|
|
1242
|
+
}
|
|
1243
|
+
} finally { local.recycle() }
|
|
1244
|
+
}
|
|
1245
|
+
return null
|
|
1246
|
+
}
|
|
1247
|
+
val target = overflowTouchTarget ?: return null
|
|
1248
|
+
val local = childEvent(target, event)
|
|
1249
|
+
try {
|
|
1250
|
+
if (target.parent !== this) local.action = MotionEvent.ACTION_CANCEL
|
|
1251
|
+
target.dispatchTouchEvent(local)
|
|
1252
|
+
if (local.actionMasked == MotionEvent.ACTION_UP || local.actionMasked == MotionEvent.ACTION_CANCEL) overflowTouchTarget = null
|
|
1253
|
+
return true
|
|
1254
|
+
} finally { local.recycle() }
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1015
1257
|
private var shieldedModalTouch = false
|
|
1016
1258
|
private var dismissibleModalTouch: CraftNativeModalView? = null
|
|
1017
1259
|
|
|
1018
|
-
override fun dispatchTouchEvent(event: MotionEvent): Boolean
|
|
1260
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
1261
|
+
CraftNativePointers.dispatch(this, event) { dispatchNativeTouchEvent(it) }
|
|
1262
|
+
|
|
1263
|
+
private fun dispatchNativeTouchEvent(event: MotionEvent): Boolean {
|
|
1019
1264
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
1020
1265
|
val x = event.x.roundToInt()
|
|
1021
1266
|
val y = event.y.roundToInt()
|
|
@@ -1023,12 +1268,12 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1023
1268
|
.map { getChildAt(it) }
|
|
1024
1269
|
.filterIsInstance<CraftNativeModalView>()
|
|
1025
1270
|
.firstOrNull { child ->
|
|
1026
|
-
child.dismissOnOutsideTap && child.visibility == View.VISIBLE && child.alpha > 0.01f
|
|
1271
|
+
CraftNativePointers.ownsTouch(child) && child.dismissOnOutsideTap && child.visibility == View.VISIBLE && child.alpha > 0.01f
|
|
1027
1272
|
&& (x < child.left || x >= child.right || y < child.top || y >= child.bottom)
|
|
1028
1273
|
}
|
|
1029
1274
|
shieldedModalTouch = (childCount - 1 downTo 0).any { index ->
|
|
1030
1275
|
val child = getChildAt(index)
|
|
1031
|
-
child is CraftNativeModalView && !child.blocksBackground && child.visibility == View.VISIBLE
|
|
1276
|
+
child is CraftNativeModalView && CraftNativePointers.ownsTouch(child) && !child.blocksBackground && child.visibility == View.VISIBLE
|
|
1032
1277
|
&& (x < child.left || x >= child.right || y < child.top || y >= child.bottom)
|
|
1033
1278
|
&& child.hasBlockingModalBelow()
|
|
1034
1279
|
}
|
|
@@ -1046,6 +1291,7 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
1046
1291
|
if (event.actionMasked == MotionEvent.ACTION_UP || event.actionMasked == MotionEvent.ACTION_CANCEL) shieldedModalTouch = false
|
|
1047
1292
|
return true
|
|
1048
1293
|
}
|
|
1294
|
+
dispatchOverflow(event)?.let { return it }
|
|
1049
1295
|
return super.dispatchTouchEvent(event)
|
|
1050
1296
|
}
|
|
1051
1297
|
|
|
@@ -2328,7 +2574,15 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
2328
2574
|
|
|
2329
2575
|
/** An image-backed flex container with ordinary native children over the image. */
|
|
2330
2576
|
private class CraftNativeImageBackgroundView(context: Context) : FrameLayout(context) {
|
|
2331
|
-
|
|
2577
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean =
|
|
2578
|
+
CraftNativePointers.ownsTouch(this) && super.onInterceptTouchEvent(event)
|
|
2579
|
+
override fun onTouchEvent(event: MotionEvent): Boolean =
|
|
2580
|
+
(event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
2581
|
+
|
|
2582
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
2583
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
2584
|
+
|
|
2585
|
+
val image = CraftNativePointerImageView(context)
|
|
2332
2586
|
val content = CraftNativeFlexLayout(context)
|
|
2333
2587
|
|
|
2334
2588
|
init {
|
|
@@ -2342,6 +2596,14 @@ private class CraftNativeImageBackgroundView(context: Context) : FrameLayout(con
|
|
|
2342
2596
|
|
|
2343
2597
|
/** A flex container that responds to the activity's IME inset. */
|
|
2344
2598
|
private class CraftNativeKeyboardAvoidingView(context: Context) : FrameLayout(context) {
|
|
2599
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean =
|
|
2600
|
+
CraftNativePointers.ownsTouch(this) && super.onInterceptTouchEvent(event)
|
|
2601
|
+
override fun onTouchEvent(event: MotionEvent): Boolean =
|
|
2602
|
+
(event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
2603
|
+
|
|
2604
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
2605
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
2606
|
+
|
|
2345
2607
|
val content = CraftNativeFlexLayout(context)
|
|
2346
2608
|
private var behavior = "padding"
|
|
2347
2609
|
private var keyboardVerticalOffset = 0
|
|
@@ -2426,17 +2688,23 @@ internal fun craftNativeFontFamily(family: String?, bundledFonts: Map<String, Ty
|
|
|
2426
2688
|
}?.firstOrNull() ?: Typeface.DEFAULT
|
|
2427
2689
|
|
|
2428
2690
|
internal class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(context) {
|
|
2691
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
2692
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
2693
|
+
|
|
2694
|
+
override fun onTouchEvent(event: MotionEvent): Boolean =
|
|
2695
|
+
(event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
2696
|
+
|
|
2429
2697
|
val content = CraftNativeFlexLayout(context)
|
|
2430
2698
|
// Keep one refresh target across axis changes. Replacing all children of
|
|
2431
2699
|
// SwipeRefreshLayout would also detach its own animated indicator.
|
|
2432
2700
|
private val scrollContainer = FrameLayout(context)
|
|
2433
2701
|
private val vertical = object : ScrollView(context) {
|
|
2434
|
-
override fun onInterceptTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onInterceptTouchEvent(event)
|
|
2435
|
-
override fun onTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onTouchEvent(event)
|
|
2702
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean = isEnabled && CraftNativePointers.ownsTouch(this) && super.onInterceptTouchEvent(event)
|
|
2703
|
+
override fun onTouchEvent(event: MotionEvent): Boolean = isEnabled && (event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
2436
2704
|
}
|
|
2437
2705
|
private val horizontal = object : HorizontalScrollView(context) {
|
|
2438
|
-
override fun onInterceptTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onInterceptTouchEvent(event)
|
|
2439
|
-
override fun onTouchEvent(event: MotionEvent): Boolean = isEnabled && super.onTouchEvent(event)
|
|
2706
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean = isEnabled && CraftNativePointers.ownsTouch(this) && super.onInterceptTouchEvent(event)
|
|
2707
|
+
override fun onTouchEvent(event: MotionEvent): Boolean = isEnabled && (event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
2440
2708
|
}
|
|
2441
2709
|
private var horizontalMode: Boolean? = null
|
|
2442
2710
|
private var pagingEnabled = false
|
|
@@ -2534,7 +2802,7 @@ internal class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(cont
|
|
|
2534
2802
|
}
|
|
2535
2803
|
|
|
2536
2804
|
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
2537
|
-
if (refreshHandler == null) return false
|
|
2805
|
+
if (refreshHandler == null || !CraftNativePointers.ownsTouch(this)) return false
|
|
2538
2806
|
return super.onInterceptTouchEvent(event)
|
|
2539
2807
|
}
|
|
2540
2808
|
|
|
@@ -2914,6 +3182,7 @@ internal class CraftNativeScrollView(context: Context) : SwipeRefreshLayout(cont
|
|
|
2914
3182
|
onScroll?.invoke(x, y)
|
|
2915
3183
|
}
|
|
2916
3184
|
scroller.setOnTouchListener { _, event ->
|
|
3185
|
+
if (!CraftNativePointers.ownsTouch(scroller) && event.actionMasked != MotionEvent.ACTION_CANCEL) return@setOnTouchListener false
|
|
2917
3186
|
when (event.actionMasked) {
|
|
2918
3187
|
android.view.MotionEvent.ACTION_DOWN -> {
|
|
2919
3188
|
pageDragging = true
|
|
@@ -2984,6 +3253,9 @@ private class CraftNativeFlexSpacer(context: Context) : View(context)
|
|
|
2984
3253
|
* the other native leaf controls without adding an icon-font dependency.
|
|
2985
3254
|
*/
|
|
2986
3255
|
private class CraftNativeIconView(context: Context) : TextView(context) {
|
|
3256
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
3257
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
3258
|
+
|
|
2987
3259
|
/** The app's vector for the icon (CraftNativeIcons), drawn in place of the glyph. */
|
|
2988
3260
|
var vector: Drawable? = null
|
|
2989
3261
|
set(value) {
|
|
@@ -3010,6 +3282,9 @@ private class CraftNativeIconView(context: Context) : TextView(context) {
|
|
|
3010
3282
|
|
|
3011
3283
|
/** A platform EditText with the native end clear affordance and TalkBack action. */
|
|
3012
3284
|
private class CraftNativeTextField(context: Context) : EditText(context) {
|
|
3285
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
3286
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
3287
|
+
|
|
3013
3288
|
companion object { val CLEAR_ACTION_ID = View.generateViewId() }
|
|
3014
3289
|
var clearButtonMode = "never"
|
|
3015
3290
|
var onClearRequest: (() -> Unit)? = null
|
|
@@ -3054,8 +3329,14 @@ private class CraftNativeTextField(context: Context) : EditText(context) {
|
|
|
3054
3329
|
}
|
|
3055
3330
|
|
|
3056
3331
|
private class CraftNativeModalView(context: Context) : FrameLayout(context) {
|
|
3332
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
3333
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
3334
|
+
|
|
3057
3335
|
val content = CraftNativeFlexLayout(context)
|
|
3058
|
-
private val blocker = View(context)
|
|
3336
|
+
private val blocker = object : View(context) {
|
|
3337
|
+
override fun onTouchEvent(event: MotionEvent): Boolean =
|
|
3338
|
+
(event.actionMasked == MotionEvent.ACTION_CANCEL || CraftNativePointers.ownsTouch(this)) && super.onTouchEvent(event)
|
|
3339
|
+
}
|
|
3059
3340
|
private var renderedVisible = false
|
|
3060
3341
|
private var animationGeneration = 0
|
|
3061
3342
|
var focusToRestore: View? = null
|
|
@@ -3095,6 +3376,7 @@ private class CraftNativeModalView(context: Context) : FrameLayout(context) {
|
|
|
3095
3376
|
isClickable = true
|
|
3096
3377
|
blocker.isClickable = true
|
|
3097
3378
|
blocker.setOnTouchListener { _, event ->
|
|
3379
|
+
if (!CraftNativePointers.ownsTouch(this)) return@setOnTouchListener false
|
|
3098
3380
|
if (event.action == MotionEvent.ACTION_UP) requestClose(reason = "backdrop")
|
|
3099
3381
|
true
|
|
3100
3382
|
}
|
|
@@ -3175,6 +3457,7 @@ private class CraftNativeModalView(context: Context) : FrameLayout(context) {
|
|
|
3175
3457
|
}
|
|
3176
3458
|
|
|
3177
3459
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
3460
|
+
if (event.actionMasked != MotionEvent.ACTION_CANCEL && !CraftNativePointers.ownsTouch(this)) return false
|
|
3178
3461
|
if (!blocksBackground) {
|
|
3179
3462
|
if (dismissOnOutsideTap && event.action == MotionEvent.ACTION_UP) {
|
|
3180
3463
|
requestClose(reason = "backdrop")
|
|
@@ -3192,7 +3475,7 @@ private class CraftNativeModalView(context: Context) : FrameLayout(context) {
|
|
|
3192
3475
|
val index = group.indexOfChild(this)
|
|
3193
3476
|
return index > 0 && (0 until index).any { siblingIndex ->
|
|
3194
3477
|
val sibling = group.getChildAt(siblingIndex)
|
|
3195
|
-
sibling is CraftNativeModalView && sibling.blocksBackground && sibling.visibility == View.VISIBLE && sibling.alpha > 0.01f
|
|
3478
|
+
sibling is CraftNativeModalView && CraftNativePointers.ownsTouch(sibling) && sibling.blocksBackground && sibling.visibility == View.VISIBLE && sibling.alpha > 0.01f
|
|
3196
3479
|
}
|
|
3197
3480
|
}
|
|
3198
3481
|
}
|
|
@@ -3213,6 +3496,9 @@ private data class LayoutBounds(
|
|
|
3213
3496
|
*/
|
|
3214
3497
|
private class CraftNativeActivityIndicator(context: Context) :
|
|
3215
3498
|
android.widget.ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal) {
|
|
3499
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
3500
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
3501
|
+
|
|
3216
3502
|
var indicatorScale = 1f
|
|
3217
3503
|
|
|
3218
3504
|
init {
|
|
@@ -3224,6 +3510,9 @@ private class CraftNativeActivityIndicator(context: Context) :
|
|
|
3224
3510
|
|
|
3225
3511
|
/** Android counterpart to iOS's UIDatePicker-backed native DatePicker. */
|
|
3226
3512
|
private class CraftNativeDatePickerView(context: Context) : FrameLayout(context) {
|
|
3513
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
3514
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
3515
|
+
|
|
3227
3516
|
private enum class PickerMode { DATE, TIME, DATE_TIME, COUNTDOWN }
|
|
3228
3517
|
private val maxCountdownSeconds = 23 * 3600 + 59 * 60 + 59
|
|
3229
3518
|
|
|
@@ -3470,6 +3759,9 @@ internal class CraftNativeInputEcho {
|
|
|
3470
3759
|
* while this view keeps its place.
|
|
3471
3760
|
*/
|
|
3472
3761
|
private class CraftNativeVideoView(context: Context) : VideoView(context) {
|
|
3762
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean =
|
|
3763
|
+
CraftNativePointers.dispatch(this, event) { super.dispatchTouchEvent(it) }
|
|
3764
|
+
|
|
3473
3765
|
private var sourceUri = ""
|
|
3474
3766
|
private var shouldLoop = false
|
|
3475
3767
|
private var shouldPlay = false
|
|
@@ -5748,7 +6040,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5748
6040
|
val previous = protocolId?.let { previousControls["id:$it"] } ?: keyedPrevious
|
|
5749
6041
|
val reusableInput = previous as? CraftNativeTextField
|
|
5750
6042
|
val control = when (type) {
|
|
5751
|
-
"Text" -> ((previous as? TextView)?.takeUnless { it is Button || it is EditText } ?:
|
|
6043
|
+
"Text" -> ((previous as? TextView)?.takeUnless { it is Button || it is EditText } ?: CraftNativePointerTextView(this)).apply {
|
|
5752
6044
|
includeFontPadding = false
|
|
5753
6045
|
maxLines = craftNativeInt(props.opt("numberOfLines"), 0).takeIf { it > 0 } ?: Int.MAX_VALUE
|
|
5754
6046
|
ellipsize = when (craftNativeOptionalString(props.opt("ellipsizeMode"))) {
|
|
@@ -5771,7 +6063,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5771
6063
|
"RefreshControl" -> (previous as? CraftNativeFlexLayout ?: CraftNativeFlexLayout(this)).apply {
|
|
5772
6064
|
visibility = View.GONE
|
|
5773
6065
|
}
|
|
5774
|
-
"Link" -> ((previous as? TextView)?.takeUnless { it is Button } ?:
|
|
6066
|
+
"Link" -> ((previous as? TextView)?.takeUnless { it is Button } ?: CraftNativePointerTextView(this)).apply {
|
|
5775
6067
|
includeFontPadding = false
|
|
5776
6068
|
configureText(this, (props.opt("title") as? String) ?: childText(children), style)
|
|
5777
6069
|
val linkColor = craftNativeOptionalString(props.opt("color")) ?: craftNativeOptionalString(style.opt("color"))
|
|
@@ -5794,7 +6086,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5794
6086
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject()))
|
|
5795
6087
|
}
|
|
5796
6088
|
}
|
|
5797
|
-
"Button" -> (previous as? Button ?:
|
|
6089
|
+
"Button" -> (previous as? Button ?: CraftNativePointerButton(this).apply {
|
|
5798
6090
|
// A plain button, as on iOS (UIButton) and the web: its
|
|
5799
6091
|
// style draws any fill, not Material's grey raised box.
|
|
5800
6092
|
background = null
|
|
@@ -5819,7 +6111,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
5819
6111
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject()))
|
|
5820
6112
|
}
|
|
5821
6113
|
}
|
|
5822
|
-
"Checkbox" -> (previous as? CheckBox ?:
|
|
6114
|
+
"Checkbox" -> (previous as? CheckBox ?: CraftNativePointerCheckBox(this)).apply {
|
|
5823
6115
|
text = (props.opt("label") as? String) ?: childText(children)
|
|
5824
6116
|
configureText(this, text.toString(), style)
|
|
5825
6117
|
val checkboxChecked = props.opt("checked")
|
|
@@ -6004,7 +6296,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6004
6296
|
addTextChangedListener(watcher)
|
|
6005
6297
|
}
|
|
6006
6298
|
}
|
|
6007
|
-
"SegmentedControl" -> (previous as? android.widget.RadioGroup ?:
|
|
6299
|
+
"SegmentedControl" -> (previous as? android.widget.RadioGroup ?: CraftNativePointerRadioGroup(this)).apply {
|
|
6008
6300
|
orientation = android.widget.LinearLayout.HORIZONTAL
|
|
6009
6301
|
// Reconciliation is silent. Only the platform's user selection
|
|
6010
6302
|
// listener below emits a value, with the stable option value.
|
|
@@ -6055,7 +6347,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6055
6347
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject().put("value", value).put("index", index)))
|
|
6056
6348
|
}
|
|
6057
6349
|
}
|
|
6058
|
-
"Picker" -> (previous as? Spinner ?:
|
|
6350
|
+
"Picker" -> (previous as? Spinner ?: CraftNativePointerSpinner(this)).apply {
|
|
6059
6351
|
val itemOptions = props.optJSONArray("items")?.let { items ->
|
|
6060
6352
|
(0 until items.length()).mapNotNull { index ->
|
|
6061
6353
|
val item = items.optJSONObject(index) ?: return@mapNotNull null
|
|
@@ -6199,7 +6491,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6199
6491
|
screen.pressBaseBackgrounds[this] = this.background
|
|
6200
6492
|
reconcileChildren(screen, this, children, identity, next, style, previousControls)
|
|
6201
6493
|
}
|
|
6202
|
-
"Switch" -> (previous as? Switch ?:
|
|
6494
|
+
"Switch" -> (previous as? Switch ?: CraftNativePointerSwitch(this)).apply {
|
|
6203
6495
|
setOnCheckedChangeListener(null)
|
|
6204
6496
|
val requestedValue = props.opt("value")
|
|
6205
6497
|
val requestedChecked = props.opt("checked")
|
|
@@ -6238,7 +6530,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6238
6530
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject().put("value", checked)))
|
|
6239
6531
|
}
|
|
6240
6532
|
}
|
|
6241
|
-
"Slider" -> (previous as? SeekBar ?:
|
|
6533
|
+
"Slider" -> (previous as? SeekBar ?: CraftNativePointerSeekBar(this)).apply {
|
|
6242
6534
|
val minimum = craftNativeFiniteNumber(props, "minimumValue", 0.0)
|
|
6243
6535
|
val maximumCandidate = craftNativeFiniteNumber(props, "maximumValue", 1.0)
|
|
6244
6536
|
val maximum = if (maximumCandidate > minimum) maximumCandidate else minimum + Double.MIN_VALUE
|
|
@@ -6319,13 +6611,14 @@ class MainActivity : AppCompatActivity() {
|
|
|
6319
6611
|
"Icon" -> (previous as? CraftNativeIconView ?: CraftNativeIconView(this)).apply {
|
|
6320
6612
|
configureIcon(this, props, style)
|
|
6321
6613
|
}
|
|
6322
|
-
"Image" -> (previous as?
|
|
6614
|
+
"Image" -> (previous as? CraftNativePointerImageView ?: CraftNativePointerImageView(this)).apply {
|
|
6323
6615
|
scaleType = when (craftNativeResizeMode(style, props)) {
|
|
6324
6616
|
"cover" -> ImageView.ScaleType.CENTER_CROP
|
|
6325
6617
|
"stretch" -> ImageView.ScaleType.FIT_XY
|
|
6326
6618
|
"center" -> ImageView.ScaleType.CENTER
|
|
6327
6619
|
else -> ImageView.ScaleType.CENTER_INSIDE
|
|
6328
6620
|
}
|
|
6621
|
+
configureObjectGeometry(props, style)
|
|
6329
6622
|
adjustViewBounds = false
|
|
6330
6623
|
val onLoadStart = craftNativeEventName(events, "onLoadStart")
|
|
6331
6624
|
if (onLoadStart.isNotBlank()) screen.imageLoadStartHandlers[this] = onLoadStart else screen.imageLoadStartHandlers.remove(this)
|
|
@@ -6344,6 +6637,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6344
6637
|
"center" -> ImageView.ScaleType.CENTER
|
|
6345
6638
|
else -> ImageView.ScaleType.CENTER_INSIDE
|
|
6346
6639
|
}
|
|
6640
|
+
image.configureObjectGeometry(props, style)
|
|
6347
6641
|
val tint = craftNativeOptionalString(style.opt("tintColor"))
|
|
6348
6642
|
?.let { runCatching { craftNativeColor(it) }.getOrNull() }
|
|
6349
6643
|
if (tint == null) image.clearColorFilter() else image.setColorFilter(tint)
|
|
@@ -6568,6 +6862,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6568
6862
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject()))
|
|
6569
6863
|
}
|
|
6570
6864
|
control.setOnTouchListener { view, event ->
|
|
6865
|
+
if (!CraftNativePointers.ownsTouch(view) && event.actionMasked != MotionEvent.ACTION_CANCEL) return@setOnTouchListener false
|
|
6571
6866
|
when (event.actionMasked) {
|
|
6572
6867
|
android.view.MotionEvent.ACTION_DOWN -> {
|
|
6573
6868
|
val active = screen.pressActiveOpacities[view] ?: 0.5f
|
|
@@ -6636,6 +6931,8 @@ class MainActivity : AppCompatActivity() {
|
|
|
6636
6931
|
control.setOnLongClickListener(null)
|
|
6637
6932
|
control.isLongClickable = false
|
|
6638
6933
|
}
|
|
6934
|
+
CraftNativePointers.configure(control, props, style, control is CraftNativeFlexLayout || control is CraftNativeImageBackgroundView ||
|
|
6935
|
+
control is CraftNativeKeyboardAvoidingView || control is CraftNativeScrollView || control is CraftNativeRefreshableFlatList || control is CraftNativeModalView)
|
|
6639
6936
|
applyAccessibility(control, props, type, explicitKey ?: protocolId ?: path)
|
|
6640
6937
|
// One element across an animated change (craft.animation.next).
|
|
6641
6938
|
control.transitionName = craftNativeOptionalString(props.opt("transitionID"))?.takeIf { it.isNotBlank() }
|
package/dist/cli.js
CHANGED
|
@@ -3047,7 +3047,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
3047
3047
|
`);
|
|
3048
3048
|
}
|
|
3049
3049
|
// package.json
|
|
3050
|
-
var version = "0.0.
|
|
3050
|
+
var version = "0.0.396";
|
|
3051
3051
|
|
|
3052
3052
|
// bin/cli.ts
|
|
3053
3053
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|