peachsim 0.1.939 → 0.1.1399

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 (396) hide show
  1. package/README.md +28 -22
  2. package/cli/app-catalog.ts +29 -14
  3. package/cli/app-fonts.ts +5 -3
  4. package/cli/bridge-flow-runner.ts +40 -29
  5. package/cli/cloud-client.ts +57 -21
  6. package/cli/cloud-test-tunnel.ts +12 -18
  7. package/cli/commands/agent.ts +1 -1
  8. package/cli/commands/app-fonts.ts +3 -3
  9. package/cli/commands/assert.ts +8 -8
  10. package/cli/commands/auth.ts +8 -3
  11. package/cli/commands/box/bundle-plane.ts +13 -1
  12. package/cli/commands/box.ts +16 -5
  13. package/cli/commands/compat.ts +1 -1
  14. package/cli/commands/config.ts +2 -2
  15. package/cli/commands/control.ts +125 -71
  16. package/cli/commands/cpu-profile.ts +45 -1
  17. package/cli/commands/daemon.ts +131 -33
  18. package/cli/commands/debug.ts +24 -17
  19. package/cli/commands/desktop.ts +7 -1
  20. package/cli/commands/detect.ts +101 -0
  21. package/cli/commands/detox.ts +6 -6
  22. package/cli/commands/device.ts +12 -12
  23. package/cli/commands/electron.ts +32 -14
  24. package/cli/commands/flow.ts +49 -41
  25. package/cli/commands/guest-host.ts +39 -1
  26. package/cli/commands/inspect/core.ts +14 -8
  27. package/cli/commands/inspect/list.ts +1 -1
  28. package/cli/commands/inspect/settle.ts +5 -3
  29. package/cli/commands/inspect/settling.ts +229 -44
  30. package/cli/commands/inspect/wait-idle.ts +3 -2
  31. package/cli/commands/inspect.ts +105 -93
  32. package/cli/commands/install-cli.ts +36 -15
  33. package/cli/commands/install-desktop.ts +68 -195
  34. package/cli/commands/kotlin.ts +6 -5
  35. package/cli/commands/login.ts +5 -5
  36. package/cli/commands/maestro-compare.ts +554 -0
  37. package/cli/commands/maestro-generate.ts +6 -3
  38. package/cli/commands/maestro.ts +22 -0
  39. package/cli/commands/mode.ts +2 -2
  40. package/cli/commands/no-bridge-hint.ts +6 -2
  41. package/cli/commands/platform.ts +35 -6
  42. package/cli/commands/preview.ts +6 -0
  43. package/cli/commands/project-report.ts +10 -12
  44. package/cli/commands/record.ts +37 -37
  45. package/cli/commands/runtime.ts +9 -9
  46. package/cli/commands/screenshot-layers.ts +4 -4
  47. package/cli/commands/screenshot-mode.ts +2 -2
  48. package/cli/commands/screenshot.ts +8 -8
  49. package/cli/commands/screenshots-capture.ts +2 -2
  50. package/cli/commands/serve.ts +9 -12
  51. package/cli/commands/setup.ts +29 -14
  52. package/cli/commands/shell-boolean-mode.ts +2 -2
  53. package/cli/commands/show-touches-mode.ts +2 -2
  54. package/cli/commands/skills.ts +11 -11
  55. package/cli/commands/swift.ts +29 -11
  56. package/cli/commands/telemetry.ts +2 -2
  57. package/cli/commands/test.ts +5 -0
  58. package/cli/commands/three-mode.ts +3 -3
  59. package/cli/commands/timeline.ts +4 -4
  60. package/cli/commands/upgrade.ts +2 -2
  61. package/cli/commands/upload.ts +15 -15
  62. package/cli/commands/what-happened.ts +2 -2
  63. package/cli/current-sim.ts +6 -3
  64. package/cli/desktop-companion.ts +55 -149
  65. package/cli/dev-build-freshness.ts +2 -2
  66. package/cli/drivers/desktop.ts +17 -9
  67. package/cli/drivers/electron.ts +1 -2
  68. package/cli/drivers/playwright-sim-host.ts +11 -2
  69. package/cli/drivers/playwright.ts +35 -2
  70. package/cli/drivers/types.ts +8 -0
  71. package/cli/maestro-compare.ts +670 -0
  72. package/cli/outbound-endpoints.ts +46 -8
  73. package/cli/recording-access.ts +6 -6
  74. package/cli/run-registry.ts +1 -1
  75. package/cli/runtime-compat.ts +5 -1
  76. package/cli/send-to-box.ts +3 -3
  77. package/cli/shell-init.ts +2 -1
  78. package/cli/ws-bridge.ts +9 -5
  79. package/detox/element-types.ts +1 -0
  80. package/detox/gestures.ts +3 -3
  81. package/detox/index.ts +67 -38
  82. package/detox/navigation-lifecycle.ts +9 -6
  83. package/detox/proof-frame.cjs +6 -4
  84. package/dist-lib/agent-daemon-client.cjs +1 -1
  85. package/dist-lib/agent-events.cjs +1 -1
  86. package/dist-lib/attached-projects.cjs +1 -1
  87. package/dist-lib/auth/shared-session.cjs +1 -1
  88. package/dist-lib/backend-origin.cjs +1 -1
  89. package/dist-lib/beta.cjs +1 -1
  90. package/dist-lib/beta.mjs +1 -1
  91. package/dist-lib/bridge-constants.cjs +1 -1
  92. package/dist-lib/bridge-contract-input.cjs +42 -17
  93. package/dist-lib/bridge-contract-input.mjs +41 -16
  94. package/dist-lib/bridge-contract.cjs +1 -4
  95. package/dist-lib/bridge-contract.mjs +1 -3
  96. package/dist-lib/bundle-channel.cjs +2918 -550
  97. package/dist-lib/capture-contract.cjs +65 -24
  98. package/dist-lib/capture-contract.mjs +63 -24
  99. package/dist-lib/cloud-contract.cjs +2 -2
  100. package/dist-lib/cloud-contract.mjs +2 -2
  101. package/dist-lib/cloud-test-args.cjs +1 -1
  102. package/dist-lib/cloud-test-args.mjs +1 -1
  103. package/dist-lib/cloud.cjs +3 -3
  104. package/dist-lib/cloud.mjs +3 -3
  105. package/dist-lib/config.cjs +15 -5
  106. package/dist-lib/config.mjs +154 -0
  107. package/dist-lib/detox/index.cjs +495 -139
  108. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  109. package/dist-lib/expo-swift-bundle.cjs +1168 -238
  110. package/dist-lib/expo-swift-metadata.cjs +34 -23
  111. package/dist-lib/expo-swift-metadata.mjs +32 -23
  112. package/dist-lib/home-paths.cjs +2 -2
  113. package/dist-lib/host/bridge-host.cjs +2938 -654
  114. package/dist-lib/host/fetch-proxy-handler.cjs +14 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +7 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +5 -1
  117. package/dist-lib/host/replacement-module-handler.cjs +2 -2
  118. package/dist-lib/host/websocket-proxy.cjs +1 -1
  119. package/dist-lib/index.cjs +999 -353
  120. package/dist-lib/jump-to-source-babel.cjs +1 -1
  121. package/dist-lib/jump-to-source-native.cjs +1 -1
  122. package/dist-lib/kotlin-host.cjs +332 -19
  123. package/dist-lib/menu.cjs +1 -1
  124. package/dist-lib/menu.mjs +1 -1
  125. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  126. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  127. package/dist-lib/metro-production-bundle.cjs +7 -7
  128. package/dist-lib/metro-production-bundle.mjs +5 -5
  129. package/dist-lib/metro.cjs +688 -250
  130. package/dist-lib/native-app-identity-project.cjs +2647 -0
  131. package/dist-lib/native-app-identity-project.mjs +1257 -0
  132. package/dist-lib/native-app-identity.cjs +325 -25
  133. package/dist-lib/native-app-identity.mjs +323 -25
  134. package/dist-lib/native-firebase-metadata.cjs +1 -1
  135. package/dist-lib/native-firebase-metadata.mjs +1 -1
  136. package/dist-lib/plist.cjs +1 -1
  137. package/dist-lib/plist.mjs +1 -1
  138. package/dist-lib/profiles.cjs +1 -1
  139. package/dist-lib/public-brand.cjs +1 -1
  140. package/dist-lib/react-native-host-modules.cjs +5 -1
  141. package/dist-lib/react-native-host-modules.mjs +5 -1
  142. package/dist-lib/scripts/dev-server-scanner.cjs +57 -32
  143. package/dist-lib/sdk.cjs +231 -51
  144. package/dist-lib/sdk.mjs +231 -51
  145. package/dist-lib/skills.cjs +4107 -1374
  146. package/dist-lib/swift-compile.cjs +290 -30
  147. package/dist-lib/swift-compile.mjs +290 -30
  148. package/dist-lib/swift-package.cjs +143 -12
  149. package/dist-lib/swift-package.mjs +137 -11
  150. package/dist-lib/swift-submit.cjs +47 -5
  151. package/dist-lib/swift-submit.mjs +42 -5
  152. package/dist-lib/swift-toolchain.cjs +7 -2
  153. package/dist-lib/swift.cjs +1 -1
  154. package/dist-lib/vite-swift.cjs +1392 -458
  155. package/dist-lib/vite.cjs +13 -17
  156. package/dist-lib/worklet-executable.cjs +248 -33
  157. package/dist-lib/worklet-executable.mjs +248 -33
  158. package/install.sh +10 -1
  159. package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Resources.kt +9 -9
  160. package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +20 -0
  161. package/kotlin/AndroidViewSources/android/view/View.kt +211 -0
  162. package/kotlin/AndroidViewSources/android/widget/FrameLayout.kt +61 -0
  163. package/kotlin/AndroidViewSources/android/widget/LinearLayout.kt +49 -0
  164. package/kotlin/AppSources/android/view/Window.kt +36 -0
  165. package/kotlin/AppSources/android/view/WindowInsets.kt +9 -0
  166. package/kotlin/AppSources/android/view/WindowInsetsController.kt +5 -0
  167. package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +48 -0
  168. package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +20 -5
  169. package/kotlin/AppSources/androidx/compose/foundation/layout/WindowInsets.kt +15 -0
  170. package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +2 -1
  171. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +42 -50
  172. package/kotlin/ComposeSources/PeachComposeHost.kt +200 -84
  173. package/kotlin/ExpoComposeSources/PeachAndroidView.kt +87 -0
  174. package/kotlin/ExpoComposeSources/PeachExpoViewMount.kt +24 -0
  175. package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +28 -0
  176. package/kotlin/ExpoComposeSources/expo/modules/kotlin/views/ExpoComposeView.kt +70 -0
  177. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +513 -0
  178. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +173 -0
  179. package/kotlin/ExpoSources/expo/modules/kotlin/AppContext.kt +20 -0
  180. package/kotlin/ExpoSources/expo/modules/kotlin/Promise.kt +19 -0
  181. package/kotlin/ExpoSources/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +198 -0
  182. package/kotlin/ExpoSources/expo/modules/kotlin/exception/CodedException.kt +126 -0
  183. package/kotlin/ExpoSources/expo/modules/kotlin/functions/Functions.kt +132 -0
  184. package/kotlin/ExpoSources/expo/modules/kotlin/jni/JavaScriptTypedArray.kt +81 -0
  185. package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +98 -0
  186. package/kotlin/ExpoSources/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +236 -0
  187. package/kotlin/ExpoSources/expo/modules/kotlin/records/Record.kt +12 -0
  188. package/kotlin/ExpoSources/expo/modules/kotlin/runtime/Runtime.kt +9 -0
  189. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObject.kt +50 -0
  190. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +57 -0
  191. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedRef.kt +19 -0
  192. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/ConcreteTypedArrays.kt +158 -0
  193. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/GenericTypedArray.kt +8 -0
  194. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArray.kt +29 -0
  195. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArrayIterator.kt +9 -0
  196. package/kotlin/ExpoSources/expo/modules/kotlin/types/AnyType.kt +155 -0
  197. package/kotlin/ExpoSources/expo/modules/kotlin/types/Either.kt +91 -0
  198. package/kotlin/ExpoSources/expo/modules/kotlin/types/Enumerable.kt +6 -0
  199. package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +54 -0
  200. package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +23 -0
  201. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +71 -0
  202. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +35 -0
  203. package/kotlin/README.md +13 -3
  204. package/kotlin/Sources/android/os/Build.kt +17 -0
  205. package/kotlin/Sources/android/os/Handler.kt +35 -0
  206. package/kotlin/Sources/android/os/Looper.kt +17 -0
  207. package/kotlin/Sources/android/os/MessageQueue.kt +56 -0
  208. package/kotlin/Sources/android/os/SystemClock.kt +14 -0
  209. package/kotlin/Sources/android/util/Log.kt +64 -0
  210. package/kotlin/Sources/java/security/MessageDigest.kt +114 -0
  211. package/kotlin/Sources/kotlin/text/StringFormat.kt +9 -0
  212. package/kotlin/Sources/org/json/JSON.kt +44 -0
  213. package/kotlin/fixtures/counter/Counter.d.kt.ts +1 -0
  214. package/kotlin/fixtures/counter/Counter.kt +10 -3
  215. package/kotlin/fixtures/counter/CounterApp.native.tsx +1 -1
  216. package/kotlin/fixtures/counter/vite.config.ts +2 -2
  217. package/kotlin/fixtures/headless-counter/Headless.kt +7 -6
  218. package/kotlin/fixtures/import-animation/Animation.d.kt.ts +7 -0
  219. package/kotlin/fixtures/import-animation/Animation.kt +80 -0
  220. package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +13 -0
  221. package/kotlin/fixtures/import-animation/README.md +24 -0
  222. package/kotlin/fixtures/import-animation/app/_layout.tsx +4 -0
  223. package/kotlin/fixtures/import-animation/app/index+spa.tsx +1 -0
  224. package/kotlin/fixtures/import-animation/app/routes.d.ts +18 -0
  225. package/kotlin/fixtures/import-animation/package.json +23 -0
  226. package/kotlin/fixtures/import-animation/tsconfig.json +20 -0
  227. package/kotlin/fixtures/import-animation/vite.config.ts +20 -0
  228. package/kotlin/fixtures/import-editor/Editor.d.kt.ts +7 -0
  229. package/kotlin/fixtures/import-editor/Editor.kt +59 -0
  230. package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +23 -0
  231. package/kotlin/fixtures/import-editor/README.md +27 -0
  232. package/kotlin/fixtures/import-editor/app/_layout.tsx +4 -0
  233. package/kotlin/fixtures/import-editor/app/index+spa.tsx +1 -0
  234. package/kotlin/fixtures/import-editor/package.json +23 -0
  235. package/kotlin/fixtures/import-editor/tsconfig.json +20 -0
  236. package/kotlin/fixtures/import-editor/vite.config.ts +20 -0
  237. package/kotlin/fixtures/import-effects/Effects.d.kt.ts +7 -0
  238. package/kotlin/fixtures/import-effects/Effects.kt +87 -0
  239. package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +13 -0
  240. package/kotlin/fixtures/import-effects/README.md +19 -0
  241. package/kotlin/fixtures/import-effects/app/_layout.tsx +4 -0
  242. package/kotlin/fixtures/import-effects/app/index+spa.tsx +1 -0
  243. package/kotlin/fixtures/import-effects/package.json +23 -0
  244. package/kotlin/fixtures/import-effects/tsconfig.json +20 -0
  245. package/kotlin/fixtures/import-effects/vite.config.ts +20 -0
  246. package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +13 -0
  247. package/kotlin/fixtures/import-layout/Layout.d.kt.ts +7 -0
  248. package/kotlin/fixtures/import-layout/Layout.kt +72 -0
  249. package/kotlin/fixtures/import-layout/README.md +24 -0
  250. package/kotlin/fixtures/import-layout/app/_layout.tsx +4 -0
  251. package/kotlin/fixtures/import-layout/app/index+spa.tsx +1 -0
  252. package/kotlin/fixtures/import-layout/package.json +23 -0
  253. package/kotlin/fixtures/import-layout/tsconfig.json +20 -0
  254. package/kotlin/fixtures/import-layout/vite.config.ts +20 -0
  255. package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +18 -0
  256. package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +7 -0
  257. package/kotlin/fixtures/import-navigation/Navigation.kt +104 -0
  258. package/kotlin/fixtures/import-navigation/README.md +31 -0
  259. package/kotlin/fixtures/import-navigation/app/_layout.tsx +4 -0
  260. package/kotlin/fixtures/import-navigation/app/index+spa.tsx +1 -0
  261. package/kotlin/fixtures/import-navigation/package.json +23 -0
  262. package/kotlin/fixtures/import-navigation/tsconfig.json +20 -0
  263. package/kotlin/fixtures/import-navigation/vite.config.ts +20 -0
  264. package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +29 -0
  265. package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +7 -0
  266. package/kotlin/fixtures/import-overlays/Overlays.kt +93 -0
  267. package/kotlin/fixtures/import-overlays/README.md +34 -0
  268. package/kotlin/fixtures/import-overlays/app/_layout.tsx +4 -0
  269. package/kotlin/fixtures/import-overlays/app/index+spa.tsx +1 -0
  270. package/kotlin/fixtures/import-overlays/package.json +23 -0
  271. package/kotlin/fixtures/import-overlays/tsconfig.json +20 -0
  272. package/kotlin/fixtures/import-overlays/vite.config.ts +20 -0
  273. package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +13 -0
  274. package/kotlin/fixtures/import-scroll/README.md +23 -0
  275. package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +7 -0
  276. package/kotlin/fixtures/import-scroll/Scroll.kt +91 -0
  277. package/kotlin/fixtures/import-scroll/app/_layout.tsx +4 -0
  278. package/kotlin/fixtures/import-scroll/app/index+spa.tsx +1 -0
  279. package/kotlin/fixtures/import-scroll/package.json +23 -0
  280. package/kotlin/fixtures/import-scroll/tsconfig.json +20 -0
  281. package/kotlin/fixtures/import-scroll/vite.config.ts +20 -0
  282. package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +44 -0
  283. package/kotlin/fixtures/import-selection/README.md +32 -0
  284. package/kotlin/fixtures/import-selection/Selection.d.kt.ts +8 -0
  285. package/kotlin/fixtures/import-selection/Selection.kt +78 -0
  286. package/kotlin/fixtures/import-selection/app/_layout.tsx +4 -0
  287. package/kotlin/fixtures/import-selection/app/index+spa.tsx +1 -0
  288. package/kotlin/fixtures/import-selection/package.json +23 -0
  289. package/kotlin/fixtures/import-selection/tsconfig.json +20 -0
  290. package/kotlin/fixtures/import-selection/vite.config.ts +20 -0
  291. package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +13 -0
  292. package/kotlin/fixtures/import-surfaces/README.md +22 -0
  293. package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +7 -0
  294. package/kotlin/fixtures/import-surfaces/Surfaces.kt +64 -0
  295. package/kotlin/fixtures/import-surfaces/app/_layout.tsx +4 -0
  296. package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +1 -0
  297. package/kotlin/fixtures/import-surfaces/package.json +23 -0
  298. package/kotlin/fixtures/import-surfaces/tsconfig.json +20 -0
  299. package/kotlin/fixtures/import-surfaces/vite.config.ts +20 -0
  300. package/kotlin/fixtures/import-values/ImportValues.native.tsx +35 -0
  301. package/kotlin/fixtures/import-values/README.md +23 -0
  302. package/kotlin/fixtures/import-values/Values.d.kt.ts +11 -0
  303. package/kotlin/fixtures/import-values/Values.kt +66 -0
  304. package/kotlin/fixtures/import-values/app/_layout.tsx +4 -0
  305. package/kotlin/fixtures/import-values/app/index+spa.tsx +1 -0
  306. package/kotlin/fixtures/import-values/package.json +23 -0
  307. package/kotlin/fixtures/import-values/tsconfig.json +20 -0
  308. package/kotlin/fixtures/import-values/vite.config.ts +20 -0
  309. package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +38 -0
  310. package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +36 -0
  311. package/kotlin/fixtures/kotlin-app-variants/Ime.kt +3 -1
  312. package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +50 -0
  313. package/kotlin/fork/NOTICE +6 -1
  314. package/kotlin/fork/README.md +15 -7
  315. package/kotlin/fork/build.sh +2 -0
  316. package/kotlin/fork/compose-worker-globals.patch +186 -4
  317. package/kotlin/fork/fork.json +2 -2
  318. package/kotlin/fork/skiko-worker-clock.patch +12 -0
  319. package/kotlin/toolchain.json +12 -12
  320. package/kotlin/tools/expo-types.main.kts +115 -0
  321. package/package.json +17 -23
  322. package/scripts/dev-server-scanner.ts +92 -66
  323. package/skills/contrast/SKILL.md +2 -2
  324. package/skills/peach-debug/SKILL.md +1 -1
  325. package/skills/peach-perf/SKILL.md +1 -1
  326. package/skills/peach-setup/SKILL.md +2 -1
  327. package/skills/peach-test/SKILL.md +8 -0
  328. package/src/assetCatalogContract.ts +43 -1
  329. package/src/bridge-contract-input.ts +46 -19
  330. package/src/bridge-contract.ts +0 -1
  331. package/src/bundle-channel.mjs +197 -84
  332. package/src/bundleGlobalFooter.ts +38 -0
  333. package/src/capture-contract.ts +107 -33
  334. package/src/cloud-contract.ts +5 -1
  335. package/src/cloud.ts +5 -2
  336. package/src/config.ts +22 -3
  337. package/src/configured-bundle-producer.ts +1 -1
  338. package/src/desktop-host-delivery.ts +95 -1
  339. package/src/expo-kotlin-bundle.ts +29 -0
  340. package/src/expo-kotlin-host.ts +201 -0
  341. package/src/expo-swift-host.ts +96 -76
  342. package/src/expoKotlinContract.ts +70 -0
  343. package/src/expoSwiftContract.ts +4 -25
  344. package/src/home-paths.ts +7 -4
  345. package/src/host/bridge-host.ts +23 -3
  346. package/src/host/fetch-proxy-handler.ts +13 -0
  347. package/src/host/fetch-proxy-overrides.ts +11 -0
  348. package/src/host/replacement-module-handler.ts +5 -2
  349. package/src/index.ts +3 -1
  350. package/src/kotlin-host.ts +463 -19
  351. package/src/metro-plugin.ts +56 -28
  352. package/src/metro-production-bundle.ts +2 -2
  353. package/src/native-app-identity-project.ts +190 -0
  354. package/src/native-app-identity.ts +398 -34
  355. package/src/native-firebase-config.ts +69 -15
  356. package/src/native-seam-manifest.ts +6 -0
  357. package/src/one-widget-discovery.ts +2 -1
  358. package/src/openstep-plist.ts +107 -0
  359. package/src/react-native-host-modules.ts +4 -0
  360. package/src/runtime-assets.ts +2 -2
  361. package/src/sim-client.ts +2 -2
  362. package/src/swift-binary-modules.ts +3 -1
  363. package/src/swift-compile.ts +286 -38
  364. package/src/swift-distribution-contract.ts +4 -0
  365. package/src/swift-distribution.lock.json +123 -12
  366. package/src/swift-distribution.ts +7 -3
  367. package/src/swift-host.ts +298 -83
  368. package/src/swift-package-manifest.ts +29 -2
  369. package/src/swift-package.ts +180 -10
  370. package/src/swift-packages.ts +4 -0
  371. package/src/swift-standin-emit.ts +4 -1
  372. package/src/swift-standins.ts +274 -15
  373. package/src/swift-submit.ts +62 -7
  374. package/src/swift-toolchain.ts +6 -1
  375. package/src/swiftContract.ts +126 -3
  376. package/src/vite-plugin-one.ts +13 -16
  377. package/src/vite-plugin-swift.ts +4 -5
  378. package/src/vite-plugin.ts +360 -144
  379. package/src/vite.d.ts +1 -1
  380. package/src/worker-system-chunks.ts +221 -0
  381. package/src/worklet-executable.ts +348 -38
  382. package/src/worklets-babel.ts +1 -1
  383. package/src/xcode-project.ts +243 -127
  384. package/dist-lib/agent-identity.cjs +0 -39
  385. package/dist-lib/agent-sessions.cjs +0 -760
  386. package/dist-lib/cli-constants.cjs +0 -32
  387. package/dist-lib/render-mode.cjs +0 -44
  388. package/kotlin/AppSources/android/view/View.kt +0 -74
  389. package/kotlin/AppSources/android/widget/FrameLayout.kt +0 -6
  390. package/src/render-mode.ts +0 -15
  391. /package/kotlin/{AppSources → AndroidViewSources}/android/content/Context.kt +0 -0
  392. /package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Configuration.kt +0 -0
  393. /package/kotlin/{AppSources → AndroidViewSources}/android/graphics/Color.kt +0 -0
  394. /package/kotlin/{AppSources → AndroidViewSources}/android/util/DisplayMetrics.kt +0 -0
  395. /package/kotlin/{AppSources → AndroidViewSources}/dev/peach/app/JavaFormat.kt +0 -0
  396. /package/kotlin/{AppSources → Sources}/java/lang/Runnable.kt +0 -0
