craft-native 0.0.435 → 0.0.442
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/LICENSE.md +30 -0
- package/README.md +35 -0
- package/dist/android/src/index.d.ts +8 -0
- package/dist/android/src/index.js +17 -2
- package/dist/android/templates/CraftHealthServices.kt.template +2 -0
- package/dist/android/templates/CraftNativeCapabilities.kt.template +42 -1
- package/dist/android/templates/CraftNativeMotion.kt.template +269 -0
- package/dist/android/templates/CraftNativeServices.kt.template +6 -1
- package/dist/android/templates/CraftPassiveSteps.kt.template +159 -0
- package/dist/android/templates/CraftRecordingPressure.kt.template +156 -0
- package/dist/android/templates/LocationRecordingService.kt.template +77 -9
- package/dist/android/templates/MainActivityNative.kt.template +129 -1
- package/dist/cli.js +289 -108
- package/dist/components/index.d.ts +25 -0
- package/dist/index.cjs +207 -27
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +321 -140
- package/dist/installer-background.d.ts +2 -0
- package/dist/installer-layout.d.ts +1 -0
- package/dist/ios/src/index.d.ts +10 -0
- package/dist/ios/src/index.js +28 -2
- package/dist/ios/templates/CraftApp.swift +14 -0
- package/dist/ios/templates/CraftHealth.swift +2 -1
- package/dist/ios/templates/CraftHealthBackground.swift +308 -0
- package/dist/ios/templates/CraftNativeActions.swift +153 -0
- package/dist/ios/templates/CraftNativeMutation.swift +18 -3
- package/dist/ios/templates/CraftNativePedometer.swift +181 -0
- package/dist/ios/templates/CraftNativeScreen.swift +76 -0
- package/dist/ios/templates/testing/DriverTests.swift.template +24 -4
- package/dist/macos/src/index.js +1 -1
- package/dist/macos/src/toolchain.d.ts +1 -1
- package/dist/macos/templates/CraftMacApplication.swift +124 -39
- package/dist/macos/templates/CraftMacRenderer.swift +169 -37
- package/dist/macos/templates/CraftMacRuntime.swift +298 -77
- package/dist/macos/templates/CraftNativeMutation.swift +18 -3
- package/dist/package.d.ts +40 -0
- package/dist/types.d.ts +26 -0
- package/package.json +1 -1
|
@@ -4563,6 +4563,11 @@ class MainActivity : AppCompatActivity() {
|
|
|
4563
4563
|
val pressUnderlayShowHandlers = mutableMapOf<View, String>()
|
|
4564
4564
|
val pressUnderlayHideHandlers = mutableMapOf<View, String>()
|
|
4565
4565
|
val longPressHandlers = mutableMapOf<View, String>()
|
|
4566
|
+
val accessibilityActionHandlers = mutableMapOf<View, String>()
|
|
4567
|
+
// TalkBack actions are added by id, so removing them on a reconcile
|
|
4568
|
+
// needs the ids back; without this a renamed action stacks up beside
|
|
4569
|
+
// the old one every render.
|
|
4570
|
+
val accessibilityActionIds = mutableMapOf<View, List<Int>>()
|
|
4566
4571
|
val scrollHandlers = mutableMapOf<View, String>()
|
|
4567
4572
|
val scrollBeginHandlers = mutableMapOf<View, String>()
|
|
4568
4573
|
val scrollEndHandlers = mutableMapOf<View, String>()
|
|
@@ -4596,6 +4601,9 @@ class MainActivity : AppCompatActivity() {
|
|
|
4596
4601
|
val capabilityTimeouts = mutableMapOf<String, Runnable>()
|
|
4597
4602
|
val audio = CraftNativeAudio()
|
|
4598
4603
|
val sounds = CraftNativeSounds(view.context)
|
|
4604
|
+
var motion: CraftNativeMotion? = null
|
|
4605
|
+
var barometer: CraftNativeBarometer? = null
|
|
4606
|
+
var pedometer: CraftNativePedometer? = null
|
|
4599
4607
|
val soundRequestCancellers = mutableMapOf<String, () -> Unit>()
|
|
4600
4608
|
/** Snapshot writes awaiting the writer thread; close rejects them once. */
|
|
4601
4609
|
val pendingSyncResults = mutableSetOf<String>()
|
|
@@ -4617,6 +4625,9 @@ class MainActivity : AppCompatActivity() {
|
|
|
4617
4625
|
soundRequestCancellers.values.toList().forEach { it() }
|
|
4618
4626
|
soundRequestCancellers.clear()
|
|
4619
4627
|
sounds.close()
|
|
4628
|
+
motion?.close()
|
|
4629
|
+
barometer?.close()
|
|
4630
|
+
pedometer?.close()
|
|
4620
4631
|
// Evaluation completion does not mean its outbound messages have
|
|
4621
4632
|
// reached the host. Close only after the ordered channel barrier,
|
|
4622
4633
|
// so onDestroy's final writes run before navigation continues.
|
|
@@ -4688,6 +4699,10 @@ class MainActivity : AppCompatActivity() {
|
|
|
4688
4699
|
private var hapticsEnabled = false
|
|
4689
4700
|
private var clipboardEnabled = false
|
|
4690
4701
|
private var shakeEnabled = false
|
|
4702
|
+
private var motionSensorsEnabled = false
|
|
4703
|
+
private var barometerEnabled = false
|
|
4704
|
+
private var pedometerEnabled = false
|
|
4705
|
+
private var motionForeground = false
|
|
4691
4706
|
internal var nativeAppState = "inactive"
|
|
4692
4707
|
private set
|
|
4693
4708
|
private var deliveredInitialDeepLink = false
|
|
@@ -4761,6 +4776,9 @@ class MainActivity : AppCompatActivity() {
|
|
|
4761
4776
|
hapticsEnabled = config.optBoolean("enableHaptics", false)
|
|
4762
4777
|
clipboardEnabled = config.optBoolean("enableClipboard", false)
|
|
4763
4778
|
shakeEnabled = config.optBoolean("enableShakeGesture", false)
|
|
4779
|
+
motionSensorsEnabled = config.optBoolean("enableMotionSensors", false)
|
|
4780
|
+
barometerEnabled = config.optBoolean("enableBarometer", false)
|
|
4781
|
+
pedometerEnabled = config.optBoolean("enablePedometer", false)
|
|
4764
4782
|
// Normally started already by its content provider; this covers a
|
|
4765
4783
|
// process that skipped providers (instrumentation).
|
|
4766
4784
|
CraftCrashReporter.start(this)
|
|
@@ -5153,6 +5171,30 @@ class MainActivity : AppCompatActivity() {
|
|
|
5153
5171
|
activeScreen.view.onLayoutChanged = {
|
|
5154
5172
|
if (activeScreen.active) emitLayoutEvents(activeScreen)
|
|
5155
5173
|
}
|
|
5174
|
+
if (motionSensorsEnabled && !headless) {
|
|
5175
|
+
activeScreen.motion = CraftNativeMotion(CraftAndroidMotionSource(this)).apply {
|
|
5176
|
+
emit = { detail ->
|
|
5177
|
+
if (activeScreen.active && motionForeground) send(activeScreen, "CRAFT_EVENT",
|
|
5178
|
+
JSONObject().put("event", "craftRawMotionUpdate").put("detail", detail))
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
if (barometerEnabled && !headless) {
|
|
5183
|
+
activeScreen.barometer = CraftNativeBarometer(CraftAndroidMotionSource(this)).apply {
|
|
5184
|
+
emit = { detail ->
|
|
5185
|
+
if (activeScreen.active) send(activeScreen, "CRAFT_EVENT",
|
|
5186
|
+
JSONObject().put("event", "craftBarometerUpdate").put("detail", detail))
|
|
5187
|
+
}
|
|
5188
|
+
}
|
|
5189
|
+
}
|
|
5190
|
+
if (pedometerEnabled && !headless) {
|
|
5191
|
+
activeScreen.pedometer = CraftNativePedometer(CraftAndroidMotionSource(this), capabilities::pedometerPermissionGranted).apply {
|
|
5192
|
+
emit = { detail ->
|
|
5193
|
+
if (activeScreen.active) send(activeScreen, "CRAFT_EVENT",
|
|
5194
|
+
JSONObject().put("event", "craftPedometerUpdate").put("detail", detail))
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5156
5198
|
activeScreen.sounds.emit = { payload ->
|
|
5157
5199
|
if (activeScreen.active) send(activeScreen, "SOUND_EVENT", payload)
|
|
5158
5200
|
}
|
|
@@ -5534,6 +5576,9 @@ class MainActivity : AppCompatActivity() {
|
|
|
5534
5576
|
private fun capabilityNames(): JSONArray = capabilities.names().apply {
|
|
5535
5577
|
services.names().forEach { name -> put(name) }
|
|
5536
5578
|
put("audio")
|
|
5579
|
+
if (motionSensorsEnabled) put("rawMotionSensors")
|
|
5580
|
+
if (barometerEnabled) put("barometer")
|
|
5581
|
+
if (pedometerEnabled) put("pedometer")
|
|
5537
5582
|
put("viewFocus")
|
|
5538
5583
|
put("viewMeasure")
|
|
5539
5584
|
put("viewScroll")
|
|
@@ -6952,6 +6997,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
6952
6997
|
CraftNativePointers.configure(control, props, style, control is CraftNativeFlexLayout || control is CraftNativeImageBackgroundView ||
|
|
6953
6998
|
control is CraftNativeKeyboardAvoidingView || control is CraftNativeScrollView || control is CraftNativeRefreshableFlatList || control is CraftNativeModalView)
|
|
6954
6999
|
applyAccessibility(control, props, type, explicitKey ?: protocolId ?: path)
|
|
7000
|
+
applyAccessibilityActions(screen, control, props, events, longPressDisabled)
|
|
6955
7001
|
// One element across an animated change (craft.animation.next).
|
|
6956
7002
|
control.transitionName = craftNativeOptionalString(props.opt("transitionID"))?.takeIf { it.isNotBlank() }
|
|
6957
7003
|
val layoutHandler = craftNativeEventName(events, "onLayout")
|
|
@@ -7854,6 +7900,54 @@ class MainActivity : AppCompatActivity() {
|
|
|
7854
7900
|
field.setSelection(minOf(boundedStart, boundedEnd), maxOf(boundedStart, boundedEnd))
|
|
7855
7901
|
}
|
|
7856
7902
|
|
|
7903
|
+
/**
|
|
7904
|
+
* What a hold offers, published where TalkBack can reach it.
|
|
7905
|
+
*
|
|
7906
|
+
* A long click is invisible to a screen reader: nothing announces that it
|
|
7907
|
+
* is there and nothing can perform it, so an action living only behind a
|
|
7908
|
+
* hold does not exist for anyone driving the screen by assistive
|
|
7909
|
+
* technology. A thread that holds a message for Copy and Report is the
|
|
7910
|
+
* case this was written for; without this the honest mitigation is a
|
|
7911
|
+
* permanently visible button under every message.
|
|
7912
|
+
*
|
|
7913
|
+
* Runs after applyAccessibility, which installs its own delegate and
|
|
7914
|
+
* would drop actions added before it.
|
|
7915
|
+
*/
|
|
7916
|
+
private fun applyAccessibilityActions(
|
|
7917
|
+
screen: Screen,
|
|
7918
|
+
control: View,
|
|
7919
|
+
props: JSONObject,
|
|
7920
|
+
events: JSONObject,
|
|
7921
|
+
disabled: Boolean,
|
|
7922
|
+
) {
|
|
7923
|
+
screen.accessibilityActionIds.remove(control)?.forEach { ViewCompat.removeAccessibilityAction(control, it) }
|
|
7924
|
+
val handler = craftNativeEventName(events, "onAccessibilityAction").takeUnless { disabled } ?: ""
|
|
7925
|
+
val authored = props.optJSONArray("accessibilityActions")
|
|
7926
|
+
if (handler.isBlank() || authored == null || authored.length() == 0) {
|
|
7927
|
+
screen.accessibilityActionHandlers.remove(control)
|
|
7928
|
+
return
|
|
7929
|
+
}
|
|
7930
|
+
screen.accessibilityActionHandlers[control] = handler
|
|
7931
|
+
val ids = mutableListOf<Int>()
|
|
7932
|
+
for (index in 0 until authored.length()) {
|
|
7933
|
+
val entry = authored.optJSONObject(index) ?: continue
|
|
7934
|
+
val name = craftNativeOptionalString(entry.opt("name"))?.takeIf { it.isNotBlank() } ?: continue
|
|
7935
|
+
val label = craftNativeOptionalString(entry.opt("label"))?.takeIf { it.isNotBlank() } ?: name
|
|
7936
|
+
ids += ViewCompat.addAccessibilityAction(control, label) { _, _ ->
|
|
7937
|
+
// Read the handler at firing time: a reconcile can rename it
|
|
7938
|
+
// while the action sits in TalkBack's menu.
|
|
7939
|
+
val current = screen.accessibilityActionHandlers[control]
|
|
7940
|
+
if (current.isNullOrBlank()) {
|
|
7941
|
+
false
|
|
7942
|
+
} else {
|
|
7943
|
+
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject().put("actionName", name)))
|
|
7944
|
+
true
|
|
7945
|
+
}
|
|
7946
|
+
}
|
|
7947
|
+
}
|
|
7948
|
+
if (ids.isEmpty()) screen.accessibilityActionHandlers.remove(control) else screen.accessibilityActionIds[control] = ids
|
|
7949
|
+
}
|
|
7950
|
+
|
|
7857
7951
|
private fun applyAccessibility(view: View, props: JSONObject, type: String, fallbackLabel: String) {
|
|
7858
7952
|
val testId = craftNativeOptionalString(props.opt("testID"))
|
|
7859
7953
|
view.tag = testId?.takeIf { it.isNotBlank() } ?: fallbackLabel
|
|
@@ -8039,6 +8133,37 @@ class MainActivity : AppCompatActivity() {
|
|
|
8039
8133
|
val method = payload.optString("method")
|
|
8040
8134
|
val perform: ((CraftNativeCapabilityResult) -> Unit) -> Unit = if (module == "View") {
|
|
8041
8135
|
{ completion -> performView(screen, method, args, completion) }
|
|
8136
|
+
} else if (module == "Pedometer") {
|
|
8137
|
+
{ completion ->
|
|
8138
|
+
val pedometer = screen.pedometer
|
|
8139
|
+
if (!pedometerEnabled) completion(CraftNativeCapabilityResult(code = "CAPABILITY_DISABLED", message = "Pedometer is disabled"))
|
|
8140
|
+
else if (pedometer == null) completion(CraftNativeCapabilityResult(code = "NEEDS_ACTIVITY", message = "Pedometer needs a visible app"))
|
|
8141
|
+
else if (method in listOf("start", "requestPermission") && !motionForeground) completion(CraftNativeCapabilityResult(code = "APP_INACTIVE", message = "Pedometer needs a foreground app"))
|
|
8142
|
+
else if (method == "requestPermission") capabilities.perform(token, payload.optInt("version", CRAFT_NATIVE_CAPABILITY_PROTOCOL_VERSION), module, method, args, completion)
|
|
8143
|
+
else completion(pedometer.perform(method, args))
|
|
8144
|
+
}
|
|
8145
|
+
} else if (module == "Barometer") {
|
|
8146
|
+
{ completion ->
|
|
8147
|
+
val barometer = screen.barometer
|
|
8148
|
+
completion(if (!barometerEnabled) {
|
|
8149
|
+
CraftNativeCapabilityResult(code = "CAPABILITY_DISABLED", message = "Barometer is disabled")
|
|
8150
|
+
} else if (barometer == null) {
|
|
8151
|
+
CraftNativeCapabilityResult(code = "NEEDS_ACTIVITY", message = "Barometer needs a visible app")
|
|
8152
|
+
} else if (method == "start" && !motionForeground) {
|
|
8153
|
+
CraftNativeCapabilityResult(code = "APP_INACTIVE", message = "Barometer needs a foreground app")
|
|
8154
|
+
} else barometer.perform(method, args))
|
|
8155
|
+
}
|
|
8156
|
+
} else if (module == "MotionSensors") {
|
|
8157
|
+
{ completion ->
|
|
8158
|
+
val motion = screen.motion
|
|
8159
|
+
completion(if (!motionSensorsEnabled) {
|
|
8160
|
+
CraftNativeCapabilityResult(code = "CAPABILITY_DISABLED", message = "Motion sensors are disabled")
|
|
8161
|
+
} else if (motion == null) {
|
|
8162
|
+
CraftNativeCapabilityResult(code = "NEEDS_ACTIVITY", message = "Motion sensors need a visible app")
|
|
8163
|
+
} else if (method == "start" && !motionForeground) {
|
|
8164
|
+
CraftNativeCapabilityResult(code = "APP_INACTIVE", message = "Motion sensors need a foreground app")
|
|
8165
|
+
} else motion.perform(method, args))
|
|
8166
|
+
}
|
|
8042
8167
|
} else if (module == "Audio") {
|
|
8043
8168
|
{ completion ->
|
|
8044
8169
|
val id = args.optString(0)
|
|
@@ -8290,6 +8415,8 @@ class MainActivity : AppCompatActivity() {
|
|
|
8290
8415
|
}
|
|
8291
8416
|
|
|
8292
8417
|
override fun onPause() {
|
|
8418
|
+
motionForeground = false
|
|
8419
|
+
allScreens().forEach { it.motion?.stopAll(); it.barometer?.stop("background"); it.pedometer?.stop("background") }
|
|
8293
8420
|
disarmShakeGesture()
|
|
8294
8421
|
if (::services.isInitialized) services.pauseVoice()
|
|
8295
8422
|
nativeAppState = "inactive"
|
|
@@ -8350,13 +8477,14 @@ class MainActivity : AppCompatActivity() {
|
|
|
8350
8477
|
|
|
8351
8478
|
override fun onResume() {
|
|
8352
8479
|
super.onResume()
|
|
8480
|
+
motionForeground = true
|
|
8353
8481
|
armShakeGesture()
|
|
8354
8482
|
if (::services.isInitialized) services.resumed()
|
|
8355
8483
|
}
|
|
8356
8484
|
|
|
8357
8485
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
8358
8486
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
8359
|
-
if (::capabilities.isInitialized) { capabilities.onBluetoothPermissions(requestCode); capabilities.onNotificationPermissions(requestCode) }
|
|
8487
|
+
if (::capabilities.isInitialized) { capabilities.onBluetoothPermissions(requestCode); capabilities.onNotificationPermissions(requestCode); capabilities.onPedometerPermissions(requestCode) }
|
|
8360
8488
|
if (::services.isInitialized) services.onRequestPermissionsResult(requestCode)
|
|
8361
8489
|
}
|
|
8362
8490
|
|