@glassly/engine 0.1.0-dev.99 → 0.2.9-beta.448

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.
Files changed (501) hide show
  1. package/README.md +28 -0
  2. package/build/engine.d.ts +32 -10
  3. package/build/engine.d.ts.map +1 -1
  4. package/build/engine.js +24 -16
  5. package/build/engine.js.map +1 -1
  6. package/build/facades/dev.d.ts +9 -0
  7. package/build/facades/dev.d.ts.map +1 -1
  8. package/build/facades/dev.js +9 -0
  9. package/build/facades/dev.js.map +1 -1
  10. package/build/facades/display.d.ts +10 -3
  11. package/build/facades/display.d.ts.map +1 -1
  12. package/build/facades/display.js +22 -8
  13. package/build/facades/display.js.map +1 -1
  14. package/build/facades/displayMirror.d.ts +11 -0
  15. package/build/facades/displayMirror.d.ts.map +1 -1
  16. package/build/facades/displayMirror.js +22 -0
  17. package/build/facades/displayMirror.js.map +1 -1
  18. package/build/facades/glasses.d.ts +31 -1
  19. package/build/facades/glasses.d.ts.map +1 -1
  20. package/build/facades/glasses.js +51 -0
  21. package/build/facades/glasses.js.map +1 -1
  22. package/build/facades/memory.d.ts +0 -6
  23. package/build/facades/memory.d.ts.map +1 -1
  24. package/build/facades/memory.js +1 -9
  25. package/build/facades/memory.js.map +1 -1
  26. package/build/facades/miniapps.d.ts +3 -1
  27. package/build/facades/miniapps.d.ts.map +1 -1
  28. package/build/facades/miniapps.js +3 -1
  29. package/build/facades/miniapps.js.map +1 -1
  30. package/build/facades/pairing.d.ts.map +1 -1
  31. package/build/facades/pairing.js +5 -4
  32. package/build/facades/pairing.js.map +1 -1
  33. package/build/facades/permissions.d.ts +2 -0
  34. package/build/facades/permissions.d.ts.map +1 -1
  35. package/build/facades/permissions.js +48 -0
  36. package/build/facades/permissions.js.map +1 -1
  37. package/build/facades/phoneNotifications.d.ts +20 -9
  38. package/build/facades/phoneNotifications.d.ts.map +1 -1
  39. package/build/facades/phoneNotifications.js +33 -26
  40. package/build/facades/phoneNotifications.js.map +1 -1
  41. package/build/facades/settings.d.ts.map +1 -1
  42. package/build/facades/settings.js +1 -2
  43. package/build/facades/settings.js.map +1 -1
  44. package/build/generated/releaseMetadata.js +4 -4
  45. package/build/generated/releaseMetadata.js.map +1 -1
  46. package/build/index.d.ts +6 -4
  47. package/build/index.d.ts.map +1 -1
  48. package/build/index.js +5 -4
  49. package/build/index.js.map +1 -1
  50. package/build/react/MentraLiveOtaFlow.js +2 -2
  51. package/build/react/MentraLiveOtaFlow.js.map +1 -1
  52. package/build/react/useMentraLiveOta.d.ts.map +1 -1
  53. package/build/react/useMentraLiveOta.js +8 -7
  54. package/build/react/useMentraLiveOta.js.map +1 -1
  55. package/build/runtime/config.d.ts +1 -1
  56. package/build/runtime/config.d.ts.map +1 -1
  57. package/build/runtime/config.js.map +1 -1
  58. package/build/services/AppRegistry.d.ts +4 -1
  59. package/build/services/AppRegistry.d.ts.map +1 -1
  60. package/build/services/AppRegistry.js +21 -1
  61. package/build/services/AppRegistry.js.map +1 -1
  62. package/build/services/BlobStore.d.ts +2 -2
  63. package/build/services/BlobStore.js +3 -3
  64. package/build/services/BlobStore.js.map +1 -1
  65. package/build/services/CloudClientService.d.ts +7 -3
  66. package/build/services/CloudClientService.d.ts.map +1 -1
  67. package/build/services/CloudClientService.js +34 -9
  68. package/build/services/CloudClientService.js.map +1 -1
  69. package/build/services/DevServerBridge.d.ts +1 -18
  70. package/build/services/DevServerBridge.d.ts.map +1 -1
  71. package/build/services/DevServerBridge.js +9 -8
  72. package/build/services/DevServerBridge.js.map +1 -1
  73. package/build/services/DeviceEventRouter.d.ts.map +1 -1
  74. package/build/services/DeviceEventRouter.js +58 -71
  75. package/build/services/DeviceEventRouter.js.map +1 -1
  76. package/build/services/DisplayDiagnostics.d.ts +5 -0
  77. package/build/services/DisplayDiagnostics.d.ts.map +1 -0
  78. package/build/services/DisplayDiagnostics.js +105 -0
  79. package/build/services/DisplayDiagnostics.js.map +1 -0
  80. package/build/services/DisplayProcessor.d.ts +6 -7
  81. package/build/services/DisplayProcessor.d.ts.map +1 -1
  82. package/build/services/DisplayProcessor.js +17 -45
  83. package/build/services/DisplayProcessor.js.map +1 -1
  84. package/build/services/GestureDotsService.d.ts +10 -4
  85. package/build/services/GestureDotsService.d.ts.map +1 -1
  86. package/build/services/GestureDotsService.js +70 -16
  87. package/build/services/GestureDotsService.js.map +1 -1
  88. package/build/services/GlassesKeyboardInput.d.ts +77 -0
  89. package/build/services/GlassesKeyboardInput.d.ts.map +1 -0
  90. package/build/services/GlassesKeyboardInput.js +261 -0
  91. package/build/services/GlassesKeyboardInput.js.map +1 -0
  92. package/build/services/GlassesSensorService.d.ts +47 -0
  93. package/build/services/GlassesSensorService.d.ts.map +1 -0
  94. package/build/services/GlassesSensorService.js +242 -0
  95. package/build/services/GlassesSensorService.js.map +1 -0
  96. package/build/services/GlassesTouchInput.d.ts +14 -0
  97. package/build/services/GlassesTouchInput.d.ts.map +1 -0
  98. package/build/services/GlassesTouchInput.js +107 -0
  99. package/build/services/GlassesTouchInput.js.map +1 -0
  100. package/build/services/HeadingService.d.ts +0 -6
  101. package/build/services/HeadingService.d.ts.map +1 -1
  102. package/build/services/HeadingService.js +0 -27
  103. package/build/services/HeadingService.js.map +1 -1
  104. package/build/services/HotspotShutdown.d.ts.map +1 -1
  105. package/build/services/HotspotShutdown.js +2 -1
  106. package/build/services/HotspotShutdown.js.map +1 -1
  107. package/build/services/JSCrashloopReportService.js +2 -2
  108. package/build/services/JSCrashloopReportService.js.map +1 -1
  109. package/build/services/JSRouter.d.ts +6 -4
  110. package/build/services/JSRouter.d.ts.map +1 -1
  111. package/build/services/JSRouter.js +15 -13
  112. package/build/services/JSRouter.js.map +1 -1
  113. package/build/services/LocalDisplayManager.d.ts +35 -7
  114. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  115. package/build/services/LocalDisplayManager.js +105 -27
  116. package/build/services/LocalDisplayManager.js.map +1 -1
  117. package/build/services/LocalMiniappDataMigration.d.ts +1 -1
  118. package/build/services/LocalMiniappDataMigration.js +1 -1
  119. package/build/services/LocalMiniappDataMigration.js.map +1 -1
  120. package/build/services/LocalMiniappRuntime.d.ts +64 -11
  121. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  122. package/build/services/LocalMiniappRuntime.js +441 -35
  123. package/build/services/LocalMiniappRuntime.js.map +1 -1
  124. package/build/services/LocalSttFallbackCoordinator.d.ts +3 -0
  125. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  126. package/build/services/LocalSttFallbackCoordinator.js +27 -8
  127. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  128. package/build/services/MemoryStore.d.ts +8 -33
  129. package/build/services/MemoryStore.d.ts.map +1 -1
  130. package/build/services/MemoryStore.js +30 -56
  131. package/build/services/MemoryStore.js.map +1 -1
  132. package/build/services/MiniappEngine.d.ts +3 -3
  133. package/build/services/MiniappEngine.js +7 -7
  134. package/build/services/MiniappEngine.js.map +1 -1
  135. package/build/services/MiniappLauncher.d.ts +8 -0
  136. package/build/services/MiniappLauncher.d.ts.map +1 -1
  137. package/build/services/MiniappLauncher.js +19 -1
  138. package/build/services/MiniappLauncher.js.map +1 -1
  139. package/build/services/MirrorService.d.ts +24 -0
  140. package/build/services/MirrorService.d.ts.map +1 -0
  141. package/build/services/MirrorService.js +132 -0
  142. package/build/services/MirrorService.js.map +1 -0
  143. package/build/services/NativeNavigationService.d.ts +2 -3
  144. package/build/services/NativeNavigationService.d.ts.map +1 -1
  145. package/build/services/NativeNavigationService.js +24 -21
  146. package/build/services/NativeNavigationService.js.map +1 -1
  147. package/build/services/NavigationHandlers.d.ts.map +1 -1
  148. package/build/services/NavigationHandlers.js +10 -5
  149. package/build/services/NavigationHandlers.js.map +1 -1
  150. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  151. package/build/services/OtaInstallCoordinator.js +24 -23
  152. package/build/services/OtaInstallCoordinator.js.map +1 -1
  153. package/build/services/PairedGlassesLatch.d.ts +7 -0
  154. package/build/services/PairedGlassesLatch.d.ts.map +1 -0
  155. package/build/services/PairedGlassesLatch.js +38 -0
  156. package/build/services/PairedGlassesLatch.js.map +1 -0
  157. package/build/services/PhoneActivity.d.ts +23 -0
  158. package/build/services/PhoneActivity.d.ts.map +1 -0
  159. package/build/services/PhoneActivity.js +111 -0
  160. package/build/services/PhoneActivity.js.map +1 -0
  161. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
  162. package/build/services/PhoneCameraFovCoordinator.js +4 -3
  163. package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
  164. package/build/services/PhoneNotificationsSync.d.ts +40 -6
  165. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  166. package/build/services/PhoneNotificationsSync.js +160 -84
  167. package/build/services/PhoneNotificationsSync.js.map +1 -1
  168. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  169. package/build/services/PhonePhotoCoordinator.js +6 -5
  170. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  171. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  172. package/build/services/PhoneStreamCoordinator.js +8 -7
  173. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  174. package/build/services/STTModelManager.d.ts +3 -0
  175. package/build/services/STTModelManager.d.ts.map +1 -1
  176. package/build/services/STTModelManager.js +15 -1
  177. package/build/services/STTModelManager.js.map +1 -1
  178. package/build/services/SceneRenderer.d.ts +43 -2
  179. package/build/services/SceneRenderer.d.ts.map +1 -1
  180. package/build/services/SceneRenderer.js +123 -8
  181. package/build/services/SceneRenderer.js.map +1 -1
  182. package/build/services/StreamLifecycleController.d.ts.map +1 -1
  183. package/build/services/StreamLifecycleController.js +6 -14
  184. package/build/services/StreamLifecycleController.js.map +1 -1
  185. package/build/services/TTSModelManager.js +1 -1
  186. package/build/services/TTSModelManager.js.map +1 -1
  187. package/build/services/UIRouter.d.ts +2 -2
  188. package/build/services/UIRouter.js +5 -5
  189. package/build/services/UIRouter.js.map +1 -1
  190. package/build/services/asg/galleryPathMigration.js +1 -1
  191. package/build/services/asg/galleryPathMigration.js.map +1 -1
  192. package/build/services/asg/gallerySyncService.js +2 -2
  193. package/build/services/asg/gallerySyncService.js.map +1 -1
  194. package/build/services/asg/localStorageService.d.ts.map +1 -1
  195. package/build/services/asg/localStorageService.js +3 -3
  196. package/build/services/asg/localStorageService.js.map +1 -1
  197. package/build/services/debug/DashboardOpenTrace.d.ts +32 -0
  198. package/build/services/debug/DashboardOpenTrace.d.ts.map +1 -0
  199. package/build/services/debug/DashboardOpenTrace.js +128 -0
  200. package/build/services/debug/DashboardOpenTrace.js.map +1 -0
  201. package/build/services/debug/dashboardOpenTimeline.d.ts +77 -0
  202. package/build/services/debug/dashboardOpenTimeline.d.ts.map +1 -0
  203. package/build/services/debug/dashboardOpenTimeline.js +195 -0
  204. package/build/services/debug/dashboardOpenTimeline.js.map +1 -0
  205. package/build/services/effectiveCapabilities.d.ts.map +1 -1
  206. package/build/services/effectiveCapabilities.js +25 -13
  207. package/build/services/effectiveCapabilities.js.map +1 -1
  208. package/build/services/gestureClaims.d.ts +34 -15
  209. package/build/services/gestureClaims.d.ts.map +1 -1
  210. package/build/services/gestureClaims.js +42 -21
  211. package/build/services/gestureClaims.js.map +1 -1
  212. package/build/services/manifestFields.d.ts +9 -0
  213. package/build/services/manifestFields.d.ts.map +1 -0
  214. package/build/services/manifestFields.js +26 -0
  215. package/build/services/manifestFields.js.map +1 -0
  216. package/build/services/memoryStoreInstance.d.ts +0 -10
  217. package/build/services/memoryStoreInstance.d.ts.map +1 -1
  218. package/build/services/memoryStoreInstance.js +2 -31
  219. package/build/services/memoryStoreInstance.js.map +1 -1
  220. package/build/services/mirrorSnapshot.d.ts +16 -0
  221. package/build/services/mirrorSnapshot.d.ts.map +1 -0
  222. package/build/services/mirrorSnapshot.js +102 -0
  223. package/build/services/mirrorSnapshot.js.map +1 -0
  224. package/build/services/nativeNavigationGate.d.ts +8 -0
  225. package/build/services/nativeNavigationGate.d.ts.map +1 -0
  226. package/build/services/nativeNavigationGate.js +12 -0
  227. package/build/services/nativeNavigationGate.js.map +1 -0
  228. package/build/services/notificationAppCatalog.d.ts +7 -0
  229. package/build/services/notificationAppCatalog.d.ts.map +1 -0
  230. package/build/services/notificationAppCatalog.js +16 -0
  231. package/build/services/notificationAppCatalog.js.map +1 -0
  232. package/build/services/notifications/notificationPolicy.d.ts +55 -0
  233. package/build/services/notifications/notificationPolicy.d.ts.map +1 -0
  234. package/build/services/notifications/notificationPolicy.js +41 -0
  235. package/build/services/notifications/notificationPolicy.js.map +1 -0
  236. package/build/services/pages/OverlayPages.d.ts +26 -0
  237. package/build/services/pages/OverlayPages.d.ts.map +1 -0
  238. package/build/services/pages/OverlayPages.js +80 -0
  239. package/build/services/pages/OverlayPages.js.map +1 -0
  240. package/build/services/pages/PageHost.d.ts +32 -0
  241. package/build/services/pages/PageHost.d.ts.map +1 -0
  242. package/build/services/pages/PageHost.js +99 -0
  243. package/build/services/pages/PageHost.js.map +1 -0
  244. package/build/services/pages/overlayApps.d.ts +25 -0
  245. package/build/services/pages/overlayApps.d.ts.map +1 -0
  246. package/build/services/pages/overlayApps.js +66 -0
  247. package/build/services/pages/overlayApps.js.map +1 -0
  248. package/build/services/pages/pageEligibility.d.ts +9 -0
  249. package/build/services/pages/pageEligibility.d.ts.map +1 -0
  250. package/build/services/pages/pageEligibility.js +27 -0
  251. package/build/services/pages/pageEligibility.js.map +1 -0
  252. package/build/services/settingsBridge.d.ts +58 -0
  253. package/build/services/settingsBridge.d.ts.map +1 -0
  254. package/build/services/settingsBridge.js +90 -0
  255. package/build/services/settingsBridge.js.map +1 -0
  256. package/build/services/speakerProfileStoreInstance.js +1 -1
  257. package/build/services/speakerProfileStoreInstance.js.map +1 -1
  258. package/build/services/uiShim.d.ts +1 -1
  259. package/build/services/uiShim.js +4 -4
  260. package/build/services/uiShim.js.map +1 -1
  261. package/build/stores/appVisibility.d.ts +28 -0
  262. package/build/stores/appVisibility.d.ts.map +1 -1
  263. package/build/stores/appVisibility.js +34 -0
  264. package/build/stores/appVisibility.js.map +1 -1
  265. package/build/stores/apps.d.ts +13 -0
  266. package/build/stores/apps.d.ts.map +1 -1
  267. package/build/stores/apps.js +66 -12
  268. package/build/stores/apps.js.map +1 -1
  269. package/build/stores/bluetoothSettingKeys.js +1 -1
  270. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  271. package/build/stores/display.d.ts +3 -3
  272. package/build/stores/display.d.ts.map +1 -1
  273. package/build/stores/display.js +16 -4
  274. package/build/stores/display.js.map +1 -1
  275. package/build/stores/glasses.d.ts.map +1 -1
  276. package/build/stores/glasses.js +14 -1
  277. package/build/stores/glasses.js.map +1 -1
  278. package/build/stores/settings.d.ts +1 -0
  279. package/build/stores/settings.d.ts.map +1 -1
  280. package/build/stores/settings.js +170 -44
  281. package/build/stores/settings.js.map +1 -1
  282. package/build/types/applet.d.ts +14 -1
  283. package/build/types/applet.d.ts.map +1 -1
  284. package/build/types/applet.js.map +1 -1
  285. package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
  286. package/build/types/capabilities/even-realities-g2.js +5 -0
  287. package/build/types/capabilities/even-realities-g2.js.map +1 -1
  288. package/build/types/capabilities/simulated-glasses.d.ts +1 -1
  289. package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
  290. package/build/types/capabilities/simulated-glasses.js +7 -4
  291. package/build/types/capabilities/simulated-glasses.js.map +1 -1
  292. package/build/types/hardware.d.ts +20 -1
  293. package/build/types/hardware.d.ts.map +1 -1
  294. package/build/types/hardware.js +2 -0
  295. package/build/types/hardware.js.map +1 -1
  296. package/build/types/index.d.ts +1 -0
  297. package/build/types/index.d.ts.map +1 -1
  298. package/build/types/index.js +1 -0
  299. package/build/types/index.js.map +1 -1
  300. package/build/utils/debouncedPatch.d.ts +3 -1
  301. package/build/utils/debouncedPatch.d.ts.map +1 -1
  302. package/build/utils/debouncedPatch.js +6 -3
  303. package/build/utils/debouncedPatch.js.map +1 -1
  304. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  305. package/build/utils/devMiniappLaunch.js +4 -3
  306. package/build/utils/devMiniappLaunch.js.map +1 -1
  307. package/build/utils/display/measurer/TextMeasurer.d.ts +2 -159
  308. package/build/utils/display/measurer/TextMeasurer.d.ts.map +1 -1
  309. package/build/utils/display/measurer/TextMeasurer.js +2 -272
  310. package/build/utils/display/measurer/TextMeasurer.js.map +1 -1
  311. package/build/utils/display/measurer/script-detection.d.ts +1 -52
  312. package/build/utils/display/measurer/script-detection.d.ts.map +1 -1
  313. package/build/utils/display/measurer/script-detection.js +2 -183
  314. package/build/utils/display/measurer/script-detection.js.map +1 -1
  315. package/build/utils/display/pixelArt.d.ts +3 -0
  316. package/build/utils/display/pixelArt.d.ts.map +1 -0
  317. package/build/utils/display/pixelArt.js +3 -0
  318. package/build/utils/display/pixelArt.js.map +1 -0
  319. package/build/utils/display/profiles/g1.d.ts +1 -32
  320. package/build/utils/display/profiles/g1.d.ts.map +1 -1
  321. package/build/utils/display/profiles/g1.js +2 -212
  322. package/build/utils/display/profiles/g1.js.map +1 -1
  323. package/build/utils/display/profiles/g2.d.ts +1 -12
  324. package/build/utils/display/profiles/g2.d.ts.map +1 -1
  325. package/build/utils/display/profiles/g2.js +2 -33
  326. package/build/utils/display/profiles/g2.js.map +1 -1
  327. package/build/utils/display/profiles/nex.d.ts +1 -9
  328. package/build/utils/display/profiles/nex.d.ts.map +1 -1
  329. package/build/utils/display/profiles/nex.js +2 -149
  330. package/build/utils/display/profiles/nex.js.map +1 -1
  331. package/build/utils/display/profiles/types.d.ts +1 -102
  332. package/build/utils/display/profiles/types.d.ts.map +1 -1
  333. package/build/utils/display/profiles/types.js.map +1 -1
  334. package/build/utils/display/profiles/z100.d.ts +1 -32
  335. package/build/utils/display/profiles/z100.d.ts.map +1 -1
  336. package/build/utils/display/profiles/z100.js +2 -181
  337. package/build/utils/display/profiles/z100.js.map +1 -1
  338. package/build/utils/display/scene/degrade.d.ts.map +1 -1
  339. package/build/utils/display/scene/degrade.js +4 -1
  340. package/build/utils/display/scene/degrade.js.map +1 -1
  341. package/build/utils/display/scene/differ.d.ts +13 -1
  342. package/build/utils/display/scene/differ.d.ts.map +1 -1
  343. package/build/utils/display/scene/differ.js +22 -0
  344. package/build/utils/display/scene/differ.js.map +1 -1
  345. package/build/utils/display/scene/index.d.ts +1 -1
  346. package/build/utils/display/scene/index.d.ts.map +1 -1
  347. package/build/utils/display/scene/index.js.map +1 -1
  348. package/build/utils/display/scene/process.d.ts.map +1 -1
  349. package/build/utils/display/scene/process.js +183 -11
  350. package/build/utils/display/scene/process.js.map +1 -1
  351. package/build/utils/display/scene/store.d.ts +1 -1
  352. package/build/utils/display/scene/store.d.ts.map +1 -1
  353. package/build/utils/display/scene/store.js +0 -0
  354. package/build/utils/display/scene/store.js.map +1 -1
  355. package/build/utils/display/scene/svgPath.d.ts +9 -0
  356. package/build/utils/display/scene/svgPath.d.ts.map +1 -0
  357. package/build/utils/display/scene/svgPath.js +167 -0
  358. package/build/utils/display/scene/svgPath.js.map +1 -0
  359. package/build/utils/display/scene/types.d.ts +2 -142
  360. package/build/utils/display/scene/types.d.ts.map +1 -1
  361. package/build/utils/display/scene/types.js +0 -0
  362. package/build/utils/display/scene/types.js.map +1 -1
  363. package/build/utils/display/wrapper/TextWrapper.d.ts +1 -101
  364. package/build/utils/display/wrapper/TextWrapper.d.ts.map +1 -1
  365. package/build/utils/display/wrapper/TextWrapper.js +2 -470
  366. package/build/utils/display/wrapper/TextWrapper.js.map +1 -1
  367. package/build/utils/display/wrapper/types.d.ts +2 -74
  368. package/build/utils/display/wrapper/types.d.ts.map +1 -1
  369. package/build/utils/display/wrapper/types.js +2 -10
  370. package/build/utils/display/wrapper/types.js.map +1 -1
  371. package/build/utils/hardware/hardware.js +1 -1
  372. package/build/utils/hardware/hardware.js.map +1 -1
  373. package/build/utils/timers/timers.d.ts.map +1 -1
  374. package/build/utils/timers/timers.js +26 -4
  375. package/build/utils/timers/timers.js.map +1 -1
  376. package/package.json +8 -8
  377. package/src/engine.ts +24 -15
  378. package/src/facades/dev.ts +10 -0
  379. package/src/facades/display.ts +21 -8
  380. package/src/facades/displayMirror.ts +29 -0
  381. package/src/facades/glasses.ts +61 -1
  382. package/src/facades/memory.ts +1 -12
  383. package/src/facades/miniapps.ts +4 -1
  384. package/src/facades/pairing.ts +8 -6
  385. package/src/facades/permissions.ts +46 -0
  386. package/src/facades/phoneNotifications.ts +45 -26
  387. package/src/facades/settings.ts +1 -2
  388. package/src/generated/releaseMetadata.ts +4 -4
  389. package/src/index.ts +6 -9
  390. package/src/react/MentraLiveOtaFlow.tsx +2 -2
  391. package/src/react/useMentraLiveOta.ts +14 -8
  392. package/src/runtime/config.ts +1 -1
  393. package/src/services/AppRegistry.ts +43 -7
  394. package/src/services/BlobStore.ts +3 -3
  395. package/src/services/CloudClientService.ts +37 -10
  396. package/src/services/DevServerBridge.ts +12 -10
  397. package/src/services/DeviceEventRouter.ts +73 -74
  398. package/src/services/DisplayDiagnostics.ts +107 -0
  399. package/src/services/DisplayProcessor.ts +20 -55
  400. package/src/services/GestureDotsService.ts +77 -16
  401. package/src/services/GlassesKeyboardInput.ts +306 -0
  402. package/src/services/GlassesSensorService.ts +233 -0
  403. package/src/services/GlassesTouchInput.ts +128 -0
  404. package/src/services/HeadingService.ts +0 -24
  405. package/src/services/HotspotShutdown.ts +3 -1
  406. package/src/services/JSCrashloopReportService.ts +2 -2
  407. package/src/services/JSRouter.ts +29 -14
  408. package/src/services/LocalDisplayManager.ts +112 -26
  409. package/src/services/LocalMiniappDataMigration.ts +1 -1
  410. package/src/services/LocalMiniappRuntime.ts +500 -43
  411. package/src/services/LocalSttFallbackCoordinator.ts +28 -7
  412. package/src/services/MemoryStore.ts +32 -80
  413. package/src/services/MiniappEngine.ts +7 -7
  414. package/src/services/MiniappLauncher.ts +25 -1
  415. package/src/services/MirrorService.ts +139 -0
  416. package/src/services/NativeNavigationService.ts +29 -25
  417. package/src/services/NavigationHandlers.ts +10 -5
  418. package/src/services/OtaInstallCoordinator.ts +36 -34
  419. package/src/services/PairedGlassesLatch.ts +39 -0
  420. package/src/services/PhoneActivity.ts +116 -0
  421. package/src/services/PhoneCameraFovCoordinator.ts +6 -4
  422. package/src/services/PhoneNotificationsSync.ts +185 -103
  423. package/src/services/PhonePhotoCoordinator.ts +9 -10
  424. package/src/services/PhoneStreamCoordinator.ts +13 -11
  425. package/src/services/STTModelManager.ts +15 -1
  426. package/src/services/SceneRenderer.ts +148 -10
  427. package/src/services/StreamLifecycleController.ts +9 -7
  428. package/src/services/TTSModelManager.ts +1 -1
  429. package/src/services/UIRouter.ts +5 -5
  430. package/src/services/asg/galleryPathMigration.ts +1 -1
  431. package/src/services/asg/gallerySyncService.ts +2 -2
  432. package/src/services/asg/localStorageService.ts +3 -3
  433. package/src/services/debug/DashboardOpenTrace.ts +153 -0
  434. package/src/services/debug/dashboardOpenTimeline.ts +237 -0
  435. package/src/services/effectiveCapabilities.ts +32 -13
  436. package/src/services/gestureClaims.ts +72 -23
  437. package/src/services/manifestFields.ts +23 -0
  438. package/src/services/memoryStoreInstance.ts +2 -34
  439. package/src/services/mirrorSnapshot.ts +116 -0
  440. package/src/services/nativeNavigationGate.ts +14 -0
  441. package/src/services/notificationAppCatalog.ts +21 -0
  442. package/src/services/notifications/notificationPolicy.ts +87 -0
  443. package/src/services/pages/OverlayPages.ts +86 -0
  444. package/src/services/pages/PageHost.ts +116 -0
  445. package/src/services/pages/overlayApps.ts +72 -0
  446. package/src/services/pages/pageEligibility.ts +30 -0
  447. package/src/services/settingsBridge.ts +111 -0
  448. package/src/services/speakerProfileStoreInstance.ts +1 -1
  449. package/src/services/uiShim.ts +4 -4
  450. package/src/stores/appVisibility.ts +45 -0
  451. package/src/stores/apps.ts +110 -32
  452. package/src/stores/bluetoothSettingKeys.ts +1 -1
  453. package/src/stores/display.ts +18 -7
  454. package/src/stores/glasses.ts +15 -1
  455. package/src/stores/settings.ts +175 -51
  456. package/src/types/applet.ts +14 -1
  457. package/src/types/capabilities/even-realities-g2.ts +6 -0
  458. package/src/types/capabilities/simulated-glasses.ts +8 -4
  459. package/src/types/hardware.ts +34 -1
  460. package/src/types/index.ts +1 -0
  461. package/src/utils/debouncedPatch.ts +8 -4
  462. package/src/utils/devMiniappLaunch.ts +5 -3
  463. package/src/utils/display/measurer/TextMeasurer.ts +3 -346
  464. package/src/utils/display/measurer/script-detection.ts +10 -218
  465. package/src/utils/display/pixelArt.ts +3 -0
  466. package/src/utils/display/profiles/g1.ts +2 -236
  467. package/src/utils/display/profiles/g2.ts +2 -39
  468. package/src/utils/display/profiles/nex.ts +2 -166
  469. package/src/utils/display/profiles/types.ts +9 -132
  470. package/src/utils/display/profiles/z100.ts +2 -198
  471. package/src/utils/display/scene/degrade.ts +4 -1
  472. package/src/utils/display/scene/differ.ts +25 -1
  473. package/src/utils/display/scene/index.ts +5 -0
  474. package/src/utils/display/scene/process.ts +196 -13
  475. package/src/utils/display/scene/store.ts +0 -0
  476. package/src/utils/display/scene/svgPath.ts +163 -0
  477. package/src/utils/display/scene/types.ts +0 -0
  478. package/src/utils/display/wrapper/TextWrapper.ts +2 -546
  479. package/src/utils/display/wrapper/types.ts +3 -102
  480. package/src/utils/hardware/hardware.ts +1 -1
  481. package/src/utils/timers/timers.ts +32 -4
  482. package/build/services/CustomDashboardModel.d.ts +0 -48
  483. package/build/services/CustomDashboardModel.d.ts.map +0 -1
  484. package/build/services/CustomDashboardModel.js +0 -73
  485. package/build/services/CustomDashboardModel.js.map +0 -1
  486. package/build/services/CustomDashboardService.d.ts +0 -63
  487. package/build/services/CustomDashboardService.d.ts.map +0 -1
  488. package/build/services/CustomDashboardService.js +0 -576
  489. package/build/services/CustomDashboardService.js.map +0 -1
  490. package/build/services/DashboardCoordinator.d.ts +0 -26
  491. package/build/services/DashboardCoordinator.d.ts.map +0 -1
  492. package/build/services/DashboardCoordinator.js +0 -125
  493. package/build/services/DashboardCoordinator.js.map +0 -1
  494. package/build/services/iosNotificationAppCatalog.d.ts +0 -13
  495. package/build/services/iosNotificationAppCatalog.d.ts.map +0 -1
  496. package/build/services/iosNotificationAppCatalog.js +0 -28
  497. package/build/services/iosNotificationAppCatalog.js.map +0 -1
  498. package/src/services/CustomDashboardModel.ts +0 -83
  499. package/src/services/CustomDashboardService.ts +0 -598
  500. package/src/services/DashboardCoordinator.ts +0 -121
  501. package/src/services/iosNotificationAppCatalog.ts +0 -39
