@mentra/engine 0.1.0-beta.0 → 0.1.0-dev.1

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 (355) hide show
  1. package/README.md +42 -1
  2. package/build/engine.d.ts +11 -3
  3. package/build/engine.d.ts.map +1 -1
  4. package/build/engine.js +7 -2
  5. package/build/engine.js.map +1 -1
  6. package/build/facades/dev.d.ts.map +1 -1
  7. package/build/facades/dev.js +9 -5
  8. package/build/facades/dev.js.map +1 -1
  9. package/build/facades/gallery.js +1 -1
  10. package/build/facades/gallery.js.map +1 -1
  11. package/build/facades/glasses.d.ts +1 -0
  12. package/build/facades/glasses.d.ts.map +1 -1
  13. package/build/facades/glasses.js +19 -4
  14. package/build/facades/glasses.js.map +1 -1
  15. package/build/facades/glassesSettings.d.ts.map +1 -1
  16. package/build/facades/glassesSettings.js +1 -0
  17. package/build/facades/glassesSettings.js.map +1 -1
  18. package/build/facades/miniapps.d.ts +4 -0
  19. package/build/facades/miniapps.d.ts.map +1 -1
  20. package/build/facades/miniapps.js +5 -0
  21. package/build/facades/miniapps.js.map +1 -1
  22. package/build/facades/ota.d.ts +11 -2
  23. package/build/facades/ota.d.ts.map +1 -1
  24. package/build/facades/ota.js +19 -4
  25. package/build/facades/ota.js.map +1 -1
  26. package/build/facades/pairing.d.ts +4 -0
  27. package/build/facades/pairing.d.ts.map +1 -1
  28. package/build/facades/pairing.js +10 -8
  29. package/build/facades/pairing.js.map +1 -1
  30. package/build/facades/phoneNotifications.d.ts +0 -4
  31. package/build/facades/phoneNotifications.d.ts.map +1 -1
  32. package/build/facades/phoneNotifications.js +4 -14
  33. package/build/facades/phoneNotifications.js.map +1 -1
  34. package/build/index.d.ts +6 -3
  35. package/build/index.d.ts.map +1 -1
  36. package/build/index.js +4 -2
  37. package/build/index.js.map +1 -1
  38. package/build/internal.d.ts +2 -2
  39. package/build/internal.d.ts.map +1 -1
  40. package/build/internal.js +1 -1
  41. package/build/internal.js.map +1 -1
  42. package/build/react/MentraLiveOtaFlow.d.ts +38 -0
  43. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  44. package/build/react/MentraLiveOtaFlow.js +528 -0
  45. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  46. package/build/react/index.d.ts +2 -0
  47. package/build/react/index.d.ts.map +1 -0
  48. package/build/react/index.js +2 -0
  49. package/build/react/index.js.map +1 -0
  50. package/build/react/useEngineSnapshot.d.ts +2 -0
  51. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  52. package/build/react/useEngineSnapshot.js +14 -0
  53. package/build/react/useEngineSnapshot.js.map +1 -0
  54. package/build/runtime/bootstrap.d.ts +24 -1
  55. package/build/runtime/bootstrap.d.ts.map +1 -1
  56. package/build/runtime/bootstrap.js +17 -0
  57. package/build/runtime/bootstrap.js.map +1 -1
  58. package/build/runtime/scanQrSeam.d.ts +7 -0
  59. package/build/runtime/scanQrSeam.d.ts.map +1 -0
  60. package/build/runtime/scanQrSeam.js +16 -0
  61. package/build/runtime/scanQrSeam.js.map +1 -0
  62. package/build/services/AppRegistry.d.ts +18 -8
  63. package/build/services/AppRegistry.d.ts.map +1 -1
  64. package/build/services/AppRegistry.js +44 -45
  65. package/build/services/AppRegistry.js.map +1 -1
  66. package/build/services/AudioCloudUplink.d.ts +9 -3
  67. package/build/services/AudioCloudUplink.d.ts.map +1 -1
  68. package/build/services/AudioCloudUplink.js +9 -3
  69. package/build/services/AudioCloudUplink.js.map +1 -1
  70. package/build/services/AudioPlaybackService.d.ts +9 -1
  71. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  72. package/build/services/AudioPlaybackService.js +77 -32
  73. package/build/services/AudioPlaybackService.js.map +1 -1
  74. package/build/services/BlobStore.d.ts +2 -1
  75. package/build/services/BlobStore.d.ts.map +1 -1
  76. package/build/services/BlobStore.js +17 -9
  77. package/build/services/BlobStore.js.map +1 -1
  78. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
  79. package/build/services/CloudAudioSubscriptionSync.js +13 -1
  80. package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
  81. package/build/services/CloudClientService.d.ts +15 -0
  82. package/build/services/CloudClientService.d.ts.map +1 -1
  83. package/build/services/CloudClientService.js +75 -0
  84. package/build/services/CloudClientService.js.map +1 -1
  85. package/build/services/ForegroundLocationPermission.d.ts +13 -0
  86. package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
  87. package/build/services/ForegroundLocationPermission.js +12 -0
  88. package/build/services/ForegroundLocationPermission.js.map +1 -0
  89. package/build/services/GlassesSettingsSync.d.ts.map +1 -1
  90. package/build/services/GlassesSettingsSync.js +9 -3
  91. package/build/services/GlassesSettingsSync.js.map +1 -1
  92. package/build/services/GlassesStatusProjection.d.ts +2 -1
  93. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  94. package/build/services/GlassesStatusProjection.js +15 -8
  95. package/build/services/GlassesStatusProjection.js.map +1 -1
  96. package/build/services/HotspotOtaTransport.d.ts +29 -0
  97. package/build/services/HotspotOtaTransport.d.ts.map +1 -0
  98. package/build/services/HotspotOtaTransport.js +146 -0
  99. package/build/services/HotspotOtaTransport.js.map +1 -0
  100. package/build/services/HotspotShutdown.d.ts +17 -0
  101. package/build/services/HotspotShutdown.d.ts.map +1 -0
  102. package/build/services/HotspotShutdown.js +29 -0
  103. package/build/services/HotspotShutdown.js.map +1 -0
  104. package/build/services/LocalDisplayManager.d.ts +15 -0
  105. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  106. package/build/services/LocalDisplayManager.js +106 -20
  107. package/build/services/LocalDisplayManager.js.map +1 -1
  108. package/build/services/LocalMiniappRuntime.d.ts +67 -1
  109. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  110. package/build/services/LocalMiniappRuntime.js +486 -126
  111. package/build/services/LocalMiniappRuntime.js.map +1 -1
  112. package/build/services/LocalMiniappStorage.d.ts +32 -0
  113. package/build/services/LocalMiniappStorage.d.ts.map +1 -0
  114. package/build/services/LocalMiniappStorage.js +66 -0
  115. package/build/services/LocalMiniappStorage.js.map +1 -0
  116. package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
  117. package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
  118. package/build/services/LocalMiniappUserIdentity.js +43 -0
  119. package/build/services/LocalMiniappUserIdentity.js.map +1 -0
  120. package/build/services/MicStateCoordinator.d.ts +42 -1
  121. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  122. package/build/services/MicStateCoordinator.js +141 -3
  123. package/build/services/MicStateCoordinator.js.map +1 -1
  124. package/build/services/MiniappLauncher.d.ts.map +1 -1
  125. package/build/services/MiniappLauncher.js +23 -3
  126. package/build/services/MiniappLauncher.js.map +1 -1
  127. package/build/services/MiniappLiveness.d.ts +12 -0
  128. package/build/services/MiniappLiveness.d.ts.map +1 -0
  129. package/build/services/MiniappLiveness.js +16 -0
  130. package/build/services/MiniappLiveness.js.map +1 -0
  131. package/build/services/OtaArtifactDownloader.d.ts +65 -0
  132. package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
  133. package/build/services/OtaArtifactDownloader.js +226 -0
  134. package/build/services/OtaArtifactDownloader.js.map +1 -0
  135. package/build/services/OtaAutoChain.d.ts +34 -0
  136. package/build/services/OtaAutoChain.d.ts.map +1 -0
  137. package/build/services/OtaAutoChain.js +83 -0
  138. package/build/services/OtaAutoChain.js.map +1 -0
  139. package/build/services/OtaErrorMapping.d.ts +18 -0
  140. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  141. package/build/services/OtaErrorMapping.js +63 -0
  142. package/build/services/OtaErrorMapping.js.map +1 -0
  143. package/build/services/OtaInstallCoordinator.d.ts +94 -14
  144. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  145. package/build/services/OtaInstallCoordinator.js +574 -130
  146. package/build/services/OtaInstallCoordinator.js.map +1 -1
  147. package/build/services/OtaService.d.ts.map +1 -1
  148. package/build/services/OtaService.js +8 -1
  149. package/build/services/OtaService.js.map +1 -1
  150. package/build/services/OtaUpdateCheckService.d.ts +38 -3
  151. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  152. package/build/services/OtaUpdateCheckService.js +142 -22
  153. package/build/services/OtaUpdateCheckService.js.map +1 -1
  154. package/build/services/PhoneCalendarService.d.ts.map +1 -1
  155. package/build/services/PhoneCalendarService.js +22 -1
  156. package/build/services/PhoneCalendarService.js.map +1 -1
  157. package/build/services/PhoneCameraFovCoordinator.d.ts +2 -0
  158. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
  159. package/build/services/PhoneCameraFovCoordinator.js +14 -0
  160. package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
  161. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  162. package/build/services/PhoneNotificationsSync.js +12 -10
  163. package/build/services/PhoneNotificationsSync.js.map +1 -1
  164. package/build/services/PhonePhotoCoordinator.d.ts +10 -3
  165. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  166. package/build/services/PhonePhotoCoordinator.js +21 -3
  167. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  168. package/build/services/PhoneStreamCoordinator.d.ts +8 -1
  169. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  170. package/build/services/PhoneStreamCoordinator.js +125 -13
  171. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  172. package/build/services/PhoneVideoCoordinator.d.ts +2 -0
  173. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
  174. package/build/services/PhoneVideoCoordinator.js +10 -0
  175. package/build/services/PhoneVideoCoordinator.js.map +1 -1
  176. package/build/services/SceneRenderer.d.ts.map +1 -1
  177. package/build/services/SceneRenderer.js +15 -0
  178. package/build/services/SceneRenderer.js.map +1 -1
  179. package/build/services/SupportProfileSync.d.ts +22 -0
  180. package/build/services/SupportProfileSync.d.ts.map +1 -0
  181. package/build/services/SupportProfileSync.js +213 -0
  182. package/build/services/SupportProfileSync.js.map +1 -0
  183. package/build/services/TtsTextSanitizer.d.ts +5 -0
  184. package/build/services/TtsTextSanitizer.d.ts.map +1 -0
  185. package/build/services/TtsTextSanitizer.js +61 -0
  186. package/build/services/TtsTextSanitizer.js.map +1 -0
  187. package/build/services/WifiAdbRequest.d.ts +17 -0
  188. package/build/services/WifiAdbRequest.d.ts.map +1 -0
  189. package/build/services/WifiAdbRequest.js +35 -0
  190. package/build/services/WifiAdbRequest.js.map +1 -0
  191. package/build/services/asg/asgCameraApi.d.ts +3 -0
  192. package/build/services/asg/asgCameraApi.d.ts.map +1 -1
  193. package/build/services/asg/asgCameraApi.js +72 -2
  194. package/build/services/asg/asgCameraApi.js.map +1 -1
  195. package/build/services/asg/gallerySyncService.d.ts.map +1 -1
  196. package/build/services/asg/gallerySyncService.js +26 -14
  197. package/build/services/asg/gallerySyncService.js.map +1 -1
  198. package/build/services/asg/localNetworkTransport.d.ts +2 -2
  199. package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
  200. package/build/services/asg/localNetworkTransport.js +6 -6
  201. package/build/services/asg/localNetworkTransport.js.map +1 -1
  202. package/build/services/audioPlaybackAssets.d.ts +8 -0
  203. package/build/services/audioPlaybackAssets.d.ts.map +1 -0
  204. package/build/services/audioPlaybackAssets.js +7 -0
  205. package/build/services/audioPlaybackAssets.js.map +1 -0
  206. package/build/services/glassesClockSync.js +2 -2
  207. package/build/services/glassesClockSync.js.map +1 -1
  208. package/build/services/manifestActions.d.ts +7 -0
  209. package/build/services/manifestActions.d.ts.map +1 -0
  210. package/build/services/manifestActions.js +25 -0
  211. package/build/services/manifestActions.js.map +1 -0
  212. package/build/services/otaDisplayState.d.ts +22 -11
  213. package/build/services/otaDisplayState.d.ts.map +1 -1
  214. package/build/services/otaDisplayState.js +36 -14
  215. package/build/services/otaDisplayState.js.map +1 -1
  216. package/build/services/otaInstallPolicy.d.ts +15 -3
  217. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  218. package/build/services/otaInstallPolicy.js +24 -3
  219. package/build/services/otaInstallPolicy.js.map +1 -1
  220. package/build/services/otaManifestUrl.d.ts +2 -0
  221. package/build/services/otaManifestUrl.d.ts.map +1 -0
  222. package/build/services/{asgOtaVersionUrl.js → otaManifestUrl.js} +15 -5
  223. package/build/services/otaManifestUrl.js.map +1 -0
  224. package/build/services/slimStreamStatus.d.ts +11 -0
  225. package/build/services/slimStreamStatus.d.ts.map +1 -1
  226. package/build/services/slimStreamStatus.js +14 -4
  227. package/build/services/slimStreamStatus.js.map +1 -1
  228. package/build/stores/apps.d.ts.map +1 -1
  229. package/build/stores/apps.js +11 -0
  230. package/build/stores/apps.js.map +1 -1
  231. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  232. package/build/stores/bluetoothSettingKeys.js +2 -0
  233. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  234. package/build/stores/gallerySync.d.ts +2 -0
  235. package/build/stores/gallerySync.d.ts.map +1 -1
  236. package/build/stores/gallerySync.js +2 -0
  237. package/build/stores/gallerySync.js.map +1 -1
  238. package/build/stores/glasses.d.ts.map +1 -1
  239. package/build/stores/glasses.js +3 -0
  240. package/build/stores/glasses.js.map +1 -1
  241. package/build/stores/settings.d.ts +17 -0
  242. package/build/stores/settings.d.ts.map +1 -1
  243. package/build/stores/settings.js +152 -19
  244. package/build/stores/settings.js.map +1 -1
  245. package/build/types/applet.d.ts +2 -0
  246. package/build/types/applet.d.ts.map +1 -1
  247. package/build/types/applet.js.map +1 -1
  248. package/build/types/enums.d.ts +1 -0
  249. package/build/types/enums.d.ts.map +1 -1
  250. package/build/types/enums.js +1 -0
  251. package/build/types/enums.js.map +1 -1
  252. package/build/types/hardware.d.ts +1 -0
  253. package/build/types/hardware.d.ts.map +1 -1
  254. package/build/types/hardware.js +14 -0
  255. package/build/types/hardware.js.map +1 -1
  256. package/build/utils/configuredDevHost.d.ts +6 -0
  257. package/build/utils/configuredDevHost.d.ts.map +1 -0
  258. package/build/utils/configuredDevHost.js +19 -0
  259. package/build/utils/configuredDevHost.js.map +1 -0
  260. package/build/utils/devMiniappLaunch.d.ts +19 -8
  261. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  262. package/build/utils/devMiniappLaunch.js +144 -21
  263. package/build/utils/devMiniappLaunch.js.map +1 -1
  264. package/build/utils/diagnosticContext.d.ts.map +1 -1
  265. package/build/utils/diagnosticContext.js +15 -17
  266. package/build/utils/diagnosticContext.js.map +1 -1
  267. package/build/utils/hardware/hardware.d.ts.map +1 -1
  268. package/build/utils/hardware/hardware.js +7 -3
  269. package/build/utils/hardware/hardware.js.map +1 -1
  270. package/build/utils/miniappDiagnostics.d.ts +64 -0
  271. package/build/utils/miniappDiagnostics.d.ts.map +1 -0
  272. package/build/utils/miniappDiagnostics.js +173 -0
  273. package/build/utils/miniappDiagnostics.js.map +1 -0
  274. package/build/utils/timers/timers.d.ts.map +1 -1
  275. package/build/utils/timers/timers.js +55 -18
  276. package/build/utils/timers/timers.js.map +1 -1
  277. package/package.json +27 -18
  278. package/src/assets/silence.wav +0 -0
  279. package/src/engine.ts +7 -2
  280. package/src/facades/dev.ts +9 -5
  281. package/src/facades/gallery.ts +1 -1
  282. package/src/facades/glasses.ts +17 -4
  283. package/src/facades/glassesSettings.ts +5 -0
  284. package/src/facades/miniapps.ts +7 -0
  285. package/src/facades/ota.ts +19 -4
  286. package/src/facades/pairing.ts +11 -7
  287. package/src/facades/phoneNotifications.ts +4 -13
  288. package/src/index.ts +26 -2
  289. package/src/internal.ts +2 -1
  290. package/src/react/MentraLiveOtaFlow.tsx +856 -0
  291. package/src/react/index.ts +7 -0
  292. package/src/react/useEngineSnapshot.ts +16 -0
  293. package/src/runtime/bootstrap.ts +33 -1
  294. package/src/runtime/scanQrSeam.ts +20 -0
  295. package/src/services/AppRegistry.ts +72 -48
  296. package/src/services/AudioCloudUplink.ts +9 -3
  297. package/src/services/AudioPlaybackService.ts +94 -34
  298. package/src/services/BlobStore.ts +22 -9
  299. package/src/services/CloudAudioSubscriptionSync.ts +13 -1
  300. package/src/services/CloudClientService.ts +74 -0
  301. package/src/services/ForegroundLocationPermission.ts +24 -0
  302. package/src/services/GlassesSettingsSync.ts +9 -3
  303. package/src/services/GlassesStatusProjection.ts +16 -8
  304. package/src/services/HotspotOtaTransport.ts +184 -0
  305. package/src/services/HotspotShutdown.ts +41 -0
  306. package/src/services/LocalDisplayManager.ts +112 -21
  307. package/src/services/LocalMiniappRuntime.ts +576 -130
  308. package/src/services/LocalMiniappStorage.ts +82 -0
  309. package/src/services/LocalMiniappUserIdentity.ts +46 -0
  310. package/src/services/MicStateCoordinator.ts +169 -4
  311. package/src/services/MiniappLauncher.ts +30 -3
  312. package/src/services/MiniappLiveness.ts +24 -0
  313. package/src/services/OtaArtifactDownloader.ts +312 -0
  314. package/src/services/OtaAutoChain.ts +106 -0
  315. package/src/services/OtaErrorMapping.ts +80 -0
  316. package/src/services/OtaInstallCoordinator.ts +645 -143
  317. package/src/services/OtaService.ts +11 -5
  318. package/src/services/OtaUpdateCheckService.ts +180 -20
  319. package/src/services/PhoneCalendarService.ts +27 -4
  320. package/src/services/PhoneCameraFovCoordinator.ts +15 -0
  321. package/src/services/PhoneNotificationsSync.ts +12 -10
  322. package/src/services/PhonePhotoCoordinator.ts +33 -7
  323. package/src/services/PhoneStreamCoordinator.ts +139 -25
  324. package/src/services/PhoneVideoCoordinator.ts +11 -0
  325. package/src/services/SceneRenderer.ts +16 -0
  326. package/src/services/SupportProfileSync.ts +218 -0
  327. package/src/services/TtsTextSanitizer.ts +66 -0
  328. package/src/services/WifiAdbRequest.ts +53 -0
  329. package/src/services/asg/asgCameraApi.ts +99 -8
  330. package/src/services/asg/gallerySyncService.ts +28 -19
  331. package/src/services/asg/localNetworkTransport.ts +7 -11
  332. package/src/services/audioPlaybackAssets.ts +8 -0
  333. package/src/services/glassesClockSync.ts +2 -2
  334. package/src/services/manifestActions.ts +30 -0
  335. package/src/services/otaDisplayState.ts +57 -16
  336. package/src/services/otaInstallPolicy.ts +29 -3
  337. package/src/services/{asgOtaVersionUrl.ts → otaManifestUrl.ts} +16 -4
  338. package/src/services/slimStreamStatus.ts +16 -5
  339. package/src/stores/apps.ts +12 -0
  340. package/src/stores/bluetoothSettingKeys.ts +2 -0
  341. package/src/stores/gallerySync.ts +4 -0
  342. package/src/stores/glasses.ts +3 -0
  343. package/src/stores/settings.ts +174 -21
  344. package/src/types/applet.ts +2 -0
  345. package/src/types/enums.ts +2 -1
  346. package/src/types/hardware.ts +17 -0
  347. package/src/utils/configuredDevHost.ts +17 -0
  348. package/src/utils/devMiniappLaunch.ts +151 -23
  349. package/src/utils/diagnosticContext.ts +17 -17
  350. package/src/utils/hardware/hardware.ts +7 -9
  351. package/src/utils/miniappDiagnostics.ts +226 -0
  352. package/src/utils/timers/timers.ts +57 -21
  353. package/build/services/asgOtaVersionUrl.d.ts +0 -2
  354. package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
  355. package/build/services/asgOtaVersionUrl.js.map +0 -1
