@glassly/engine 0.3.7 → 0.3.8-dev.1000
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/README.md +4 -0
- package/build/engine.d.ts +10 -2
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +7 -4
- package/build/engine.js.map +1 -1
- package/build/facades/ai.d.ts +3 -0
- package/build/facades/ai.d.ts.map +1 -1
- package/build/facades/ai.js +3 -0
- package/build/facades/ai.js.map +1 -1
- package/build/facades/backup.d.ts +14 -0
- package/build/facades/backup.d.ts.map +1 -0
- package/build/facades/backup.js +22 -0
- package/build/facades/backup.js.map +1 -0
- package/build/facades/glasses.d.ts +4 -4
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +4 -4
- package/build/facades/glasses.js.map +1 -1
- package/build/generated/releaseMetadata.js +4 -4
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/services/AppRegistry.d.ts +2 -1
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +38 -8
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/AppStateBackup.d.ts +98 -0
- package/build/services/AppStateBackup.d.ts.map +1 -0
- package/build/services/AppStateBackup.js +224 -0
- package/build/services/AppStateBackup.js.map +1 -0
- package/build/services/BlobStore.d.ts.map +1 -1
- package/build/services/BlobStore.js +5 -12
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/CloudClientService.d.ts +1 -0
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +34 -2
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DisplayDiagnostics.d.ts.map +1 -1
- package/build/services/DisplayDiagnostics.js +4 -2
- package/build/services/DisplayDiagnostics.js.map +1 -1
- package/build/services/DisplayProcessor.d.ts +2 -0
- package/build/services/DisplayProcessor.d.ts.map +1 -1
- package/build/services/DisplayProcessor.js +15 -1
- package/build/services/DisplayProcessor.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/JSCrashloopReportService.d.ts.map +1 -1
- package/build/services/JSCrashloopReportService.js +5 -0
- package/build/services/JSCrashloopReportService.js.map +1 -1
- package/build/services/JSRouter.d.ts +11 -3
- package/build/services/JSRouter.d.ts.map +1 -1
- package/build/services/JSRouter.js +36 -6
- package/build/services/JSRouter.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +5 -2
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +13 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +61 -22
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js +2 -0
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/LocalTranslationService.d.ts +2 -0
- package/build/services/LocalTranslationService.d.ts.map +1 -1
- package/build/services/LocalTranslationService.js +22 -0
- package/build/services/LocalTranslationService.js.map +1 -1
- package/build/services/MiniappEngine.d.ts +9 -0
- package/build/services/MiniappEngine.d.ts.map +1 -1
- package/build/services/MiniappEngine.js +60 -27
- package/build/services/MiniappEngine.js.map +1 -1
- package/build/services/MiniappLauncher.d.ts +2 -0
- package/build/services/MiniappLauncher.d.ts.map +1 -1
- package/build/services/MiniappLauncher.js +6 -0
- package/build/services/MiniappLauncher.js.map +1 -1
- package/build/services/NavigationService.d.ts +1 -0
- package/build/services/NavigationService.d.ts.map +1 -1
- package/build/services/NavigationService.js +20 -6
- package/build/services/NavigationService.js.map +1 -1
- package/build/services/OfflineActivity.d.ts +54 -0
- package/build/services/OfflineActivity.d.ts.map +1 -0
- package/build/services/OfflineActivity.js +86 -0
- package/build/services/OfflineActivity.js.map +1 -0
- package/build/services/PhoneCalendarService.d.ts.map +1 -1
- package/build/services/PhoneCalendarService.js +8 -0
- package/build/services/PhoneCalendarService.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +7 -3
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/STTModelManager.d.ts +1 -0
- package/build/services/STTModelManager.d.ts.map +1 -1
- package/build/services/STTModelManager.js +6 -0
- package/build/services/STTModelManager.js.map +1 -1
- package/build/services/SceneRenderer.js +1 -1
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/appStateBackupFile.d.ts +32 -0
- package/build/services/appStateBackupFile.d.ts.map +1 -0
- package/build/services/appStateBackupFile.js +135 -0
- package/build/services/appStateBackupFile.js.map +1 -0
- package/build/services/controllers.d.ts.map +1 -1
- package/build/services/controllers.js +12 -3
- package/build/services/controllers.js.map +1 -1
- package/build/services/effectiveCapabilities.js +6 -1
- package/build/services/effectiveCapabilities.js.map +1 -1
- package/build/services/pages/pageEligibility.d.ts.map +1 -1
- package/build/services/pages/pageEligibility.js +8 -1
- package/build/services/pages/pageEligibility.js.map +1 -1
- package/build/services/settingsBridge.d.ts.map +1 -1
- package/build/services/settingsBridge.js +1 -0
- package/build/services/settingsBridge.js.map +1 -1
- package/build/services/{appleWatch/AppleWatchLink.d.ts → watch/WatchLink.d.ts} +8 -7
- package/build/services/watch/WatchLink.d.ts.map +1 -0
- package/build/services/{appleWatch/AppleWatchLink.js → watch/WatchLink.js} +14 -15
- package/build/services/watch/WatchLink.js.map +1 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +22 -10
- package/build/stores/apps.js.map +1 -1
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +63 -6
- package/build/stores/settings.js.map +1 -1
- package/build/types/capabilities/even-realities-g1.d.ts.map +1 -1
- package/build/types/capabilities/even-realities-g1.js +3 -0
- package/build/types/capabilities/even-realities-g1.js.map +1 -1
- package/build/types/capabilities/memomind-one.d.ts +3 -0
- package/build/types/capabilities/memomind-one.d.ts.map +1 -0
- package/build/types/capabilities/memomind-one.js +42 -0
- package/build/types/capabilities/memomind-one.js.map +1 -0
- package/build/types/capabilities/rayneo-io.d.ts.map +1 -1
- package/build/types/capabilities/rayneo-io.js +3 -2
- package/build/types/capabilities/rayneo-io.js.map +1 -1
- package/build/types/enums.d.ts +7 -2
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +5 -0
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +3 -1
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +3 -1
- package/build/types/hardware.js.map +1 -1
- package/build/utils/display/index.d.ts +2 -1
- package/build/utils/display/index.d.ts.map +1 -1
- package/build/utils/display/index.js +3 -2
- package/build/utils/display/index.js.map +1 -1
- package/build/utils/display/profiles/index.d.ts +2 -1
- package/build/utils/display/profiles/index.d.ts.map +1 -1
- package/build/utils/display/profiles/index.js +3 -2
- package/build/utils/display/profiles/index.js.map +1 -1
- package/build/utils/display/profiles/rayneo-io.d.ts +1 -1
- package/build/utils/display/profiles/rayneo-io.d.ts.map +1 -1
- package/build/utils/display/profiles/rayneo-io.js +1 -1
- package/build/utils/display/profiles/rayneo-io.js.map +1 -1
- package/build/utils/display/scene/index.d.ts +1 -1
- package/build/utils/display/scene/index.d.ts.map +1 -1
- package/build/utils/display/scene/index.js +1 -1
- package/build/utils/display/scene/index.js.map +1 -1
- package/build/utils/display/scene/process.d.ts +6 -0
- package/build/utils/display/scene/process.d.ts.map +1 -1
- package/build/utils/display/scene/process.js +22 -7
- package/build/utils/display/scene/process.js.map +1 -1
- package/build/utils/miniappGlobals.d.ts +13 -17
- package/build/utils/miniappGlobals.d.ts.map +1 -1
- package/build/utils/miniappGlobals.js +24 -56
- package/build/utils/miniappGlobals.js.map +1 -1
- package/package.json +7 -7
- package/src/engine.ts +7 -4
- package/src/facades/ai.ts +4 -0
- package/src/facades/backup.ts +28 -0
- package/src/facades/glasses.ts +5 -5
- package/src/generated/releaseMetadata.ts +4 -4
- package/src/index.ts +9 -0
- package/src/services/AppRegistry.ts +36 -9
- package/src/services/AppStateBackup.ts +283 -0
- package/src/services/BlobStore.ts +5 -11
- package/src/services/CloudClientService.ts +35 -4
- package/src/services/DisplayDiagnostics.ts +4 -2
- package/src/services/DisplayProcessor.ts +20 -8
- package/src/services/GlassesTouchInput.ts +6 -2
- package/src/services/JSCrashloopReportService.ts +5 -0
- package/src/services/JSRouter.ts +37 -6
- package/src/services/LocalDisplayManager.ts +5 -2
- package/src/services/LocalMiniappRuntime.ts +61 -22
- package/src/services/LocalSttFallbackCoordinator.ts +4 -0
- package/src/services/LocalTranslationService.ts +20 -0
- package/src/services/MiniappEngine.ts +62 -27
- package/src/services/MiniappLauncher.ts +7 -0
- package/src/services/NavigationService.ts +28 -8
- package/src/services/OfflineActivity.ts +131 -0
- package/src/services/PhoneCalendarService.ts +7 -0
- package/src/services/PhoneNotificationsSync.ts +8 -3
- package/src/services/STTModelManager.ts +6 -0
- package/src/services/SceneRenderer.ts +1 -1
- package/src/services/appStateBackupFile.ts +171 -0
- package/src/services/controllers.ts +13 -3
- package/src/services/effectiveCapabilities.ts +6 -1
- package/src/services/pages/pageEligibility.ts +9 -1
- package/src/services/settingsBridge.ts +1 -0
- package/src/services/{appleWatch/AppleWatchLink.ts → watch/WatchLink.ts} +20 -20
- package/src/stores/apps.ts +22 -11
- package/src/stores/settings.ts +70 -10
- package/src/types/capabilities/even-realities-g1.ts +4 -0
- package/src/types/capabilities/memomind-one.ts +43 -0
- package/src/types/capabilities/rayneo-io.ts +3 -2
- package/src/types/enums.ts +5 -0
- package/src/types/hardware.ts +14 -1
- package/src/utils/display/index.ts +4 -2
- package/src/utils/display/profiles/index.ts +9 -2
- package/src/utils/display/profiles/rayneo-io.ts +6 -1
- package/src/utils/display/scene/index.ts +1 -1
- package/src/utils/display/scene/process.ts +22 -7
- package/src/utils/miniappGlobals.ts +32 -64
- package/build/services/appleWatch/AppleWatchLink.d.ts.map +0 -1
- package/build/services/appleWatch/AppleWatchLink.js.map +0 -1
package/src/stores/settings.ts
CHANGED
|
@@ -132,6 +132,13 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
132
132
|
saveOnServer: true,
|
|
133
133
|
persist: true,
|
|
134
134
|
},
|
|
135
|
+
memomind_accessory_picker: {
|
|
136
|
+
key: "memomind_accessory_picker",
|
|
137
|
+
defaultValue: () => false,
|
|
138
|
+
writable: true,
|
|
139
|
+
saveOnServer: false,
|
|
140
|
+
persist: true,
|
|
141
|
+
},
|
|
135
142
|
debug_console: {
|
|
136
143
|
key: "debug_console",
|
|
137
144
|
defaultValue: () => false,
|
|
@@ -803,8 +810,8 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
803
810
|
// OFF by default: they crowd out everything else in the ten-minute buffer.
|
|
804
811
|
// Synced to the Bluetooth SDK, which keeps counting either way and only
|
|
805
812
|
// logs while this is on. Device-local debug knob, so not saved on the server.
|
|
806
|
-
|
|
807
|
-
key: "
|
|
813
|
+
perf_logs: {
|
|
814
|
+
key: "perf_logs",
|
|
808
815
|
defaultValue: () => false,
|
|
809
816
|
writable: true,
|
|
810
817
|
saveOnServer: false,
|
|
@@ -841,12 +848,21 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
841
848
|
saveOnServer: false,
|
|
842
849
|
persist: true,
|
|
843
850
|
},
|
|
844
|
-
// Apple Watch: draw the glasses' current frame behind the watch
|
|
845
|
-
// cross
|
|
851
|
+
// Watch (Apple Watch, Wear OS): draw the glasses' current frame behind the watch
|
|
852
|
+
// trackpad. Frames cross the watch link while the watch app is up, so it stays off
|
|
853
|
+
// unless asked for.
|
|
854
|
+
watch_mirror: {
|
|
855
|
+
key: "watch_mirror",
|
|
856
|
+
defaultValue: () => false,
|
|
857
|
+
writable: true,
|
|
858
|
+
saveOnServer: false,
|
|
859
|
+
persist: true,
|
|
860
|
+
},
|
|
861
|
+
// Deprecated: the setting above under its Apple-only name; read once to migrate.
|
|
846
862
|
apple_watch_mirror: {
|
|
847
863
|
key: "apple_watch_mirror",
|
|
848
864
|
defaultValue: () => false,
|
|
849
|
-
writable:
|
|
865
|
+
writable: false,
|
|
850
866
|
saveOnServer: false,
|
|
851
867
|
persist: true,
|
|
852
868
|
},
|
|
@@ -904,6 +920,23 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
904
920
|
saveOnServer: false,
|
|
905
921
|
persist: true,
|
|
906
922
|
},
|
|
923
|
+
// Debug: keep each miniapp's switcher-card screenshot on disk so the card
|
|
924
|
+
// comes back after an app restart. Off keeps captures in memory only, for
|
|
925
|
+
// checking the capture path itself. Device-local, default on.
|
|
926
|
+
persist_miniapp_screenshots: {
|
|
927
|
+
key: "persist_miniapp_screenshots",
|
|
928
|
+
defaultValue: () => true,
|
|
929
|
+
writable: true,
|
|
930
|
+
saveOnServer: false,
|
|
931
|
+
persist: true,
|
|
932
|
+
},
|
|
933
|
+
home_offline_card: {
|
|
934
|
+
key: "home_offline_card",
|
|
935
|
+
defaultValue: () => true,
|
|
936
|
+
writable: true,
|
|
937
|
+
saveOnServer: false,
|
|
938
|
+
persist: true,
|
|
939
|
+
},
|
|
907
940
|
// Gesture-dots debug indicator: flash a glyph on the glasses when a touch
|
|
908
941
|
// gesture is received while the display is empty. Works on any
|
|
909
942
|
// scene-capable device, not only CFW. Device-local debug knob, default off.
|
|
@@ -1128,6 +1161,13 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
1128
1161
|
saveOnServer: true,
|
|
1129
1162
|
persist: true,
|
|
1130
1163
|
},
|
|
1164
|
+
notifications_batch_seconds: {
|
|
1165
|
+
key: "notifications_batch_seconds",
|
|
1166
|
+
defaultValue: () => 0,
|
|
1167
|
+
writable: true,
|
|
1168
|
+
saveOnServer: true,
|
|
1169
|
+
persist: true,
|
|
1170
|
+
},
|
|
1131
1171
|
// Hold popups while another glasses feature (navigation, a miniapp) is on screen.
|
|
1132
1172
|
notifications_hold_during_apps: {
|
|
1133
1173
|
key: "notifications_hold_during_apps",
|
|
@@ -1205,7 +1245,8 @@ export const BLUETOOTH_SETTING_KEYS: string[] = [
|
|
|
1205
1245
|
SETTINGS.calendar_events.key,
|
|
1206
1246
|
SETTINGS.cfw_scene_renderer.key,
|
|
1207
1247
|
SETTINGS.cfw_fast_ble.key,
|
|
1208
|
-
SETTINGS.
|
|
1248
|
+
SETTINGS.perf_logs.key,
|
|
1249
|
+
SETTINGS.memomind_accessory_picker.key,
|
|
1209
1250
|
SETTINGS.ring_via_glasses.key,
|
|
1210
1251
|
SETTINGS.display_max_fps.key,
|
|
1211
1252
|
SETTINGS.twelve_hour_time.key,
|
|
@@ -1276,10 +1317,13 @@ export interface SettingsState {
|
|
|
1276
1317
|
}
|
|
1277
1318
|
|
|
1278
1319
|
const getDefaultSettings = () =>
|
|
1279
|
-
Object.keys(SETTINGS).reduce(
|
|
1280
|
-
acc
|
|
1281
|
-
|
|
1282
|
-
|
|
1320
|
+
Object.keys(SETTINGS).reduce(
|
|
1321
|
+
(acc, key) => {
|
|
1322
|
+
acc[key] = SETTINGS[key].defaultValue()
|
|
1323
|
+
return acc
|
|
1324
|
+
},
|
|
1325
|
+
{} as Record<string, any>,
|
|
1326
|
+
)
|
|
1283
1327
|
|
|
1284
1328
|
// Single-flight for loadAllSettings: the host fires it at module load and
|
|
1285
1329
|
// engine.start()'s device-store hydration awaits it — without the memo the
|
|
@@ -1619,6 +1663,22 @@ export const useSettingsStore = create<SettingsState>()(
|
|
|
1619
1663
|
}
|
|
1620
1664
|
if (menuMigrated) storage.save(MENU_SETTINGS_MIGRATION_KEY, true)
|
|
1621
1665
|
}
|
|
1666
|
+
|
|
1667
|
+
// The watch mirror switch lost its Apple-only name when Wear OS joined: carry a
|
|
1668
|
+
// turned-on `apple_watch_mirror` over to `watch_mirror` once.
|
|
1669
|
+
const WATCH_MIRROR_MIGRATION_KEY = "migration:watch_mirror_v1"
|
|
1670
|
+
const watchMirrorMigrationDone = storage.load<boolean>(WATCH_MIRROR_MIGRATION_KEY)
|
|
1671
|
+
if (watchMirrorMigrationDone.is_error() || !watchMirrorMigrationDone.value) {
|
|
1672
|
+
let watchMirrorMigrated = true
|
|
1673
|
+
if (get().getSetting(SETTINGS.apple_watch_mirror.key) === true) {
|
|
1674
|
+
const result = await get().setSetting(SETTINGS.watch_mirror.key, true, false)
|
|
1675
|
+
if (result.is_error()) {
|
|
1676
|
+
console.log("SETTINGS: watch_mirror migration failed:", result.error)
|
|
1677
|
+
watchMirrorMigrated = false
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
if (watchMirrorMigrated) storage.save(WATCH_MIRROR_MIGRATION_KEY, true)
|
|
1681
|
+
}
|
|
1622
1682
|
})
|
|
1623
1683
|
loadAllSettingsInFlight = inFlight
|
|
1624
1684
|
void Promise.resolve(inFlight).then((result) => {
|
|
@@ -68,4 +68,8 @@ export const evenRealitiesG1: Capabilities = {
|
|
|
68
68
|
|
|
69
69
|
// OTA capabilities - G1 firmware updates are not driven by the ASG OTA flow
|
|
70
70
|
hasOta: false,
|
|
71
|
+
|
|
72
|
+
// The app flashes the bundled Glassly CFW over MCUmgr SMP (see
|
|
73
|
+
// bluetooth-sdk/ios/Source/Resources/G1Firmware/README.md).
|
|
74
|
+
hasCustomFirmware: true,
|
|
71
75
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type {Capabilities} from "../hardware"
|
|
2
|
+
|
|
3
|
+
export const memoMindOne: Capabilities = {
|
|
4
|
+
modelName: "MemoMind One",
|
|
5
|
+
hasCamera: false,
|
|
6
|
+
camera: null,
|
|
7
|
+
hasDisplay: true,
|
|
8
|
+
display: {
|
|
9
|
+
// One panel: the vector canvas offers no depth on it.
|
|
10
|
+
count: 1,
|
|
11
|
+
isColor: false,
|
|
12
|
+
canDisplayBitmap: true,
|
|
13
|
+
resolution: {width: 600, height: 350},
|
|
14
|
+
width: 600,
|
|
15
|
+
height: 350,
|
|
16
|
+
canPosition: true,
|
|
17
|
+
intensityLevels: 16,
|
|
18
|
+
partialUpdate: true,
|
|
19
|
+
adjustBrightness: true,
|
|
20
|
+
positionRange: {height: {min: 0, max: 8}, depth: {min: 0, max: 8}},
|
|
21
|
+
},
|
|
22
|
+
hasMicrophone: true,
|
|
23
|
+
microphone: {count: 1, hasVAD: false},
|
|
24
|
+
hasSpeaker: false,
|
|
25
|
+
speaker: null,
|
|
26
|
+
hasIMU: false,
|
|
27
|
+
imu: null,
|
|
28
|
+
hasButton: true,
|
|
29
|
+
button: {
|
|
30
|
+
count: 1,
|
|
31
|
+
buttons: [{type: "press", events: ["TAP", "DOUBLE_TAP", "PRESS_HOLD", "RELEASE"], isCapacitive: false}],
|
|
32
|
+
},
|
|
33
|
+
hasLight: false,
|
|
34
|
+
light: null,
|
|
35
|
+
power: {hasExternalBattery: false},
|
|
36
|
+
hasWifi: false,
|
|
37
|
+
hasOta: false,
|
|
38
|
+
hasCustomFirmware: true,
|
|
39
|
+
hasNativeDashboard: false,
|
|
40
|
+
hasNativeNavigation: false,
|
|
41
|
+
hasNativeNotifications: false,
|
|
42
|
+
hasNotificationRelay: true,
|
|
43
|
+
}
|
|
@@ -19,10 +19,11 @@ export const rayneoIO: Capabilities = {
|
|
|
19
19
|
hasCamera: false,
|
|
20
20
|
camera: null,
|
|
21
21
|
|
|
22
|
-
// Display capabilities -
|
|
22
|
+
// Display capabilities - a monochrome panel per eye; the Glassly CFW keeps
|
|
23
|
+
// a scene per lens, so element depth is a real disparity here
|
|
23
24
|
hasDisplay: true,
|
|
24
25
|
display: {
|
|
25
|
-
count:
|
|
26
|
+
count: 2,
|
|
26
27
|
isColor: false,
|
|
27
28
|
color: "green",
|
|
28
29
|
// Bitmaps and positioned elements need the Glassly CFW; stock firmware
|
package/src/types/enums.ts
CHANGED
|
@@ -13,10 +13,15 @@ export enum DeviceTypes {
|
|
|
13
13
|
NIMO = "NIMO",
|
|
14
14
|
FRAME = "Brilliant Frame",
|
|
15
15
|
RAYNEO_IO = "RayNeo iO",
|
|
16
|
+
MEMOMIND_ONE = "MemoMind One",
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export enum ControllerTypes {
|
|
19
20
|
R1 = "Even Realities R1",
|
|
20
21
|
NEURAL_BAND = "Meta Neural Band",
|
|
21
22
|
APPLE_WATCH = "Apple Watch",
|
|
23
|
+
WEAR_OS = "Wear OS Watch",
|
|
24
|
+
GAMEBRICK = "IINE Gamebrick",
|
|
25
|
+
IINE_ANANKE = "IINE Ananke Gen 2",
|
|
26
|
+
ZERO2 = "8BitDo Zero 2",
|
|
22
27
|
}
|
package/src/types/hardware.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {mentraLive} from "./capabilities/mentra-live"
|
|
|
9
9
|
import {simulatedGlasses} from "./capabilities/simulated-glasses"
|
|
10
10
|
import {nimo} from "./capabilities/nimo"
|
|
11
11
|
import {rayneoIO} from "./capabilities/rayneo-io"
|
|
12
|
+
import {memoMindOne} from "./capabilities/memomind-one"
|
|
12
13
|
import {vuzixZ100} from "./capabilities/vuzix-z100"
|
|
13
14
|
import {none} from "./capabilities/none"
|
|
14
15
|
import {DeviceTypes} from "./enums"
|
|
@@ -217,6 +218,7 @@ export interface Capabilities {
|
|
|
217
218
|
// (reading the phone's stream, or an upload from the phone) is the driver's
|
|
218
219
|
// business; the engine only decides who presents.
|
|
219
220
|
hasNativeNotifications?: boolean
|
|
221
|
+
hasNotificationRelay?: boolean
|
|
220
222
|
// Popup durations the firmware accepts, in seconds (0 = firmware default).
|
|
221
223
|
// Drivers snap other values; the settings UI offers exactly these.
|
|
222
224
|
nativeNotificationPopupSeconds?: number[]
|
|
@@ -236,6 +238,7 @@ export const HARDWARE_CAPABILITIES: Record<string, Capabilities> = {
|
|
|
236
238
|
[vuzixZ100.modelName]: vuzixZ100,
|
|
237
239
|
[nimo.modelName]: nimo,
|
|
238
240
|
[rayneoIO.modelName]: rayneoIO,
|
|
241
|
+
[memoMindOne.modelName]: memoMindOne,
|
|
239
242
|
[DeviceTypes.MACH1]: vuzixZ100, // Mach1 uses same Vuzix Ultralite hardware as Z100
|
|
240
243
|
[DeviceTypes.AR99]: {
|
|
241
244
|
...evenRealitiesG1,
|
|
@@ -265,4 +268,14 @@ export const getModelCapabilities = (deviceType: DeviceTypes): Capabilities => {
|
|
|
265
268
|
}
|
|
266
269
|
|
|
267
270
|
// export * from "./capabilities"
|
|
268
|
-
export {
|
|
271
|
+
export {
|
|
272
|
+
simulatedGlasses,
|
|
273
|
+
evenRealitiesG1,
|
|
274
|
+
evenRealitiesG2,
|
|
275
|
+
mentraLive,
|
|
276
|
+
vuzixZ100,
|
|
277
|
+
mentraDisplay,
|
|
278
|
+
nimo,
|
|
279
|
+
rayneoIO,
|
|
280
|
+
memoMindOne,
|
|
281
|
+
}
|
|
@@ -70,8 +70,8 @@ export {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from "./profile
|
|
|
70
70
|
// Mentra Nex Profile (a.k.a. Mentra Display)
|
|
71
71
|
export {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from "./profiles"
|
|
72
72
|
|
|
73
|
-
// RayNeo iO
|
|
74
|
-
export {RAYNEO_IO_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX} from "./profiles"
|
|
73
|
+
// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)
|
|
74
|
+
export {RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX} from "./profiles"
|
|
75
75
|
|
|
76
76
|
// =============================================================================
|
|
77
77
|
// Measurer - Pixel-accurate text measurement
|
|
@@ -274,3 +274,5 @@ export function createNexToolkit(): {
|
|
|
274
274
|
breakMode: "character-no-hyphen",
|
|
275
275
|
})
|
|
276
276
|
}
|
|
277
|
+
|
|
278
|
+
export {MEMOMIND_ONE_PROFILE} from "./profiles"
|
|
@@ -27,5 +27,12 @@ export {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from "./g2"
|
|
|
27
27
|
// Mentra Nex Profile (a.k.a. Mentra Display)
|
|
28
28
|
export {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from "./nex"
|
|
29
29
|
|
|
30
|
-
// RayNeo iO
|
|
31
|
-
export {
|
|
30
|
+
// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)
|
|
31
|
+
export {
|
|
32
|
+
RAYNEO_IO_PROFILE,
|
|
33
|
+
RAYNEO_IO_CFW_PROFILE,
|
|
34
|
+
RAYNEO_IO_HYPHEN_WIDTH_PX,
|
|
35
|
+
RAYNEO_IO_SPACE_WIDTH_PX,
|
|
36
|
+
} from "./rayneo-io"
|
|
37
|
+
|
|
38
|
+
export {MEMOMIND_ONE_PROFILE} from "@glassly/miniapp/display"
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
// Moved into the SDK (@glassly/miniapp/display) so miniapps lay text out the way the host measures it; this path re-exports it for the engine.
|
|
2
|
-
export {
|
|
2
|
+
export {
|
|
3
|
+
RAYNEO_IO_PROFILE,
|
|
4
|
+
RAYNEO_IO_CFW_PROFILE,
|
|
5
|
+
RAYNEO_IO_HYPHEN_WIDTH_PX,
|
|
6
|
+
RAYNEO_IO_SPACE_WIDTH_PX,
|
|
7
|
+
} from "@glassly/miniapp/display"
|
|
@@ -24,7 +24,7 @@ export {resolveAnchors} from "./anchor"
|
|
|
24
24
|
export type {DiffResult, DiffableElement} from "./differ"
|
|
25
25
|
export {diffScene} from "./differ"
|
|
26
26
|
export type {ProcessedScene} from "./process"
|
|
27
|
-
export {processScene, profileLineHeightPx} from "./process"
|
|
27
|
+
export {processScene, profileLineHeightPx, wrapsOnDevice} from "./process"
|
|
28
28
|
export type {DegradedScene} from "./degrade"
|
|
29
29
|
export {degradeScene} from "./degrade"
|
|
30
30
|
export {SceneStore} from "./store"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import {compileSvgPath} from "./svgPath"
|
|
12
|
+
import {isUnsupportedScript} from "../measurer/script-detection"
|
|
12
13
|
import {TextMeasurer} from "../measurer/TextMeasurer"
|
|
13
14
|
import {TextWrapper} from "../wrapper/TextWrapper"
|
|
14
15
|
import type {DisplayProfile} from "../profiles/types"
|
|
@@ -47,6 +48,18 @@ function clampBox(box: SceneBox, width: number, height: number): SceneBox | null
|
|
|
47
48
|
|
|
48
49
|
const isFinite = (n: unknown): n is number => typeof n === "number" && Number.isFinite(n)
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Text the host cannot wrap: a script the measurer has no widths or break
|
|
53
|
+
* rules for (Thai has no spaces between words, for one). It is passed through
|
|
54
|
+
* unwrapped and the device's text engine lays it out in the box.
|
|
55
|
+
*/
|
|
56
|
+
export function wrapsOnDevice(text: string): boolean {
|
|
57
|
+
for (const char of text) {
|
|
58
|
+
if (isUnsupportedScript(char)) return true
|
|
59
|
+
}
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
50
63
|
/** Integer points, or null when the count/values are invalid for the type. */
|
|
51
64
|
function validPoints(el: SceneElementInput): ScenePoint[] | null {
|
|
52
65
|
const raw = (el as {points?: unknown}).points
|
|
@@ -372,10 +385,11 @@ export function processScene(
|
|
|
372
385
|
// Height clipping only applies with a CALIBRATED line height — otherwise
|
|
373
386
|
// the firmware clips vertically in-box (legacy behavior).
|
|
374
387
|
const style: SceneTextStyle = el.style ?? {}
|
|
375
|
-
if (style.font === "mono" || style.font === "builtin") {
|
|
376
|
-
// Grid text is laid out by the app (cols × rows)
|
|
377
|
-
// glasses' own font engine
|
|
378
|
-
//
|
|
388
|
+
if (style.font === "mono" || style.font === "builtin" || wrapsOnDevice(el.text ?? "")) {
|
|
389
|
+
// Grid text is laid out by the app (cols × rows), builtin text by the
|
|
390
|
+
// glasses' own font engine and unsupported scripts by the device's text
|
|
391
|
+
// engine; the host's proportional wrap metrics don't apply to any of
|
|
392
|
+
// them. Pass lines through and let the device wrap and clip.
|
|
379
393
|
const monoText = el.text ?? ""
|
|
380
394
|
out.push({
|
|
381
395
|
id: el.id,
|
|
@@ -390,8 +404,9 @@ export function processScene(
|
|
|
390
404
|
continue
|
|
391
405
|
}
|
|
392
406
|
const maxLines = lineHeight ? Math.max(1, Math.floor(clamped.h / lineHeight)) : profile.maxLines
|
|
407
|
+
const maxWidthPx = Math.max(1, clamped.w - 2 * (profile.textInsetPx ?? 0))
|
|
393
408
|
const result = wrapper.wrap(el.text ?? "", {
|
|
394
|
-
maxWidthPx
|
|
409
|
+
maxWidthPx,
|
|
395
410
|
maxLines,
|
|
396
411
|
...(style.breakMode ? {breakMode: style.breakMode} : {}),
|
|
397
412
|
})
|
|
@@ -402,12 +417,12 @@ export function processScene(
|
|
|
402
417
|
// Trim the last line until it fits WITH the ellipsis appended —
|
|
403
418
|
// otherwise the extra glyph can overflow the clamped box width.
|
|
404
419
|
let last = lines[lines.length - 1]
|
|
405
|
-
while (last.length > 0 && !measurer.fitsInWidth(`${last}…`,
|
|
420
|
+
while (last.length > 0 && !measurer.fitsInWidth(`${last}…`, maxWidthPx)) {
|
|
406
421
|
last = last.slice(0, -1)
|
|
407
422
|
}
|
|
408
423
|
// A box narrower than the ellipsis glyph itself gets an empty line —
|
|
409
424
|
// never emit a line wider than the clamped box.
|
|
410
|
-
const ellipsized = last.length > 0 || measurer.fitsInWidth("…",
|
|
425
|
+
const ellipsized = last.length > 0 || measurer.fitsInWidth("…", maxWidthPx) ? `${last}…` : ""
|
|
411
426
|
lines = [...lines.slice(0, -1), ellipsized]
|
|
412
427
|
}
|
|
413
428
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* same API surface.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {Platform} from "react-native"
|
|
11
11
|
|
|
12
12
|
export interface MiniappSafeArea {
|
|
13
13
|
top: number
|
|
@@ -16,6 +16,11 @@ export interface MiniappSafeArea {
|
|
|
16
16
|
right: number
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The host's capsule menu in the WebView's own coordinate space. `corner`
|
|
21
|
+
* floats over the page's top-right; `rail` sits in the iPhone Duo's status
|
|
22
|
+
* rail, inside the side safe-area inset and clear of the page content.
|
|
23
|
+
*/
|
|
19
24
|
export interface CapsuleMenuRect {
|
|
20
25
|
top: number
|
|
21
26
|
right: number
|
|
@@ -23,36 +28,7 @@ export interface CapsuleMenuRect {
|
|
|
23
28
|
left: number
|
|
24
29
|
width: number
|
|
25
30
|
height: number
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The capsule menu bounding rect in the WebView's own coordinate space.
|
|
30
|
-
*
|
|
31
|
-
* Keep in sync with CapsuleMenu.tsx:
|
|
32
|
-
* - CapsuleButton height ≈ h-7.5 (30px), width ≈ 73px
|
|
33
|
-
* - Positioned at right-2 (8px), top = theme.spacing.s2 (8px) below insets.top
|
|
34
|
-
*/
|
|
35
|
-
const CAPSULE_MENU_HEIGHT = 30
|
|
36
|
-
const CAPSULE_MENU_WIDTH = 73
|
|
37
|
-
const CAPSULE_MENU_PADDING = 8
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @param topInsetOffset extra top offset to add when the WebView container does
|
|
41
|
-
* NOT already pad by the safe-area inset (i.e. WebView fills edge-to-edge under
|
|
42
|
-
* the status bar). Pass `insets.top` in that case, or 0 when the container
|
|
43
|
-
* already applies top padding.
|
|
44
|
-
*/
|
|
45
|
-
export function getCapsuleMenuRect(topInsetOffset = 0): CapsuleMenuRect {
|
|
46
|
-
const screenWidth = Dimensions.get("window").width
|
|
47
|
-
const top = topInsetOffset + CAPSULE_MENU_PADDING
|
|
48
|
-
return {
|
|
49
|
-
top,
|
|
50
|
-
right: CAPSULE_MENU_PADDING,
|
|
51
|
-
bottom: top + CAPSULE_MENU_HEIGHT,
|
|
52
|
-
left: screenWidth - CAPSULE_MENU_PADDING - CAPSULE_MENU_WIDTH,
|
|
53
|
-
width: CAPSULE_MENU_WIDTH,
|
|
54
|
-
height: CAPSULE_MENU_HEIGHT,
|
|
55
|
-
}
|
|
31
|
+
placement: "corner" | "rail"
|
|
56
32
|
}
|
|
57
33
|
|
|
58
34
|
export type MiniappColorScheme = "light" | "dark"
|
|
@@ -63,37 +39,48 @@ export interface BuildMiniappGlobalsOptions {
|
|
|
63
39
|
miniappLocal?: boolean
|
|
64
40
|
miniappDeveloperMode?: boolean
|
|
65
41
|
safeAreaInsets: MiniappSafeArea
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
* the status bar). In that case the capsule menu rect needs to shift down by
|
|
69
|
-
* the top inset so its coords match where it's actually drawn on screen.
|
|
70
|
-
*/
|
|
71
|
-
webviewFillsStatusBar?: boolean
|
|
42
|
+
/** Where the host draws its capsule menu over this WebView. */
|
|
43
|
+
capsuleMenu: CapsuleMenuRect
|
|
72
44
|
/** Current host color scheme. Miniapps may follow this to match the phone. */
|
|
73
45
|
colorScheme?: MiniappColorScheme
|
|
74
46
|
}
|
|
75
47
|
|
|
76
|
-
|
|
48
|
+
// CSS custom properties that mirror the safe-area and capsule menu data, so
|
|
49
|
+
// miniapp CSS (or Tailwind arbitrary values) can read them without touching
|
|
50
|
+
// JS: e.g. `style="margin-top: var(--glassly-capsule-top)"`.
|
|
51
|
+
function layoutCssVars(insets: MiniappSafeArea, capsule: CapsuleMenuRect): Record<string, string> {
|
|
77
52
|
return {
|
|
78
53
|
"--glassly-safe-top": `${insets.top}px`,
|
|
79
54
|
"--glassly-safe-bottom": `${insets.bottom}px`,
|
|
80
55
|
"--glassly-safe-left": `${insets.left}px`,
|
|
81
56
|
"--glassly-safe-right": `${insets.right}px`,
|
|
57
|
+
"--glassly-capsule-top": `${capsule.top}px`,
|
|
58
|
+
"--glassly-capsule-bottom": `${capsule.bottom}px`,
|
|
59
|
+
"--glassly-capsule-left": `${capsule.left}px`,
|
|
60
|
+
"--glassly-capsule-right": `${capsule.right}px`,
|
|
61
|
+
"--glassly-capsule-width": `${capsule.width}px`,
|
|
62
|
+
"--glassly-capsule-height": `${capsule.height}px`,
|
|
63
|
+
"--glassly-capsule-center-y": `${capsule.top + capsule.height / 2}px`,
|
|
64
|
+
// Right-side gutter to reserve so content doesn't slide under the
|
|
65
|
+
// capsule: its width + 16px breathing room, none when it sits in the rail.
|
|
66
|
+
"--glassly-capsule-gutter": `${capsule.placement === "rail" ? 0 : capsule.width + 16}px`,
|
|
82
67
|
}
|
|
83
68
|
}
|
|
84
69
|
|
|
85
70
|
/**
|
|
86
|
-
* JS to inject into a running miniapp when the host's safe area
|
|
87
|
-
* iPhone Duo folding
|
|
88
|
-
* CSS variables, then fires
|
|
71
|
+
* JS to inject into a running miniapp when the host's safe area or capsule
|
|
72
|
+
* menu moves (an iPhone Duo folding, or its rail's reserved regions growing):
|
|
73
|
+
* updates window.Glassly and the CSS variables, then fires
|
|
74
|
+
* `glassly:safe-area-change`.
|
|
89
75
|
*/
|
|
90
|
-
export function buildSafeAreaUpdateScript(insets: MiniappSafeArea): string {
|
|
91
|
-
const sets = Object.entries(
|
|
76
|
+
export function buildSafeAreaUpdateScript(insets: MiniappSafeArea, capsuleMenu: CapsuleMenuRect): string {
|
|
77
|
+
const sets = Object.entries(layoutCssVars(insets, capsuleMenu))
|
|
92
78
|
.map(([k, v]) => `document.documentElement.style.setProperty(${JSON.stringify(k)}, ${JSON.stringify(v)});`)
|
|
93
79
|
.join("\n ")
|
|
94
80
|
return `
|
|
95
81
|
window.Glassly = window.Glassly || {};
|
|
96
82
|
window.Glassly.safeAreaInsets = ${JSON.stringify(insets)};
|
|
83
|
+
window.Glassly.capsuleMenu = ${JSON.stringify(capsuleMenu)};
|
|
97
84
|
try {
|
|
98
85
|
${sets}
|
|
99
86
|
} catch (e) { /* ignore */ }
|
|
@@ -115,37 +102,18 @@ export function buildSafeAreaUpdateScript(insets: MiniappSafeArea): string {
|
|
|
115
102
|
* assign to it before the native bridge wires in.
|
|
116
103
|
*/
|
|
117
104
|
export function buildMiniappGlobalsScript(opts: BuildMiniappGlobalsOptions): string {
|
|
118
|
-
const capsuleTopOffset = opts.webviewFillsStatusBar ? opts.safeAreaInsets.top : 0
|
|
119
105
|
const globals: Record<string, unknown> = {
|
|
120
106
|
platform: Platform.OS,
|
|
121
107
|
capabilities: opts.capabilities ?? ["share", "open_url", "copy_clipboard", "download"],
|
|
122
108
|
safeAreaInsets: opts.safeAreaInsets,
|
|
123
|
-
capsuleMenu:
|
|
109
|
+
capsuleMenu: opts.capsuleMenu,
|
|
124
110
|
}
|
|
125
111
|
if (opts.packageName) globals.packageName = opts.packageName
|
|
126
112
|
if (opts.miniappLocal) globals.miniappLocal = true
|
|
127
113
|
if (opts.miniappDeveloperMode) globals.miniappDeveloperMode = true
|
|
128
114
|
if (opts.colorScheme) globals.colorScheme = opts.colorScheme
|
|
129
115
|
|
|
130
|
-
|
|
131
|
-
// Miniapp CSS (or Tailwind arbitrary values) can read these without
|
|
132
|
-
// touching JS: e.g. `style="margin-top: var(--glassly-capsule-top)"`.
|
|
133
|
-
const capsule = globals.capsuleMenu as CapsuleMenuRect
|
|
134
|
-
const insets = opts.safeAreaInsets
|
|
135
|
-
const capsuleCenter = capsule.top + capsule.height / 2
|
|
136
|
-
const cssVars: Record<string, string> = {
|
|
137
|
-
...safeAreaCssVars(insets),
|
|
138
|
-
"--glassly-capsule-top": `${capsule.top}px`,
|
|
139
|
-
"--glassly-capsule-bottom": `${capsule.bottom}px`,
|
|
140
|
-
"--glassly-capsule-left": `${capsule.left}px`,
|
|
141
|
-
"--glassly-capsule-right": `${capsule.right}px`,
|
|
142
|
-
"--glassly-capsule-width": `${capsule.width}px`,
|
|
143
|
-
"--glassly-capsule-height": `${capsule.height}px`,
|
|
144
|
-
"--glassly-capsule-center-y": `${capsuleCenter}px`,
|
|
145
|
-
// Right-side gutter to reserve so content doesn't slide under the
|
|
146
|
-
// capsule: capsule width + 16px breathing room.
|
|
147
|
-
"--glassly-capsule-gutter": `${capsule.width + 16}px`,
|
|
148
|
-
}
|
|
116
|
+
const cssVars = layoutCssVars(opts.safeAreaInsets, opts.capsuleMenu)
|
|
149
117
|
const cssVarsBlock = Object.entries(cssVars)
|
|
150
118
|
.map(([k, v]) => `${k}: ${v};`)
|
|
151
119
|
.join(" ")
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AppleWatchLink.d.ts","sourceRoot":"","sources":["../../../src/services/appleWatch/AppleWatchLink.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,wBAAwB,CAAA;AAElE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAOpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAA;AAO1C,eAAO,MAAM,cAAc,0BAA0B,CAAA;AACrD,eAAO,MAAM,aAAa,QAAQ,CAAA;AAQlC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAA;IAC7D,IAAI,EAAE,SAAS,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,GAAG;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,EAAE,CAMhG;AAED,wBAAgB,UAAU,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAC,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUpG;AAOD,+FAA+F;AAC/F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA4EpF;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,SAAS,SAAS,EAAE,CAAA;IAChC,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/C,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAChD,GAAG,EAAE,MAAM,MAAM,CAAA;CAClB;AAWD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,sBAAsB,EAC7B,IAAI,GAAE,qBAAmC,GACxC,OAAO,CAAC,IAAI,CAAC,CA4Bf;AA6DD,wBAAgB,mBAAmB,IAAI,IAAI,CAqC1C;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AppleWatchLink.js","sourceRoot":"","sources":["../../../src/services/appleWatch/AppleWatchLink.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Apple Watch remote's phone half: the watch app's status context (glasses, the miniapp in\n * front, launchable miniapps, whether Assist takes questions, the mirror setting), mirror frames\n * while the setting is on, and the commands the watch sends back. Native adds whether the active\n * watch is paired and keeps the newest frame for when the watch app opens. Gestures ride\n * `touch_event` like any controller's.\n */\nimport type {AppleWatchCommandEvent} from \"@glassly/bluetooth-sdk\"\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport type {MirrorSnapshot} from \"@glassly/miniapp\"\nimport {MiniappStreamType} from \"@glassly/miniapp\"\nimport {Platform} from \"react-native\"\n\nimport {useAppStatusStore} from \"../../stores/apps\"\nimport {useGlassesStore} from \"../../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../../stores/settings\"\nimport type {ClientApp} from \"../../types\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {isGlassesConnected} from \"../GlassesReadiness\"\nimport localMiniappRuntime from \"../LocalMiniappRuntime\"\nimport {mirrorService} from \"../MirrorService\"\nimport {keyEventsForTextChange} from \"../neuralBand/NeuralBandInput\"\n\nexport const ASSIST_PACKAGE = \"com.glassly.assistant\"\nexport const ASSIST_ACTION = \"ask\"\n/** WatchConnectivity messages top out near 64 KB; frames past this are skipped, not truncated. */\nconst MAX_FRAME_BYTES = 48_000\nconst MAX_IMAGE_CHARS = 16_000\nconst MAX_APPS = 24\nconst STATE_DEBOUNCE_MS = 250\nconst MIRROR_INTERVAL_MS = 500\n\nexport interface WatchStateInput {\n glasses: {connected: boolean; model: string; battery: number}\n apps: readonly ClientApp[]\n assist: boolean\n mirror: boolean\n}\n\n/** Miniapps the watch can open: shown, compatible, and drawing on the glasses. */\nexport function launchableApps(apps: readonly ClientApp[]): {packageName: string; name: string}[] {\n return apps\n .filter((app) => app.type === \"standard\" && !app.hidden && app.compatibility?.isCompatible !== false)\n .filter((app) => app.packageName && !app.packageName.includes(\"@empty\"))\n .slice(0, MAX_APPS)\n .map((app) => ({packageName: app.packageName, name: app.name}))\n}\n\nexport function watchState({glasses, apps, assist, mirror}: WatchStateInput): Record<string, unknown> {\n const front = apps.find((app) => app.foregrounded && app.running && app.type === \"standard\")\n const state: Record<string, unknown> = {\n glasses: {connected: glasses.connected, name: glasses.model || \"Glasses\", battery: glasses.battery},\n apps: launchableApps(apps),\n assist,\n mirror,\n }\n if (front) state.app = {packageName: front.packageName, name: front.name}\n return state\n}\n\ntype WatchElement = Record<string, string | number | boolean | number[]>\n\nconst level = (color: unknown, fallback = 15) =>\n typeof color === \"number\" ? Math.max(0, Math.min(15, color)) : fallback\n\n/** The glasses frame in the watch's drawing vocabulary; null when there is nothing to draw. */\nexport function mirrorFrame(snapshot: MirrorSnapshot): Record<string, unknown> | null {\n const canvas = snapshot.canvas\n if (!canvas) return null\n const content = snapshot.content\n if (content.kind === \"bitmap\") {\n if (content.data.length > MAX_FRAME_BYTES) return null\n return {width: canvas.width, height: canvas.height, bitmap: content.data, elements: []}\n }\n if (content.kind !== \"scene\") return null\n const elements: WatchElement[] = []\n for (const element of content.elements) {\n const {x, y, w, h} = element.box\n const style = element.style ?? {}\n switch (element.type) {\n case \"text\":\n if (!element.text) break\n elements.push({\n type: \"text\",\n x,\n y,\n w,\n h,\n text: element.text,\n size: style.fontSize ?? 20,\n color: level(style.color),\n })\n break\n case \"rect\":\n elements.push({\n type: \"rect\",\n x,\n y,\n w,\n h,\n fill: style.fill === true,\n border: style.border ?? 1,\n radius: style.radius ?? 0,\n color: level(style.color),\n })\n break\n case \"circle\":\n elements.push({\n type: \"circle\",\n x,\n y,\n w,\n h,\n fill: style.fill === true,\n border: style.border ?? 1,\n color: level(style.color),\n })\n break\n case \"line\":\n case \"triangle\":\n case \"quad\": {\n const points = (element.points ?? []).flatMap((point) => [point.x, point.y])\n if (points.length < 4) break\n const closed = element.type !== \"line\"\n elements.push({\n type: \"line\",\n points,\n width: style.width ?? style.border ?? 1,\n color: level(style.color),\n closed,\n fill: closed && style.fill === true,\n })\n break\n }\n case \"image\":\n if (element.data && element.data.length <= MAX_IMAGE_CHARS)\n elements.push({type: \"image\", x, y, w, h, data: element.data})\n break\n }\n }\n const frame = {width: canvas.width, height: canvas.height, elements}\n return JSON.stringify(frame).length > MAX_FRAME_BYTES ? null : frame\n}\n\nexport interface AppleWatchCommandDeps {\n apps: () => readonly ClientApp[]\n start: (app: ClientApp) => Promise<unknown>\n stop: (packageName: string) => Promise<unknown>\n ask: (query: string) => Promise<unknown>\n type: (stream: string, payload: unknown) => void\n now: () => number\n}\n\nconst defaultDeps: AppleWatchCommandDeps = {\n apps: () => useAppStatusStore.getState().apps,\n start: (app) => useAppStatusStore.getState().start(app),\n stop: (packageName) => useAppStatusStore.getState().stop(packageName),\n ask: (query) => localMiniappRuntime.invokeActionFromHost(ASSIST_PACKAGE, ASSIST_ACTION, {query}),\n type: (stream, payload) => localMiniappRuntime.forwardEvent(stream, payload),\n now: () => Date.now(),\n}\n\nexport async function handleAppleWatchCommand(\n event: AppleWatchCommandEvent,\n deps: AppleWatchCommandDeps = defaultDeps,\n): Promise<void> {\n switch (event.command) {\n case \"launch\": {\n const app = launchableApps(deps.apps()).some((entry) => entry.packageName === event.packageName)\n ? deps.apps().find((entry) => entry.packageName === event.packageName)\n : undefined\n if (!app) {\n console.warn(`AppleWatch: launch of unknown miniapp ${event.packageName}`)\n return\n }\n await deps.start(app)\n return\n }\n case \"stop\": {\n const front = deps.apps().find((app) => app.foregrounded && app.running && app.type === \"standard\")\n if (front) await deps.stop(front.packageName)\n return\n }\n case \"assist\": {\n const query = event.text.trim()\n if (query) await deps.ask(query)\n return\n }\n case \"text\":\n for (const key of keyEventsForTextChange(\"\", event.text, deps.now()))\n deps.type(MiniappStreamType.KEYBOARD_EVENT, key)\n return\n }\n}\n\nlet stops: (() => void)[] = []\nlet stopMirror: (() => void) | null = null\n\nfunction currentState(): Record<string, unknown> {\n const glasses = useGlassesStore.getState()\n return watchState({\n glasses: {\n connected: isGlassesConnected(glasses.connection),\n model: glasses.deviceModel,\n battery: glasses.batteryLevel,\n },\n apps: useAppStatusStore.getState().apps,\n assist: localMiniappRuntime.hostActionAvailable(ASSIST_PACKAGE, ASSIST_ACTION),\n mirror: useSettingsStore.getState().getSetting(SETTINGS.apple_watch_mirror.key) === true,\n })\n}\n\nfunction syncMirror(enabled: boolean): void {\n if (!enabled) {\n if (stopMirror) {\n stopMirror()\n stopMirror = null\n void BluetoothSdk.setWatchMirror(null).catch(() => {})\n }\n return\n }\n if (stopMirror) return\n let lastSentAt = 0\n let pending: MirrorSnapshot | null = null\n let timer: ReturnType<typeof BgTimer.setTimeout> | null = null\n const send = (snapshot: MirrorSnapshot) => {\n lastSentAt = Date.now()\n void BluetoothSdk.setWatchMirror(mirrorFrame(snapshot)).catch((err) =>\n console.warn(\"AppleWatch: mirror push failed:\", err),\n )\n }\n const unsubscribe = mirrorService.subscribe((snapshot) => {\n const wait = lastSentAt + MIRROR_INTERVAL_MS - Date.now()\n if (wait <= 0 && !timer) {\n send(snapshot)\n return\n }\n pending = snapshot\n timer ??= BgTimer.setTimeout(\n () => {\n timer = null\n if (pending) send(pending)\n pending = null\n },\n Math.max(wait, 0),\n )\n })\n stopMirror = () => {\n unsubscribe()\n if (timer) BgTimer.clearTimeout(timer)\n timer = null\n }\n}\n\nexport function startAppleWatchLink(): void {\n if (Platform.OS !== \"ios\" || stops.length > 0) return\n let lastKey = \"\"\n let timer: ReturnType<typeof BgTimer.setTimeout> | null = null\n const push = () => {\n timer = null\n const state = currentState()\n const key = JSON.stringify(state)\n if (key === lastKey) return\n lastKey = key\n void BluetoothSdk.setWatchState(state).catch((err) => console.warn(\"AppleWatch: state push failed:\", err))\n }\n const schedule = () => {\n timer ??= BgTimer.setTimeout(push, STATE_DEBOUNCE_MS)\n }\n const mirrorEnabled = () => useSettingsStore.getState().getSetting(SETTINGS.apple_watch_mirror.key) === true\n const commands = BluetoothSdk.addListener(\"apple_watch_command\", (event) => {\n handleAppleWatchCommand(event).catch((err) => console.warn(`AppleWatch: ${event.command} failed:`, err))\n })\n stops = [\n () => commands.remove(),\n useGlassesStore.subscribe(schedule),\n useAppStatusStore.subscribe(schedule),\n useSettingsStore.subscribe(\n (s) => s.getSetting(SETTINGS.apple_watch_mirror.key),\n () => {\n syncMirror(mirrorEnabled())\n schedule()\n },\n ),\n () => {\n if (timer) BgTimer.clearTimeout(timer)\n timer = null\n },\n ]\n syncMirror(mirrorEnabled())\n schedule()\n}\n\nexport function stopAppleWatchLink(): void {\n stops.splice(0).forEach((stop) => stop())\n syncMirror(false)\n}\n"]}
|