@@ -1,598 +0,0 @@
1
- /**
2
- * Scene API dashboard for G2 custom firmware.
3
- *
4
- * G2.swift marks the published firmware version after it detects the CFW
5
- * capability advertisement. DashboardCoordinator owns open/close and display
6
- * switching; this service renders the widgets and handles gestures while open.
7
- *
8
- * The dashboard is composed of user-orderable widgets (clock, calendar, apps
9
- * button, notifications button) stacked vertically on the CFW scene canvas.
10
- * The apps button switches to a second, dashboard-rendered app menu view.
11
- */
12
- import {File} from "expo-file-system"
13
-
14
- import {BluetoothSdk} from "@glassly/bluetooth-sdk"
15
- import {MiniappErrorCode, type CalendarEvent} from "@glassly/miniapp"
16
-
17
- import {useAppStatusStore} from "../stores/apps"
18
- import {useGlassesStore} from "../stores/glasses"
19
- import {SETTINGS, useSettingsStore} from "../stores/settings"
20
- import type {ClientApp} from "../types/applet"
21
- import {TextMeasurer} from "../utils/display/measurer"
22
- import type {SceneElementInput} from "../utils/display/scene"
23
- import {BgTimer} from "../utils/timers"
24
- import {
25
- appMenuActions,
26
- dashboardActions,
27
- formatDashboardClock,
28
- isCustomDashboardEligible,
29
- normalizeDashboardWidgets,
30
- orderedDashboardApps,
31
- type CustomDashboardClockStyle,
32
- type DashboardWidgetSetting,
33
- type MenuAppSetting,
34
- } from "./CustomDashboardModel"
35
- import displayProcessor from "./DisplayProcessor"
36
- import {isGlassesConnected} from "./GlassesReadiness"
37
- import localDisplayManager from "./LocalDisplayManager"
38
- import {listPhoneCalendarEvents, PhoneCalendarError} from "./PhoneCalendarService"
39
- import sceneRenderer from "./SceneRenderer"
40
-
41
- const DASHBOARD_APP_ID = "system.custom-dashboard"
42
- const CLOCK_REFRESH_MS = 30_000
43
- const CALENDAR_REFRESH_MS = 5 * 60_000
44
- /** Matches the boot message's window; stops have no unmount-driven end signal. */
45
- const STOP_NOTICE_MS = 1500
46
-
47
- // CFW blits the stock compositor's 576×288 canvas; used when the firmware has
48
- // not reported scene capabilities yet.
49
- const FALLBACK_CANVAS = {width: 576, height: 288}
50
- const MARGIN_X = 16
51
- const MARGIN_TOP = 10
52
- const WIDGET_GAP = 10
53
- /** Row height for the glasses' builtin 20px font engine. */
54
- const LINE_H = 24
55
- const BUTTON_H = 34
56
- /**
57
- * Selection marker: a text-hugging bar under the focused label instead of a
58
- * boxed border. Drawn as a rect (h 3, border 2 — the strokes overlap into a
59
- * solid bar) because mode 15 renders only glyphs; the bar must be in the
60
- * raster or the firmware never shows it.
61
- */
62
- const UNDERLINE_H = 3
63
- /** Row-top → underline-top: just under the builtin font's 27px line. */
64
- const UNDERLINE_OFFSET_Y = BUTTON_H - 4
65
- /**
66
- * App-menu icon grid: 2 rows × 4 columns per page. CFW rasterizes scenes
67
- * phone-side, so the stock firmware's 4-image container pool does not bound
68
- * the page (getEffectiveCapabilities lifts the element caps while the CFW
69
- * canvas is active).
70
- */
71
- const APP_GRID_COLS = 4
72
- const APP_GRID_ROWS = 2
73
- const APPS_PER_PAGE = APP_GRID_COLS * APP_GRID_ROWS
74
- const APP_CELL = 36
75
- const APP_CELL_GAP = 12
76
- const APP_ICON_INSET = 2
77
- const APP_ICON = APP_CELL - APP_ICON_INSET * 2
78
-
79
- function eventLine(event: CalendarEvent): string {
80
- const when = event.allDay
81
- ? "All day"
82
- : new Intl.DateTimeFormat(undefined, {hour: "numeric", minute: "2-digit"}).format(new Date(event.startsAt))
83
- return `${when} ${event.title}`
84
- }
85
-
86
- class CustomDashboardService {
87
- private started = false
88
- private open = false
89
- /** Set by DashboardCoordinator; asks it to close (and restore main content). */
90
- public onRequestClose: (() => void) | null = null
91
- private view: "main" | "apps" = "main"
92
- private mainIndex = 0
93
- private appsIndex = 0
94
- /** "loading" until the first fetch resolves; "no-access" only for a real permission denial. */
95
- private calendarStatus: "loading" | "ok" | "no-access" | "unavailable" = "loading"
96
- /** packageName → base64 icon bytes, or null when the icon can't be loaded (monogram fallback). */
97
- private iconCache = new Map<string, string | null>()
98
- private iconLoads = new Set<string>()
99
- private calendarEvents: CalendarEvent[] = []
100
- private unsubs: Array<() => void> = []
101
- private clockTimer: number | null = null
102
- private calendarTimer: number | null = null
103
- /** Last observed eligibility, for transition detection. */
104
- private eligible = false
105
-
106
- start(): void {
107
- if (this.started) return
108
- this.started = true
109
- this.unsubs.push(
110
- useGlassesStore.subscribe(
111
- (state) => `${state.connection.state}:${state.deviceModel}:${state.firmwareVersion}`,
112
- () => {
113
- if (!this.syncEligibility()) return
114
- void this.refreshCalendarAndRender()
115
- },
116
- ),
117
- // Selector: only dashboard-relevant settings retrigger a refresh. The
118
- // whole-store form fired a calendar query on every settings write.
119
- useSettingsStore.subscribe(
120
- (state) =>
121
- JSON.stringify([
122
- state.getSetting(SETTINGS.custom_dashboard_enabled.key),
123
- state.getSetting(SETTINGS.custom_dashboard_widgets.key),
124
- state.getSetting(SETTINGS.custom_dashboard_clock_style.key),
125
- state.getSetting(SETTINGS.custom_dashboard_clock_show_date.key),
126
- state.getSetting(SETTINGS.twelve_hour_time.key),
127
- state.getSetting(SETTINGS.custom_dashboard_calendar_event_count.key),
128
- state.getSetting(SETTINGS.custom_dashboard_calendar_days_ahead.key),
129
- state.getSetting(SETTINGS.menu_apps.key),
130
- ]),
131
- () => {
132
- if (!this.syncEligibility()) return
133
- void this.refreshCalendarAndRender()
134
- },
135
- ),
136
- useAppStatusStore.subscribe(() => {
137
- if (this.isEligible()) this.render()
138
- }),
139
- )
140
- this.clockTimer = BgTimer.setInterval(() => {
141
- if (this.isEligible()) this.render()
142
- }, CLOCK_REFRESH_MS)
143
- this.calendarTimer = BgTimer.setInterval(() => {
144
- if (this.isEligible()) void this.refreshCalendarAndRender()
145
- }, CALENDAR_REFRESH_MS)
146
- this.eligible = this.isEligible()
147
- }
148
-
149
- /**
150
- * Track eligible⇄ineligible transitions from any trigger (setting toggle,
151
- * connect/disconnect, firmware change). Leaving closes the dashboard via the
152
- * coordinator (which restores main content) and drops the retained scene so
153
- * a stale frame can't be replayed after the feature was turned off.
154
- */
155
- private syncEligibility(): boolean {
156
- const eligible = this.isEligible()
157
- if (eligible === this.eligible) return eligible
158
- this.eligible = eligible
159
- if (!eligible) {
160
- if (this.open) this.onRequestClose?.()
161
- this.open = false
162
- this.resetNavigation()
163
- sceneRenderer.clearApp(DASHBOARD_APP_ID)
164
- }
165
- return eligible
166
- }
167
-
168
- stop(): void {
169
- for (const unsub of this.unsubs) unsub()
170
- this.unsubs = []
171
- if (this.clockTimer !== null) BgTimer.clearInterval(this.clockTimer)
172
- if (this.calendarTimer !== null) BgTimer.clearInterval(this.calendarTimer)
173
- this.clockTimer = null
174
- this.calendarTimer = null
175
- if (this.open) this.onRequestClose?.()
176
- this.open = false
177
- this.eligible = false
178
- this.resetNavigation()
179
- this.started = false
180
- sceneRenderer.clearApp(DASHBOARD_APP_ID)
181
- }
182
-
183
- isEligible(): boolean {
184
- if (useSettingsStore.getState().getSetting(SETTINGS.custom_dashboard_enabled.key) === false) return false
185
- const state = useGlassesStore.getState()
186
- return (
187
- isGlassesConnected(state.connection) &&
188
- isCustomDashboardEligible({
189
- model: state.deviceModel,
190
- firmwareVersion: state.firmwareVersion,
191
- })
192
- )
193
- }
194
-
195
- get isOpen(): boolean {
196
- return this.open
197
- }
198
-
199
- /** Coordinator opened the dashboard: render fresh from the top. */
200
- show(): void {
201
- this.open = true
202
- this.resetNavigation()
203
- void this.refreshCalendarAndRender()
204
- }
205
-
206
- /** Coordinator closed the dashboard. */
207
- hide(): void {
208
- this.open = false
209
- this.resetNavigation()
210
- }
211
-
212
- /** Returns true when an open custom dashboard consumed the gesture. */
213
- handleGesture(gestureName: string): boolean {
214
- if (!this.open || !this.isEligible()) return false
215
- if (gestureName === "double_tap") {
216
- // In the app menu a double tap backs out to the top of the dashboard
217
- // (there is no Back row); on the main view it closes the dashboard.
218
- if (this.view === "apps") {
219
- this.resetNavigation()
220
- this.render()
221
- return true
222
- }
223
- this.onRequestClose?.()
224
- return true
225
- }
226
- if (this.view === "apps") return this.handleAppMenuGesture(gestureName)
227
- return this.handleMainGesture(gestureName)
228
- }
229
-
230
- private resetNavigation(): void {
231
- this.view = "main"
232
- this.mainIndex = 0
233
- this.appsIndex = 0
234
- }
235
-
236
- private handleMainGesture(gestureName: string): boolean {
237
- const actions = dashboardActions(this.widgets())
238
- if (this.mainIndex >= actions.length) this.mainIndex = Math.max(0, actions.length - 1)
239
- if (gestureName === "swipe_down" || gestureName === "swipe_up") {
240
- if (actions.length === 0) return true
241
- const delta = gestureName === "swipe_down" ? 1 : -1
242
- this.mainIndex = (this.mainIndex + delta + actions.length) % actions.length
243
- this.render()
244
- return true
245
- }
246
- if (gestureName === "single_tap") {
247
- const action = actions[this.mainIndex]
248
- if (action?.kind === "apps-menu") {
249
- this.view = "apps"
250
- this.appsIndex = 0
251
- this.render()
252
- } else if (action?.kind === "notifications") {
253
- void this.openNotificationsPanel()
254
- }
255
- return true
256
- }
257
- return false
258
- }
259
-
260
- private handleAppMenuGesture(gestureName: string): boolean {
261
- const rows = appMenuActions(this.menuApps())
262
- if (this.appsIndex >= rows.length) this.appsIndex = Math.max(0, rows.length - 1)
263
- if (gestureName === "swipe_down" || gestureName === "swipe_up") {
264
- const delta = gestureName === "swipe_down" ? 1 : -1
265
- this.appsIndex = (this.appsIndex + delta + rows.length) % rows.length
266
- this.render()
267
- return true
268
- }
269
- if (gestureName === "single_tap") {
270
- const row = rows[this.appsIndex]
271
- if (row?.kind === "app") {
272
- void this.toggleApp(row.packageName)
273
- }
274
- return true
275
- }
276
- return false
277
- }
278
-
279
- private menuApps(): ClientApp[] {
280
- const menu = useSettingsStore.getState().getSetting(SETTINGS.menu_apps.key) as MenuAppSetting[] | null
281
- return orderedDashboardApps(menu, useAppStatusStore.getState().apps)
282
- }
283
-
284
- private widgets(): DashboardWidgetSetting[] {
285
- return normalizeDashboardWidgets(useSettingsStore.getState().getSetting(SETTINGS.custom_dashboard_widgets.key))
286
- }
287
-
288
- private async openNotificationsPanel(): Promise<void> {
289
- this.onRequestClose?.()
290
- await BluetoothSdk.showNativeNotificationPanel().catch((error) => {
291
- console.error("CustomDashboard: notification panel failed", error)
292
- })
293
- }
294
-
295
- private async toggleApp(packageName: string): Promise<void> {
296
- this.onRequestClose?.()
297
- const app = useAppStatusStore.getState().apps.find((candidate) => candidate.packageName === packageName)
298
- if (!app) return
299
- if (app.running) {
300
- // Mirror the "Starting X…" boot message: without this the dashboard just
301
- // closes and the stop is invisible on the glasses.
302
- localDisplayManager.showSystemNotice(`Stopping ${app.name}…`, STOP_NOTICE_MS)
303
- await useAppStatusStore.getState().stop(app.packageName)
304
- } else {
305
- await useAppStatusStore.getState().start(app, {skipNavigation: true})
306
- }
307
- }
308
-
309
- private calendarWidgetEnabled(): boolean {
310
- return this.widgets().some((widget) => widget.id === "calendar" && widget.enabled)
311
- }
312
-
313
- private async refreshCalendarAndRender(): Promise<void> {
314
- if (!this.open) return
315
- if (!this.calendarWidgetEnabled()) {
316
- this.calendarStatus = "loading"
317
- this.calendarEvents = []
318
- this.render()
319
- return
320
- }
321
- const settings = useSettingsStore.getState()
322
- const count = Number(settings.getSetting(SETTINGS.custom_dashboard_calendar_event_count.key) ?? 2)
323
- const days = Number(settings.getSetting(SETTINGS.custom_dashboard_calendar_days_ahead.key) ?? 3)
324
- const startsAt = new Date()
325
- const endsAt = new Date(startsAt.getTime() + Math.max(1, days) * 24 * 60 * 60 * 1000)
326
- try {
327
- const result = await listPhoneCalendarEvents({
328
- startsAt: startsAt.toISOString(),
329
- endsAt: endsAt.toISOString(),
330
- limit: Math.max(1, Math.min(3, count)),
331
- })
332
- this.calendarStatus = "ok"
333
- this.calendarEvents = result.events
334
- } catch (error) {
335
- // Permission is requested from the Custom Dashboard settings screen;
336
- // only a real denial should read as one — any other failure is
337
- // "Unavailable" (and logged) so it can't masquerade as a permission
338
- // problem.
339
- const denied = error instanceof PhoneCalendarError && error.code === MiniappErrorCode.PERMISSION_DENIED
340
- this.calendarStatus = denied ? "no-access" : "unavailable"
341
- this.calendarEvents = []
342
- if (!denied) console.warn("CustomDashboard: calendar fetch failed", error)
343
- }
344
- this.render()
345
- }
346
-
347
- /** Underline hugging a builtin-font label. x/rowY are the label box's origin. */
348
- private labelUnderline(id: string, x: number, rowY: number, label: string): SceneElementInput {
349
- // Same metrics processScene uses to ellipsize builtin text; the raster
350
- // insets text by 2px, so the bar starts under the first glyph.
351
- const textW = new TextMeasurer(displayProcessor.getProfile()).measureText(label)
352
- return {
353
- type: "rect",
354
- id,
355
- box: {x: x + 2, y: rowY + UNDERLINE_OFFSET_Y, w: textW + 4, h: UNDERLINE_H},
356
- style: {border: 2},
357
- }
358
- }
359
-
360
- private canvas(): {width: number; height: number} {
361
- const {sceneCanvasWidth, sceneCanvasHeight} = useGlassesStore.getState()
362
- if (sceneCanvasWidth && sceneCanvasWidth > 0 && sceneCanvasHeight && sceneCanvasHeight > 0) {
363
- return {width: sceneCanvasWidth, height: sceneCanvasHeight}
364
- }
365
- return FALLBACK_CANVAS
366
- }
367
-
368
- private render(): void {
369
- // Only while open: emitting into the single native view while closed
370
- // would clobber the main content.
371
- if (!this.open || !this.isEligible()) return
372
- const elements = this.view === "apps" ? this.appMenuElements() : this.mainElements()
373
- sceneRenderer.emitScene(DASHBOARD_APP_ID, "dashboard", elements)
374
- }
375
-
376
- private mainElements(): SceneElementInput[] {
377
- const canvas = this.canvas()
378
- const settings = useSettingsStore.getState()
379
- const widgets = this.widgets().filter((widget) => widget.enabled)
380
- const actions = dashboardActions(widgets)
381
- if (this.mainIndex >= actions.length) this.mainIndex = Math.max(0, actions.length - 1)
382
- const selected = actions[this.mainIndex]
383
-
384
- const clockStyle =
385
- (settings.getSetting(SETTINGS.custom_dashboard_clock_style.key) as CustomDashboardClockStyle) === "large"
386
- ? "large"
387
- : "compact"
388
- const calendarEnabled = widgets.some((widget) => widget.id === "calendar")
389
- // Calendar lives in the right half; everything else stacks in the left
390
- // half (full width when the calendar widget is off).
391
- const halfW = Math.floor(canvas.width / 2) - MARGIN_X - Math.floor(WIDGET_GAP / 2)
392
- const width = calendarEnabled ? halfW : canvas.width - MARGIN_X * 2
393
- const rightX = Math.floor(canvas.width / 2) + Math.floor(WIDGET_GAP / 2)
394
-
395
- const elements: SceneElementInput[] = []
396
- let y = MARGIN_TOP
397
- for (const widget of widgets) {
398
- if (widget.id === "clock") {
399
- const fontSize = clockStyle === "large" ? 48 : 32
400
- const clock = formatDashboardClock(new Date(), {
401
- twelveHour: settings.getSetting(SETTINGS.twelve_hour_time.key) === true,
402
- showDate: settings.getSetting(SETTINGS.custom_dashboard_clock_show_date.key) !== false,
403
- })
404
- elements.push({
405
- type: "text",
406
- id: "clock",
407
- box: {x: MARGIN_X, y, w: width, h: fontSize + 6},
408
- text: clock.time,
409
- style: {font: "mono", fontSize, breakMode: "strict-word"},
410
- })
411
- y += fontSize + 6
412
- if (clock.date) {
413
- elements.push({
414
- type: "text",
415
- id: "clock-date",
416
- box: {x: MARGIN_X, y, w: width, h: LINE_H},
417
- text: clock.date,
418
- style: {font: "builtin", breakMode: "strict-word"},
419
- })
420
- y += LINE_H
421
- }
422
- y += WIDGET_GAP
423
- } else if (widget.id === "calendar") {
424
- // Right half, top-aligned, independent of the left stack. A missing
425
- // calendar shows a hint instead of silently vanishing — "No access"
426
- // strictly for permission denial, "Unavailable" for any other failure.
427
- const lines =
428
- this.calendarStatus === "ok"
429
- ? [
430
- "Calendar",
431
- ...(this.calendarEvents.length
432
- ? this.calendarEvents.slice(0, 3).map(eventLine)
433
- : ["No upcoming events"]),
434
- ]
435
- : this.calendarStatus === "loading"
436
- ? ["Calendar"]
437
- : ["Calendar", this.calendarStatus === "no-access" ? "No access" : "Unavailable"]
438
- elements.push({
439
- type: "text",
440
- id: "calendar",
441
- box: {x: rightX, y: MARGIN_TOP, w: halfW, h: lines.length * LINE_H},
442
- text: lines.join("\n"),
443
- style: {font: "builtin", breakMode: "strict-word", overflow: "ellipsis"},
444
- })
445
- } else if (widget.id === "apps") {
446
- elements.push({
447
- type: "text",
448
- id: "apps-button",
449
- box: {x: MARGIN_X, y, w: width, h: BUTTON_H},
450
- text: "Apps",
451
- style: {font: "builtin"},
452
- })
453
- if (selected?.kind === "apps-menu") elements.push(this.labelUnderline("apps-underline", MARGIN_X, y, "Apps"))
454
- y += BUTTON_H + WIDGET_GAP
455
- } else if (widget.id === "notifications") {
456
- elements.push({
457
- type: "text",
458
- id: "notifications",
459
- box: {x: MARGIN_X, y, w: width, h: BUTTON_H},
460
- text: "Notifications",
461
- style: {font: "builtin"},
462
- })
463
- if (selected?.kind === "notifications") {
464
- elements.push(this.labelUnderline("notifications-underline", MARGIN_X, y, "Notifications"))
465
- }
466
- y += BUTTON_H + WIDGET_GAP
467
- }
468
- }
469
- return elements
470
- }
471
-
472
- /**
473
- * Resolve a miniapp icon to base64 for the glasses. Local/bundled miniapps
474
- * carry a file:// icon.png; store apps an https URL; the offline system
475
- * tiles a bundler asset id (unsupported here — monogram fallback). Loads
476
- * are async and cached; a finished load repaints the open app menu.
477
- */
478
- private loadIcon(app: ClientApp): void {
479
- if (this.iconCache.has(app.packageName) || this.iconLoads.has(app.packageName)) return
480
- const url = typeof app.logoUrl === "string" ? app.logoUrl : ""
481
- if (!/^(file|https?):/.test(url)) {
482
- this.iconCache.set(app.packageName, null)
483
- return
484
- }
485
- this.iconLoads.add(app.packageName)
486
- void (async () => {
487
- try {
488
- let base64: string
489
- if (url.startsWith("file:")) {
490
- base64 = await new File(url).base64()
491
- } else {
492
- const response = await fetch(url)
493
- const blob = await response.blob()
494
- base64 = await new Promise<string>((resolve, reject) => {
495
- const reader = new FileReader()
496
- reader.onload = () => resolve(String(reader.result).split(",")[1] ?? "")
497
- reader.onerror = () => reject(reader.error)
498
- reader.readAsDataURL(blob)
499
- })
500
- }
501
- this.iconCache.set(app.packageName, base64 || null)
502
- } catch {
503
- this.iconCache.set(app.packageName, null)
504
- } finally {
505
- this.iconLoads.delete(app.packageName)
506
- if (this.open && this.view === "apps") this.render()
507
- }
508
- })()
509
- }
510
-
511
- private appMenuElements(): SceneElementInput[] {
512
- const canvas = this.canvas()
513
- const width = canvas.width - MARGIN_X * 2
514
- const apps = this.menuApps()
515
- const rows = appMenuActions(apps)
516
- if (this.appsIndex >= rows.length) this.appsIndex = Math.max(0, rows.length - 1)
517
-
518
- const elements: SceneElementInput[] = [
519
- {
520
- type: "text",
521
- id: "apps-title",
522
- box: {x: MARGIN_X, y: MARGIN_TOP, w: width, h: LINE_H},
523
- text: "Apps",
524
- style: {font: "builtin"},
525
- },
526
- ]
527
- const listTop = MARGIN_TOP + LINE_H + 16
528
- if (apps.length === 0) {
529
- elements.push({
530
- type: "text",
531
- id: "apps-empty",
532
- box: {x: MARGIN_X, y: listTop, w: width, h: LINE_H},
533
- text: "No apps in Glasses Menu",
534
- style: {font: "builtin"},
535
- })
536
- return elements
537
- }
538
-
539
- // Icon grid, paged, row-major. Selection is the underlined cell.
540
- const perPage = APPS_PER_PAGE
541
- const pageStart = Math.floor(this.appsIndex / perPage) * perPage
542
- const page = apps.slice(pageStart, pageStart + perPage)
543
- const cols = Math.min(page.length, APP_GRID_COLS)
544
- const totalW = cols * APP_CELL + (cols - 1) * APP_CELL_GAP
545
- const startX = Math.max(MARGIN_X, Math.round((canvas.width - totalW) / 2))
546
- page.forEach((app, cell) => {
547
- const x = startX + (cell % APP_GRID_COLS) * (APP_CELL + APP_CELL_GAP)
548
- const y = listTop + Math.floor(cell / APP_GRID_COLS) * (APP_CELL + APP_CELL_GAP)
549
- const selected = pageStart + cell === this.appsIndex
550
- const icon = this.iconCache.get(app.packageName)
551
- if (icon === undefined) this.loadIcon(app)
552
- if (icon) {
553
- elements.push({
554
- type: "image",
555
- id: `app-icon:${app.packageName}`,
556
- box: {x: x + APP_ICON_INSET, y: y + APP_ICON_INSET, w: APP_ICON, h: APP_ICON},
557
- data: icon,
558
- })
559
- } else {
560
- // Monogram fallback for icons that can't load (bundler-asset tiles).
561
- elements.push({
562
- type: "text",
563
- id: `app-icon:${app.packageName}`,
564
- box: {x: x + APP_ICON_INSET, y: y + APP_ICON_INSET, w: APP_ICON, h: APP_ICON},
565
- text: (app.name.trim()[0] ?? "?").toUpperCase(),
566
- style: {font: "mono", fontSize: 20},
567
- })
568
- }
569
- if (selected) {
570
- elements.push({
571
- type: "rect",
572
- id: "apps-selection",
573
- box: {x, y: y + APP_CELL + 2, w: APP_CELL, h: UNDERLINE_H},
574
- style: {border: 2},
575
- })
576
- }
577
- })
578
-
579
- // Grayscale mini icons are ambiguous on their own: caption the selection.
580
- const gridRows = Math.ceil(page.length / APP_GRID_COLS)
581
- const gridH = gridRows * APP_CELL + (gridRows - 1) * APP_CELL_GAP
582
- const selectedApp = apps[this.appsIndex]
583
- if (selectedApp) {
584
- elements.push({
585
- type: "text",
586
- id: "apps-selected-name",
587
- box: {x: MARGIN_X, y: listTop + gridH + 12, w: width, h: LINE_H},
588
- text: `${selectedApp.name}${selectedApp.running ? " (running)" : ""}`,
589
- style: {font: "builtin", breakMode: "strict-word", overflow: "ellipsis"},
590
- })
591
- }
592
- return elements
593
- }
594
- }
595
-
596
- const customDashboardService = new CustomDashboardService()
597
- export default customDashboardService
598
- export {CustomDashboardService}