@@ -0,0 +1,528 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import { ActivityIndicator, Pressable, StyleSheet, Text, View } from "react-native";
3
+ import { SafeAreaView } from "react-native-safe-area-context";
4
+ import Svg, { Path, Rect } from "react-native-svg";
5
+ import { ota } from "../facades/ota";
6
+ import { beginOtaAutoChain, clearOtaAutoChainReconnectWait, isOtaAutoChainActive, otaAutoChainFingerprint, otaAutoChainReconnectWaitRemaining, stopOtaAutoChain, tryAdvanceOtaAutoChain, } from "../services/OtaAutoChain";
7
+ import { BES_INSTALL_RESTART_MESSAGE, getOtaErrorMessage, shouldRequireGlassesRebootForBesFailure, shouldShowChangeWifiForOtaDownloadFailure, } from "../services/OtaErrorMapping";
8
+ import { useEngineSnapshot } from "./useEngineSnapshot";
9
+ const AUTO_CHAIN_NETWORK_RETRY_DELAY_MS = 5000;
10
+ const AUTO_CHAIN_COMPLETE_DELAY_MS = 750;
11
+ const DEFAULT_THEME = {
12
+ background: "#FFFFFF",
13
+ border: "#D7DFDA",
14
+ error: "#C43131",
15
+ foreground: "#0E2C1A",
16
+ primary: "#00B869",
17
+ primaryText: "#FFFFFF",
18
+ textDim: "#66736B",
19
+ };
20
+ const ENGLISH_COPY = {
21
+ "common:continue": "Continue",
22
+ "ota:checkingForUpdates": "Checking for updates",
23
+ "ota:checkingForUpdatesMessage": "Connected devices will perform automatic updates. Automatic updates can be disabled in Device Settings",
24
+ "ota:updateAvailable": "{{deviceName}} Update Available",
25
+ "ota:updateConnectWifi": "Connect your {{deviceName}} to WiFi to install the update.",
26
+ "ota:updateDescription": "A new update is available for your glasses. We recommend updating now for the best experience.",
27
+ "ota:downgradeAvailable": "{{deviceName}} Version Change Required",
28
+ "ota:downgradeDescription": "This app requires an earlier glasses software version. Your photos and videos will be preserved, but glasses settings will be reset and restored automatically after the change.",
29
+ "ota:updateNow": "Update Now",
30
+ "ota:setupWifi": "Setup WiFi",
31
+ "ota:updateLater": "Later",
32
+ "ota:upToDate": "Up To Date",
33
+ "ota:devBuild": "Development Build",
34
+ "ota:devBuildNoOta": "This mobile app is a development build, so automatic glasses updates are disabled. Use the developer settings manifest override to update them manually.",
35
+ "ota:noUpdatesAvailable": "Your glasses are running the latest version.",
36
+ "ota:checkFailed": "Check Failed",
37
+ "ota:checkFailedMessage": "Couldn't check for updates. Please check your connection and try again.",
38
+ "ota:updateInfoUnavailable": "Update Info Unavailable",
39
+ "ota:updateInfoUnavailableMessage": "Update information for this version of the app is unavailable. Please check the app store for a newer version of the Mentra App.",
40
+ "ota:downgradeDuration": "Your glasses will restart twice — this may take up to 2 minutes.",
41
+ "ota:versionChangeRestarting": "Installing a different version…",
42
+ "ota:versionChangeVerifying": "Verifying your glasses…",
43
+ "ota:versionChangeKeepNearby": "Keep your glasses nearby and connected. They will restart on their own.",
44
+ "ota:versionChangeComplete": "Version Change Complete",
45
+ "ota:versionChangeCompleteMessage": "Your glasses are now on the required version. Their settings were reset and are being restored automatically.",
46
+ "ota:versionChangeFirmwarePassComplete": "Firmware updated",
47
+ "ota:versionChangeFirmwarePassCompleteMessage": "Your glasses restarted with new firmware. One more step: they'll now continue to the required version.",
48
+ };
49
+ function defaultTranslate(key, options) {
50
+ let value = ENGLISH_COPY[key] ?? key;
51
+ for (const [name, replacement] of Object.entries(options ?? {})) {
52
+ value = value.replaceAll(`{{${name}}}`, replacement);
53
+ }
54
+ return value;
55
+ }
56
+ export function MentraLiveOtaFlow({ allowDevSkip = typeof __DEV__ !== "undefined" && __DEV__, deviceName = "Mentra Live", initialPage = "check", initializeRuntime = true, onFinished, onFirmwareRestartingChange, onOpenWifiSetup, style, superMode = false, theme, translate = defaultTranslate, }) {
57
+ const colors = useMemo(() => ({ ...DEFAULT_THEME, ...theme }), [theme]);
58
+ const [page, setPage] = useState(initialPage);
59
+ const [checkGeneration, setCheckGeneration] = useState(0);
60
+ const [runtimeReady, setRuntimeReady] = useState(!initializeRuntime);
61
+ useEffect(() => {
62
+ if (!initializeRuntime) {
63
+ setRuntimeReady(true);
64
+ return;
65
+ }
66
+ let cancelled = false;
67
+ setRuntimeReady(false);
68
+ void ota.initialize().finally(() => {
69
+ if (!cancelled)
70
+ setRuntimeReady(true);
71
+ });
72
+ return () => {
73
+ cancelled = true;
74
+ };
75
+ }, [initializeRuntime]);
76
+ const showCheck = useCallback(() => {
77
+ setPage("check");
78
+ setCheckGeneration((generation) => generation + 1);
79
+ }, []);
80
+ return (<SafeAreaView style={[styles.safeArea, { backgroundColor: colors.background }, style]}>
81
+ <View style={styles.header}>
82
+ <View />
83
+ <MentraMark color={colors.primary}/>
84
+ </View>
85
+ {!runtimeReady ? (<FlowPage colors={colors} icon="download" title={translate("ota:checkingForUpdates")}>
86
+ <ActivityIndicator size="large" color={colors.foreground}/>
87
+ </FlowPage>) : page === "check" ? (<OtaCheckPage allowDevSkip={allowDevSkip} colors={colors} deviceName={deviceName} generation={checkGeneration} onFinished={onFinished} onOpenWifiSetup={onOpenWifiSetup} onStartProgress={() => setPage("progress")} translate={translate}/>) : (<OtaProgressPage colors={colors} onFirmwareRestartingChange={onFirmwareRestartingChange} onOpenWifiSetup={onOpenWifiSetup} onReturnToCheck={showCheck} superMode={superMode} translate={translate}/>)}
88
+ </SafeAreaView>);
89
+ }
90
+ function OtaCheckPage({ allowDevSkip, colors, deviceName, generation, onFinished, onOpenWifiSetup, onStartProgress, translate, }) {
91
+ const otaSnapshot = useEngineSnapshot(ota.snapshot, ota.onSnapshot);
92
+ const [checkState, setCheckState] = useState("checking");
93
+ const [isUpdateRequired, setIsUpdateRequired] = useState(true);
94
+ const [isDowngradeUpdate, setIsDowngradeUpdate] = useState(false);
95
+ const [errorKind, setErrorKind] = useState("network");
96
+ const [updateFingerprint, setUpdateFingerprint] = useState(null);
97
+ const [retryGeneration, setRetryGeneration] = useState(0);
98
+ const performCheckGenerationRef = useRef(0);
99
+ const activeCheckKeyRef = useRef(null);
100
+ const checkStartedRef = useRef(false);
101
+ const checkCompletedRef = useRef(false);
102
+ const selectedCheckResultRef = useRef(null);
103
+ const onFinishedRef = useRef(onFinished);
104
+ const onStartProgressRef = useRef(onStartProgress);
105
+ onFinishedRef.current = onFinished;
106
+ onStartProgressRef.current = onStartProgress;
107
+ const glassesWifiConnected = otaSnapshot.wifiConnected;
108
+ const glassesWifiStatusKnown = otaSnapshot.wifiStatusKnown;
109
+ const hotspotOtaSupported = otaSnapshot.hotspotOtaVersion === 1;
110
+ const canInstallUpdate = glassesWifiStatusKnown && (glassesWifiConnected || hotspotOtaSupported);
111
+ const checkKey = `${generation}:${retryGeneration}`;
112
+ const navigateToProgress = useCallback(() => {
113
+ ota.clearProgress();
114
+ onStartProgressRef.current();
115
+ }, []);
116
+ useEffect(() => {
117
+ const MIN_DISPLAY_TIME_MS = 1100;
118
+ const MAX_WAIT_FOR_VERSION_INFO_MS = 10_000;
119
+ if (activeCheckKeyRef.current !== checkKey) {
120
+ activeCheckKeyRef.current = checkKey;
121
+ checkStartedRef.current = false;
122
+ checkCompletedRef.current = false;
123
+ setCheckState("checking");
124
+ }
125
+ const myGeneration = ++performCheckGenerationRef.current;
126
+ let cancelled = false;
127
+ let reconnectTimeout = null;
128
+ const performCheck = async () => {
129
+ if (checkCompletedRef.current)
130
+ return;
131
+ if (!otaSnapshot.connected) {
132
+ if (isOtaAutoChainActive()) {
133
+ const remainingMs = otaAutoChainReconnectWaitRemaining();
134
+ if (remainingMs === null)
135
+ return;
136
+ reconnectTimeout = setTimeout(() => {
137
+ if (cancelled || myGeneration !== performCheckGenerationRef.current || ota.snapshot().connected)
138
+ return;
139
+ stopOtaAutoChain();
140
+ checkCompletedRef.current = true;
141
+ setCheckState("error");
142
+ }, remainingMs);
143
+ return;
144
+ }
145
+ if (checkStartedRef.current) {
146
+ stopOtaAutoChain();
147
+ checkCompletedRef.current = true;
148
+ setCheckState("error");
149
+ return;
150
+ }
151
+ checkCompletedRef.current = true;
152
+ onFinishedRef.current();
153
+ return;
154
+ }
155
+ clearOtaAutoChainReconnectWait();
156
+ checkStartedRef.current = true;
157
+ const startTime = Date.now();
158
+ try {
159
+ let result = await ota.checkForUpdates({
160
+ waitForBuildNumberMs: MAX_WAIT_FOR_VERSION_INFO_MS,
161
+ waitForBesVersionMs: 5000,
162
+ waitForMtkVersionMs: 2000,
163
+ refreshVersionInfo: true,
164
+ fixClockBeforeCheck: false,
165
+ });
166
+ if (cancelled || myGeneration !== performCheckGenerationRef.current)
167
+ return;
168
+ if (!result.hasCheckCompleted && result.checkFailureReason === "network" && isOtaAutoChainActive()) {
169
+ await new Promise((resolve) => setTimeout(resolve, AUTO_CHAIN_NETWORK_RETRY_DELAY_MS));
170
+ if (cancelled || myGeneration !== performCheckGenerationRef.current)
171
+ return;
172
+ result = await ota.checkForUpdates({
173
+ waitForBuildNumberMs: MAX_WAIT_FOR_VERSION_INFO_MS,
174
+ waitForBesVersionMs: 5000,
175
+ waitForMtkVersionMs: 2000,
176
+ refreshVersionInfo: true,
177
+ fixClockBeforeCheck: false,
178
+ });
179
+ }
180
+ if (cancelled || myGeneration !== performCheckGenerationRef.current)
181
+ return;
182
+ selectedCheckResultRef.current = result;
183
+ await new Promise((resolve) => setTimeout(resolve, Math.max(0, MIN_DISPLAY_TIME_MS - (Date.now() - startTime))));
184
+ if (cancelled || myGeneration !== performCheckGenerationRef.current)
185
+ return;
186
+ if (result.skippedReason === "disconnected") {
187
+ stopOtaAutoChain();
188
+ checkCompletedRef.current = true;
189
+ setCheckState("error");
190
+ return;
191
+ }
192
+ if (result.skippedReason === "missing_build") {
193
+ checkCompletedRef.current = true;
194
+ if (isOtaAutoChainActive()) {
195
+ stopOtaAutoChain();
196
+ setCheckState("error");
197
+ }
198
+ else {
199
+ onFinishedRef.current();
200
+ }
201
+ return;
202
+ }
203
+ if (result.skippedReason === "dev_build") {
204
+ stopOtaAutoChain();
205
+ checkCompletedRef.current = true;
206
+ ota.clearUpdateAvailable();
207
+ setCheckState("dev_build");
208
+ return;
209
+ }
210
+ if (!result.hasCheckCompleted) {
211
+ stopOtaAutoChain();
212
+ checkCompletedRef.current = true;
213
+ setErrorKind(result.checkFailureReason === "pin_unavailable" ? "pin_unavailable" : "network");
214
+ setCheckState("error");
215
+ return;
216
+ }
217
+ if (result.updateAvailable && result.updateInfo) {
218
+ setIsUpdateRequired(result.isRequired);
219
+ setIsDowngradeUpdate(result.updateInfo.isDowngrade === true);
220
+ const fingerprint = otaAutoChainFingerprint(result);
221
+ setUpdateFingerprint(fingerprint);
222
+ if (isOtaAutoChainActive()) {
223
+ const snapshot = ota.snapshot();
224
+ if (!snapshot.wifiStatusKnown)
225
+ return;
226
+ if (!snapshot.wifiConnected && snapshot.hotspotOtaVersion !== 1) {
227
+ stopOtaAutoChain();
228
+ }
229
+ else {
230
+ const admission = tryAdvanceOtaAutoChain(fingerprint, result.updateInfo.isDowngrade === true);
231
+ if (admission.advance) {
232
+ checkCompletedRef.current = true;
233
+ ota.installSession.prepare(result);
234
+ navigateToProgress();
235
+ return;
236
+ }
237
+ }
238
+ }
239
+ checkCompletedRef.current = true;
240
+ setCheckState("update_available");
241
+ return;
242
+ }
243
+ stopOtaAutoChain();
244
+ checkCompletedRef.current = true;
245
+ ota.clearUpdateAvailable();
246
+ setCheckState("no_update");
247
+ }
248
+ catch (error) {
249
+ console.error("OTA check failed:", error);
250
+ await new Promise((resolve) => setTimeout(resolve, Math.max(0, MIN_DISPLAY_TIME_MS - (Date.now() - startTime))));
251
+ if (cancelled || myGeneration !== performCheckGenerationRef.current)
252
+ return;
253
+ stopOtaAutoChain();
254
+ checkCompletedRef.current = true;
255
+ setCheckState("error");
256
+ }
257
+ };
258
+ void performCheck();
259
+ return () => {
260
+ cancelled = true;
261
+ if (reconnectTimeout)
262
+ clearTimeout(reconnectTimeout);
263
+ };
264
+ }, [
265
+ checkKey,
266
+ otaSnapshot.connected,
267
+ otaSnapshot.wifiStatusKnown,
268
+ navigateToProgress,
269
+ ]);
270
+ const retry = () => {
271
+ setCheckState("checking");
272
+ setRetryGeneration((value) => value + 1);
273
+ };
274
+ const updateNow = () => {
275
+ const result = selectedCheckResultRef.current;
276
+ if (!result) {
277
+ setCheckState("error");
278
+ return;
279
+ }
280
+ const snapshot = ota.snapshot();
281
+ if (!snapshot.wifiStatusKnown) {
282
+ retry();
283
+ return;
284
+ }
285
+ if (!snapshot.wifiConnected && snapshot.hotspotOtaVersion !== 1) {
286
+ onOpenWifiSetup();
287
+ return;
288
+ }
289
+ ota.installSession.prepare(result);
290
+ if (updateFingerprint)
291
+ beginOtaAutoChain(updateFingerprint, isDowngradeUpdate);
292
+ navigateToProgress();
293
+ };
294
+ if (checkState === "checking") {
295
+ return (<FlowPage colors={colors} icon="download" title={translate("ota:checkingForUpdates")}>
296
+ <BodyText colors={colors}>{translate("ota:checkingForUpdatesMessage")}</BodyText>
297
+ <ActivityIndicator size="large" color={colors.foreground}/>
298
+ </FlowPage>);
299
+ }
300
+ if (checkState === "update_available") {
301
+ return (<FlowPage colors={colors} icon="download" title={translate(isDowngradeUpdate ? "ota:downgradeAvailable" : "ota:updateAvailable", { deviceName })} actions={<>
302
+ <FlowButton colors={colors} disabled={!glassesWifiStatusKnown} label={translate(!glassesWifiStatusKnown || canInstallUpdate ? "ota:updateNow" : "ota:setupWifi")} onPress={updateNow}/>
303
+ {!isUpdateRequired ? (<FlowButton colors={colors} label={translate("ota:updateLater")} onPress={onFinished} secondary/>) : null}
304
+ {allowDevSkip && isUpdateRequired ? (<FlowButton colors={colors} label="Skip (dev only)" onPress={onFinished} secondary/>) : null}
305
+ </>}>
306
+ <BodyText colors={colors}>
307
+ {canInstallUpdate
308
+ ? translate(isDowngradeUpdate ? "ota:downgradeDescription" : "ota:updateDescription")
309
+ : translate("ota:updateConnectWifi", { deviceName })}
310
+ </BodyText>
311
+ </FlowPage>);
312
+ }
313
+ if (checkState === "dev_build") {
314
+ return (<FlowPage actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={onFinished}/>} colors={colors} icon="settings" title={translate("ota:devBuild")}>
315
+ <BodyText colors={colors}>{translate("ota:devBuildNoOta")}</BodyText>
316
+ </FlowPage>);
317
+ }
318
+ if (checkState === "no_update") {
319
+ return (<FlowPage actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={onFinished}/>} colors={colors} icon="check" title={translate("ota:upToDate")}>
320
+ <BodyText colors={colors}>{translate("ota:noUpdatesAvailable")}</BodyText>
321
+ </FlowPage>);
322
+ }
323
+ if (errorKind === "pin_unavailable") {
324
+ return (<FlowPage actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={onFinished}/>} colors={colors} icon="alert" title={translate("ota:updateInfoUnavailable")}>
325
+ <BodyText colors={colors}>{translate("ota:updateInfoUnavailableMessage")}</BodyText>
326
+ </FlowPage>);
327
+ }
328
+ return (<FlowPage actions={<>
329
+ <FlowButton colors={colors} label="Retry" onPress={retry}/>
330
+ {allowDevSkip ? <FlowButton colors={colors} label="Skip (dev only)" onPress={onFinished} secondary/> : null}
331
+ </>} colors={colors} icon="alert" title={translate("ota:checkFailed")}>
332
+ <BodyText colors={colors}>{translate("ota:checkFailedMessage")}</BodyText>
333
+ </FlowPage>);
334
+ }
335
+ function OtaProgressPage({ colors, onFirmwareRestartingChange, onOpenWifiSetup, onReturnToCheck, superMode, translate, }) {
336
+ const install = useEngineSnapshot(ota.installSession.snapshot, ota.installSession.onSnapshot);
337
+ const autoChainAdvancedRef = useRef(false);
338
+ const { connected, continueButtonDisabled, displayState, errorMsg, hotspotArtifactPercent, hotspotPhase, isVersionChange, mtkInstallStallSimulatedPercent, otaProgress, otaStatus, versionChangeConverged, versionChangePhase, } = install;
339
+ const firmwareRestarting = (!connected && displayState === "restarting") || versionChangePhase === "restarting";
340
+ useEffect(() => {
341
+ onFirmwareRestartingChange?.(firmwareRestarting, true);
342
+ }, [firmwareRestarting, onFirmwareRestartingChange]);
343
+ useEffect(() => () => {
344
+ onFirmwareRestartingChange?.(false, false);
345
+ }, [onFirmwareRestartingChange]);
346
+ useEffect(() => {
347
+ ota.installSession.attach();
348
+ return () => ota.installSession.detach();
349
+ }, []);
350
+ useEffect(() => {
351
+ if (displayState !== "complete" || !connected || !isOtaAutoChainActive() || autoChainAdvancedRef.current)
352
+ return;
353
+ const timeout = setTimeout(() => {
354
+ if (!isOtaAutoChainActive())
355
+ return;
356
+ autoChainAdvancedRef.current = true;
357
+ ota.installSession.finish();
358
+ onReturnToCheck();
359
+ }, AUTO_CHAIN_COMPLETE_DELAY_MS);
360
+ return () => clearTimeout(timeout);
361
+ }, [connected, displayState, onReturnToCheck]);
362
+ const finishAndCheck = () => {
363
+ ota.installSession.finish();
364
+ onReturnToCheck();
365
+ };
366
+ const stopAndCheck = () => {
367
+ stopOtaAutoChain();
368
+ finishAndCheck();
369
+ };
370
+ const retryInstall = () => {
371
+ onFirmwareRestartingChange?.(false, true);
372
+ ota.installSession.retry();
373
+ };
374
+ if (versionChangePhase === "restarting" || versionChangePhase === "verifying") {
375
+ return (<FlowPage colors={colors} icon="download" title={translate(versionChangePhase === "verifying" ? "ota:versionChangeVerifying" : "ota:versionChangeRestarting")}>
376
+ <ActivityIndicator size="large" color={colors.foreground}/>
377
+ <BodyText colors={colors}>{translate("ota:versionChangeKeepNearby")}</BodyText>
378
+ <BodyText colors={colors}>{translate("ota:downgradeDuration")}</BodyText>
379
+ </FlowPage>);
380
+ }
381
+ if (displayState === "starting") {
382
+ const hotspotTitle = hotspotPhase === "downloading"
383
+ ? "Downloading update to phone..."
384
+ : hotspotPhase === "starting_hotspot"
385
+ ? "Starting glasses hotspot..."
386
+ : hotspotPhase === "joining_hotspot"
387
+ ? "Connecting phone to glasses..."
388
+ : "Starting update...";
389
+ return (<FlowPage colors={colors} icon="download" title={hotspotTitle}>
390
+ {hotspotPhase === "downloading" && hotspotArtifactPercent !== null ? (<PercentText colors={colors} percent={hotspotArtifactPercent}/>) : null}
391
+ <ActivityIndicator size="large" color={colors.foreground}/>
392
+ <BodyText colors={colors}>Do not disconnect your glasses</BodyText>
393
+ </FlowPage>);
394
+ }
395
+ if (displayState === "updating") {
396
+ const isDownload = otaStatus?.phase === "download";
397
+ const totalSteps = otaStatus?.totalSteps ?? 1;
398
+ const isApkOnlyInstalling = otaStatus?.stepType === "apk" && otaStatus.phase === "install" && totalSteps === 1;
399
+ const rawPercent = isDownload
400
+ ? otaStatus?.stepPercent ?? 0
401
+ : totalSteps >= 2
402
+ ? otaStatus?.overallPercent ?? 0
403
+ : otaStatus?.stepPercent ?? 0;
404
+ const percent = Math.min(Math.max(rawPercent, mtkInstallStallSimulatedPercent ?? 0, 0), 100);
405
+ return (<FlowPage colors={colors} icon="download" title={isDownload ? "Downloading..." : "Installing..."}>
406
+ {isApkOnlyInstalling ? (<ActivityIndicator size="large" color={colors.foreground}/>) : (<>
407
+ <PercentText colors={colors} percent={percent}/>
408
+ <View style={[styles.progressTrack, { backgroundColor: colors.border }]}>
409
+ <View style={[styles.progressFill, { backgroundColor: colors.primary, width: `${percent}%` }]}/>
410
+ </View>
411
+ </>)}
412
+ <BodyText colors={colors}>Do not disconnect your glasses</BodyText>
413
+ {isVersionChange && otaStatus?.phase === "install" ? (<BodyText colors={colors}>{translate("ota:downgradeDuration")}</BodyText>) : null}
414
+ </FlowPage>);
415
+ }
416
+ if (displayState === "restarting") {
417
+ return (<FlowPage actions={<FlowButton colors={colors} disabled={continueButtonDisabled} label="Continue" onPress={stopAndCheck}/>} colors={colors} icon="check" title="Update Installed"/>);
418
+ }
419
+ if (displayState === "complete") {
420
+ const title = versionChangeConverged
421
+ ? translate("ota:versionChangeComplete")
422
+ : isVersionChange
423
+ ? translate("ota:versionChangeFirmwarePassComplete")
424
+ : "Update complete!";
425
+ const message = versionChangeConverged
426
+ ? translate("ota:versionChangeCompleteMessage")
427
+ : isVersionChange
428
+ ? translate("ota:versionChangeFirmwarePassCompleteMessage")
429
+ : "Your glasses are up to date.";
430
+ return (<FlowPage actions={<FlowButton colors={colors} label={isVersionChange && !versionChangeConverged ? "Continue" : "Done"} onPress={finishAndCheck}/>} colors={colors} icon="check" title={title}>
431
+ <BodyText colors={colors}>{message}</BodyText>
432
+ </FlowPage>);
433
+ }
434
+ if (displayState === "failed") {
435
+ const requiresGlassesReboot = shouldRequireGlassesRebootForBesFailure(otaStatus, otaProgress, errorMsg);
436
+ const displayedError = requiresGlassesReboot
437
+ ? BES_INSTALL_RESTART_MESSAGE
438
+ : errorMsg || getOtaErrorMessage(otaStatus?.error);
439
+ const showChangeWifi = shouldShowChangeWifiForOtaDownloadFailure(otaStatus, otaProgress, errorMsg);
440
+ return (<FlowPage actions={<>
441
+ <FlowButton colors={colors} label={requiresGlassesReboot ? "Done" : "Retry"} onPress={requiresGlassesReboot ? stopAndCheck : retryInstall}/>
442
+ {showChangeWifi ? (<FlowButton colors={colors} label="Change WiFi" onPress={() => {
443
+ stopOtaAutoChain();
444
+ onOpenWifiSetup();
445
+ }} secondary/>) : null}
446
+ </>} colors={colors} icon="alert" title="Update Failed">
447
+ <BodyText colors={colors}>{displayedError}</BodyText>
448
+ </FlowPage>);
449
+ }
450
+ return (<FlowPage actions={superMode ? (<FlowButton colors={colors} label="Skip (super)" onPress={() => {
451
+ stopOtaAutoChain();
452
+ ota.installSession.discard();
453
+ onReturnToCheck();
454
+ }} secondary/>) : undefined} colors={colors} icon="bluetooth" title="Glasses disconnected">
455
+ <BodyText colors={colors}>Reconnecting...</BodyText>
456
+ <ActivityIndicator size="large" color={colors.foreground}/>
457
+ </FlowPage>);
458
+ }
459
+ function FlowPage({ actions, children, colors, icon, title }) {
460
+ return (<View style={styles.page} testID="mentra-live-ota-flow">
461
+ <View style={styles.centerContent}>
462
+ <FlowIcon colors={colors} name={icon}/>
463
+ <Text style={[styles.title, { color: colors.foreground }]}>{title}</Text>
464
+ {children}
465
+ </View>
466
+ {actions ? <View style={styles.actions}>{actions}</View> : <View style={styles.actionSpacer}/>}
467
+ </View>);
468
+ }
469
+ function BodyText({ children, colors }) {
470
+ return <Text style={[styles.body, { color: colors.textDim }]}>{children}</Text>;
471
+ }
472
+ function PercentText({ colors, percent }) {
473
+ return <Text style={[styles.percent, { color: colors.primary }]}>{Math.round(percent)}%</Text>;
474
+ }
475
+ function FlowButton({ colors, disabled = false, label, onPress, secondary = false, }) {
476
+ return (<Pressable accessibilityRole="button" disabled={disabled} onPress={onPress} style={({ pressed }) => [
477
+ styles.button,
478
+ {
479
+ backgroundColor: secondary ? colors.background : colors.primary,
480
+ borderColor: secondary ? colors.border : colors.primary,
481
+ opacity: disabled ? 0.45 : pressed ? 0.75 : 1,
482
+ },
483
+ ]} testID={`button-${label}`}>
484
+ <Text style={[styles.buttonText, { color: secondary ? colors.foreground : colors.primaryText }]}>{label}</Text>
485
+ </Pressable>);
486
+ }
487
+ function MentraMark({ color }) {
488
+ return (<Svg width={33} height={18} viewBox="0 0 50 27" fill="none">
489
+ <Rect y={14.8072} width={11.8457} height={11.8457} fill={color}/>
490
+ <Path d="M9.36639 0L30.7163 14.8072V26.6529L9.36639 11.8457V0Z" fill={color}/>
491
+ <Path d="M28.6501 0L50 14.8072V26.6529L28.6501 11.8457V0Z" fill={color}/>
492
+ </Svg>);
493
+ }
494
+ function FlowIcon({ colors, name }) {
495
+ const color = name === "alert" || name === "bluetooth" ? colors.error : colors.primary;
496
+ const glyph = name === "check" ? "✓" : name === "alert" ? "!" : name === "settings" ? "⚙" : name === "bluetooth" ? "⌁" : "↓";
497
+ return <Text style={[styles.icon, { color }]}>{glyph}</Text>;
498
+ }
499
+ const styles = StyleSheet.create({
500
+ safeArea: { flex: 1 },
501
+ header: {
502
+ alignItems: "center",
503
+ flexDirection: "row",
504
+ height: 48,
505
+ justifyContent: "space-between",
506
+ paddingHorizontal: 20,
507
+ },
508
+ page: { flex: 1, paddingBottom: 24, paddingHorizontal: 24 },
509
+ centerContent: { alignItems: "center", flex: 1, gap: 16, justifyContent: "center" },
510
+ actionSpacer: { height: 48 },
511
+ actions: { gap: 12 },
512
+ icon: { fontSize: 64, fontWeight: "500", lineHeight: 72, textAlign: "center" },
513
+ title: { fontSize: 20, fontWeight: "600", textAlign: "center" },
514
+ body: { fontSize: 14, lineHeight: 20, maxWidth: 420, textAlign: "center" },
515
+ percent: { fontSize: 30, fontVariant: ["tabular-nums"], fontWeight: "700" },
516
+ progressTrack: { borderRadius: 4, height: 8, maxWidth: 420, overflow: "hidden", width: "100%" },
517
+ progressFill: { borderRadius: 4, height: 8 },
518
+ button: {
519
+ alignItems: "center",
520
+ borderRadius: 10,
521
+ borderWidth: 1,
522
+ justifyContent: "center",
523
+ minHeight: 48,
524
+ paddingHorizontal: 20,
525
+ },
526
+ buttonText: { fontSize: 15, fontWeight: "700" },
527
+ });
528
+ //# sourceMappingURL=MentraLiveOtaFlow.js.map