@@ -1,55 +1,270 @@
1
- /*! rnx v0.1.939 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! peach v0.1.1399 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/worklet-executable.ts
4
4
  import { parse } from "acorn";
5
5
  function isNode(value) {
6
6
  return value !== null && typeof value === "object" && typeof Reflect.get(value, "type") === "string";
7
7
  }
8
- function walk(node, visit) {
9
- visit(node);
10
- for (const value of Object.values(node)) {
11
- if (isNode(value)) walk(value, visit);
12
- else if (Array.isArray(value)) {
13
- for (const child of value) if (isNode(child)) walk(child, visit);
14
- }
15
- }
8
+ function childNodes(value) {
9
+ return Array.isArray(value) ? value.filter(isNode) : [];
10
+ }
11
+ function identifierName(node) {
12
+ if (!isNode(node) || node.type !== "Identifier") return void 0;
13
+ const name = Reflect.get(node, "name");
14
+ return typeof name === "string" ? name : void 0;
16
15
  }
17
16
  function propertyName(node) {
18
17
  if (!isNode(node)) return void 0;
19
18
  const name = Reflect.get(node, node.type === "Identifier" ? "name" : "value");
20
19
  return typeof name === "string" ? name : void 0;
21
20
  }
22
- function workletExecutableBodies(syntax) {
23
- if (!isNode(syntax)) throw new Error("peach: expected worklet syntax");
24
- const tree = syntax;
25
- const initNames = /* @__PURE__ */ new Set();
26
- const objects = /* @__PURE__ */ new Set();
27
- walk(tree, (node) => {
28
- if (node.type !== "AssignmentExpression") return;
29
- const left = Reflect.get(node, "left");
30
- if (!isNode(left) || left.type !== "MemberExpression" || propertyName(Reflect.get(left, "property")) !== "__initData")
21
+ function keyName(owner, key) {
22
+ if (Reflect.get(owner, "computed") === true && isNode(key) && key.type === "Identifier")
23
+ return void 0;
24
+ return propertyName(key);
25
+ }
26
+ function patternNames(node) {
27
+ if (!isNode(node)) return [];
28
+ switch (node.type) {
29
+ case "Identifier": {
30
+ const name = identifierName(node);
31
+ return name === void 0 ? [] : [name];
32
+ }
33
+ case "AssignmentPattern":
34
+ return patternNames(Reflect.get(node, "left"));
35
+ case "RestElement":
36
+ return patternNames(Reflect.get(node, "argument"));
37
+ case "ArrayPattern":
38
+ return childNodes(Reflect.get(node, "elements")).flatMap(patternNames);
39
+ case "ObjectPattern":
40
+ return childNodes(Reflect.get(node, "properties")).flatMap(
41
+ (property) => patternNames(
42
+ property.type === "Property" || property.type === "ObjectProperty" ? Reflect.get(property, "value") : property
43
+ )
44
+ );
45
+ default:
46
+ return [];
47
+ }
48
+ }
49
+ var FUNCTION_TYPES = /* @__PURE__ */ new Set([
50
+ "FunctionDeclaration",
51
+ "FunctionExpression",
52
+ "ArrowFunctionExpression"
53
+ ]);
54
+ var MAX_RESOLUTION_DEPTH = 32;
55
+ function newScope(parent, hoist) {
56
+ return { parent, hoist, names: /* @__PURE__ */ new Map() };
57
+ }
58
+ function hoistScope(scope) {
59
+ let current = scope;
60
+ while (!current.hoist && current.parent) current = current.parent;
61
+ return current;
62
+ }
63
+ function declare(scope, name, binding) {
64
+ scope.names.set(name, scope.names.has(name) ? { kind: "opaque" } : binding);
65
+ }
66
+ function declareOpaque(scope, names) {
67
+ for (const name of names) declare(scope, name, { kind: "opaque" });
68
+ }
69
+ function lookup(scope, name) {
70
+ for (let current = scope; current; current = current.parent) {
71
+ const binding = current.names.get(name);
72
+ if (binding) return binding;
73
+ }
74
+ return void 0;
75
+ }
76
+ function declareParam(inner, fn, index, param) {
77
+ const name = identifierName(param);
78
+ if (name !== void 0) {
79
+ declare(inner, name, { kind: "param", fn, index });
80
+ return;
81
+ }
82
+ if (!isNode(param) || param.type !== "ObjectPattern") {
83
+ declareOpaque(inner, patternNames(param));
84
+ return;
85
+ }
86
+ for (const property of childNodes(Reflect.get(param, "properties"))) {
87
+ const key = keyName(property, Reflect.get(property, "key"));
88
+ const value = Reflect.get(property, "value");
89
+ const valueName = identifierName(value);
90
+ if (key !== void 0 && valueName !== void 0 && ["Property", "ObjectProperty"].includes(property.type))
91
+ declare(inner, valueName, { kind: "param", fn, index, key });
92
+ else
93
+ declareOpaque(
94
+ inner,
95
+ patternNames(property.type === "RestElement" ? property : value)
96
+ );
97
+ }
98
+ }
99
+ function enter(node, scope) {
100
+ switch (node.type) {
101
+ case "FunctionDeclaration":
102
+ case "FunctionExpression":
103
+ case "ArrowFunctionExpression": {
104
+ const inner = newScope(scope, true);
105
+ const params = Reflect.get(node, "params");
106
+ if (Array.isArray(params)) {
107
+ params.forEach((param, index) => declareParam(inner, node, index, param));
108
+ }
109
+ const id = Reflect.get(node, "id");
110
+ if (node.type === "FunctionExpression") declareOpaque(inner, patternNames(id));
111
+ if (node.type === "FunctionDeclaration") {
112
+ declareOpaque(scope, patternNames(id));
113
+ declareOpaque(hoistScope(scope), patternNames(id));
114
+ }
115
+ return inner;
116
+ }
117
+ case "BlockStatement":
118
+ case "ForStatement":
119
+ case "ForInStatement":
120
+ case "ForOfStatement":
121
+ case "SwitchStatement":
122
+ case "StaticBlock":
123
+ return newScope(scope, false);
124
+ case "CatchClause": {
125
+ const inner = newScope(scope, false);
126
+ declareOpaque(inner, patternNames(Reflect.get(node, "param")));
127
+ return inner;
128
+ }
129
+ case "VariableDeclaration": {
130
+ const target = Reflect.get(node, "kind") === "var" ? hoistScope(scope) : scope;
131
+ for (const declarator of childNodes(Reflect.get(node, "declarations"))) {
132
+ const id = Reflect.get(declarator, "id");
133
+ const init = Reflect.get(declarator, "init");
134
+ const name = identifierName(id);
135
+ if (name !== void 0 && isNode(init))
136
+ declare(target, name, { kind: "value", init, scope });
137
+ else declareOpaque(target, patternNames(id));
138
+ }
139
+ return scope;
140
+ }
141
+ case "ImportDeclaration":
142
+ for (const specifier of childNodes(Reflect.get(node, "specifiers")))
143
+ declareOpaque(scope, patternNames(Reflect.get(specifier, "local")));
144
+ return scope;
145
+ case "ClassDeclaration":
146
+ declareOpaque(scope, patternNames(Reflect.get(node, "id")));
147
+ return scope;
148
+ default:
149
+ return scope;
150
+ }
151
+ }
152
+ function recordWrites(target, scope, collection) {
153
+ for (const name of patternNames(target)) collection.writes.push({ name, scope });
154
+ }
155
+ function record(node, scope, collection) {
156
+ switch (node.type) {
157
+ case "AssignmentExpression": {
158
+ const left = Reflect.get(node, "left");
159
+ const right = Reflect.get(node, "right");
160
+ if (isNode(left) && left.type === "MemberExpression" && keyName(left, Reflect.get(left, "property")) === "__initData" && isNode(right))
161
+ collection.inits.push({ value: right, scope });
162
+ recordWrites(left, scope, collection);
31
163
  return;
32
- const right = Reflect.get(node, "right");
33
- if (!isNode(right)) return;
34
- if (right.type === "ObjectExpression") objects.add(right);
35
- else if (right.type === "Identifier") {
36
- const name = propertyName(right);
37
- if (name) initNames.add(name);
38
164
  }
39
- });
40
- walk(tree, (node) => {
41
- if (node.type !== "VariableDeclarator") return;
42
- const name = propertyName(Reflect.get(node, "id"));
43
- const init = Reflect.get(node, "init");
44
- if (name && initNames.has(name) && isNode(init) && init.type === "ObjectExpression") {
45
- objects.add(init);
165
+ case "UpdateExpression":
166
+ recordWrites(Reflect.get(node, "argument"), scope, collection);
167
+ return;
168
+ case "ForInStatement":
169
+ case "ForOfStatement":
170
+ recordWrites(Reflect.get(node, "left"), scope, collection);
171
+ return;
172
+ case "CallExpression": {
173
+ const callee = Reflect.get(node, "callee");
174
+ if (isNode(callee) && FUNCTION_TYPES.has(callee.type))
175
+ collection.immediate.set(callee, { call: node, scope });
176
+ return;
46
177
  }
47
- });
178
+ default:
179
+ return;
180
+ }
181
+ }
182
+ function visit(node, scope, collection) {
183
+ record(node, scope, collection);
184
+ const inner = enter(node, scope);
185
+ for (const value of Object.values(node)) {
186
+ if (isNode(value)) visit(value, inner, collection);
187
+ else for (const child of childNodes(value)) visit(child, inner, collection);
188
+ }
189
+ }
190
+ function collectInitData(root) {
191
+ const collection = {
192
+ inits: [],
193
+ immediate: /* @__PURE__ */ new Map(),
194
+ writes: [],
195
+ reassigned: /* @__PURE__ */ new Set()
196
+ };
197
+ visit(root, newScope(void 0, true), collection);
198
+ for (const { name, scope } of collection.writes) {
199
+ const binding = lookup(scope, name);
200
+ if (binding) collection.reassigned.add(binding);
201
+ }
202
+ return collection;
203
+ }
204
+ function immediateArgument(fn, index, collection) {
205
+ const immediate = collection.immediate.get(fn);
206
+ const args = immediate && Reflect.get(immediate.call, "arguments");
207
+ if (!immediate || !Array.isArray(args)) return void 0;
208
+ const preceding = args.slice(0, index + 1);
209
+ if (preceding.some((arg) => isNode(arg) && arg.type === "SpreadElement"))
210
+ return void 0;
211
+ return { argument: args[index], scope: immediate.scope };
212
+ }
213
+ function propertyValue(object, name) {
214
+ let value;
215
+ for (const property of childNodes(Reflect.get(object, "properties"))) {
216
+ if (property.type === "SpreadElement") return void 0;
217
+ if (!["Property", "ObjectProperty"].includes(property.type)) continue;
218
+ if (keyName(property, Reflect.get(property, "key")) !== name) continue;
219
+ const next = Reflect.get(property, "value");
220
+ value = isNode(next) ? next : void 0;
221
+ }
222
+ return value;
223
+ }
224
+ function resolveProperty(owner, name, collection, depth) {
225
+ if (!owner) return void 0;
226
+ const value = propertyValue(owner.object, name);
227
+ return value && resolveObject(value, owner.scope, collection, depth + 1);
228
+ }
229
+ function resolveObject(expression, scope, collection, depth) {
230
+ if (depth > MAX_RESOLUTION_DEPTH) return void 0;
231
+ if (expression.type === "ObjectExpression") return { object: expression, scope };
232
+ if (expression.type === "Identifier") {
233
+ const name = identifierName(expression);
234
+ const binding = name === void 0 ? void 0 : lookup(scope, name);
235
+ if (!binding || collection.reassigned.has(binding)) return void 0;
236
+ if (binding.kind === "value")
237
+ return resolveObject(binding.init, binding.scope, collection, depth + 1);
238
+ if (binding.kind === "param") {
239
+ const passed = immediateArgument(binding.fn, binding.index, collection);
240
+ if (!passed || !isNode(passed.argument)) return void 0;
241
+ const argument = resolveObject(passed.argument, passed.scope, collection, depth + 1);
242
+ return binding.key === void 0 ? argument : resolveProperty(argument, binding.key, collection, depth);
243
+ }
244
+ return void 0;
245
+ }
246
+ if (expression.type === "MemberExpression") {
247
+ const name = keyName(expression, Reflect.get(expression, "property"));
248
+ const object = Reflect.get(expression, "object");
249
+ if (name === void 0 || !isNode(object)) return void 0;
250
+ const owner = resolveObject(object, scope, collection, depth + 1);
251
+ return resolveProperty(owner, name, collection, depth);
252
+ }
253
+ return void 0;
254
+ }
255
+ function workletExecutableBodies(syntax, includeCompiled = false) {
256
+ if (!isNode(syntax)) throw new Error("peach: expected worklet syntax");
257
+ const collection = collectInitData(syntax);
258
+ const objects = /* @__PURE__ */ new Set();
259
+ for (const { value, scope } of collection.inits) {
260
+ const resolved = resolveObject(value, scope, collection, 0);
261
+ if (resolved) objects.add(resolved.object);
262
+ }
48
263
  const bodies = [];
49
264
  for (const object of objects) {
50
265
  const properties = Reflect.get(object, "properties");
51
266
  if (!Array.isArray(properties)) continue;
52
- if (properties.some(
267
+ if (!includeCompiled && properties.some(
53
268
  (property2) => isNode(property2) && propertyName(Reflect.get(property2, "key")) === "__peachExecutable"
54
269
  ))
55
270
  continue;
package/install.sh CHANGED
@@ -178,7 +178,16 @@ if [ "${PEACH_NO_MODIFY_PATH:-0}" = "1" ]; then
178
178
  else
179
179
  case "${SHELL:-}" in
180
180
  */zsh) update_shell_profile "$HOME/.zshrc" zsh ;;
181
- */bash) update_shell_profile "$HOME/.bashrc" bash ;;
181
+ */bash)
182
+ update_shell_profile "$HOME/.bashrc" bash
183
+ # bash login shells read only the first readable profile in this order.
184
+ for profile in "$HOME/.bash_profile" "$HOME/.bash_login" "$HOME/.profile"; do
185
+ if [ -r "$profile" ] || [ "$profile" = "$HOME/.profile" ]; then
186
+ update_shell_profile "$profile" bash
187
+ break
188
+ fi
189
+ done
190
+ ;;
182
191
  *) update_shell_profile "$HOME/.profile" "" ;;
183
192
  esac
184
193
  fi
@@ -2,14 +2,14 @@ package android.content.res
2
2
 
3
3
  import android.util.DisplayMetrics
4
4
  import dev.peach.app.javaFormat
5
- import dev.peach.app.peachAppArrays
6
- import dev.peach.app.peachAppColors
7
- import dev.peach.app.peachAppPlurals
8
- import dev.peach.app.peachAppStrings
9
5
 
10
6
  class Resources internal constructor(
11
7
  val configuration: Configuration,
12
8
  val displayMetrics: DisplayMetrics,
9
+ private val strings: Map<Int, Map<String, String>>,
10
+ private val plurals: Map<Int, Map<String, Map<String, String>>>,
11
+ private val arrays: Map<Int, Map<String, List<String>>>,
12
+ private val colors: Map<Int, IntArray>,
13
13
  ) {
14
14
  class NotFoundException(name: String) : RuntimeException(name)
15
15
 
@@ -18,7 +18,7 @@ class Resources internal constructor(
18
18
  class Theme internal constructor()
19
19
 
20
20
  fun getString(id: Int): String =
21
- resolve(peachAppStrings[id]) ?: throw NotFoundException("String resource ID #0x${id.toString(16)}")
21
+ resolve(strings[id]) ?: throw NotFoundException("String resource ID #0x${id.toString(16)}")
22
22
 
23
23
  fun getString(id: Int, vararg formatArgs: Any?): String =
24
24
  javaFormat(configuration.localeTag, getString(id), formatArgs)
@@ -26,7 +26,7 @@ class Resources internal constructor(
26
26
  // ResourcesImpl.getQuantityText: the item the locale's plural rule
27
27
  // selects for the quantity, then the other item
28
28
  fun getQuantityString(id: Int, quantity: Int): String {
29
- val items = resolve(peachAppPlurals[id])
29
+ val items = resolve(plurals[id])
30
30
  ?: throw NotFoundException("Plural resource ID #0x${id.toString(16)}")
31
31
  val rule = pluralRule(configuration.localeTag, quantity)
32
32
  return items[rule] ?: items["other"]
@@ -37,14 +37,14 @@ class Resources internal constructor(
37
37
  javaFormat(configuration.localeTag, getQuantityString(id, quantity), formatArgs)
38
38
 
39
39
  fun getStringArray(id: Int): Array<String> =
40
- resolve(peachAppArrays[id])?.toTypedArray()
40
+ resolve(arrays[id])?.toTypedArray()
41
41
  ?: throw NotFoundException("String array resource ID #0x${id.toString(16)}")
42
42
 
43
43
  // the color the configuration's night mode selects, values-night over
44
44
  // values
45
45
  fun getColor(id: Int, theme: Theme?): Int {
46
- val colors = peachAppColors[id] ?: throw NotFoundException("Resource ID #0x${id.toString(16)}")
47
- return colors[if (configuration.isNight()) 1 else 0]
46
+ val values = colors[id] ?: throw NotFoundException("Resource ID #0x${id.toString(16)}")
47
+ return values[if (configuration.isNight()) 1 else 0]
48
48
  }
49
49
 
50
50
  @Deprecated("Use getColor(int, Theme) instead.")
@@ -0,0 +1,20 @@
1
+ package android.graphics
2
+
3
+ // the Android view's canvas draws into its existing native scene. module-only
4
+ // processes carry this contract without linking a renderer.
5
+ internal interface ViewCanvas {
6
+ fun drawColor(color: Int)
7
+ fun save(): Int
8
+ fun restoreToCount(count: Int)
9
+ fun translate(dx: Float, dy: Float)
10
+ fun clipRect(left: Float, top: Float, right: Float, bottom: Float): Boolean
11
+ }
12
+
13
+ class Canvas internal constructor(private val target: ViewCanvas) {
14
+ fun drawColor(color: Int) = target.drawColor(color)
15
+ fun save(): Int = target.save()
16
+ fun restoreToCount(saveCount: Int) = target.restoreToCount(saveCount)
17
+ fun translate(dx: Float, dy: Float) = target.translate(dx, dy)
18
+ fun clipRect(left: Float, top: Float, right: Float, bottom: Float): Boolean = target.clipRect(left, top, right, bottom)
19
+ fun clipRect(left: Int, top: Int, right: Int, bottom: Int): Boolean = clipRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
20
+ }
@@ -0,0 +1,211 @@
1
+ package android.view
2
+
3
+ import android.content.Context
4
+ import android.content.res.Resources
5
+ import android.graphics.Canvas
6
+
7
+ open class View(val context: Context) {
8
+ val resources: Resources get() = context.resources
9
+ var parent: ViewGroup? = null
10
+ internal set
11
+ var layoutParams: ViewGroup.LayoutParams? = null
12
+ internal var attachedWindow: Any? = null
13
+
14
+ var left: Int = 0
15
+ private set
16
+ var top: Int = 0
17
+ private set
18
+ var right: Int = 0
19
+ private set
20
+ var bottom: Int = 0
21
+ private set
22
+ val width: Int get() = right - left
23
+ val height: Int get() = bottom - top
24
+ var measuredWidth: Int = 0
25
+ private set
26
+ var measuredHeight: Int = 0
27
+ private set
28
+ var minimumWidth: Int = 0
29
+ var minimumHeight: Int = 0
30
+ var paddingLeft: Int = 0
31
+ private set
32
+ var paddingTop: Int = 0
33
+ private set
34
+ var paddingRight: Int = 0
35
+ private set
36
+ var paddingBottom: Int = 0
37
+ private set
38
+ var isLayoutRequested: Boolean = true
39
+ private set
40
+ val isLaidOut: Boolean get() = laidOut
41
+ private var laidOut = false
42
+ private var skipDraw = false
43
+ private var backgroundColor: Int = 0
44
+ internal var invalidateHost: ((Boolean) -> Unit)? = null
45
+
46
+ open fun invalidate() {
47
+ invalidateHost?.invoke(false) ?: parent?.invalidate()
48
+ }
49
+
50
+ open fun requestLayout() {
51
+ isLayoutRequested = true
52
+ parent?.requestLayout() ?: invalidateHost?.invoke(true)
53
+ }
54
+
55
+ open fun forceLayout() { isLayoutRequested = true }
56
+
57
+ fun setWillNotDraw(willNotDraw: Boolean) { skipDraw = willNotDraw }
58
+ fun willNotDraw(): Boolean = skipDraw
59
+ fun setBackgroundColor(color: Int) { backgroundColor = color; invalidate() }
60
+ fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
61
+ paddingLeft = left; paddingTop = top; paddingRight = right; paddingBottom = bottom
62
+ requestLayout()
63
+ }
64
+
65
+ fun measure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
66
+ onMeasure(widthMeasureSpec, heightMeasureSpec)
67
+ }
68
+
69
+ protected open fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
70
+ setMeasuredDimension(getDefaultSize(minimumWidth, widthMeasureSpec), getDefaultSize(minimumHeight, heightMeasureSpec))
71
+ }
72
+
73
+ protected fun setMeasuredDimension(width: Int, height: Int) {
74
+ measuredWidth = width; measuredHeight = height
75
+ }
76
+
77
+ fun layout(l: Int, t: Int, r: Int, b: Int) {
78
+ val oldWidth = width
79
+ val oldHeight = height
80
+ val changed = left != l || top != t || right != r || bottom != b
81
+ left = l; top = t; right = r; bottom = b
82
+ if (oldWidth != width || oldHeight != height) onSizeChanged(width, height, oldWidth, oldHeight)
83
+ if (changed || isLayoutRequested) onLayout(changed, l, t, r, b)
84
+ isLayoutRequested = false
85
+ laidOut = true
86
+ }
87
+
88
+ protected open fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {}
89
+ protected open fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {}
90
+ protected open fun onDraw(canvas: Canvas) {}
91
+ protected open fun dispatchDraw(canvas: Canvas) {}
92
+
93
+ open fun draw(canvas: Canvas) {
94
+ if (backgroundColor != 0) canvas.drawColor(backgroundColor)
95
+ if (!skipDraw) onDraw(canvas)
96
+ dispatchDraw(canvas)
97
+ }
98
+
99
+ object MeasureSpec {
100
+ const val UNSPECIFIED = 0
101
+ const val EXACTLY = 0x40000000
102
+ const val AT_MOST = -0x80000000
103
+ fun makeMeasureSpec(size: Int, mode: Int): Int = (size and 0x3fffffff) or mode
104
+ fun getMode(spec: Int): Int = spec and -0x40000000
105
+ fun getSize(spec: Int): Int = spec and 0x3fffffff
106
+ }
107
+
108
+ companion object {
109
+ fun getDefaultSize(size: Int, measureSpec: Int): Int =
110
+ if (MeasureSpec.getMode(measureSpec) == MeasureSpec.UNSPECIFIED) size else MeasureSpec.getSize(measureSpec)
111
+
112
+ fun resolveSize(size: Int, measureSpec: Int): Int = when (MeasureSpec.getMode(measureSpec)) {
113
+ MeasureSpec.EXACTLY -> MeasureSpec.getSize(measureSpec)
114
+ MeasureSpec.AT_MOST -> minOf(size, MeasureSpec.getSize(measureSpec))
115
+ else -> size
116
+ }
117
+ }
118
+
119
+ val isAttachedToWindow: Boolean get() = attachedWindow != null
120
+
121
+ // view root dispatches attach through the tree once the window is added
122
+ internal open fun dispatchAttachedToWindow(window: Any) {
123
+ attachedWindow = window
124
+ onAttachedToWindow()
125
+ }
126
+
127
+ internal open fun dispatchDetachedFromWindow() {
128
+ onDetachedFromWindow()
129
+ attachedWindow = null
130
+ }
131
+
132
+ protected open fun onAttachedToWindow() {}
133
+ protected open fun onDetachedFromWindow() {}
134
+ }
135
+
136
+ open class ViewGroup(context: Context) : View(context) {
137
+ open class LayoutParams(val width: Int, val height: Int) {
138
+ companion object {
139
+ const val MATCH_PARENT = -1
140
+ const val WRAP_CONTENT = -2
141
+ }
142
+ }
143
+
144
+ init { setWillNotDraw(true) }
145
+
146
+ private val children = mutableListOf<View>()
147
+
148
+ val childCount: Int get() = children.size
149
+ fun getChildAt(index: Int): View? = children.getOrNull(index)
150
+
151
+ protected open fun generateDefaultLayoutParams(): LayoutParams =
152
+ LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
153
+
154
+ fun addView(child: View, params: LayoutParams) {
155
+ child.layoutParams = params
156
+ addView(child)
157
+ }
158
+
159
+ open fun addView(child: View) {
160
+ check(child.parent == null) {
161
+ "The specified child already has a parent. You must call removeView() on the child's parent first."
162
+ }
163
+ if (child.layoutParams == null) child.layoutParams = generateDefaultLayoutParams()
164
+ children += child
165
+ child.parent = this
166
+ attachedWindow?.let { child.dispatchAttachedToWindow(it) }
167
+ requestLayout()
168
+ }
169
+
170
+ fun removeAllViews() {
171
+ for (child in children) {
172
+ if (child.isAttachedToWindow) child.dispatchDetachedFromWindow()
173
+ child.parent = null
174
+ }
175
+ children.clear()
176
+ requestLayout()
177
+ }
178
+
179
+ override fun dispatchDraw(canvas: Canvas) {
180
+ for (child in children) {
181
+ val checkpoint = canvas.save()
182
+ canvas.translate(child.left.toFloat(), child.top.toFloat())
183
+ canvas.clipRect(0f, 0f, child.width.toFloat(), child.height.toFloat())
184
+ child.draw(canvas)
185
+ canvas.restoreToCount(checkpoint)
186
+ }
187
+ }
188
+
189
+ override fun dispatchAttachedToWindow(window: Any) {
190
+ super.dispatchAttachedToWindow(window)
191
+ for (child in children.toList()) child.dispatchAttachedToWindow(window)
192
+ }
193
+
194
+ override fun dispatchDetachedFromWindow() {
195
+ for (child in children.toList()) child.dispatchDetachedFromWindow()
196
+ super.dispatchDetachedFromWindow()
197
+ }
198
+
199
+ companion object {
200
+ fun getChildMeasureSpec(spec: Int, padding: Int, childDimension: Int): Int {
201
+ if (childDimension >= 0) return MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY)
202
+ val mode = MeasureSpec.getMode(spec)
203
+ val size = (MeasureSpec.getSize(spec) - padding).coerceAtLeast(0)
204
+ return MeasureSpec.makeMeasureSpec(if (mode == MeasureSpec.UNSPECIFIED) 0 else size, when {
205
+ mode == MeasureSpec.UNSPECIFIED -> MeasureSpec.UNSPECIFIED
206
+ childDimension == LayoutParams.MATCH_PARENT && mode == MeasureSpec.EXACTLY -> MeasureSpec.EXACTLY
207
+ else -> MeasureSpec.AT_MOST
208
+ })
209
+ }
210
+ }
211
+ }
@@ -0,0 +1,61 @@
1
+ package android.widget
2
+
3
+ import android.content.Context
4
+ import android.view.View
5
+ import android.view.ViewGroup
6
+
7
+ open class FrameLayout(context: Context) : ViewGroup(context) {
8
+ private val matchParentChildren = mutableListOf<View>()
9
+
10
+ override fun generateDefaultLayoutParams(): LayoutParams =
11
+ LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
12
+
13
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
14
+ val horizontalPadding = paddingLeft + paddingRight
15
+ val verticalPadding = paddingTop + paddingBottom
16
+ val measureMatchParentChildren = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
17
+ MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY
18
+ matchParentChildren.clear()
19
+ var maxWidth = 0
20
+ var maxHeight = 0
21
+ for (index in 0 until childCount) {
22
+ val child = checkNotNull(getChildAt(index))
23
+ val params = checkNotNull(child.layoutParams)
24
+ child.measure(
25
+ getChildMeasureSpec(widthMeasureSpec, horizontalPadding, params.width),
26
+ getChildMeasureSpec(heightMeasureSpec, verticalPadding, params.height),
27
+ )
28
+ maxWidth = maxOf(maxWidth, child.measuredWidth)
29
+ maxHeight = maxOf(maxHeight, child.measuredHeight)
30
+ if (measureMatchParentChildren &&
31
+ (params.width == LayoutParams.MATCH_PARENT || params.height == LayoutParams.MATCH_PARENT)) {
32
+ matchParentChildren += child
33
+ }
34
+ }
35
+ setMeasuredDimension(
36
+ View.resolveSize(maxOf(minimumWidth, maxWidth + horizontalPadding), widthMeasureSpec),
37
+ View.resolveSize(maxOf(minimumHeight, maxHeight + verticalPadding), heightMeasureSpec),
38
+ )
39
+ // android repeats measurement only when multiple children match the parent.
40
+ if (matchParentChildren.size > 1) {
41
+ for (child in matchParentChildren) {
42
+ val params = checkNotNull(child.layoutParams)
43
+ child.measure(
44
+ if (params.width == LayoutParams.MATCH_PARENT)
45
+ MeasureSpec.makeMeasureSpec((measuredWidth - horizontalPadding).coerceAtLeast(0), MeasureSpec.EXACTLY)
46
+ else getChildMeasureSpec(widthMeasureSpec, horizontalPadding, params.width),
47
+ if (params.height == LayoutParams.MATCH_PARENT)
48
+ MeasureSpec.makeMeasureSpec((measuredHeight - verticalPadding).coerceAtLeast(0), MeasureSpec.EXACTLY)
49
+ else getChildMeasureSpec(heightMeasureSpec, verticalPadding, params.height),
50
+ )
51
+ }
52
+ }
53
+ }
54
+
55
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
56
+ for (index in 0 until childCount) {
57
+ val child = checkNotNull(getChildAt(index))
58
+ child.layout(paddingLeft, paddingTop, paddingLeft + child.measuredWidth, paddingTop + child.measuredHeight)
59
+ }
60
+ }
61
+ }