@glassly/engine 0.3.7-dev.940 → 0.3.7-dev.941
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/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/GlassesTouchInput.d.ts.map +1 -1
- package/build/services/GlassesTouchInput.js +4 -2
- package/build/services/GlassesTouchInput.js.map +1 -1
- package/build/services/controllers.d.ts.map +1 -1
- package/build/services/controllers.js +1 -0
- package/build/services/controllers.js.map +1 -1
- package/build/types/enums.d.ts +2 -1
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -0
- package/build/types/enums.js.map +1 -1
- package/package.json +7 -7
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/services/GlassesTouchInput.ts +6 -2
- package/src/services/controllers.ts +1 -0
- package/src/types/enums.ts +1 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export const ENGINE_RELEASE_METADATA = Object.freeze({
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"familyBaseVersion": "0.3.7",
|
|
4
|
-
"releaseIdentity": "0.3.7-dev.
|
|
5
|
-
"releaseSetId": "glassly-0.3.7-dev.
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"releaseIdentity": "0.3.7-dev.941",
|
|
5
|
+
"releaseSetId": "glassly-0.3.7-dev.941",
|
|
6
|
+
"sourceCommit": "09063a406fbf950b99db19cc3be3e56f0a8bc6ed",
|
|
7
7
|
"otaManifestUrl": null,
|
|
8
8
|
"otaManifestSha256": null
|
|
9
9
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.7\",\n \"releaseIdentity\": \"0.3.7-dev.
|
|
1
|
+
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.7\",\n \"releaseIdentity\": \"0.3.7-dev.941\",\n \"releaseSetId\": \"glassly-0.3.7-dev.941\",\n \"sourceCommit\": \"09063a406fbf950b99db19cc3be3e56f0a8bc6ed\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlassesTouchInput.d.ts","sourceRoot":"","sources":["../../src/services/GlassesTouchInput.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,UAAU,EAAC,MAAM,wBAAwB,CAAA;AAkFpE;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAQ1D;
|
|
1
|
+
{"version":3,"file":"GlassesTouchInput.d.ts","sourceRoot":"","sources":["../../src/services/GlassesTouchInput.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,UAAU,EAAC,MAAM,wBAAwB,CAAA;AAkFpE;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAQ1D;AAkED,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,WAAW,EACP,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,SAAS,GACT,eAAe,GACf,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,YAAY,GACZ,SAAS,GACT,WAAW,GACX,SAAS,GACT,WAAW,GACd,IAAI,CAQN"}
|
|
@@ -101,7 +101,7 @@ function routeTouchEvent(event) {
|
|
|
101
101
|
const doubleTap = gesture === "double_tap";
|
|
102
102
|
// The Neural Band's middle finger (index 1) shares the tap names. Either
|
|
103
103
|
// finger leaves the app on screen; the firmware dashboard is the index finger's.
|
|
104
|
-
const osDoubleTap = doubleTap && event.index
|
|
104
|
+
const osDoubleTap = doubleTap && !(event.source === 3 && event.index === 1);
|
|
105
105
|
const osHeadUp = gesture === "head_up";
|
|
106
106
|
if (doubleTap) {
|
|
107
107
|
// The app being left opts out of OS exit by registering double tap (the
|
|
@@ -140,7 +140,9 @@ function routeTouchEvent(event) {
|
|
|
140
140
|
// pagesEligible: connected Glassly CFW glasses, whose firmware leaves the
|
|
141
141
|
// dashboard to the phone; other firmware opens its own on a lift.
|
|
142
142
|
const opensNativeDashboard = osDoubleTap || (osHeadUp && pagesEligible());
|
|
143
|
-
if (opensNativeDashboard &&
|
|
143
|
+
if (opensNativeDashboard &&
|
|
144
|
+
!nativeNavigationService.isActive &&
|
|
145
|
+
isGlassesConnected(useGlassesStore.getState().connection)) {
|
|
144
146
|
useDisplayStore.getState().setDisplayEvent({ layout: { layoutType: "unavailable", reason: "firmware-dashboard" } });
|
|
145
147
|
void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {
|
|
146
148
|
console.error("DeviceEventRouter: showDashboard failed:", err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlassesTouchInput.js","sourceRoot":"","sources":["../../src/services/GlassesTouchInput.ts"],"names":[],"mappings":"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","sourcesContent":["import {useDisplayStore} from \"../stores/display\"\nimport {DeviceModels, type TouchEvent} from \"@glassly/bluetooth-sdk\"\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\nimport {useAppStatusStore} from \"../stores/apps\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {BgTimer} from \"../utils/timers\"\nimport {hasInput2d} from \"./controllers\"\nimport dashboardOpenTrace from \"./debug/DashboardOpenTrace\"\nimport gestureDotsService from \"./GestureDotsService\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport localMiniappRuntime from \"./LocalMiniappRuntime\"\nimport {MiniappExitGesture} from \"./MiniappExitGesture\"\nimport nativeNavigationService from \"./NativeNavigationService\"\nimport {isOverlayApp} from \"./pages/overlayApps\"\nimport {pagesEligible} from \"./pages/pageEligibility\"\n\nconst miniappExitGesture = new MiniappExitGesture({\n getState: () => useAppStatusStore.getState(),\n getTargetPackageName: () => localDisplayManager.getMiniappToLeave(),\n beginExitNotice: (packageName, text) => localDisplayManager.beginMiniappExit(packageName, text),\n finishExitNotice: (packageName) => localDisplayManager.finishMiniappExit(packageName),\n cancelExitNotice: (packageName) => localDisplayManager.cancelMiniappExit(packageName),\n setTimeout: (callback, delay) => BgTimer.setTimeout(callback, delay),\n clearTimeout: (timerId) => BgTimer.clearTimeout(timerId),\n})\n\n// The ring reports a slide once per step of travel, whether the CFW forwards\n// it (deviceModel G2) or the ring sends it to the phone itself (deviceModel\n// R1); both tag source 2. One press is one swipe: the stroke's first step goes\n// out as swipe_up / swipe_down, and every step, the first included, as\n// scroll_up / scroll_down with its distance and speed for smooth scrolling. A\n// stroke ends at the ring's next touch_down or tap_end, or after\n// RING_STROKE_IDLE_MS without a step when a report was lost. Reversing within\n// a stroke fires no swipe (a finger rolling back at lift-off). Native receipt\n// timestamps keep strokes apart when JS drains a backlog.\nconst RING_STROKE_IDLE_MS = 1000\n/** Per ring, when the open stroke's last step arrived. */\nconst ringStrokes = new Map<string, number>()\n\nfunction ringKey(event: TouchEvent): string {\n return event.controllerId ?? `source:${event.source}`\n}\n\nfunction isRingSlideStep(event: TouchEvent): boolean {\n return event.source === 2 && (event.gestureName === \"swipe_up\" || event.gestureName === \"swipe_down\")\n}\n\nfunction opensRingStroke(event: TouchEvent): boolean {\n const last = ringStrokes.get(ringKey(event))\n ringStrokes.set(ringKey(event), event.timestamp)\n const elapsed = last === undefined ? null : event.timestamp - last\n return elapsed === null || elapsed < 0 || elapsed >= RING_STROKE_IDLE_MS\n}\n\nfunction endRingStroke(event: TouchEvent): void {\n if (event.source === 2 && (event.gestureName === \"touch_down\" || event.gestureName === \"tap_end\")) {\n ringStrokes.delete(ringKey(event))\n }\n}\n\n/** The discrete swipe a stroke opens with: the step's travel belongs to scroll_*. */\nfunction strokeSwipe(step: TouchEvent): TouchEvent {\n const swipe = {...step}\n delete swipe.distance\n delete swipe.speed\n return swipe\n}\n\n/**\n * Miniapps' copy of the touch: `input2d: true` when it came from a controller\n * that swipes in two dimensions (the Neural Band), the field absent otherwise,\n * so a 1D swipe from the temples or the ring stays tellable while a band is\n * connected under the same gesture names.\n */\nfunction toMiniapps(event: TouchEvent): TouchEvent & {input2d?: true} {\n const id = event.controllerId\n if (id === undefined) return event\n const model = useGlassesStore.getState().controllers?.[id]?.model\n return model !== undefined && hasInput2d(model) ? {...event, input2d: true} : event\n}\n\n/**\n * Route both real glasses input and phone mirror controls through the same\n * policy. A claimed gesture goes to the app holding the claim, alone; an\n * unclaimed one goes to every subscriber and then the engine's default. The\n * one rule ahead of the claims: an unclaimed double tap leaves the miniapp\n * the wearer is in — the one visibly on the glasses, else the running\n * standard app on an empty screen — whoever else claimed the gesture; the\n * dashboard's claim is for the screen with no app in it. Head position\n * (head_up / head_down) is a gesture like any other: the dashboard claims it\n * while it runs, and an unclaimed head_up on glasses that defer the dashboard\n * to the phone opens the native one, as it would with no app at all. A ring\n * slide step becomes one swipe per stroke plus a scroll step (see above).\n */\nexport function dispatchTouchEvent(event: TouchEvent): void {\n if (isRingSlideStep(event)) {\n if (opensRingStroke(event)) routeTouchEvent(strokeSwipe(event))\n routeTouchEvent({...event, gestureName: event.gestureName === \"swipe_up\" ? \"scroll_up\" : \"scroll_down\"})\n return\n }\n endRingStroke(event)\n routeTouchEvent(event)\n}\n\nfunction routeTouchEvent(event: TouchEvent): void {\n const gesture = event.gestureName\n const claimant = localMiniappRuntime.gestureClaimant(gesture)\n const doubleTap = gesture === \"double_tap\"\n // The Neural Band's middle finger (index 1) shares the tap names. Either\n // finger leaves the app on screen; the firmware dashboard is the index finger's.\n const osDoubleTap = doubleTap && event.index !== 1\n const osHeadUp = gesture === \"head_up\"\n\n if (doubleTap) {\n // The app being left opts out of OS exit by registering double tap (the\n // terminal's back-to-menu). The latest claimant still receives it. Otherwise\n // the tap means \"leave the app\". The controller shows the bounded OS\n // notice first, then uses the normal store stop path (and closes its\n // phone overlay).\n const leaving = localDisplayManager.getMiniappToLeave()\n if (\n leaving !== null &&\n !localMiniappRuntime.hasGestureClaim(leaving, gesture) &&\n miniappExitGesture.tryExitMiniapp()\n ) {\n gestureDotsService.noteGesture(gesture, true, event.index, event.controllerId)\n return\n }\n }\n\n if (claimant !== null) {\n // An overlay app claims the double tap and head-up on an empty screen to open the dashboard.\n if ((gesture === \"double_tap\" || osHeadUp) && isOverlayApp(claimant)) {\n dashboardOpenTrace.trigger(osHeadUp ? \"head-up\" : \"double-tap\", event.timestamp)\n }\n // The press may have started before this app claimed its release edge.\n gestureDotsService.noteGesture(gesture, true, event.index, event.controllerId)\n localMiniappRuntime.forwardEvent(\"touch_event\", toMiniapps(event), undefined, claimant)\n return\n }\n\n // Gesture-dots debug indicator (any device, gated by its setting). It\n // only paints while the screen is otherwise empty.\n gestureDotsService.noteGesture(gesture, false, event.index, event.controllerId)\n\n localMiniappRuntime.forwardEvent(\"touch_event\", toMiniapps(event))\n\n // Nobody claimed a double tap or a head-up: the glasses' native dashboard.\n // On eligible Glassly CFW glasses the dashboard miniapp claims both while it\n // runs (ADR-0006); stock firmware keeps its native dashboard (ADR-0002) and\n // opens it on a head-up by itself, so only the double tap is relayed there.\n // The modal nav UI owns the screen; showDashboard would fight it. Without\n // glasses there is no dashboard to open, and the mirror keeps its frame.\n // pagesEligible: connected Glassly CFW glasses, whose firmware leaves the\n // dashboard to the phone; other firmware opens its own on a lift.\n const opensNativeDashboard = osDoubleTap || (osHeadUp && pagesEligible())\n if (opensNativeDashboard && !nativeNavigationService.isActive && isGlassesConnected(useGlassesStore.getState().connection)) {\n useDisplayStore.getState().setDisplayEvent({layout: {layoutType: \"unavailable\", reason: \"firmware-dashboard\"}})\n void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {\n console.error(\"DeviceEventRouter: showDashboard failed:\", err)\n })\n }\n}\n\nexport function resetTouchInput(): void {\n miniappExitGesture.reset()\n ringStrokes.clear()\n}\n\n/** Phone mirror input uses the same dashboard/miniapp policy as real glasses. */\nexport function sendGesture(\n gestureName:\n | \"single_tap\"\n | \"tap_start\"\n | \"double_tap\"\n | \"tap_end\"\n | \"tap_then_hold\"\n | \"touch_down\"\n | \"swipe_up\"\n | \"swipe_down\"\n | \"swipe_left\"\n | \"swipe_right\"\n | \"long_press\"\n | \"dial_up\"\n | \"dial_down\"\n | \"head_up\"\n | \"head_down\",\n): void {\n const model = useGlassesStore.getState().deviceModel\n dispatchTouchEvent({\n type: \"touch_event\",\n gestureName,\n deviceModel: Object.values(DeviceModels).find((candidate) => candidate === model) ?? DeviceModels.Simulated,\n timestamp: Date.now(),\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"GlassesTouchInput.js","sourceRoot":"","sources":["../../src/services/GlassesTouchInput.ts"],"names":[],"mappings":"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","sourcesContent":["import {useDisplayStore} from \"../stores/display\"\nimport {DeviceModels, type TouchEvent} from \"@glassly/bluetooth-sdk\"\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\nimport {useAppStatusStore} from \"../stores/apps\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {BgTimer} from \"../utils/timers\"\nimport {hasInput2d} from \"./controllers\"\nimport dashboardOpenTrace from \"./debug/DashboardOpenTrace\"\nimport gestureDotsService from \"./GestureDotsService\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport localMiniappRuntime from \"./LocalMiniappRuntime\"\nimport {MiniappExitGesture} from \"./MiniappExitGesture\"\nimport nativeNavigationService from \"./NativeNavigationService\"\nimport {isOverlayApp} from \"./pages/overlayApps\"\nimport {pagesEligible} from \"./pages/pageEligibility\"\n\nconst miniappExitGesture = new MiniappExitGesture({\n getState: () => useAppStatusStore.getState(),\n getTargetPackageName: () => localDisplayManager.getMiniappToLeave(),\n beginExitNotice: (packageName, text) => localDisplayManager.beginMiniappExit(packageName, text),\n finishExitNotice: (packageName) => localDisplayManager.finishMiniappExit(packageName),\n cancelExitNotice: (packageName) => localDisplayManager.cancelMiniappExit(packageName),\n setTimeout: (callback, delay) => BgTimer.setTimeout(callback, delay),\n clearTimeout: (timerId) => BgTimer.clearTimeout(timerId),\n})\n\n// The ring reports a slide once per step of travel, whether the CFW forwards\n// it (deviceModel G2) or the ring sends it to the phone itself (deviceModel\n// R1); both tag source 2. One press is one swipe: the stroke's first step goes\n// out as swipe_up / swipe_down, and every step, the first included, as\n// scroll_up / scroll_down with its distance and speed for smooth scrolling. A\n// stroke ends at the ring's next touch_down or tap_end, or after\n// RING_STROKE_IDLE_MS without a step when a report was lost. Reversing within\n// a stroke fires no swipe (a finger rolling back at lift-off). Native receipt\n// timestamps keep strokes apart when JS drains a backlog.\nconst RING_STROKE_IDLE_MS = 1000\n/** Per ring, when the open stroke's last step arrived. */\nconst ringStrokes = new Map<string, number>()\n\nfunction ringKey(event: TouchEvent): string {\n return event.controllerId ?? `source:${event.source}`\n}\n\nfunction isRingSlideStep(event: TouchEvent): boolean {\n return event.source === 2 && (event.gestureName === \"swipe_up\" || event.gestureName === \"swipe_down\")\n}\n\nfunction opensRingStroke(event: TouchEvent): boolean {\n const last = ringStrokes.get(ringKey(event))\n ringStrokes.set(ringKey(event), event.timestamp)\n const elapsed = last === undefined ? null : event.timestamp - last\n return elapsed === null || elapsed < 0 || elapsed >= RING_STROKE_IDLE_MS\n}\n\nfunction endRingStroke(event: TouchEvent): void {\n if (event.source === 2 && (event.gestureName === \"touch_down\" || event.gestureName === \"tap_end\")) {\n ringStrokes.delete(ringKey(event))\n }\n}\n\n/** The discrete swipe a stroke opens with: the step's travel belongs to scroll_*. */\nfunction strokeSwipe(step: TouchEvent): TouchEvent {\n const swipe = {...step}\n delete swipe.distance\n delete swipe.speed\n return swipe\n}\n\n/**\n * Miniapps' copy of the touch: `input2d: true` when it came from a controller\n * that swipes in two dimensions (the Neural Band), the field absent otherwise,\n * so a 1D swipe from the temples or the ring stays tellable while a band is\n * connected under the same gesture names.\n */\nfunction toMiniapps(event: TouchEvent): TouchEvent & {input2d?: true} {\n const id = event.controllerId\n if (id === undefined) return event\n const model = useGlassesStore.getState().controllers?.[id]?.model\n return model !== undefined && hasInput2d(model) ? {...event, input2d: true} : event\n}\n\n/**\n * Route both real glasses input and phone mirror controls through the same\n * policy. A claimed gesture goes to the app holding the claim, alone; an\n * unclaimed one goes to every subscriber and then the engine's default. The\n * one rule ahead of the claims: an unclaimed double tap leaves the miniapp\n * the wearer is in — the one visibly on the glasses, else the running\n * standard app on an empty screen — whoever else claimed the gesture; the\n * dashboard's claim is for the screen with no app in it. Head position\n * (head_up / head_down) is a gesture like any other: the dashboard claims it\n * while it runs, and an unclaimed head_up on glasses that defer the dashboard\n * to the phone opens the native one, as it would with no app at all. A ring\n * slide step becomes one swipe per stroke plus a scroll step (see above).\n */\nexport function dispatchTouchEvent(event: TouchEvent): void {\n if (isRingSlideStep(event)) {\n if (opensRingStroke(event)) routeTouchEvent(strokeSwipe(event))\n routeTouchEvent({...event, gestureName: event.gestureName === \"swipe_up\" ? \"scroll_up\" : \"scroll_down\"})\n return\n }\n endRingStroke(event)\n routeTouchEvent(event)\n}\n\nfunction routeTouchEvent(event: TouchEvent): void {\n const gesture = event.gestureName\n const claimant = localMiniappRuntime.gestureClaimant(gesture)\n const doubleTap = gesture === \"double_tap\"\n // The Neural Band's middle finger (index 1) shares the tap names. Either\n // finger leaves the app on screen; the firmware dashboard is the index finger's.\n const osDoubleTap = doubleTap && !(event.source === 3 && event.index === 1)\n const osHeadUp = gesture === \"head_up\"\n\n if (doubleTap) {\n // The app being left opts out of OS exit by registering double tap (the\n // terminal's back-to-menu). The latest claimant still receives it. Otherwise\n // the tap means \"leave the app\". The controller shows the bounded OS\n // notice first, then uses the normal store stop path (and closes its\n // phone overlay).\n const leaving = localDisplayManager.getMiniappToLeave()\n if (\n leaving !== null &&\n !localMiniappRuntime.hasGestureClaim(leaving, gesture) &&\n miniappExitGesture.tryExitMiniapp()\n ) {\n gestureDotsService.noteGesture(gesture, true, event.index, event.controllerId)\n return\n }\n }\n\n if (claimant !== null) {\n // An overlay app claims the double tap and head-up on an empty screen to open the dashboard.\n if ((gesture === \"double_tap\" || osHeadUp) && isOverlayApp(claimant)) {\n dashboardOpenTrace.trigger(osHeadUp ? \"head-up\" : \"double-tap\", event.timestamp)\n }\n // The press may have started before this app claimed its release edge.\n gestureDotsService.noteGesture(gesture, true, event.index, event.controllerId)\n localMiniappRuntime.forwardEvent(\"touch_event\", toMiniapps(event), undefined, claimant)\n return\n }\n\n // Gesture-dots debug indicator (any device, gated by its setting). It\n // only paints while the screen is otherwise empty.\n gestureDotsService.noteGesture(gesture, false, event.index, event.controllerId)\n\n localMiniappRuntime.forwardEvent(\"touch_event\", toMiniapps(event))\n\n // Nobody claimed a double tap or a head-up: the glasses' native dashboard.\n // On eligible Glassly CFW glasses the dashboard miniapp claims both while it\n // runs (ADR-0006); stock firmware keeps its native dashboard (ADR-0002) and\n // opens it on a head-up by itself, so only the double tap is relayed there.\n // The modal nav UI owns the screen; showDashboard would fight it. Without\n // glasses there is no dashboard to open, and the mirror keeps its frame.\n // pagesEligible: connected Glassly CFW glasses, whose firmware leaves the\n // dashboard to the phone; other firmware opens its own on a lift.\n const opensNativeDashboard = osDoubleTap || (osHeadUp && pagesEligible())\n if (\n opensNativeDashboard &&\n !nativeNavigationService.isActive &&\n isGlassesConnected(useGlassesStore.getState().connection)\n ) {\n useDisplayStore.getState().setDisplayEvent({layout: {layoutType: \"unavailable\", reason: \"firmware-dashboard\"}})\n void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {\n console.error(\"DeviceEventRouter: showDashboard failed:\", err)\n })\n }\n}\n\nexport function resetTouchInput(): void {\n miniappExitGesture.reset()\n ringStrokes.clear()\n}\n\n/** Phone mirror input uses the same dashboard/miniapp policy as real glasses. */\nexport function sendGesture(\n gestureName:\n | \"single_tap\"\n | \"tap_start\"\n | \"double_tap\"\n | \"tap_end\"\n | \"tap_then_hold\"\n | \"touch_down\"\n | \"swipe_up\"\n | \"swipe_down\"\n | \"swipe_left\"\n | \"swipe_right\"\n | \"long_press\"\n | \"dial_up\"\n | \"dial_down\"\n | \"head_up\"\n | \"head_down\",\n): void {\n const model = useGlassesStore.getState().deviceModel\n dispatchTouchEvent({\n type: \"touch_event\",\n gestureName,\n deviceModel: Object.values(DeviceModels).find((candidate) => candidate === model) ?? DeviceModels.Simulated,\n timestamp: Date.now(),\n })\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controllers.d.ts","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,wBAAwB,CAAA;AAE9E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,UAAU,CAAA;AAGhD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"controllers.d.ts","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,wBAAwB,CAAA;AAE9E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,UAAU,CAAA;AAGhD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAkD7E,iFAAiF;AACjF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAErE;AAED,0CAA0C;AAC1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAED,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAUxE;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAE/E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,GAAG,gBAAgB,EAAE,CAE3G;AAED,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,GAAG,MAAM,CAKlG"}
|
|
@@ -40,6 +40,7 @@ const INPUT_SURFACES = {
|
|
|
40
40
|
[ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],
|
|
41
41
|
[ControllerTypes.WEAR_OS]: [WATCH_SURFACE],
|
|
42
42
|
[ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],
|
|
43
|
+
[ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],
|
|
43
44
|
[ControllerTypes.R1]: [],
|
|
44
45
|
};
|
|
45
46
|
/** The input surfaces a connected controller of `model` adds to the glasses'. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controllers.js","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Controller registry read-model: the paired records (the native-authoritative\n * `controllers` setting) and the live driver statuses (glasses status\n * `controllers`), plus what each model adds to the input surfaces. Pure.\n */\nimport type {ControllerStatus, PairedController} from \"@glassly/bluetooth-sdk\"\n\nimport type {ButtonCapabilities} from \"../types\"\nimport {ControllerTypes} from \"../types/enums\"\n\nexport type InputSurface = NonNullable<ButtonCapabilities[\"buttons\"]>[number]\n\n/** The Neural Band's thumb swipes, pinches and dial. */\nconst NEURAL_BAND_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** A watch trackpad's taps and four-way swipes, and the crown (Apple) or rotary bezel (Wear OS) as the dial. */\nconst WATCH_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** The Gamebrick's D-pad is four absolute swipes; A is the press lifecycle (tap and hold) and B a double tap. */\nconst GAMEBRICK_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\"TAP\", \"DOUBLE_TAP\", \"PRESS_HOLD\", \"SWIPE_UP\", \"SWIPE_DOWN\", \"SWIPE_LEFT\", \"SWIPE_RIGHT\"],\n}\n\n// The R1 swipes up/down like the temples it stands in for, so it adds nothing.\nconst INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {\n [ControllerTypes.NEURAL_BAND]: [NEURAL_BAND_SURFACE],\n [ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],\n [ControllerTypes.WEAR_OS]: [WATCH_SURFACE],\n [ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],\n [ControllerTypes.R1]: [],\n}\n\n/** The input surfaces a connected controller of `model` adds to the glasses'. */\nexport function controllerInputSurfaces(model: string): InputSurface[] {\n return (INPUT_SURFACES[model] ?? []).map((surface) => ({...surface, events: [...surface.events]}))\n}\n\n/** The model swipes in two dimensions. */\nexport function hasInput2d(model: string): boolean {\n return (INPUT_SURFACES[model] ?? []).some((surface) => surface.type === \"swipe2d\")\n}\n\nexport function isControllerModel(model: string | undefined): boolean {\n return model !== undefined && (Object.values(ControllerTypes) as string[]).includes(model)\n}\n\n/** The `controllers` setting as records; malformed entries are dropped. */\nexport function pairedControllersFrom(value: unknown): PairedController[] {\n if (!Array.isArray(value)) return []\n const records: PairedController[] = []\n for (const entry of value) {\n if (!entry || typeof entry !== \"object\") continue\n const {id, model, name} = entry as Record<string, unknown>\n if (typeof id !== \"string\" || !id || typeof model !== \"string\") continue\n records.push({id, model, name: typeof name === \"string\" ? name : id})\n }\n return records\n}\n\n/** Delivering input: link up and the route or claim done. */\nexport function isControllerReady(status: ControllerStatus | undefined): boolean {\n return status?.connected === true && status.fullyBooted === true\n}\n\nexport function readyControllers(statuses: Record<string, ControllerStatus> | undefined): ControllerStatus[] {\n return Object.values(statuses ?? {}).filter(isControllerReady)\n}\n\n/** Change key over the controllers delivering input. */\nexport function readyControllersKey(statuses: Record<string, ControllerStatus> | undefined): string {\n return readyControllers(statuses)\n .map((status) => `${status.id}=${status.model}`)\n .sort()\n .join(\",\")\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controllers.js","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Controller registry read-model: the paired records (the native-authoritative\n * `controllers` setting) and the live driver statuses (glasses status\n * `controllers`), plus what each model adds to the input surfaces. Pure.\n */\nimport type {ControllerStatus, PairedController} from \"@glassly/bluetooth-sdk\"\n\nimport type {ButtonCapabilities} from \"../types\"\nimport {ControllerTypes} from \"../types/enums\"\n\nexport type InputSurface = NonNullable<ButtonCapabilities[\"buttons\"]>[number]\n\n/** The Neural Band's thumb swipes, pinches and dial. */\nconst NEURAL_BAND_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** A watch trackpad's taps and four-way swipes, and the crown (Apple) or rotary bezel (Wear OS) as the dial. */\nconst WATCH_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** The Gamebrick's D-pad is four absolute swipes; A is the press lifecycle (tap and hold) and B a double tap. */\nconst GAMEBRICK_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\"TAP\", \"DOUBLE_TAP\", \"PRESS_HOLD\", \"SWIPE_UP\", \"SWIPE_DOWN\", \"SWIPE_LEFT\", \"SWIPE_RIGHT\"],\n}\n\n// The R1 swipes up/down like the temples it stands in for, so it adds nothing.\nconst INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {\n [ControllerTypes.NEURAL_BAND]: [NEURAL_BAND_SURFACE],\n [ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],\n [ControllerTypes.WEAR_OS]: [WATCH_SURFACE],\n [ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],\n [ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],\n [ControllerTypes.R1]: [],\n}\n\n/** The input surfaces a connected controller of `model` adds to the glasses'. */\nexport function controllerInputSurfaces(model: string): InputSurface[] {\n return (INPUT_SURFACES[model] ?? []).map((surface) => ({...surface, events: [...surface.events]}))\n}\n\n/** The model swipes in two dimensions. */\nexport function hasInput2d(model: string): boolean {\n return (INPUT_SURFACES[model] ?? []).some((surface) => surface.type === \"swipe2d\")\n}\n\nexport function isControllerModel(model: string | undefined): boolean {\n return model !== undefined && (Object.values(ControllerTypes) as string[]).includes(model)\n}\n\n/** The `controllers` setting as records; malformed entries are dropped. */\nexport function pairedControllersFrom(value: unknown): PairedController[] {\n if (!Array.isArray(value)) return []\n const records: PairedController[] = []\n for (const entry of value) {\n if (!entry || typeof entry !== \"object\") continue\n const {id, model, name} = entry as Record<string, unknown>\n if (typeof id !== \"string\" || !id || typeof model !== \"string\") continue\n records.push({id, model, name: typeof name === \"string\" ? name : id})\n }\n return records\n}\n\n/** Delivering input: link up and the route or claim done. */\nexport function isControllerReady(status: ControllerStatus | undefined): boolean {\n return status?.connected === true && status.fullyBooted === true\n}\n\nexport function readyControllers(statuses: Record<string, ControllerStatus> | undefined): ControllerStatus[] {\n return Object.values(statuses ?? {}).filter(isControllerReady)\n}\n\n/** Change key over the controllers delivering input. */\nexport function readyControllersKey(statuses: Record<string, ControllerStatus> | undefined): string {\n return readyControllers(statuses)\n .map((status) => `${status.id}=${status.model}`)\n .sort()\n .join(\",\")\n}\n"]}
|
package/build/types/enums.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare enum ControllerTypes {
|
|
|
18
18
|
NEURAL_BAND = "Meta Neural Band",
|
|
19
19
|
APPLE_WATCH = "Apple Watch",
|
|
20
20
|
WEAR_OS = "Wear OS Watch",
|
|
21
|
-
GAMEBRICK = "IINE Gamebrick"
|
|
21
|
+
GAMEBRICK = "IINE Gamebrick",
|
|
22
|
+
IINE_ANANKE = "IINE Ananke Gen 2"
|
|
22
23
|
}
|
|
23
24
|
//# sourceMappingURL=enums.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,sBAAsB;IAC/B,IAAI,SAAS;IACb,EAAE,sBAAsB;IACxB,EAAE,sBAAsB;IACxB,IAAI,gBAAgB;IACpB,KAAK,iBAAiB;IACtB,IAAI,eAAe;IACnB,GAAG,mBAAmB;IACtB,IAAI,SAAS;IACb,KAAK,oBAAoB;IACzB,SAAS,cAAc;CACxB;AAED,oBAAY,eAAe;IACzB,EAAE,sBAAsB;IACxB,WAAW,qBAAqB;IAChC,WAAW,gBAAgB;IAC3B,OAAO,kBAAkB;IACzB,SAAS,mBAAmB;
|
|
1
|
+
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,sBAAsB;IAC/B,IAAI,SAAS;IACb,EAAE,sBAAsB;IACxB,EAAE,sBAAsB;IACxB,IAAI,gBAAgB;IACpB,KAAK,iBAAiB;IACtB,IAAI,eAAe;IACnB,GAAG,mBAAmB;IACtB,IAAI,SAAS;IACb,KAAK,oBAAoB;IACzB,SAAS,cAAc;CACxB;AAED,oBAAY,eAAe;IACzB,EAAE,sBAAsB;IACxB,WAAW,qBAAqB;IAChC,WAAW,gBAAgB;IAC3B,OAAO,kBAAkB;IACzB,SAAS,mBAAmB;IAC5B,WAAW,sBAAsB;CAClC"}
|
package/build/types/enums.js
CHANGED
|
@@ -21,5 +21,6 @@ export var ControllerTypes;
|
|
|
21
21
|
ControllerTypes["APPLE_WATCH"] = "Apple Watch";
|
|
22
22
|
ControllerTypes["WEAR_OS"] = "Wear OS Watch";
|
|
23
23
|
ControllerTypes["GAMEBRICK"] = "IINE Gamebrick";
|
|
24
|
+
ControllerTypes["IINE_ANANKE"] = "IINE Ananke Gen 2";
|
|
24
25
|
})(ControllerTypes || (ControllerTypes = {}));
|
|
25
26
|
//# sourceMappingURL=enums.js.map
|
package/build/types/enums.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,MAAM,CAAN,IAAY,WAaX;AAbD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,8CAA+B,CAAA;IAC/B,4BAAa,CAAA;IACb,uCAAwB,CAAA;IACxB,uCAAwB,CAAA;IACxB,mCAAoB,CAAA;IACpB,qCAAsB,CAAA;IACtB,kCAAmB,CAAA;IACnB,qCAAsB,CAAA;IACtB,4BAAa,CAAA;IACb,wCAAyB,CAAA;IACzB,sCAAuB,CAAA;AACzB,CAAC,EAbW,WAAW,KAAX,WAAW,QAatB;AAED,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAEhF,MAAM,CAAN,IAAY,WAaX;AAbD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,8CAA+B,CAAA;IAC/B,4BAAa,CAAA;IACb,uCAAwB,CAAA;IACxB,uCAAwB,CAAA;IACxB,mCAAoB,CAAA;IACpB,qCAAsB,CAAA;IACtB,kCAAmB,CAAA;IACnB,qCAAsB,CAAA;IACtB,4BAAa,CAAA;IACb,wCAAyB,CAAA;IACzB,sCAAuB,CAAA;AACzB,CAAC,EAbW,WAAW,KAAX,WAAW,QAatB;AAED,MAAM,CAAN,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,2CAAwB,CAAA;IACxB,mDAAgC,CAAA;IAChC,8CAA2B,CAAA;IAC3B,4CAAyB,CAAA;IACzB,+CAA4B,CAAA;IAC5B,oDAAiC,CAAA;AACnC,CAAC,EAPW,eAAe,KAAf,eAAe,QAO1B","sourcesContent":["export {HardwareType, HardwareRequirementLevel} from \"@glassly/miniapp/hardware\"\n\nexport enum DeviceTypes {\n NONE = \"None\",\n SIMULATED = \"Simulated Glasses\",\n AR99 = \"AR99\",\n G1 = \"Even Realities G1\",\n G2 = \"Even Realities G2\",\n LIVE = \"Mentra Live\",\n MACH1 = \"Mentra Mach1\",\n Z100 = \"Vuzix Z100\",\n NEX = \"Mentra Display\",\n NIMO = \"NIMO\",\n FRAME = \"Brilliant Frame\",\n RAYNEO_IO = \"RayNeo iO\",\n}\n\nexport enum ControllerTypes {\n R1 = \"Even Realities R1\",\n NEURAL_BAND = \"Meta Neural Band\",\n APPLE_WATCH = \"Apple Watch\",\n WEAR_OS = \"Wear OS Watch\",\n GAMEBRICK = \"IINE Gamebrick\",\n IINE_ANANKE = \"IINE Ananke Gen 2\",\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassly/engine",
|
|
3
|
-
"version": "0.3.7-dev.
|
|
3
|
+
"version": "0.3.7-dev.941",
|
|
4
4
|
"description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -97,17 +97,17 @@
|
|
|
97
97
|
"registry": "https://registry.npmjs.org/"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@glassly/bluetooth-sdk": "0.3.7-dev.
|
|
101
|
-
"@glassly/cloud-client": "0.3.7-dev.
|
|
102
|
-
"@glassly/cloud-protocol": "0.3.7-dev.
|
|
103
|
-
"@glassly/crust": "0.3.7-dev.
|
|
104
|
-
"@glassly/miniapp": "0.3.7-dev.
|
|
100
|
+
"@glassly/bluetooth-sdk": "0.3.7-dev.941",
|
|
101
|
+
"@glassly/cloud-client": "0.3.7-dev.941",
|
|
102
|
+
"@glassly/cloud-protocol": "0.3.7-dev.941",
|
|
103
|
+
"@glassly/crust": "0.3.7-dev.941",
|
|
104
|
+
"@glassly/miniapp": "0.3.7-dev.941",
|
|
105
105
|
"buffer": "^6.0.3",
|
|
106
106
|
"events": "^3.3.0",
|
|
107
107
|
"react-native-marked": "8.3.2",
|
|
108
108
|
"semver": "^7.7.4",
|
|
109
109
|
"typesafe-ts": "^1.7.1",
|
|
110
|
-
"@glassly/llm-providers": "0.3.7-dev.
|
|
110
|
+
"@glassly/llm-providers": "0.3.7-dev.941",
|
|
111
111
|
"@huggingface/jinja": "^0.5.9",
|
|
112
112
|
"jsonrepair": "^3.12.0"
|
|
113
113
|
},
|
|
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
|
|
|
12
12
|
export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "0.3.7",
|
|
15
|
-
"releaseIdentity": "0.3.7-dev.
|
|
16
|
-
"releaseSetId": "glassly-0.3.7-dev.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.3.7-dev.941",
|
|
16
|
+
"releaseSetId": "glassly-0.3.7-dev.941",
|
|
17
|
+
"sourceCommit": "09063a406fbf950b99db19cc3be3e56f0a8bc6ed",
|
|
18
18
|
"otaManifestUrl": null,
|
|
19
19
|
"otaManifestSha256": null
|
|
20
20
|
})
|
|
@@ -110,7 +110,7 @@ function routeTouchEvent(event: TouchEvent): void {
|
|
|
110
110
|
const doubleTap = gesture === "double_tap"
|
|
111
111
|
// The Neural Band's middle finger (index 1) shares the tap names. Either
|
|
112
112
|
// finger leaves the app on screen; the firmware dashboard is the index finger's.
|
|
113
|
-
const osDoubleTap = doubleTap && event.index
|
|
113
|
+
const osDoubleTap = doubleTap && !(event.source === 3 && event.index === 1)
|
|
114
114
|
const osHeadUp = gesture === "head_up"
|
|
115
115
|
|
|
116
116
|
if (doubleTap) {
|
|
@@ -156,7 +156,11 @@ function routeTouchEvent(event: TouchEvent): void {
|
|
|
156
156
|
// pagesEligible: connected Glassly CFW glasses, whose firmware leaves the
|
|
157
157
|
// dashboard to the phone; other firmware opens its own on a lift.
|
|
158
158
|
const opensNativeDashboard = osDoubleTap || (osHeadUp && pagesEligible())
|
|
159
|
-
if (
|
|
159
|
+
if (
|
|
160
|
+
opensNativeDashboard &&
|
|
161
|
+
!nativeNavigationService.isActive &&
|
|
162
|
+
isGlassesConnected(useGlassesStore.getState().connection)
|
|
163
|
+
) {
|
|
160
164
|
useDisplayStore.getState().setDisplayEvent({layout: {layoutType: "unavailable", reason: "firmware-dashboard"}})
|
|
161
165
|
void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {
|
|
162
166
|
console.error("DeviceEventRouter: showDashboard failed:", err)
|
|
@@ -54,6 +54,7 @@ const INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {
|
|
|
54
54
|
[ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],
|
|
55
55
|
[ControllerTypes.WEAR_OS]: [WATCH_SURFACE],
|
|
56
56
|
[ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],
|
|
57
|
+
[ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],
|
|
57
58
|
[ControllerTypes.R1]: [],
|
|
58
59
|
}
|
|
59
60
|
|