@therealitycrafters/react-native-evskit 0.1.1 → 0.1.2
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/android/src/main/java/expo/modules/evskit/EvsKitModule.kt +83 -0
- package/android/src/main/java/expo/modules/evskit/EvsScreenRegistry.kt +25 -0
- package/app.plugin.js +3 -1
- package/build/EvsKit.types.d.ts +12 -0
- package/build/EvsKit.types.d.ts.map +1 -1
- package/build/EvsKit.types.js.map +1 -1
- package/build/EvsKitModule.d.ts +12 -0
- package/build/EvsKitModule.d.ts.map +1 -1
- package/build/EvsKitModule.js.map +1 -1
- package/build/index.d.ts +24 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +26 -0
- package/build/index.js.map +1 -1
- package/ios/EvsKitModule.swift +58 -0
- package/ios/EvsScreenRegistry.swift +26 -0
- package/package.json +1 -1
- package/plugin/withEvsScreens.js +256 -0
- package/src/EvsKit.types.ts +17 -0
- package/src/EvsKitModule.ts +14 -0
- package/src/index.ts +28 -0
|
@@ -28,6 +28,8 @@ import UIKit.app.data.ProximityActionType
|
|
|
28
28
|
import UIKit.app.data.YprData
|
|
29
29
|
import UIKit.app.data.QuaternionData
|
|
30
30
|
|
|
31
|
+
import UIKit.app.Viewport
|
|
32
|
+
|
|
31
33
|
class DeviceInfoRecord : Record {
|
|
32
34
|
@Field val deviceId: String = ""
|
|
33
35
|
@Field val name: String = ""
|
|
@@ -44,6 +46,12 @@ class EvsKitModule : Module() {
|
|
|
44
46
|
private var glassesEventsHandle: IEvsGlassesEvents? = null
|
|
45
47
|
private var sensorsEventsHandle: IEvsSensorsEvents? = null
|
|
46
48
|
|
|
49
|
+
// Screens pushed via showScreen(id:), keyed by the JS-facing id so
|
|
50
|
+
// removeScreen(id:) can resolve the native instance. Viewport covers
|
|
51
|
+
// Screen, FullScreen and ArScreen.
|
|
52
|
+
private val activeScreens = mutableMapOf<String, Viewport>()
|
|
53
|
+
private val activeScreenOrder = mutableListOf<String>()
|
|
54
|
+
|
|
47
55
|
override fun definition() = ModuleDefinition {
|
|
48
56
|
Name("RNEvsKit")
|
|
49
57
|
|
|
@@ -61,6 +69,7 @@ class EvsKitModule : Module() {
|
|
|
61
69
|
|
|
62
70
|
OnCreate {
|
|
63
71
|
registerNativeListeners()
|
|
72
|
+
loadAppScreens()
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
OnDestroy {
|
|
@@ -97,6 +106,69 @@ class EvsKitModule : Module() {
|
|
|
97
106
|
}
|
|
98
107
|
}
|
|
99
108
|
|
|
109
|
+
// --- App-owned screens (IEvsScreenService) -------------------------------
|
|
110
|
+
//
|
|
111
|
+
// The bridge ships no Screen subclasses. Apps register their own via
|
|
112
|
+
// EvsScreenRegistry.register(id, factory) from app-owned Kotlin sources
|
|
113
|
+
// (linked at prebuild by the `screens` plugin option), then push them
|
|
114
|
+
// from JS with showScreen(id:).
|
|
115
|
+
|
|
116
|
+
AsyncFunction("showScreen") { id: String, promise: Promise ->
|
|
117
|
+
try {
|
|
118
|
+
val screen = EvsScreenRegistry.make(id)
|
|
119
|
+
?: throw IllegalArgumentException(
|
|
120
|
+
"No screen registered for id '$id'. " +
|
|
121
|
+
"Register it via EvsScreenRegistry.register(id, factory) " +
|
|
122
|
+
"from app-owned Kotlin sources."
|
|
123
|
+
)
|
|
124
|
+
Evs.instance().screens().addScreen(screen)
|
|
125
|
+
if (!activeScreens.containsKey(id)) {
|
|
126
|
+
activeScreenOrder.add(id)
|
|
127
|
+
}
|
|
128
|
+
activeScreens[id] = screen
|
|
129
|
+
promise.resolve(null)
|
|
130
|
+
} catch (e: Exception) {
|
|
131
|
+
promise.reject("EVSKIT_SHOW_SCREEN_FAILED", e.message, e)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
AsyncFunction("removeScreen") { id: String, promise: Promise ->
|
|
136
|
+
try {
|
|
137
|
+
activeScreens.remove(id)?.let { screen ->
|
|
138
|
+
Evs.instance().screens().removeScreen(screen)
|
|
139
|
+
activeScreenOrder.remove(id)
|
|
140
|
+
}
|
|
141
|
+
promise.resolve(null)
|
|
142
|
+
} catch (e: Exception) {
|
|
143
|
+
promise.reject("EVSKIT_REMOVE_SCREEN_FAILED", e.message, e)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
AsyncFunction("removeTopmostScreen") { promise: Promise ->
|
|
148
|
+
try {
|
|
149
|
+
val removed = Evs.instance().screens().removeTopmostScreen()
|
|
150
|
+
val id = if (removed != null) {
|
|
151
|
+
activeScreens.entries.firstOrNull { it.value === removed }?.key?.also { found ->
|
|
152
|
+
activeScreens.remove(found)
|
|
153
|
+
activeScreenOrder.remove(found)
|
|
154
|
+
}
|
|
155
|
+
} else null
|
|
156
|
+
promise.resolve(id)
|
|
157
|
+
} catch (e: Exception) {
|
|
158
|
+
promise.reject("EVSKIT_REMOVE_TOPMOST_SCREEN_FAILED", e.message, e)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
AsyncFunction("getTopmostScreen") { promise: Promise ->
|
|
163
|
+
try {
|
|
164
|
+
val topmost = Evs.instance().screens().getTopmostScreen()
|
|
165
|
+
val id = activeScreens.entries.firstOrNull { it.value === topmost }?.key
|
|
166
|
+
promise.resolve(id)
|
|
167
|
+
} catch (e: Exception) {
|
|
168
|
+
promise.reject("EVSKIT_GET_TOPMOST_SCREEN_FAILED", e.message, e)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
100
172
|
// --- Communication (IEvsCommunicationService) -----------------------------
|
|
101
173
|
|
|
102
174
|
AsyncFunction("setDeviceInfo") { info: DeviceInfoRecord, promise: Promise ->
|
|
@@ -313,6 +385,17 @@ class EvsKitModule : Module() {
|
|
|
313
385
|
// `addEvsKitListener` / `useEvsKitEvent` instead of touching native code.
|
|
314
386
|
// ---------------------------------------------------------------------------
|
|
315
387
|
|
|
388
|
+
// Triggers the plugin-generated app-screens registrar, if the app
|
|
389
|
+
// configured `screens.register`. Class.forName initializes the Kotlin
|
|
390
|
+
// object, running its init block. Absent = no app screens; ignore.
|
|
391
|
+
private fun loadAppScreens() {
|
|
392
|
+
try {
|
|
393
|
+
Class.forName("evs.screens.generated.EvsAppScreensGenerated")
|
|
394
|
+
} catch (_: ClassNotFoundException) {
|
|
395
|
+
// No app-owned screens configured — nothing to register.
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
316
399
|
private fun registerNativeListeners() {
|
|
317
400
|
glassesEventsHandle = object : IEvsGlassesEvents {
|
|
318
401
|
override fun onTouch(touch: TouchDirection) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package expo.modules.evskit
|
|
2
|
+
|
|
3
|
+
import UIKit.app.Viewport
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generic app-owned screen registry.
|
|
7
|
+
*
|
|
8
|
+
* The bridge itself ships NO Screen subclasses. Each app registers its own
|
|
9
|
+
* Kotlin `Screen`/`FullScreen`/`ArScreen` subclasses under a string id
|
|
10
|
+
* (from app-owned sources linked at prebuild by the `screens` plugin
|
|
11
|
+
* option), then drives them from JS via `EvsScreens.show(id)`.
|
|
12
|
+
*/
|
|
13
|
+
object EvsScreenRegistry {
|
|
14
|
+
private val factories = mutableMapOf<String, () -> Viewport>()
|
|
15
|
+
|
|
16
|
+
fun register(id: String, factory: () -> Viewport) {
|
|
17
|
+
factories[id] = factory
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fun unregister(id: String) {
|
|
21
|
+
factories.remove(id)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fun make(id: String): Viewport? = factories[id]?.invoke()
|
|
25
|
+
}
|
package/app.plugin.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const withEverysightBundleResources = require('./plugin/withEverysightBundleResources');
|
|
2
|
+
const withEvsScreens = require('./plugin/withEvsScreens');
|
|
2
3
|
|
|
3
|
-
module.exports = (config = {}, { bundleResources = [] } = {}) => {
|
|
4
|
+
module.exports = (config = {}, { bundleResources = [], screens = {} } = {}) => {
|
|
4
5
|
let result = config;
|
|
5
6
|
result = withEverysightBundleResources(result, { bundleResources });
|
|
7
|
+
result = withEvsScreens(result, { screens });
|
|
6
8
|
return result;
|
|
7
9
|
};
|
package/build/EvsKit.types.d.ts
CHANGED
|
@@ -58,6 +58,18 @@ export interface EvsQuaternionSample extends EvsSensorSample<EvsQuaternionData>
|
|
|
58
58
|
calibrationStatus: CalibrationStatus;
|
|
59
59
|
}
|
|
60
60
|
export type EvsStockUIScreen = "configure" | "adjust" | "calibrate";
|
|
61
|
+
/**
|
|
62
|
+
* String id of an app-owned native screen.
|
|
63
|
+
*
|
|
64
|
+
* The bridge ships no Screen subclasses. Each app registers its own
|
|
65
|
+
* Swift/Kotlin `Screen`/`FullScreen`/`ArScreen` subclasses via
|
|
66
|
+
* `EvsScreenRegistry.register(id, factory)` (iOS) /
|
|
67
|
+
* `EvsScreenRegistry.register(id, factory)` (Android) from app-owned
|
|
68
|
+
* sources — e.g. `<app>/evs-screens/ios/*.swift` linked at prebuild by the
|
|
69
|
+
* bridge config plugin's `screens` option — then pushes them with
|
|
70
|
+
* `EvsScreens.show(id)`.
|
|
71
|
+
*/
|
|
72
|
+
export type EvsScreenId = string;
|
|
61
73
|
export interface EvsBeginAuthEvent {
|
|
62
74
|
serial: string;
|
|
63
75
|
fwVersion: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EvsKit.types.d.ts","sourceRoot":"","sources":["../src/EvsKit.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,kBAAkB,GAC5B,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAM3E,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;AAExE,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAMlD,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,YAAY,GAAG,UAAU,CAAC;AAEzE,kGAAkG;AAClG,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe,CAAC,UAAU,CAAC;IAC/D,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAED,MAAM,WAAW,mBAAoB,SAAQ,eAAe,CAAC,iBAAiB,CAAC;IAC7E,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAMD,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAMpE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,MAAM,MAAM,YAAY,GAAG;IACzB,wBAAwB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9D,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChD,oBAAoB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACrD,OAAO,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpD,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"EvsKit.types.d.ts","sourceRoot":"","sources":["../src/EvsKit.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,kBAAkB,GAC5B,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAM3E,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;AAExE,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAMlD,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,YAAY,GAAG,UAAU,CAAC;AAEzE,kGAAkG;AAClG,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe,CAAC,UAAU,CAAC;IAC/D,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAED,MAAM,WAAW,mBAAoB,SAAQ,eAAe,CAAC,iBAAiB,CAAC;IAC7E,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAMD,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAMpE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAMjC,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,MAAM,MAAM,YAAY,GAAG;IACzB,wBAAwB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9D,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChD,oBAAoB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACrD,OAAO,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpD,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EvsKit.types.js","sourceRoot":"","sources":["../src/EvsKit.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG","sourcesContent":["/**\n * Type definitions mirroring Everysight's Maverick SDK interfaces\n * (IEvsCommunicationService, IEvsGlassesStateService, IEvsDisplayService,\n * IEvsSensorsService, IEvsAuthService).\n *\n * Signatures confirmed against the everysight-maverick/samples repo (v2.6.1)\n * and the MCP API reference.\n */\n\n// ---------------------------------------------------------------------------\n// Communication (IEvsCommunicationService)\n// ---------------------------------------------------------------------------\n\nexport interface EvsDeviceInfo {\n /** Bluetooth device address/id, e.g. from a BLE scan (EV0080 style name). */\n deviceId: string;\n /** Bluetooth device name. */\n name: string;\n}\n\nexport type EvsConnectionState =\n \"disconnected\" | \"connecting\" | \"connected\" | \"authenticating\" | \"error\";\n\n// ---------------------------------------------------------------------------\n// Glasses (IEvsGlassesStateService)\n// ---------------------------------------------------------------------------\n\nexport interface EvsGlassesInfo {\n /** Battery percentage 0-100 from IEvsGlassesStateService.batteryPercentage(). */\n batteryLevel: number;\n /** Battery level category (Unknown/Critical/Low/Medium/High) from batteryLevel(). */\n batteryStatus: string;\n /** Estimated remaining operation time in minutes. */\n estimatedRemainingTime: number;\n /** Firmware version number (Int from fwVersion()). */\n firmwareVersion: number;\n}\n\nexport type TouchDirection = \"backward\" | \"forward\" | \"tap\" | \"longTap\";\n\nexport type ProximityEvent = \"onFace\" | \"offFace\";\n\n// ---------------------------------------------------------------------------\n// Display (IEvsDisplayService)\n// ---------------------------------------------------------------------------\n\nexport interface EvsAutoBrightnessOptions {\n enabled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Sensors (IEvsSensorsService)\n// ---------------------------------------------------------------------------\n\nexport type CalibrationStatus = \"calibrated\" | \"inProgress\" | \"required\";\n\n/** Currently only rate0 and rate1 are operational per the SDK docs; the rest are experimental. */\nexport type SensorRate = \"rate0\" | \"rate1\" | \"rate2\" | \"rate3\";\n\nexport interface EvsYprData {\n yaw: number;\n pitch: number;\n roll: number;\n}\n\nexport interface EvsQuaternionData {\n w: number;\n x: number;\n y: number;\n z: number;\n}\n\nexport interface EvsVector3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface EvsSensorSample<T> {\n timestampMs: number;\n data: T;\n}\n\nexport interface EvsYprSample extends EvsSensorSample<EvsYprData> {\n calibrationStatus: CalibrationStatus;\n}\n\nexport interface EvsQuaternionSample extends EvsSensorSample<EvsQuaternionData> {\n calibrationStatus: CalibrationStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Stock UI (Evs.instance().showUI(...))\n// ---------------------------------------------------------------------------\n\nexport type EvsStockUIScreen = \"configure\" | \"adjust\" | \"calibrate\";\n\n// ---------------------------------------------------------------------------\n// Auth (IEvsAuthService) / lifecycle events (IEvsAppEvents)\n// ---------------------------------------------------------------------------\n\nexport interface EvsBeginAuthEvent {\n serial: string;\n fwVersion: number;\n}\n\n// ---------------------------------------------------------------------------\n// Native event map — every event the native module can emit to JS via\n// EventEmitter. Keep this in sync with EvsKitModule.kt / EvsKitModule.swift.\n// ---------------------------------------------------------------------------\n\nexport type EvsKitEvents = {\n onConnectionStateChanged: (state: EvsConnectionState) => void;\n onBeginAuth: (event: EvsBeginAuthEvent) => void;\n onGlassesInfoChanged: (info: EvsGlassesInfo) => void;\n onTouch: (direction: TouchDirection) => void;\n onProximity: (event: ProximityEvent) => void;\n onAmbient: (lux: number) => void;\n onYpr: (sample: EvsYprSample) => void;\n onQuaternion: (sample: EvsQuaternionSample) => void;\n onError: (message: string) => void;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"EvsKit.types.js","sourceRoot":"","sources":["../src/EvsKit.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG","sourcesContent":["/**\n * Type definitions mirroring Everysight's Maverick SDK interfaces\n * (IEvsCommunicationService, IEvsGlassesStateService, IEvsDisplayService,\n * IEvsSensorsService, IEvsAuthService).\n *\n * Signatures confirmed against the everysight-maverick/samples repo (v2.6.1)\n * and the MCP API reference.\n */\n\n// ---------------------------------------------------------------------------\n// Communication (IEvsCommunicationService)\n// ---------------------------------------------------------------------------\n\nexport interface EvsDeviceInfo {\n /** Bluetooth device address/id, e.g. from a BLE scan (EV0080 style name). */\n deviceId: string;\n /** Bluetooth device name. */\n name: string;\n}\n\nexport type EvsConnectionState =\n \"disconnected\" | \"connecting\" | \"connected\" | \"authenticating\" | \"error\";\n\n// ---------------------------------------------------------------------------\n// Glasses (IEvsGlassesStateService)\n// ---------------------------------------------------------------------------\n\nexport interface EvsGlassesInfo {\n /** Battery percentage 0-100 from IEvsGlassesStateService.batteryPercentage(). */\n batteryLevel: number;\n /** Battery level category (Unknown/Critical/Low/Medium/High) from batteryLevel(). */\n batteryStatus: string;\n /** Estimated remaining operation time in minutes. */\n estimatedRemainingTime: number;\n /** Firmware version number (Int from fwVersion()). */\n firmwareVersion: number;\n}\n\nexport type TouchDirection = \"backward\" | \"forward\" | \"tap\" | \"longTap\";\n\nexport type ProximityEvent = \"onFace\" | \"offFace\";\n\n// ---------------------------------------------------------------------------\n// Display (IEvsDisplayService)\n// ---------------------------------------------------------------------------\n\nexport interface EvsAutoBrightnessOptions {\n enabled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Sensors (IEvsSensorsService)\n// ---------------------------------------------------------------------------\n\nexport type CalibrationStatus = \"calibrated\" | \"inProgress\" | \"required\";\n\n/** Currently only rate0 and rate1 are operational per the SDK docs; the rest are experimental. */\nexport type SensorRate = \"rate0\" | \"rate1\" | \"rate2\" | \"rate3\";\n\nexport interface EvsYprData {\n yaw: number;\n pitch: number;\n roll: number;\n}\n\nexport interface EvsQuaternionData {\n w: number;\n x: number;\n y: number;\n z: number;\n}\n\nexport interface EvsVector3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface EvsSensorSample<T> {\n timestampMs: number;\n data: T;\n}\n\nexport interface EvsYprSample extends EvsSensorSample<EvsYprData> {\n calibrationStatus: CalibrationStatus;\n}\n\nexport interface EvsQuaternionSample extends EvsSensorSample<EvsQuaternionData> {\n calibrationStatus: CalibrationStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Stock UI (Evs.instance().showUI(...))\n// ---------------------------------------------------------------------------\n\nexport type EvsStockUIScreen = \"configure\" | \"adjust\" | \"calibrate\";\n\n// ---------------------------------------------------------------------------\n// App-owned screens (IEvsScreenService via EvsScreenRegistry)\n// ---------------------------------------------------------------------------\n\n/**\n * String id of an app-owned native screen.\n *\n * The bridge ships no Screen subclasses. Each app registers its own\n * Swift/Kotlin `Screen`/`FullScreen`/`ArScreen` subclasses via\n * `EvsScreenRegistry.register(id, factory)` (iOS) /\n * `EvsScreenRegistry.register(id, factory)` (Android) from app-owned\n * sources — e.g. `<app>/evs-screens/ios/*.swift` linked at prebuild by the\n * bridge config plugin's `screens` option — then pushes them with\n * `EvsScreens.show(id)`.\n */\nexport type EvsScreenId = string;\n\n// ---------------------------------------------------------------------------\n// Auth (IEvsAuthService) / lifecycle events (IEvsAppEvents)\n// ---------------------------------------------------------------------------\n\nexport interface EvsBeginAuthEvent {\n serial: string;\n fwVersion: number;\n}\n\n// ---------------------------------------------------------------------------\n// Native event map — every event the native module can emit to JS via\n// EventEmitter. Keep this in sync with EvsKitModule.kt / EvsKitModule.swift.\n// ---------------------------------------------------------------------------\n\nexport type EvsKitEvents = {\n onConnectionStateChanged: (state: EvsConnectionState) => void;\n onBeginAuth: (event: EvsBeginAuthEvent) => void;\n onGlassesInfoChanged: (info: EvsGlassesInfo) => void;\n onTouch: (direction: TouchDirection) => void;\n onProximity: (event: ProximityEvent) => void;\n onAmbient: (lux: number) => void;\n onYpr: (sample: EvsYprSample) => void;\n onQuaternion: (sample: EvsQuaternionSample) => void;\n onError: (message: string) => void;\n};\n"]}
|
package/build/EvsKitModule.d.ts
CHANGED
|
@@ -28,6 +28,18 @@ declare class EvsKitNativeModule extends NativeModule<EvsKitEvents> {
|
|
|
28
28
|
setAutoBrightness(options: EvsAutoBrightnessOptions): Promise<void>;
|
|
29
29
|
setRenderingCenterX(dx: number): Promise<void>;
|
|
30
30
|
setRenderingCenterY(dy: number): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Push an app-registered screen onto the glasses screen stack.
|
|
33
|
+
* Rejects with EVSKIT_SHOW_SCREEN_FAILED / EVSKIT_UNKNOWN_SCREEN when no
|
|
34
|
+
* factory is registered for `id`.
|
|
35
|
+
*/
|
|
36
|
+
showScreen(id: string): Promise<void>;
|
|
37
|
+
/** Remove a previously shown screen by id. No-op when unknown. */
|
|
38
|
+
removeScreen(id: string): Promise<void>;
|
|
39
|
+
/** Pop the topmost screen; resolves with its id, or null when empty/untracked. */
|
|
40
|
+
removeTopmostScreen(): Promise<string | null>;
|
|
41
|
+
/** Resolve the topmost tracked screen id, or null. */
|
|
42
|
+
getTopmostScreen(): Promise<string | null>;
|
|
31
43
|
enableTouch(enabled: boolean): Promise<void>;
|
|
32
44
|
enableAmbient(enabled: boolean): Promise<void>;
|
|
33
45
|
enableGyro(enabled: boolean): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EvsKitModule.d.ts","sourceRoot":"","sources":["../src/EvsKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EACV,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAExB;;;;;;GAMG;AACH,OAAO,OAAO,kBAAmB,SAAQ,YAAY,CAAC,YAAY,CAAC;IAEjE,4EAA4E;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAG7B,0EAA0E;IAC1E,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAG/C,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IACjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAC/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAC3B,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAGvC,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC;IACzC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAG/B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,oCAAoC;IACpC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,yDAAyD;IACzD,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAChD,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAGnE,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9C,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAG9C,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5C,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IACnD,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IACpD,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAGpD,aAAa,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACxD,gCAAgC;IAChC,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAC5C;;AAED,wBAAmE"}
|
|
1
|
+
{"version":3,"file":"EvsKitModule.d.ts","sourceRoot":"","sources":["../src/EvsKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EACV,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAExB;;;;;;GAMG;AACH,OAAO,OAAO,kBAAmB,SAAQ,YAAY,CAAC,YAAY,CAAC;IAEjE,4EAA4E;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAG7B,0EAA0E;IAC1E,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAG/C,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IACjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAC/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAC3B,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAGvC,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC;IACzC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAG/B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,oCAAoC;IACpC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,yDAAyD;IACzD,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAChD,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAGnE,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9C,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAG9C;;;;OAIG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACrC,kEAAkE;IAClE,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACvC,kFAAkF;IAClF,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAC7C,sDAAsD;IACtD,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAG1C,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5C,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IACnD,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IACpD,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAGpD,aAAa,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACxD,gCAAgC;IAChC,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAC5C;;AAED,wBAAmE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EvsKitModule.js","sourceRoot":"","sources":["../src/EvsKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"EvsKitModule.js","sourceRoot":"","sources":["../src/EvsKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA8EtE,eAAe,mBAAmB,CAAqB,UAAU,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo-modules-core\";\n\nimport type {\n EvsAutoBrightnessOptions,\n EvsDeviceInfo,\n EvsGlassesInfo,\n EvsKitEvents,\n EvsStockUIScreen,\n} from \"./EvsKit.types\";\n\n/**\n * Raw native surface. This intentionally mirrors the SDK's service methods\n * 1:1 (comm/glasses/display/sensors/auth) rather than inventing a different\n * shape, so the JS API stays easy to cross-reference against the Maverick\n * docs. Prefer using the higher-level classes exported from `src/index.ts`\n * over calling this module directly.\n */\ndeclare class EvsKitNativeModule extends NativeModule<EvsKitEvents> {\n // --- Lifecycle -----------------------------------------------------------\n /** Evs.init(context).start() on Android / Evs.instance().start() on iOS. */\n start(): Promise<void>;\n isStarted(): Promise<boolean>;\n\n // --- Stock UI --------------------------------------------------------------\n /** Evs.instance().showUI(name) — \"configure\" | \"adjust\" | \"calibrate\". */\n showUI(screen: EvsStockUIScreen): Promise<void>;\n\n // --- Communication (IEvsCommunicationService) -----------------------------\n setDeviceInfo(info: EvsDeviceInfo): Promise<void>;\n connect(): Promise<void>;\n connectSecured(): Promise<void>;\n disconnect(): Promise<void>;\n hasConfiguredDevice(): Promise<boolean>;\n\n // --- Glasses (IEvsGlassesStateService) -------------------------------------\n getGlassesInfo(): Promise<EvsGlassesInfo>;\n turnGlassesOff(): Promise<void>;\n\n // --- Display (IEvsDisplayService) ------------------------------------------\n turnDisplayOn(): Promise<void>;\n /** Continuous brightness, 1-255. */\n setBrightness(value: number): Promise<void>;\n /** Discrete, display-optimized brightness controller. */\n setBrightnessLevel(level: number): Promise<void>;\n setAutoBrightness(options: EvsAutoBrightnessOptions): Promise<void>;\n\n // --- Screens (rendering offset) ---------------------------------------------\n setRenderingCenterX(dx: number): Promise<void>;\n setRenderingCenterY(dy: number): Promise<void>;\n\n // --- App-owned screens (IEvsScreenService via EvsScreenRegistry) ------------\n /**\n * Push an app-registered screen onto the glasses screen stack.\n * Rejects with EVSKIT_SHOW_SCREEN_FAILED / EVSKIT_UNKNOWN_SCREEN when no\n * factory is registered for `id`.\n */\n showScreen(id: string): Promise<void>;\n /** Remove a previously shown screen by id. No-op when unknown. */\n removeScreen(id: string): Promise<void>;\n /** Pop the topmost screen; resolves with its id, or null when empty/untracked. */\n removeTopmostScreen(): Promise<string | null>;\n /** Resolve the topmost tracked screen id, or null. */\n getTopmostScreen(): Promise<string | null>;\n\n // --- Sensors (IEvsSensorsService) -------------------------------------------\n enableTouch(enabled: boolean): Promise<void>;\n enableAmbient(enabled: boolean): Promise<void>;\n enableGyro(enabled: boolean): Promise<void>;\n enableMagnetometer(enabled: boolean): Promise<void>;\n enableAccelerometer(enabled: boolean): Promise<void>;\n enableSensorsFusion(enabled: boolean): Promise<void>;\n\n // --- Auth (IEvsAuthService) --------------------------------------------------\n setApiKeyName(fileNameWithoutExt: string): Promise<void>;\n /** base64-encoded key bytes. */\n setApiKey(base64Key: string): Promise<void>;\n}\n\nexport default requireNativeModule<EvsKitNativeModule>(\"RNEvsKit\");\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EventSubscription } from "expo-modules-core";
|
|
2
|
-
import type { EvsAutoBrightnessOptions, EvsDeviceInfo, EvsGlassesInfo, EvsKitEvents, EvsStockUIScreen } from "./EvsKit.types";
|
|
2
|
+
import type { EvsAutoBrightnessOptions, EvsDeviceInfo, EvsGlassesInfo, EvsKitEvents, EvsScreenId, EvsStockUIScreen } from "./EvsKit.types";
|
|
3
3
|
export * from "./EvsKit.types";
|
|
4
4
|
/**
|
|
5
5
|
* Communication service — mirrors IEvsCommunicationService
|
|
@@ -58,6 +58,23 @@ export declare const EvsAuth: {
|
|
|
58
58
|
export declare const EvsUI: {
|
|
59
59
|
show(screen: EvsStockUIScreen): Promise<void>;
|
|
60
60
|
};
|
|
61
|
+
/**
|
|
62
|
+
* App-owned glasses screens (`Evs.instance().screens()`).
|
|
63
|
+
*
|
|
64
|
+
* The bridge ships no Screen subclasses. Register yours natively per app —
|
|
65
|
+
* `EvsScreenRegistry.register(id, factory)` from app-owned Swift/Kotlin
|
|
66
|
+
* sources (linked at prebuild by the plugin's `screens` option) — then push
|
|
67
|
+
* them from JS:
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* await EvsScreens.show("hello-world");
|
|
71
|
+
*/
|
|
72
|
+
export declare const EvsScreens: {
|
|
73
|
+
show(id: EvsScreenId): Promise<void>;
|
|
74
|
+
remove(id: EvsScreenId): Promise<void>;
|
|
75
|
+
removeTopmost(): Promise<string | null>;
|
|
76
|
+
getTopmost(): Promise<string | null>;
|
|
77
|
+
};
|
|
61
78
|
/** Top-level lifecycle, matching `Evs.init(context).start()` / `Evs.instance().start()`. */
|
|
62
79
|
export declare const EvsKit: {
|
|
63
80
|
start(): Promise<void>;
|
|
@@ -100,6 +117,12 @@ export declare const EvsKit: {
|
|
|
100
117
|
ui: {
|
|
101
118
|
show(screen: EvsStockUIScreen): Promise<void>;
|
|
102
119
|
};
|
|
120
|
+
screens: {
|
|
121
|
+
show(id: EvsScreenId): Promise<void>;
|
|
122
|
+
remove(id: EvsScreenId): Promise<void>;
|
|
123
|
+
removeTopmost(): Promise<string | null>;
|
|
124
|
+
getTopmost(): Promise<string | null>;
|
|
125
|
+
};
|
|
103
126
|
};
|
|
104
127
|
export default EvsKit;
|
|
105
128
|
/** Subscribe to a single EvsKit event; call the returned function to unsubscribe. */
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,KAAK,EACV,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAGxB,cAAc,gBAAgB,CAAC;AAE/B;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO;wBACE,aAAa;;IAMjC,kEAAkE;;;;CAUnE,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,UAAU;eACV,OAAO,CAAC,cAAc,CAAC;;CAMnC,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,UAAU;;IAIrB,2EAA2E;yBACtD,MAAM;IAG3B,4EAA4E;8BAClD,MAAM;+BAGL,wBAAwB;IAGnD,oFAAoF;2BAC7D,MAAM,MAAM,MAAM;CAM1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU;yBACA,OAAO;2BAGL,OAAO;wBAGV,OAAO;gCAGC,OAAO;iCAGN,OAAO;IAGpC,mFAAmF;0BAC7D,OAAO;CAG9B,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,OAAO;sCACgB,MAAM;yBAGnB,MAAM;CAG5B,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,KAAK;iBACH,gBAAgB;CAG9B,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,MAAM;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,KAAK,EACV,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAGxB,cAAc,gBAAgB,CAAC;AAE/B;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO;wBACE,aAAa;;IAMjC,kEAAkE;;;;CAUnE,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,UAAU;eACV,OAAO,CAAC,cAAc,CAAC;;CAMnC,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,UAAU;;IAIrB,2EAA2E;yBACtD,MAAM;IAG3B,4EAA4E;8BAClD,MAAM;+BAGL,wBAAwB;IAGnD,oFAAoF;2BAC7D,MAAM,MAAM,MAAM;CAM1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU;yBACA,OAAO;2BAGL,OAAO;wBAGV,OAAO;gCAGC,OAAO;iCAGN,OAAO;IAGpC,mFAAmF;0BAC7D,OAAO;CAG9B,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,OAAO;sCACgB,MAAM;yBAGnB,MAAM;CAG5B,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,KAAK;iBACH,gBAAgB;CAG9B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU;aACZ,WAAW;eAGT,WAAW;;;CASvB,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,MAAM;;;;4BA5HG,aAAa;;QAMjC,kEAAkE;;;;;;mBAcvD,OAAO,CAAC,cAAc,CAAC;;;;;QAalC,2EAA2E;6BACtD,MAAM;QAG3B,4EAA4E;kCAClD,MAAM;mCAGL,wBAAwB;QAGnD,oFAAoF;+BAC7D,MAAM,MAAM,MAAM;;;6BAcpB,OAAO;+BAGL,OAAO;4BAGV,OAAO;oCAGC,OAAO;qCAGN,OAAO;QAGpC,mFAAmF;8BAC7D,OAAO;;;0CAOK,MAAM;6BAGnB,MAAM;;;qBAOd,gBAAgB;;;iBAiBpB,WAAW;mBAGT,WAAW;;;;CA0BvB,CAAC;AAEF,eAAe,MAAM,CAAC;AAMtB,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC5D,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,iBAAiB,CAEnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,YAAY,EACzD,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,QAO1B"}
|
package/build/index.js
CHANGED
|
@@ -103,6 +103,31 @@ export const EvsUI = {
|
|
|
103
103
|
return EvsKitNative.showUI(screen);
|
|
104
104
|
},
|
|
105
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* App-owned glasses screens (`Evs.instance().screens()`).
|
|
108
|
+
*
|
|
109
|
+
* The bridge ships no Screen subclasses. Register yours natively per app —
|
|
110
|
+
* `EvsScreenRegistry.register(id, factory)` from app-owned Swift/Kotlin
|
|
111
|
+
* sources (linked at prebuild by the plugin's `screens` option) — then push
|
|
112
|
+
* them from JS:
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* await EvsScreens.show("hello-world");
|
|
116
|
+
*/
|
|
117
|
+
export const EvsScreens = {
|
|
118
|
+
show(id) {
|
|
119
|
+
return EvsKitNative.showScreen(id);
|
|
120
|
+
},
|
|
121
|
+
remove(id) {
|
|
122
|
+
return EvsKitNative.removeScreen(id);
|
|
123
|
+
},
|
|
124
|
+
removeTopmost() {
|
|
125
|
+
return EvsKitNative.removeTopmostScreen();
|
|
126
|
+
},
|
|
127
|
+
getTopmost() {
|
|
128
|
+
return EvsKitNative.getTopmostScreen();
|
|
129
|
+
},
|
|
130
|
+
};
|
|
106
131
|
/** Top-level lifecycle, matching `Evs.init(context).start()` / `Evs.instance().start()`. */
|
|
107
132
|
export const EvsKit = {
|
|
108
133
|
start() {
|
|
@@ -117,6 +142,7 @@ export const EvsKit = {
|
|
|
117
142
|
sensors: EvsSensors,
|
|
118
143
|
auth: EvsAuth,
|
|
119
144
|
ui: EvsUI,
|
|
145
|
+
screens: EvsScreens,
|
|
120
146
|
};
|
|
121
147
|
export default EvsKit;
|
|
122
148
|
// ---------------------------------------------------------------------------
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EventSubscription } from \"expo-modules-core\";\nimport { useEffect } from \"react\";\n\nimport type {\n EvsAutoBrightnessOptions,\n EvsDeviceInfo,\n EvsGlassesInfo,\n EvsKitEvents,\n EvsScreenId,\n EvsStockUIScreen,\n} from \"./EvsKit.types\";\nimport EvsKitNative from \"./EvsKitModule\";\n\nexport * from \"./EvsKit.types\";\n\n/**\n * Communication service — mirrors IEvsCommunicationService\n * (`Evs.instance().comm()`).\n *\n * Scanning for glasses is NOT handled here: the SDK docs specify scanning\n * is done with the platform's standard BLE APIs (CBCentralManager /\n * BluetoothLeScanner) against `BTConstants.serviceUUID`, filtering for the\n * \"EV####\" name pattern. Pair that with a BLE library (e.g. react-native-ble-plx)\n * or just use `EvsUI.show('configure')` for the SDK's built-in scan/pair flow.\n */\nexport const EvsComm = {\n setDeviceInfo(info: EvsDeviceInfo) {\n return EvsKitNative.setDeviceInfo(info);\n },\n connect() {\n return EvsKitNative.connect();\n },\n /** Use instead of connect() when the app requires BLE pairing. */\n connectSecured() {\n return EvsKitNative.connectSecured();\n },\n disconnect() {\n return EvsKitNative.disconnect();\n },\n hasConfiguredDevice() {\n return EvsKitNative.hasConfiguredDevice();\n },\n};\n\n/** Mirrors IEvsGlassesStateService (`Evs.instance().glasses()`). */\nexport const EvsGlasses = {\n getInfo(): Promise<EvsGlassesInfo> {\n return EvsKitNative.getGlassesInfo();\n },\n turnOff() {\n return EvsKitNative.turnGlassesOff();\n },\n};\n\n/** Mirrors IEvsDisplayService (`Evs.instance().display()`) plus screen offset controls. */\nexport const EvsDisplay = {\n turnOn() {\n return EvsKitNative.turnDisplayOn();\n },\n /** Continuous scale, 1-255. Prefer setBrightnessLevel() where possible. */\n setBrightness(value: number) {\n return EvsKitNative.setBrightness(value);\n },\n /** Discrete brightness level via the SDK's display-optimized controller. */\n setBrightnessLevel(level: number) {\n return EvsKitNative.setBrightnessLevel(level);\n },\n setAutoBrightness(options: EvsAutoBrightnessOptions) {\n return EvsKitNative.setAutoBrightness(options);\n },\n /** Adjust the virtual rendering area's center offset within the 640x400 display. */\n setRenderingCenter(dx: number, dy: number) {\n return Promise.all([\n EvsKitNative.setRenderingCenterX(dx),\n EvsKitNative.setRenderingCenterY(dy),\n ]);\n },\n};\n\n/**\n * Mirrors IEvsSensorsService (`Evs.instance().sensors()`).\n * Remember to disable sensors and unsubscribe events when no longer needed —\n * the SDK docs call this out explicitly for battery/bandwidth reasons.\n */\nexport const EvsSensors = {\n enableTouch(enabled: boolean) {\n return EvsKitNative.enableTouch(enabled);\n },\n enableAmbient(enabled: boolean) {\n return EvsKitNative.enableAmbient(enabled);\n },\n enableGyro(enabled: boolean) {\n return EvsKitNative.enableGyro(enabled);\n },\n enableMagnetometer(enabled: boolean) {\n return EvsKitNative.enableMagnetometer(enabled);\n },\n enableAccelerometer(enabled: boolean) {\n return EvsKitNative.enableAccelerometer(enabled);\n },\n /** Enables Gyro + Magnetometer + Accelerometer and starts the fusion algorithm. */\n enableFusion(enabled: boolean) {\n return EvsKitNative.enableSensorsFusion(enabled);\n },\n};\n\n/** Mirrors IEvsAuthService (`Evs.instance().auth()`). Usually unnecessary — see API Keys docs. */\nexport const EvsAuth = {\n setApiKeyName(fileNameWithoutExt: string) {\n return EvsKitNative.setApiKeyName(fileNameWithoutExt);\n },\n setApiKey(base64Key: string) {\n return EvsKitNative.setApiKey(base64Key);\n },\n};\n\n/** Mirrors `Evs.instance().showUI(...)` — the SDK's built-in portrait UI screens. */\nexport const EvsUI = {\n show(screen: EvsStockUIScreen) {\n return EvsKitNative.showUI(screen);\n },\n};\n\n/**\n * App-owned glasses screens (`Evs.instance().screens()`).\n *\n * The bridge ships no Screen subclasses. Register yours natively per app —\n * `EvsScreenRegistry.register(id, factory)` from app-owned Swift/Kotlin\n * sources (linked at prebuild by the plugin's `screens` option) — then push\n * them from JS:\n *\n * @example\n * await EvsScreens.show(\"hello-world\");\n */\nexport const EvsScreens = {\n show(id: EvsScreenId) {\n return EvsKitNative.showScreen(id);\n },\n remove(id: EvsScreenId) {\n return EvsKitNative.removeScreen(id);\n },\n removeTopmost() {\n return EvsKitNative.removeTopmostScreen();\n },\n getTopmost() {\n return EvsKitNative.getTopmostScreen();\n },\n};\n\n/** Top-level lifecycle, matching `Evs.init(context).start()` / `Evs.instance().start()`. */\nexport const EvsKit = {\n start() {\n return EvsKitNative.start();\n },\n isStarted() {\n return EvsKitNative.isStarted();\n },\n comm: EvsComm,\n glasses: EvsGlasses,\n display: EvsDisplay,\n sensors: EvsSensors,\n auth: EvsAuth,\n ui: EvsUI,\n screens: EvsScreens,\n};\n\nexport default EvsKit;\n\n// ---------------------------------------------------------------------------\n// Event subscription helpers\n// ---------------------------------------------------------------------------\n\n/** Subscribe to a single EvsKit event; call the returned function to unsubscribe. */\nexport function addEvsKitListener<K extends keyof EvsKitEvents>(\n eventName: K,\n listener: EvsKitEvents[K],\n): EventSubscription {\n return EvsKitNative.addListener(eventName, listener as any);\n}\n\n/**\n * React hook that subscribes to an EvsKit event for the lifetime of the\n * component. Pass a stable callback (e.g. via useCallback) to avoid\n * resubscribing every render.\n *\n * @example\n * useEvsKitEvent('onTouch', (direction) => {\n * if (direction === 'tap') showPopup();\n * });\n */\nexport function useEvsKitEvent<K extends keyof EvsKitEvents>(\n eventName: K,\n listener: EvsKitEvents[K],\n) {\n useEffect(() => {\n const subscription = addEvsKitListener(eventName, listener);\n return () => subscription.remove();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [eventName, listener]);\n}\n"]}
|
package/ios/EvsKitModule.swift
CHANGED
|
@@ -23,6 +23,12 @@ public class EvsKitModule: Module {
|
|
|
23
23
|
private var yprEventsHandle: YprEventsHandler?
|
|
24
24
|
private var quaternionEventsHandle: QuaternionEventsHandler?
|
|
25
25
|
|
|
26
|
+
/// Screens pushed via showScreen(id:), keyed by the JS-facing id so
|
|
27
|
+
/// removeScreen(id:) can resolve the native instance. Viewport covers
|
|
28
|
+
/// Screen, FullScreen and ArScreen.
|
|
29
|
+
private var activeScreens: [String: Viewport] = [:]
|
|
30
|
+
private var activeScreenOrder: [String] = []
|
|
31
|
+
|
|
26
32
|
public func definition() -> ModuleDefinition {
|
|
27
33
|
Name("RNEvsKit")
|
|
28
34
|
|
|
@@ -71,6 +77,58 @@ public class EvsKitModule: Module {
|
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
79
|
|
|
80
|
+
// --- App-owned screens (IEvsScreenService) --------------------------------
|
|
81
|
+
//
|
|
82
|
+
// The bridge ships no Screen subclasses. Apps register their own via
|
|
83
|
+
// EvsScreenRegistry.register(id:factory:) from app-owned Swift sources
|
|
84
|
+
// (linked at prebuild by the `screens` plugin option), then push them
|
|
85
|
+
// from JS with showScreen(id:).
|
|
86
|
+
|
|
87
|
+
AsyncFunction("showScreen") { (id: String) -> Void in
|
|
88
|
+
await MainActor.run { () -> Void in
|
|
89
|
+
guard let screen = EvsScreenRegistry.make(id: id) else {
|
|
90
|
+
throw Exception(
|
|
91
|
+
name: "EVSKIT_UNKNOWN_SCREEN",
|
|
92
|
+
description: "No screen registered for id '\(id)'. "
|
|
93
|
+
+ "Register it via EvsScreenRegistry.register(id:factory:) "
|
|
94
|
+
+ "from app-owned Swift sources."
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
Evs.instance().screens().addScreen(screen: screen)
|
|
98
|
+
if self.activeScreens[id] == nil {
|
|
99
|
+
self.activeScreenOrder.append(id)
|
|
100
|
+
}
|
|
101
|
+
self.activeScreens[id] = screen
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
AsyncFunction("removeScreen") { (id: String) -> Void in
|
|
106
|
+
await MainActor.run { () -> Void in
|
|
107
|
+
guard let screen = self.activeScreens[id] else { return }
|
|
108
|
+
Evs.instance().screens().removeScreen(screen: screen)
|
|
109
|
+
self.activeScreens.removeValue(forKey: id)
|
|
110
|
+
self.activeScreenOrder.removeAll { $0 == id }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
AsyncFunction("removeTopmostScreen") { () -> String? in
|
|
115
|
+
await MainActor.run { () -> String? in
|
|
116
|
+
let removed: Viewport? = Evs.instance().screens().removeTopmostScreen()
|
|
117
|
+
guard let removed else { return nil }
|
|
118
|
+
if let id = self.activeScreens.first(where: { $0.value === removed })?.key {
|
|
119
|
+
self.activeScreens.removeValue(forKey: id)
|
|
120
|
+
self.activeScreenOrder.removeAll { $0 == id }
|
|
121
|
+
return id
|
|
122
|
+
}
|
|
123
|
+
return nil
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
AsyncFunction("getTopmostScreen") { () -> String? in
|
|
128
|
+
let topmost = Evs.instance().screens().getTopmostScreen()
|
|
129
|
+
return self.activeScreens.first(where: { $0.value === topmost })?.key
|
|
130
|
+
}
|
|
131
|
+
|
|
74
132
|
// --- Communication (IEvsCommunicationService) -----------------------------
|
|
75
133
|
|
|
76
134
|
AsyncFunction("setDeviceInfo") { (info: DeviceInfoRecord) -> Void in
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import NativeEvsKit
|
|
2
|
+
|
|
3
|
+
/// Generic app-owned screen registry.
|
|
4
|
+
///
|
|
5
|
+
/// The bridge itself ships NO Screen subclasses. Each app registers its own
|
|
6
|
+
/// Swift `Screen`/`FullScreen`/`ArScreen` subclasses under a string id, then
|
|
7
|
+
/// drives them from JS via `EvsScreens.show(id)`.
|
|
8
|
+
///
|
|
9
|
+
/// App screens live in app source (e.g. `<app>/evs-screens/ios/*.swift`),
|
|
10
|
+
/// linked into the app target at prebuild by the `screens` config-plugin
|
|
11
|
+
/// option — so wiping `ios/` and re-running `expo prebuild` loses nothing.
|
|
12
|
+
public enum EvsScreenRegistry {
|
|
13
|
+
public static var factories: [String: () -> Viewport] = [:]
|
|
14
|
+
|
|
15
|
+
public static func register(id: String, factory: @escaping () -> Viewport) {
|
|
16
|
+
factories[id] = factory
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static func unregister(id: String) {
|
|
20
|
+
factories.removeValue(forKey: id)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public static func make(id: String) -> Viewport? {
|
|
24
|
+
factories[id]?()
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@therealitycrafters/react-native-evskit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React Native / Expo bridge for Everysight's Maverick SDK (EvsKit + NativeEvsKit)",
|
|
5
5
|
"author": "Patrick Catanzariti",
|
|
6
6
|
"homepage": "https://therealitycrafters.com",
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
const { withAppBuildGradle, withXcodeProject } = require("@expo/config-plugins");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Links app-owned Everysight glasses screens into the native build and
|
|
7
|
+
// generates their registration with the bridge's EvsScreenRegistry.
|
|
8
|
+
//
|
|
9
|
+
// App screens live in app source (committed), e.g.:
|
|
10
|
+
//
|
|
11
|
+
// <app>/evs-screens/ios/HelloWorldScreen.swift
|
|
12
|
+
// <app>/evs-screens/android/HelloWorldScreen.kt
|
|
13
|
+
//
|
|
14
|
+
// Usage in app.config.ts:
|
|
15
|
+
//
|
|
16
|
+
// plugins: [
|
|
17
|
+
// ['react-native-evskit', {
|
|
18
|
+
// bundleResources: ['./sdk.key'],
|
|
19
|
+
// screens: {
|
|
20
|
+
// ios: './evs-screens/ios',
|
|
21
|
+
// android: './evs-screens/android',
|
|
22
|
+
// // id -> class name. Swift: class name in the app target.
|
|
23
|
+
// // Kotlin: fully-qualified class name.
|
|
24
|
+
// register: {
|
|
25
|
+
// 'hello-world': {
|
|
26
|
+
// ios: 'HelloWorldScreen',
|
|
27
|
+
// android: 'com.sampleevskitproject.screens.HelloWorldScreen',
|
|
28
|
+
// },
|
|
29
|
+
// },
|
|
30
|
+
// },
|
|
31
|
+
// }],
|
|
32
|
+
// ]
|
|
33
|
+
//
|
|
34
|
+
// On `expo prebuild` this:
|
|
35
|
+
// - iOS: adds each app-owned .swift file to the app target's Sources phase
|
|
36
|
+
// (path relative to ios/, e.g. "../evs-screens/ios/HelloWorldScreen.swift"),
|
|
37
|
+
// and writes a generated `ios/EvsAppScreens.generated.swift` that registers
|
|
38
|
+
// every id. The generated file self-registers via top-level statements, so
|
|
39
|
+
// no AppDelegate changes are needed.
|
|
40
|
+
// - Android: registers the app-owned dir (plus a generated dir) as extra
|
|
41
|
+
// sourceSets java srcDirs, and writes a generated registrar object. The
|
|
42
|
+
// bridge loads it via Class.forName on startup (no-op when absent).
|
|
43
|
+
//
|
|
44
|
+
// The source of truth is the committed evs-screens/ folder plus the config,
|
|
45
|
+
// and the plugin re-runs on every prebuild, so wiping ios/ + android/ loses
|
|
46
|
+
// nothing. Push from JS with `await EvsScreens.show("hello-world")`.
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
const GENERATED_IOS_FILE = "EvsAppScreens.generated.swift";
|
|
49
|
+
const GENERATED_ANDROID_DIR = "evs-screens-generated";
|
|
50
|
+
const GENERATED_ANDROID_PACKAGE = "evs.screens.generated";
|
|
51
|
+
const GENERATED_ANDROID_CLASS = "EvsAppScreensGenerated";
|
|
52
|
+
|
|
53
|
+
function withEvsScreens(config, { screens = {} } = {}) {
|
|
54
|
+
const { ios: iosDir, android: androidDir, register = {} } = screens;
|
|
55
|
+
if (!iosDir && !androidDir) {
|
|
56
|
+
return config;
|
|
57
|
+
}
|
|
58
|
+
if (iosDir) {
|
|
59
|
+
config = withEvsIosScreens(config, iosDir, register);
|
|
60
|
+
}
|
|
61
|
+
if (androidDir) {
|
|
62
|
+
config = withEvsAndroidScreens(config, androidDir, register);
|
|
63
|
+
}
|
|
64
|
+
return config;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function listSourceFiles(absDir, ext) {
|
|
68
|
+
if (!fs.existsSync(absDir) || !fs.statSync(absDir).isDirectory()) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return fs.readdirSync(absDir).filter((f) => f.endsWith(ext)).sort();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function toPosix(p) {
|
|
75
|
+
return p.split(path.sep).join("/");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function sanitize(id) {
|
|
79
|
+
return id.replace(/[^A-Za-z0-9_]/g, "_");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = withEvsScreens;
|
|
83
|
+
function generatedIosContents(register) {
|
|
84
|
+
const lines = [
|
|
85
|
+
"// Generated by react-native-evskit — do not edit.",
|
|
86
|
+
"// Registers app-owned screens (see `screens.register` in app.config).",
|
|
87
|
+
"",
|
|
88
|
+
"import NativeEvsKit",
|
|
89
|
+
"import RNEvsKit",
|
|
90
|
+
"",
|
|
91
|
+
];
|
|
92
|
+
for (const [id, entry] of Object.entries(register)) {
|
|
93
|
+
const className = typeof entry === "string" ? entry : entry.ios;
|
|
94
|
+
if (!className) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
lines.push(
|
|
98
|
+
`private let _evsRegister_${sanitize(id)}: Void = {`,
|
|
99
|
+
` EvsScreenRegistry.register(id: ${JSON.stringify(id)}) { ${className}() }`,
|
|
100
|
+
`}()`,
|
|
101
|
+
"",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (!Object.keys(register).length) {
|
|
105
|
+
lines.push("// No screens registered.", "");
|
|
106
|
+
}
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function addSwiftFileToSources(project, objects, sourcesPhase, fileName, relativePath) {
|
|
111
|
+
const alreadyAdded = Object.keys(objects.PBXBuildFile).some(
|
|
112
|
+
(key) =>
|
|
113
|
+
!key.endsWith("_comment") &&
|
|
114
|
+
objects.PBXBuildFile[key].fileRef_comment === fileName,
|
|
115
|
+
);
|
|
116
|
+
if (alreadyAdded) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const fileRefUuid = project.generateUuid();
|
|
120
|
+
objects.PBXFileReference[fileRefUuid] = {
|
|
121
|
+
isa: "PBXFileReference",
|
|
122
|
+
explicitFileType: "sourcecode.swift",
|
|
123
|
+
fileEncoding: 4,
|
|
124
|
+
name: fileName,
|
|
125
|
+
path: relativePath,
|
|
126
|
+
// Quotes must be embedded: the `xcode` lib's pbxWriter does not add
|
|
127
|
+
// quotes itself, and angle brackets (<>) are invalid unquoted.
|
|
128
|
+
sourceTree: '"<group>"',
|
|
129
|
+
};
|
|
130
|
+
objects.PBXFileReference[`${fileRefUuid}_comment`] = fileName;
|
|
131
|
+
const buildFileUuid = project.generateUuid();
|
|
132
|
+
objects.PBXBuildFile[buildFileUuid] = {
|
|
133
|
+
isa: "PBXBuildFile",
|
|
134
|
+
fileRef: fileRefUuid,
|
|
135
|
+
fileRef_comment: fileName,
|
|
136
|
+
};
|
|
137
|
+
objects.PBXBuildFile[`${buildFileUuid}_comment`] =
|
|
138
|
+
`${fileName} in Sources`;
|
|
139
|
+
sourcesPhase.files = sourcesPhase.files || [];
|
|
140
|
+
sourcesPhase.files.push({
|
|
141
|
+
value: buildFileUuid,
|
|
142
|
+
comment: `${fileName} in Sources`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function withEvsIosScreens(config, iosScreensDir, register) {
|
|
147
|
+
return withXcodeProject(config, (config) => {
|
|
148
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
149
|
+
const absDir = path.join(projectRoot, iosScreensDir);
|
|
150
|
+
const files = listSourceFiles(absDir, ".swift");
|
|
151
|
+
const project = config.modResults;
|
|
152
|
+
const objects = project.hash.project.objects;
|
|
153
|
+
objects.PBXBuildFile = objects.PBXBuildFile || {};
|
|
154
|
+
objects.PBXFileReference = objects.PBXFileReference || {};
|
|
155
|
+
const target = project.getFirstTarget();
|
|
156
|
+
const nativeTarget = objects.PBXNativeTarget[target.uuid];
|
|
157
|
+
const sourcesPhaseUuid = nativeTarget.buildPhases.find((phase) =>
|
|
158
|
+
/Sources/i.test(phase.comment || ""),
|
|
159
|
+
)?.value;
|
|
160
|
+
const sourcesPhase = sourcesPhaseUuid
|
|
161
|
+
? objects.PBXSourcesBuildPhase[sourcesPhaseUuid]
|
|
162
|
+
: undefined;
|
|
163
|
+
if (!sourcesPhase) {
|
|
164
|
+
return config;
|
|
165
|
+
}
|
|
166
|
+
// The Xcode project lives in <projectRoot>/ios, so file reference paths
|
|
167
|
+
// must be relative to that directory (e.g. "../evs-screens/ios/X.swift").
|
|
168
|
+
const iosDir = path.join(projectRoot, "ios");
|
|
169
|
+
for (const fileName of files) {
|
|
170
|
+
addSwiftFileToSources(
|
|
171
|
+
project,
|
|
172
|
+
objects,
|
|
173
|
+
sourcesPhase,
|
|
174
|
+
fileName,
|
|
175
|
+
toPosix(path.join(path.relative(iosDir, absDir), fileName)),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
// Generated registrar — written into the (regenerable) ios/ dir and
|
|
179
|
+
// linked the same way. Top-level `let` runs at binary load, so no
|
|
180
|
+
// AppDelegate changes are needed.
|
|
181
|
+
if (Object.keys(register).length) {
|
|
182
|
+
const generatedPath = path.join(iosDir, GENERATED_IOS_FILE);
|
|
183
|
+
fs.writeFileSync(generatedPath, generatedIosContents(register));
|
|
184
|
+
addSwiftFileToSources(
|
|
185
|
+
project,
|
|
186
|
+
objects,
|
|
187
|
+
sourcesPhase,
|
|
188
|
+
GENERATED_IOS_FILE,
|
|
189
|
+
GENERATED_IOS_FILE,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return config;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function generatedAndroidContents(register) {
|
|
196
|
+
const lines = [
|
|
197
|
+
`package ${GENERATED_ANDROID_PACKAGE}`,
|
|
198
|
+
"",
|
|
199
|
+
"// Generated by react-native-evskit — do not edit.",
|
|
200
|
+
"// Registers app-owned screens (see `screens.register` in app.config).",
|
|
201
|
+
"// Loaded via Class.forName from the bridge module's OnCreate.",
|
|
202
|
+
"",
|
|
203
|
+
"import expo.modules.evskit.EvsScreenRegistry",
|
|
204
|
+
"",
|
|
205
|
+
`object ${GENERATED_ANDROID_CLASS} {`,
|
|
206
|
+
" init {",
|
|
207
|
+
];
|
|
208
|
+
for (const [id, entry] of Object.entries(register)) {
|
|
209
|
+
const fqcn = typeof entry === "string" ? entry : entry.android;
|
|
210
|
+
if (!fqcn) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const simple = fqcn.split(".").pop();
|
|
214
|
+
lines.push(`import ${fqcn}`);
|
|
215
|
+
lines.push(` EvsScreenRegistry.register(${JSON.stringify(id)}) { ${simple}() }`);
|
|
216
|
+
}
|
|
217
|
+
lines.push(" }", "}");
|
|
218
|
+
return lines.join("\n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function withEvsAndroidScreens(config, androidScreensDir, register) {
|
|
222
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
223
|
+
// Write the generated registrar into a disposable dir under android/ and
|
|
224
|
+
// compile it via an extra srcDir (same mechanism as the app-owned dir).
|
|
225
|
+
if (Object.keys(register).length) {
|
|
226
|
+
const genDir = path.join(projectRoot, "android", GENERATED_ANDROID_DIR);
|
|
227
|
+
fs.mkdirSync(genDir, { recursive: true });
|
|
228
|
+
fs.writeFileSync(
|
|
229
|
+
path.join(genDir, `${GENERATED_ANDROID_CLASS}.kt`),
|
|
230
|
+
generatedAndroidContents(register),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
// Register the app-owned screens dir (+ generated dir) as extra java
|
|
234
|
+
// srcDirs so their .kt files compile into the app.
|
|
235
|
+
config = withAppBuildGradle(config, (config) => {
|
|
236
|
+
const marker = "// react-native-evskit: app-owned glasses screens";
|
|
237
|
+
if (config.modResults.contents.includes(marker)) {
|
|
238
|
+
return config;
|
|
239
|
+
}
|
|
240
|
+
// Paths relative to <projectRoot>/android/app.
|
|
241
|
+
const appDir = path.join(projectRoot, "android", "app");
|
|
242
|
+
const srcDirs = [toPosix(path.relative(appDir, path.join(projectRoot, androidScreensDir)))];
|
|
243
|
+
if (Object.keys(register).length) {
|
|
244
|
+
srcDirs.push(
|
|
245
|
+
toPosix(path.relative(appDir, path.join(projectRoot, "android", GENERATED_ANDROID_DIR))),
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
const srcDirsList = srcDirs.map((d) => ` '${d}'`).join(",\n");
|
|
249
|
+
config.modResults.contents = config.modResults.contents.replace(
|
|
250
|
+
/android\s*\{/,
|
|
251
|
+
`android {\n${marker}\n sourceSets {\n main {\n java.srcDirs += [\n${srcDirsList}\n ]\n }\n }`,
|
|
252
|
+
);
|
|
253
|
+
return config;
|
|
254
|
+
});
|
|
255
|
+
return config;
|
|
256
|
+
}
|
package/src/EvsKit.types.ts
CHANGED
|
@@ -95,6 +95,23 @@ export interface EvsQuaternionSample extends EvsSensorSample<EvsQuaternionData>
|
|
|
95
95
|
|
|
96
96
|
export type EvsStockUIScreen = "configure" | "adjust" | "calibrate";
|
|
97
97
|
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// App-owned screens (IEvsScreenService via EvsScreenRegistry)
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* String id of an app-owned native screen.
|
|
104
|
+
*
|
|
105
|
+
* The bridge ships no Screen subclasses. Each app registers its own
|
|
106
|
+
* Swift/Kotlin `Screen`/`FullScreen`/`ArScreen` subclasses via
|
|
107
|
+
* `EvsScreenRegistry.register(id, factory)` (iOS) /
|
|
108
|
+
* `EvsScreenRegistry.register(id, factory)` (Android) from app-owned
|
|
109
|
+
* sources — e.g. `<app>/evs-screens/ios/*.swift` linked at prebuild by the
|
|
110
|
+
* bridge config plugin's `screens` option — then pushes them with
|
|
111
|
+
* `EvsScreens.show(id)`.
|
|
112
|
+
*/
|
|
113
|
+
export type EvsScreenId = string;
|
|
114
|
+
|
|
98
115
|
// ---------------------------------------------------------------------------
|
|
99
116
|
// Auth (IEvsAuthService) / lifecycle events (IEvsAppEvents)
|
|
100
117
|
// ---------------------------------------------------------------------------
|
package/src/EvsKitModule.ts
CHANGED
|
@@ -48,6 +48,20 @@ declare class EvsKitNativeModule extends NativeModule<EvsKitEvents> {
|
|
|
48
48
|
setRenderingCenterX(dx: number): Promise<void>;
|
|
49
49
|
setRenderingCenterY(dy: number): Promise<void>;
|
|
50
50
|
|
|
51
|
+
// --- App-owned screens (IEvsScreenService via EvsScreenRegistry) ------------
|
|
52
|
+
/**
|
|
53
|
+
* Push an app-registered screen onto the glasses screen stack.
|
|
54
|
+
* Rejects with EVSKIT_SHOW_SCREEN_FAILED / EVSKIT_UNKNOWN_SCREEN when no
|
|
55
|
+
* factory is registered for `id`.
|
|
56
|
+
*/
|
|
57
|
+
showScreen(id: string): Promise<void>;
|
|
58
|
+
/** Remove a previously shown screen by id. No-op when unknown. */
|
|
59
|
+
removeScreen(id: string): Promise<void>;
|
|
60
|
+
/** Pop the topmost screen; resolves with its id, or null when empty/untracked. */
|
|
61
|
+
removeTopmostScreen(): Promise<string | null>;
|
|
62
|
+
/** Resolve the topmost tracked screen id, or null. */
|
|
63
|
+
getTopmostScreen(): Promise<string | null>;
|
|
64
|
+
|
|
51
65
|
// --- Sensors (IEvsSensorsService) -------------------------------------------
|
|
52
66
|
enableTouch(enabled: boolean): Promise<void>;
|
|
53
67
|
enableAmbient(enabled: boolean): Promise<void>;
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
EvsDeviceInfo,
|
|
7
7
|
EvsGlassesInfo,
|
|
8
8
|
EvsKitEvents,
|
|
9
|
+
EvsScreenId,
|
|
9
10
|
EvsStockUIScreen,
|
|
10
11
|
} from "./EvsKit.types";
|
|
11
12
|
import EvsKitNative from "./EvsKitModule";
|
|
@@ -120,6 +121,32 @@ export const EvsUI = {
|
|
|
120
121
|
},
|
|
121
122
|
};
|
|
122
123
|
|
|
124
|
+
/**
|
|
125
|
+
* App-owned glasses screens (`Evs.instance().screens()`).
|
|
126
|
+
*
|
|
127
|
+
* The bridge ships no Screen subclasses. Register yours natively per app —
|
|
128
|
+
* `EvsScreenRegistry.register(id, factory)` from app-owned Swift/Kotlin
|
|
129
|
+
* sources (linked at prebuild by the plugin's `screens` option) — then push
|
|
130
|
+
* them from JS:
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* await EvsScreens.show("hello-world");
|
|
134
|
+
*/
|
|
135
|
+
export const EvsScreens = {
|
|
136
|
+
show(id: EvsScreenId) {
|
|
137
|
+
return EvsKitNative.showScreen(id);
|
|
138
|
+
},
|
|
139
|
+
remove(id: EvsScreenId) {
|
|
140
|
+
return EvsKitNative.removeScreen(id);
|
|
141
|
+
},
|
|
142
|
+
removeTopmost() {
|
|
143
|
+
return EvsKitNative.removeTopmostScreen();
|
|
144
|
+
},
|
|
145
|
+
getTopmost() {
|
|
146
|
+
return EvsKitNative.getTopmostScreen();
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
123
150
|
/** Top-level lifecycle, matching `Evs.init(context).start()` / `Evs.instance().start()`. */
|
|
124
151
|
export const EvsKit = {
|
|
125
152
|
start() {
|
|
@@ -134,6 +161,7 @@ export const EvsKit = {
|
|
|
134
161
|
sensors: EvsSensors,
|
|
135
162
|
auth: EvsAuth,
|
|
136
163
|
ui: EvsUI,
|
|
164
|
+
screens: EvsScreens,
|
|
137
165
|
};
|
|
138
166
|
|
|
139
167
|
export default EvsKit;
|