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.
- package/README.md +28 -22
- package/cli/app-catalog.ts +29 -14
- package/cli/app-fonts.ts +5 -3
- package/cli/bridge-flow-runner.ts +40 -29
- package/cli/cloud-client.ts +57 -21
- package/cli/cloud-test-tunnel.ts +12 -18
- package/cli/commands/agent.ts +1 -1
- package/cli/commands/app-fonts.ts +3 -3
- package/cli/commands/assert.ts +8 -8
- package/cli/commands/auth.ts +8 -3
- package/cli/commands/box/bundle-plane.ts +13 -1
- package/cli/commands/box.ts +16 -5
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +125 -71
- package/cli/commands/cpu-profile.ts +45 -1
- package/cli/commands/daemon.ts +131 -33
- package/cli/commands/debug.ts +24 -17
- package/cli/commands/desktop.ts +7 -1
- package/cli/commands/detect.ts +101 -0
- package/cli/commands/detox.ts +6 -6
- package/cli/commands/device.ts +12 -12
- package/cli/commands/electron.ts +32 -14
- package/cli/commands/flow.ts +49 -41
- package/cli/commands/guest-host.ts +39 -1
- package/cli/commands/inspect/core.ts +14 -8
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/settle.ts +5 -3
- package/cli/commands/inspect/settling.ts +229 -44
- package/cli/commands/inspect/wait-idle.ts +3 -2
- package/cli/commands/inspect.ts +105 -93
- package/cli/commands/install-cli.ts +36 -15
- package/cli/commands/install-desktop.ts +68 -195
- package/cli/commands/kotlin.ts +6 -5
- package/cli/commands/login.ts +5 -5
- package/cli/commands/maestro-compare.ts +554 -0
- package/cli/commands/maestro-generate.ts +6 -3
- package/cli/commands/maestro.ts +22 -0
- package/cli/commands/mode.ts +2 -2
- package/cli/commands/no-bridge-hint.ts +6 -2
- package/cli/commands/platform.ts +35 -6
- package/cli/commands/preview.ts +6 -0
- package/cli/commands/project-report.ts +10 -12
- package/cli/commands/record.ts +37 -37
- package/cli/commands/runtime.ts +9 -9
- package/cli/commands/screenshot-layers.ts +4 -4
- package/cli/commands/screenshot-mode.ts +2 -2
- package/cli/commands/screenshot.ts +8 -8
- package/cli/commands/screenshots-capture.ts +2 -2
- package/cli/commands/serve.ts +9 -12
- package/cli/commands/setup.ts +29 -14
- package/cli/commands/shell-boolean-mode.ts +2 -2
- package/cli/commands/show-touches-mode.ts +2 -2
- package/cli/commands/skills.ts +11 -11
- package/cli/commands/swift.ts +29 -11
- package/cli/commands/telemetry.ts +2 -2
- package/cli/commands/test.ts +5 -0
- package/cli/commands/three-mode.ts +3 -3
- package/cli/commands/timeline.ts +4 -4
- package/cli/commands/upgrade.ts +2 -2
- package/cli/commands/upload.ts +15 -15
- package/cli/commands/what-happened.ts +2 -2
- package/cli/current-sim.ts +6 -3
- package/cli/desktop-companion.ts +55 -149
- package/cli/dev-build-freshness.ts +2 -2
- package/cli/drivers/desktop.ts +17 -9
- package/cli/drivers/electron.ts +1 -2
- package/cli/drivers/playwright-sim-host.ts +11 -2
- package/cli/drivers/playwright.ts +35 -2
- package/cli/drivers/types.ts +8 -0
- package/cli/maestro-compare.ts +670 -0
- package/cli/outbound-endpoints.ts +46 -8
- package/cli/recording-access.ts +6 -6
- package/cli/run-registry.ts +1 -1
- package/cli/runtime-compat.ts +5 -1
- package/cli/send-to-box.ts +3 -3
- package/cli/shell-init.ts +2 -1
- package/cli/ws-bridge.ts +9 -5
- package/detox/element-types.ts +1 -0
- package/detox/gestures.ts +3 -3
- package/detox/index.ts +67 -38
- package/detox/navigation-lifecycle.ts +9 -6
- package/detox/proof-frame.cjs +6 -4
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +42 -17
- package/dist-lib/bridge-contract-input.mjs +41 -16
- package/dist-lib/bridge-contract.cjs +1 -4
- package/dist-lib/bridge-contract.mjs +1 -3
- package/dist-lib/bundle-channel.cjs +2918 -550
- package/dist-lib/capture-contract.cjs +65 -24
- package/dist-lib/capture-contract.mjs +63 -24
- package/dist-lib/cloud-contract.cjs +2 -2
- package/dist-lib/cloud-contract.mjs +2 -2
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +3 -3
- package/dist-lib/cloud.mjs +3 -3
- package/dist-lib/config.cjs +15 -5
- package/dist-lib/config.mjs +154 -0
- package/dist-lib/detox/index.cjs +495 -139
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +1168 -238
- package/dist-lib/expo-swift-metadata.cjs +34 -23
- package/dist-lib/expo-swift-metadata.mjs +32 -23
- package/dist-lib/home-paths.cjs +2 -2
- package/dist-lib/host/bridge-host.cjs +2938 -654
- package/dist-lib/host/fetch-proxy-handler.cjs +14 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +7 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +5 -1
- package/dist-lib/host/replacement-module-handler.cjs +2 -2
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +999 -353
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +332 -19
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +7 -7
- package/dist-lib/metro-production-bundle.mjs +5 -5
- package/dist-lib/metro.cjs +688 -250
- package/dist-lib/native-app-identity-project.cjs +2647 -0
- package/dist-lib/native-app-identity-project.mjs +1257 -0
- package/dist-lib/native-app-identity.cjs +325 -25
- package/dist-lib/native-app-identity.mjs +323 -25
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +5 -1
- package/dist-lib/react-native-host-modules.mjs +5 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +57 -32
- package/dist-lib/sdk.cjs +231 -51
- package/dist-lib/sdk.mjs +231 -51
- package/dist-lib/skills.cjs +4107 -1374
- package/dist-lib/swift-compile.cjs +290 -30
- package/dist-lib/swift-compile.mjs +290 -30
- package/dist-lib/swift-package.cjs +143 -12
- package/dist-lib/swift-package.mjs +137 -11
- package/dist-lib/swift-submit.cjs +47 -5
- package/dist-lib/swift-submit.mjs +42 -5
- package/dist-lib/swift-toolchain.cjs +7 -2
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1392 -458
- package/dist-lib/vite.cjs +13 -17
- package/dist-lib/worklet-executable.cjs +248 -33
- package/dist-lib/worklet-executable.mjs +248 -33
- package/install.sh +10 -1
- package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Resources.kt +9 -9
- package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +20 -0
- package/kotlin/AndroidViewSources/android/view/View.kt +211 -0
- package/kotlin/AndroidViewSources/android/widget/FrameLayout.kt +61 -0
- package/kotlin/AndroidViewSources/android/widget/LinearLayout.kt +49 -0
- package/kotlin/AppSources/android/view/Window.kt +36 -0
- package/kotlin/AppSources/android/view/WindowInsets.kt +9 -0
- package/kotlin/AppSources/android/view/WindowInsetsController.kt +5 -0
- package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +48 -0
- package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +20 -5
- package/kotlin/AppSources/androidx/compose/foundation/layout/WindowInsets.kt +15 -0
- package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +2 -1
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +42 -50
- package/kotlin/ComposeSources/PeachComposeHost.kt +200 -84
- package/kotlin/ExpoComposeSources/PeachAndroidView.kt +87 -0
- package/kotlin/ExpoComposeSources/PeachExpoViewMount.kt +24 -0
- package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +28 -0
- package/kotlin/ExpoComposeSources/expo/modules/kotlin/views/ExpoComposeView.kt +70 -0
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +513 -0
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +173 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/AppContext.kt +20 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/Promise.kt +19 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +198 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/exception/CodedException.kt +126 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/functions/Functions.kt +132 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/jni/JavaScriptTypedArray.kt +81 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +98 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +236 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/records/Record.kt +12 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/runtime/Runtime.kt +9 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObject.kt +50 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +57 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedRef.kt +19 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/ConcreteTypedArrays.kt +158 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/GenericTypedArray.kt +8 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArray.kt +29 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArrayIterator.kt +9 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/AnyType.kt +155 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/Either.kt +91 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/Enumerable.kt +6 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +54 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +23 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +71 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +35 -0
- package/kotlin/README.md +13 -3
- package/kotlin/Sources/android/os/Build.kt +17 -0
- package/kotlin/Sources/android/os/Handler.kt +35 -0
- package/kotlin/Sources/android/os/Looper.kt +17 -0
- package/kotlin/Sources/android/os/MessageQueue.kt +56 -0
- package/kotlin/Sources/android/os/SystemClock.kt +14 -0
- package/kotlin/Sources/android/util/Log.kt +64 -0
- package/kotlin/Sources/java/security/MessageDigest.kt +114 -0
- package/kotlin/Sources/kotlin/text/StringFormat.kt +9 -0
- package/kotlin/Sources/org/json/JSON.kt +44 -0
- package/kotlin/fixtures/counter/Counter.d.kt.ts +1 -0
- package/kotlin/fixtures/counter/Counter.kt +10 -3
- package/kotlin/fixtures/counter/CounterApp.native.tsx +1 -1
- package/kotlin/fixtures/counter/vite.config.ts +2 -2
- package/kotlin/fixtures/headless-counter/Headless.kt +7 -6
- package/kotlin/fixtures/import-animation/Animation.d.kt.ts +7 -0
- package/kotlin/fixtures/import-animation/Animation.kt +80 -0
- package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +13 -0
- package/kotlin/fixtures/import-animation/README.md +24 -0
- package/kotlin/fixtures/import-animation/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-animation/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-animation/app/routes.d.ts +18 -0
- package/kotlin/fixtures/import-animation/package.json +23 -0
- package/kotlin/fixtures/import-animation/tsconfig.json +20 -0
- package/kotlin/fixtures/import-animation/vite.config.ts +20 -0
- package/kotlin/fixtures/import-editor/Editor.d.kt.ts +7 -0
- package/kotlin/fixtures/import-editor/Editor.kt +59 -0
- package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +23 -0
- package/kotlin/fixtures/import-editor/README.md +27 -0
- package/kotlin/fixtures/import-editor/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-editor/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-editor/package.json +23 -0
- package/kotlin/fixtures/import-editor/tsconfig.json +20 -0
- package/kotlin/fixtures/import-editor/vite.config.ts +20 -0
- package/kotlin/fixtures/import-effects/Effects.d.kt.ts +7 -0
- package/kotlin/fixtures/import-effects/Effects.kt +87 -0
- package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +13 -0
- package/kotlin/fixtures/import-effects/README.md +19 -0
- package/kotlin/fixtures/import-effects/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-effects/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-effects/package.json +23 -0
- package/kotlin/fixtures/import-effects/tsconfig.json +20 -0
- package/kotlin/fixtures/import-effects/vite.config.ts +20 -0
- package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +13 -0
- package/kotlin/fixtures/import-layout/Layout.d.kt.ts +7 -0
- package/kotlin/fixtures/import-layout/Layout.kt +72 -0
- package/kotlin/fixtures/import-layout/README.md +24 -0
- package/kotlin/fixtures/import-layout/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-layout/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-layout/package.json +23 -0
- package/kotlin/fixtures/import-layout/tsconfig.json +20 -0
- package/kotlin/fixtures/import-layout/vite.config.ts +20 -0
- package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +18 -0
- package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +7 -0
- package/kotlin/fixtures/import-navigation/Navigation.kt +104 -0
- package/kotlin/fixtures/import-navigation/README.md +31 -0
- package/kotlin/fixtures/import-navigation/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-navigation/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-navigation/package.json +23 -0
- package/kotlin/fixtures/import-navigation/tsconfig.json +20 -0
- package/kotlin/fixtures/import-navigation/vite.config.ts +20 -0
- package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +29 -0
- package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +7 -0
- package/kotlin/fixtures/import-overlays/Overlays.kt +93 -0
- package/kotlin/fixtures/import-overlays/README.md +34 -0
- package/kotlin/fixtures/import-overlays/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-overlays/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-overlays/package.json +23 -0
- package/kotlin/fixtures/import-overlays/tsconfig.json +20 -0
- package/kotlin/fixtures/import-overlays/vite.config.ts +20 -0
- package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +13 -0
- package/kotlin/fixtures/import-scroll/README.md +23 -0
- package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +7 -0
- package/kotlin/fixtures/import-scroll/Scroll.kt +91 -0
- package/kotlin/fixtures/import-scroll/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-scroll/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-scroll/package.json +23 -0
- package/kotlin/fixtures/import-scroll/tsconfig.json +20 -0
- package/kotlin/fixtures/import-scroll/vite.config.ts +20 -0
- package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +44 -0
- package/kotlin/fixtures/import-selection/README.md +32 -0
- package/kotlin/fixtures/import-selection/Selection.d.kt.ts +8 -0
- package/kotlin/fixtures/import-selection/Selection.kt +78 -0
- package/kotlin/fixtures/import-selection/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-selection/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-selection/package.json +23 -0
- package/kotlin/fixtures/import-selection/tsconfig.json +20 -0
- package/kotlin/fixtures/import-selection/vite.config.ts +20 -0
- package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +13 -0
- package/kotlin/fixtures/import-surfaces/README.md +22 -0
- package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +7 -0
- package/kotlin/fixtures/import-surfaces/Surfaces.kt +64 -0
- package/kotlin/fixtures/import-surfaces/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-surfaces/package.json +23 -0
- package/kotlin/fixtures/import-surfaces/tsconfig.json +20 -0
- package/kotlin/fixtures/import-surfaces/vite.config.ts +20 -0
- package/kotlin/fixtures/import-values/ImportValues.native.tsx +35 -0
- package/kotlin/fixtures/import-values/README.md +23 -0
- package/kotlin/fixtures/import-values/Values.d.kt.ts +11 -0
- package/kotlin/fixtures/import-values/Values.kt +66 -0
- package/kotlin/fixtures/import-values/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-values/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-values/package.json +23 -0
- package/kotlin/fixtures/import-values/tsconfig.json +20 -0
- package/kotlin/fixtures/import-values/vite.config.ts +20 -0
- package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +38 -0
- package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +36 -0
- package/kotlin/fixtures/kotlin-app-variants/Ime.kt +3 -1
- package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +50 -0
- package/kotlin/fork/NOTICE +6 -1
- package/kotlin/fork/README.md +15 -7
- package/kotlin/fork/build.sh +2 -0
- package/kotlin/fork/compose-worker-globals.patch +186 -4
- package/kotlin/fork/fork.json +2 -2
- package/kotlin/fork/skiko-worker-clock.patch +12 -0
- package/kotlin/toolchain.json +12 -12
- package/kotlin/tools/expo-types.main.kts +115 -0
- package/package.json +17 -23
- package/scripts/dev-server-scanner.ts +92 -66
- package/skills/contrast/SKILL.md +2 -2
- package/skills/peach-debug/SKILL.md +1 -1
- package/skills/peach-perf/SKILL.md +1 -1
- package/skills/peach-setup/SKILL.md +2 -1
- package/skills/peach-test/SKILL.md +8 -0
- package/src/assetCatalogContract.ts +43 -1
- package/src/bridge-contract-input.ts +46 -19
- package/src/bridge-contract.ts +0 -1
- package/src/bundle-channel.mjs +197 -84
- package/src/bundleGlobalFooter.ts +38 -0
- package/src/capture-contract.ts +107 -33
- package/src/cloud-contract.ts +5 -1
- package/src/cloud.ts +5 -2
- package/src/config.ts +22 -3
- package/src/configured-bundle-producer.ts +1 -1
- package/src/desktop-host-delivery.ts +95 -1
- package/src/expo-kotlin-bundle.ts +29 -0
- package/src/expo-kotlin-host.ts +201 -0
- package/src/expo-swift-host.ts +96 -76
- package/src/expoKotlinContract.ts +70 -0
- package/src/expoSwiftContract.ts +4 -25
- package/src/home-paths.ts +7 -4
- package/src/host/bridge-host.ts +23 -3
- package/src/host/fetch-proxy-handler.ts +13 -0
- package/src/host/fetch-proxy-overrides.ts +11 -0
- package/src/host/replacement-module-handler.ts +5 -2
- package/src/index.ts +3 -1
- package/src/kotlin-host.ts +463 -19
- package/src/metro-plugin.ts +56 -28
- package/src/metro-production-bundle.ts +2 -2
- package/src/native-app-identity-project.ts +190 -0
- package/src/native-app-identity.ts +398 -34
- package/src/native-firebase-config.ts +69 -15
- package/src/native-seam-manifest.ts +6 -0
- package/src/one-widget-discovery.ts +2 -1
- package/src/openstep-plist.ts +107 -0
- package/src/react-native-host-modules.ts +4 -0
- package/src/runtime-assets.ts +2 -2
- package/src/sim-client.ts +2 -2
- package/src/swift-binary-modules.ts +3 -1
- package/src/swift-compile.ts +286 -38
- package/src/swift-distribution-contract.ts +4 -0
- package/src/swift-distribution.lock.json +123 -12
- package/src/swift-distribution.ts +7 -3
- package/src/swift-host.ts +298 -83
- package/src/swift-package-manifest.ts +29 -2
- package/src/swift-package.ts +180 -10
- package/src/swift-packages.ts +4 -0
- package/src/swift-standin-emit.ts +4 -1
- package/src/swift-standins.ts +274 -15
- package/src/swift-submit.ts +62 -7
- package/src/swift-toolchain.ts +6 -1
- package/src/swiftContract.ts +126 -3
- package/src/vite-plugin-one.ts +13 -16
- package/src/vite-plugin-swift.ts +4 -5
- package/src/vite-plugin.ts +360 -144
- package/src/vite.d.ts +1 -1
- package/src/worker-system-chunks.ts +221 -0
- package/src/worklet-executable.ts +348 -38
- package/src/worklets-babel.ts +1 -1
- package/src/xcode-project.ts +243 -127
- package/dist-lib/agent-identity.cjs +0 -39
- package/dist-lib/agent-sessions.cjs +0 -760
- package/dist-lib/cli-constants.cjs +0 -32
- package/dist-lib/render-mode.cjs +0 -44
- package/kotlin/AppSources/android/view/View.kt +0 -74
- package/kotlin/AppSources/android/widget/FrameLayout.kt +0 -6
- package/src/render-mode.ts +0 -15
- /package/kotlin/{AppSources → AndroidViewSources}/android/content/Context.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Configuration.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/graphics/Color.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/util/DisplayMetrics.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/dev/peach/app/JavaFormat.kt +0 -0
- /package/kotlin/{AppSources → Sources}/java/lang/Runnable.kt +0 -0
|
@@ -1,55 +1,270 @@
|
|
|
1
|
-
/*!
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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)
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
47
|
-
return
|
|
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
|
+
}
|