pythonnative 0.40.0__cp313-cp313-win_amd64.whl
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.
- pythonnative/__init__.py +411 -0
- pythonnative/_ios_log.py +92 -0
- pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
- pythonnative/alerts.py +236 -0
- pythonnative/animated.py +1687 -0
- pythonnative/animation_graph.py +78 -0
- pythonnative/appearance.py +124 -0
- pythonnative/bootstrap.py +100 -0
- pythonnative/bridge/__init__.py +302 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +170 -0
- pythonnative/bridge/commits.py +114 -0
- pythonnative/bridge/fake.py +243 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/bridge/web.py +489 -0
- pythonnative/cli/__init__.py +7 -0
- pythonnative/cli/pn.py +1214 -0
- pythonnative/component.py +271 -0
- pythonnative/components/__init__.py +111 -0
- pythonnative/components/_base.py +166 -0
- pythonnative/components/controls.py +521 -0
- pythonnative/components/layout.py +518 -0
- pythonnative/components/lists.py +785 -0
- pythonnative/components/media.py +204 -0
- pythonnative/components/overlays.py +107 -0
- pythonnative/components/pressable.py +252 -0
- pythonnative/components/structural.py +167 -0
- pythonnative/components/text.py +291 -0
- pythonnative/devclient.py +824 -0
- pythonnative/devserver/__init__.py +34 -0
- pythonnative/devserver/server.py +718 -0
- pythonnative/devserver/static/animation_graph.js +82 -0
- pythonnative/devserver/static/bridge.js +147 -0
- pythonnative/devserver/static/colors.js +70 -0
- pythonnative/devserver/static/host.js +552 -0
- pythonnative/devserver/static/index.html +60 -0
- pythonnative/devserver/static/layout.js +85 -0
- pythonnative/devserver/static/preview.css +415 -0
- pythonnative/devserver/static/renderer.js +1994 -0
- pythonnative/devserver/static/shell.js +345 -0
- pythonnative/devserver/static/yoga/LICENSE +21 -0
- pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
- pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
- pythonnative/devserver/static/yoga/src/index.js +16 -0
- pythonnative/devserver/static/yoga/src/index.js.map +1 -0
- pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
- pythonnative/devserver/static/yoga/src/load.js +17 -0
- pythonnative/devserver/static/yoga/src/load.js.map +1 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
- pythonnative/devserver/watcher.py +267 -0
- pythonnative/devserver/ws.py +421 -0
- pythonnative/diagnostics.py +241 -0
- pythonnative/element.py +159 -0
- pythonnative/equality.py +19 -0
- pythonnative/events.py +231 -0
- pythonnative/gestures.py +1333 -0
- pythonnative/hooks.py +1621 -0
- pythonnative/hosts/__init__.py +63 -0
- pythonnative/hosts/base.py +596 -0
- pythonnative/hosts/native.py +302 -0
- pythonnative/hot_reload.py +585 -0
- pythonnative/layout.py +328 -0
- pythonnative/mutations.py +142 -0
- pythonnative/native/android/build.gradle +52 -0
- pythonnative/native/android/gradle.properties +3 -0
- pythonnative/native/android/settings.gradle +12 -0
- pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
- pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
- pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
- pythonnative/native/ios/Package.swift +23 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/native/yoga/LICENSE +21 -0
- pythonnative/native/yoga/Package.swift +9 -0
- pythonnative/native/yoga/VENDORED.md +2 -0
- pythonnative/native/yoga/include/PNStyle.h +10 -0
- pythonnative/native/yoga/include/module.modulemap +5 -0
- pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/python.cpp +16 -0
- pythonnative/native/yoga/style.cpp +272 -0
- pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
- pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
- pythonnative/native/yoga/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
- pythonnative/native/yoga/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
- pythonnative/native/yoga/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
- pythonnative/native/yoga/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
- pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
- pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
- pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
- pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
- pythonnative/native/yoga/yoga/config/Config.h +92 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
- pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
- pythonnative/native/yoga/yoga/debug/Log.h +34 -0
- pythonnative/native/yoga/yoga/enums/Align.h +47 -0
- pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
- pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
- pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
- pythonnative/native/yoga/yoga/enums/Display.h +41 -0
- pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
- pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
- pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
- pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
- pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
- pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
- pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
- pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
- pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
- pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
- pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
- pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
- pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
- pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
- pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
- pythonnative/native/yoga/yoga/event/event.cpp +87 -0
- pythonnative/native/yoga/yoga/event/event.h +130 -0
- pythonnative/native/yoga/yoga/module.modulemap +21 -0
- pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
- pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
- pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
- pythonnative/native/yoga/yoga/node/Node.h +337 -0
- pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
- pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
- pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
- pythonnative/native/yoga/yoga/style/Style.h +757 -0
- pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
- pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
- pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
- pythonnative/native_modules/__init__.py +124 -0
- pythonnative/native_modules/app_state.py +99 -0
- pythonnative/native_modules/battery.py +75 -0
- pythonnative/native_modules/biometrics.py +42 -0
- pythonnative/native_modules/camera.py +65 -0
- pythonnative/native_modules/clipboard.py +46 -0
- pythonnative/native_modules/fallback.py +324 -0
- pythonnative/native_modules/file_system.py +145 -0
- pythonnative/native_modules/haptics.py +75 -0
- pythonnative/native_modules/linking.py +123 -0
- pythonnative/native_modules/location.py +75 -0
- pythonnative/native_modules/net_info.py +112 -0
- pythonnative/native_modules/notifications.py +129 -0
- pythonnative/native_modules/permissions.py +108 -0
- pythonnative/native_modules/registry.py +526 -0
- pythonnative/native_modules/secure_store.py +52 -0
- pythonnative/native_modules/share.py +51 -0
- pythonnative/native_views/__init__.py +375 -0
- pythonnative/native_views/base.py +316 -0
- pythonnative/native_views/bridge_backend.py +277 -0
- pythonnative/navigation/__init__.py +103 -0
- pythonnative/navigation/container.py +154 -0
- pythonnative/navigation/handle.py +540 -0
- pythonnative/navigation/hooks.py +133 -0
- pythonnative/navigation/host.py +58 -0
- pythonnative/navigation/linking.py +200 -0
- pythonnative/navigation/navigators.py +659 -0
- pythonnative/navigation/screen.py +149 -0
- pythonnative/navigation/state.py +269 -0
- pythonnative/net.py +248 -0
- pythonnative/platform.py +166 -0
- pythonnative/platform_metrics.py +252 -0
- pythonnative/preview.py +287 -0
- pythonnative/profiling.py +101 -0
- pythonnative/project/__init__.py +68 -0
- pythonnative/project/android.py +557 -0
- pythonnative/project/builder.py +817 -0
- pythonnative/project/config.py +773 -0
- pythonnative/project/deps.py +719 -0
- pythonnative/project/devices.py +304 -0
- pythonnative/project/doctor.py +283 -0
- pythonnative/project/fingerprint.py +171 -0
- pythonnative/project/icons.py +247 -0
- pythonnative/project/ios.py +325 -0
- pythonnative/project/lockfile.py +100 -0
- pythonnative/project/permissions.py +361 -0
- pythonnative/project/plugins.py +519 -0
- pythonnative/project/runtime_assets.py +183 -0
- pythonnative/py.typed +0 -0
- pythonnative/query.py +153 -0
- pythonnative/reconciler/__init__.py +29 -0
- pythonnative/reconciler/boundaries.py +375 -0
- pythonnative/reconciler/children.py +88 -0
- pythonnative/reconciler/core.py +1165 -0
- pythonnative/reconciler/layout_pass.py +393 -0
- pythonnative/reconciler/vnode.py +266 -0
- pythonnative/refresh.py +55 -0
- pythonnative/runtime.py +306 -0
- pythonnative/scheduler.py +159 -0
- pythonnative/sdk/__init__.py +153 -0
- pythonnative/sdk/_components.py +427 -0
- pythonnative/sdk/builtins.py +91 -0
- pythonnative/sdk/codegen.py +149 -0
- pythonnative/sdk/module_codegen.py +184 -0
- pythonnative/sdk/schema.py +224 -0
- pythonnative/sdk/templates/contracts.kt +46 -0
- pythonnative/sdk/templates/contracts.swift +46 -0
- pythonnative/storage.py +184 -0
- pythonnative/style.py +841 -0
- pythonnative/suspense.py +183 -0
- pythonnative/templates/android_template/app/build.gradle +75 -0
- pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
- pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
- pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
- pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
- pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
- pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
- pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
- pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
- pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
- pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
- pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
- pythonnative/templates/android_template/build.gradle +10 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
- pythonnative/templates/android_template/gradle.properties +23 -0
- pythonnative/templates/android_template/gradlew +185 -0
- pythonnative/templates/android_template/gradlew.bat +89 -0
- pythonnative/templates/android_template/settings.gradle +17 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
- pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
- pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
- pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
- pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
- pythonnative/testing/__init__.py +53 -0
- pythonnative/testing/backend.py +276 -0
- pythonnative/testing/harness.py +369 -0
- pythonnative/utils.py +145 -0
- pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
- pythonnative-0.40.0.dist-info/METADATA +150 -0
- pythonnative-0.40.0.dist-info/RECORD +418 -0
- pythonnative-0.40.0.dist-info/WHEEL +5 -0
- pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
- pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
- pythonnative-0.40.0.dist-info/top_level.txt +1 -0
- pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
package com.pythonnative.runtime.screens
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import android.view.LayoutInflater
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import android.widget.FrameLayout
|
|
8
|
+
import androidx.activity.OnBackPressedCallback
|
|
9
|
+
import androidx.core.os.bundleOf
|
|
10
|
+
import androidx.core.view.ViewCompat
|
|
11
|
+
import androidx.fragment.app.Fragment
|
|
12
|
+
import com.pythonnative.runtime.PNBridge
|
|
13
|
+
import com.pythonnative.runtime.bridge.PNLog
|
|
14
|
+
import org.json.JSONObject
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The Fragment hosting one PythonNative screen.
|
|
18
|
+
*
|
|
19
|
+
* On view creation it asks Python to create the screen
|
|
20
|
+
* (`callback("host", screenId, "create", {...})`) and afterwards
|
|
21
|
+
* forwards lifecycle and layout: `start`, `layout`, `resume`, `pause`,
|
|
22
|
+
* `stop`, `destroy`, `back_pressed`, `save_state`, and
|
|
23
|
+
* `restore_state`. Python attaches the screen's root view through the
|
|
24
|
+
* `Host.attach_root` module call, which lands in [attachRoot].
|
|
25
|
+
*
|
|
26
|
+
* Apps subclass this (the nav graph names the subclass) and override
|
|
27
|
+
* [defaultPath] to supply the entry module when the fragment arguments
|
|
28
|
+
* don't carry one. Fast Refresh needs nothing from the fragment: the
|
|
29
|
+
* Python dev client reloads modules and refreshes mounted screens.
|
|
30
|
+
*/
|
|
31
|
+
open class PNScreenFragment : Fragment() {
|
|
32
|
+
/** The screen id assigned by [ScreenRegistry]. */
|
|
33
|
+
var screenId: Int = 0
|
|
34
|
+
private set
|
|
35
|
+
|
|
36
|
+
/** The container the root view is attached into (valid between `onCreateView` and `onDestroyView`). */
|
|
37
|
+
var container: FrameLayout? = null
|
|
38
|
+
private set
|
|
39
|
+
|
|
40
|
+
private var created = false
|
|
41
|
+
private var pendingRestore: String? = null
|
|
42
|
+
private var lastLayout: String? = null
|
|
43
|
+
|
|
44
|
+
/** Screen path when the arguments carry none (apps return the entry module). */
|
|
45
|
+
protected open fun defaultPath(): String? = null
|
|
46
|
+
|
|
47
|
+
/** The path this fragment shows. */
|
|
48
|
+
fun screenPath(): String? = arguments?.getString(ARG_PATH) ?: defaultPath()
|
|
49
|
+
|
|
50
|
+
private fun argsJson(): String? = arguments?.getString(ARG_ARGS)
|
|
51
|
+
|
|
52
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
53
|
+
super.onCreate(savedInstanceState)
|
|
54
|
+
screenId = ScreenRegistry.register(this)
|
|
55
|
+
pendingRestore = savedInstanceState?.getString(STATE_KEY)
|
|
56
|
+
requireActivity().onBackPressedDispatcher.addCallback(
|
|
57
|
+
this,
|
|
58
|
+
object : OnBackPressedCallback(true) {
|
|
59
|
+
override fun handleOnBackPressed() {
|
|
60
|
+
if (created) host("back_pressed", "{}")
|
|
61
|
+
else requireActivity().finish()
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
|
69
|
+
val frame = FrameLayout(requireContext())
|
|
70
|
+
frame.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
|
71
|
+
this.container = frame
|
|
72
|
+
return frame
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
76
|
+
super.onViewCreated(view, savedInstanceState)
|
|
77
|
+
arguments?.getString(ARG_TITLE)?.let { activity?.title = it }
|
|
78
|
+
val payload = JSONObject()
|
|
79
|
+
.put("path", screenPath() ?: JSONObject.NULL)
|
|
80
|
+
.put("args", argsJson() ?: JSONObject.NULL)
|
|
81
|
+
host("create", payload.toString())
|
|
82
|
+
created = true
|
|
83
|
+
pendingRestore?.let {
|
|
84
|
+
host("restore_state", JSONObject().put("state", it).toString())
|
|
85
|
+
pendingRestore = null
|
|
86
|
+
}
|
|
87
|
+
view.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ -> publishLayout(v) }
|
|
88
|
+
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
|
|
89
|
+
publishLayout(v, force = true)
|
|
90
|
+
insets
|
|
91
|
+
}
|
|
92
|
+
publishLayout(view, force = true)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private fun publishLayout(view: View, force: Boolean = false) {
|
|
96
|
+
if (!created) return
|
|
97
|
+
val payload = Viewport.describe(view).toString()
|
|
98
|
+
if (!force && payload == lastLayout) return
|
|
99
|
+
lastLayout = payload
|
|
100
|
+
host("layout", payload)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Current viewport payload for this screen. */
|
|
104
|
+
fun viewport(): JSONObject {
|
|
105
|
+
val v = container ?: view
|
|
106
|
+
return if (v != null) Viewport.describe(v) else JSONObject()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Attach `root` (MATCH_PARENT) into the fragment container, replacing any previous root. */
|
|
110
|
+
fun attachRoot(root: View) {
|
|
111
|
+
val target = container ?: return
|
|
112
|
+
target.removeAllViews()
|
|
113
|
+
(root.parent as? ViewGroup)?.removeView(root)
|
|
114
|
+
target.addView(root, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
|
|
115
|
+
publishLayout(target, force = true)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Detach `root` from wherever it is parented (never clears the shared container). */
|
|
119
|
+
fun detachRoot(root: View) {
|
|
120
|
+
(root.parent as? ViewGroup)?.removeView(root)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override fun onStart() {
|
|
124
|
+
super.onStart()
|
|
125
|
+
host("start", "{}")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
override fun onResume() {
|
|
129
|
+
super.onResume()
|
|
130
|
+
ScreenRegistry.setActive(screenId)
|
|
131
|
+
host("resume", viewport().toString())
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
override fun onPause() {
|
|
135
|
+
super.onPause()
|
|
136
|
+
host("pause", "{}")
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override fun onStop() {
|
|
140
|
+
super.onStop()
|
|
141
|
+
host("stop", "{}")
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
var cachedStateJSON: String? = null
|
|
145
|
+
|
|
146
|
+
override fun onSaveInstanceState(outState: Bundle) {
|
|
147
|
+
super.onSaveInstanceState(outState)
|
|
148
|
+
if (!created) return
|
|
149
|
+
host("save_state", "{}")
|
|
150
|
+
cachedStateJSON?.let { outState.putString(STATE_KEY, it) }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
override fun onDestroyView() {
|
|
154
|
+
super.onDestroyView()
|
|
155
|
+
container = null
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
override fun onDestroy() {
|
|
159
|
+
super.onDestroy()
|
|
160
|
+
if (created) host("destroy", "{}")
|
|
161
|
+
created = false
|
|
162
|
+
ScreenRegistry.unregister(screenId)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private fun host(name: String, payloadJson: String): String? {
|
|
166
|
+
return try {
|
|
167
|
+
PNBridge.callPython("host", screenId.toLong(), name, payloadJson)
|
|
168
|
+
} catch (e: Exception) {
|
|
169
|
+
PNLog.rateLimited("host:$name", "host callback '$name' failed", e)
|
|
170
|
+
null
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
companion object {
|
|
175
|
+
const val ARG_PATH = "screen_path"
|
|
176
|
+
const val ARG_ARGS = "args_json"
|
|
177
|
+
const val ARG_TITLE = "title"
|
|
178
|
+
private const val STATE_KEY = "pn_screen_state"
|
|
179
|
+
|
|
180
|
+
/** Build a fragment for `path` with optional JSON `args`. */
|
|
181
|
+
@JvmStatic
|
|
182
|
+
fun newInstance(path: String, argsJson: String?): PNScreenFragment {
|
|
183
|
+
val f = PNScreenFragment()
|
|
184
|
+
f.arguments = bundleOf(ARG_PATH to path, ARG_ARGS to argsJson)
|
|
185
|
+
return f
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
package com.pythonnative.runtime.screens
|
|
2
|
+
|
|
3
|
+
import android.content.res.Configuration
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.ViewGroup
|
|
6
|
+
import androidx.core.view.ViewCompat
|
|
7
|
+
import androidx.core.view.WindowInsetsCompat
|
|
8
|
+
import com.pythonnative.runtime.PNBridge
|
|
9
|
+
import org.json.JSONObject
|
|
10
|
+
import kotlin.math.max
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Integer ids for live [PNScreenFragment]s. Python addresses screens
|
|
14
|
+
* by these ids in `Host` module calls and receives them as the `tag`
|
|
15
|
+
* of `host` callbacks.
|
|
16
|
+
*/
|
|
17
|
+
object ScreenRegistry {
|
|
18
|
+
private val screens = LinkedHashMap<Int, PNScreenFragment>()
|
|
19
|
+
private var nextId = 1
|
|
20
|
+
private var activeId = 0
|
|
21
|
+
|
|
22
|
+
/** Assign an id to `fragment`. */
|
|
23
|
+
fun register(fragment: PNScreenFragment): Int {
|
|
24
|
+
val id = nextId++
|
|
25
|
+
screens[id] = fragment
|
|
26
|
+
return id
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fun unregister(id: Int) {
|
|
30
|
+
screens.remove(id)
|
|
31
|
+
if (activeId == id) activeId = screens.keys.lastOrNull() ?: 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fun get(id: Int): PNScreenFragment? = screens[id]
|
|
35
|
+
|
|
36
|
+
/** Mark `id` as the screen the user currently sees (called on resume). */
|
|
37
|
+
fun setActive(id: Int) {
|
|
38
|
+
activeId = id
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The visible screen's id, or `0`. */
|
|
42
|
+
fun activeId(): Int = activeId
|
|
43
|
+
|
|
44
|
+
/** The fragment container of the visible screen (overlay host for `Portal`). */
|
|
45
|
+
fun activeContainer(): ViewGroup? = screens[activeId]?.container ?: screens.values.lastOrNull()?.container
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Builds the viewport payload shared by `layout`, `resume`, and `Host.viewport`. */
|
|
49
|
+
object Viewport {
|
|
50
|
+
/**
|
|
51
|
+
* `{width, height, insets{top,left,bottom,right}, color_scheme, keyboard_height}`
|
|
52
|
+
* in dp, measured from `view` (falling back to display metrics when
|
|
53
|
+
* the view has not been laid out yet).
|
|
54
|
+
*/
|
|
55
|
+
fun describe(view: View): JSONObject {
|
|
56
|
+
val density = PNBridge.density()
|
|
57
|
+
val metrics = view.resources.displayMetrics
|
|
58
|
+
val w = if (view.width > 0) view.width else metrics.widthPixels
|
|
59
|
+
val h = if (view.height > 0) view.height else metrics.heightPixels
|
|
60
|
+
val insets = ViewCompat.getRootWindowInsets(view)
|
|
61
|
+
val bars = insets?.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
|
|
62
|
+
val ime = insets?.getInsets(WindowInsetsCompat.Type.ime())
|
|
63
|
+
val bottomBar = bars?.bottom ?: 0
|
|
64
|
+
val keyboard = max(0, (ime?.bottom ?: 0) - bottomBar) / density
|
|
65
|
+
val night = view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
66
|
+
return JSONObject()
|
|
67
|
+
.put("width", w / density.toDouble())
|
|
68
|
+
.put("height", h / density.toDouble())
|
|
69
|
+
.put(
|
|
70
|
+
"insets",
|
|
71
|
+
JSONObject()
|
|
72
|
+
.put("top", (bars?.top ?: 0) / density.toDouble())
|
|
73
|
+
.put("left", (bars?.left ?: 0) / density.toDouble())
|
|
74
|
+
.put("bottom", bottomBar / density.toDouble())
|
|
75
|
+
.put("right", (bars?.right ?: 0) / density.toDouble()),
|
|
76
|
+
)
|
|
77
|
+
.put("color_scheme", if (night == Configuration.UI_MODE_NIGHT_YES) "dark" else "light")
|
|
78
|
+
.put("keyboard_height", keyboard.toDouble())
|
|
79
|
+
}
|
|
80
|
+
}
|
pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
package com.pythonnative.runtime.views
|
|
2
|
+
|
|
3
|
+
import android.os.Build
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.accessibility.AccessibilityNodeInfo
|
|
6
|
+
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Accessibility delegate that exposes PythonNative's `test_id` and
|
|
10
|
+
* `accessibility_state` props through the Android accessibility tree.
|
|
11
|
+
*
|
|
12
|
+
* `test_id` is surfaced as the node's view-id resource name, which
|
|
13
|
+
* UI Automator-based tools (Maestro, UiAutomator2, Appium) match as
|
|
14
|
+
* `resource-id`. State flags map onto the closest
|
|
15
|
+
* [AccessibilityNodeInfo] equivalents so TalkBack announces them.
|
|
16
|
+
* Fields left null are not applied.
|
|
17
|
+
*/
|
|
18
|
+
class PNAccessibilityDelegate : View.AccessibilityDelegate() {
|
|
19
|
+
var testId: String? = null
|
|
20
|
+
var stateDisabled: Boolean? = null
|
|
21
|
+
var stateSelected: Boolean? = null
|
|
22
|
+
var stateChecked: Boolean? = null
|
|
23
|
+
var stateBusy: Boolean? = null
|
|
24
|
+
var stateExpanded: Boolean? = null
|
|
25
|
+
var role: String? = null
|
|
26
|
+
|
|
27
|
+
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
|
|
28
|
+
super.onInitializeAccessibilityNodeInfo(host, info)
|
|
29
|
+
testId?.let { info.viewIdResourceName = it }
|
|
30
|
+
stateDisabled?.let { info.isEnabled = !it }
|
|
31
|
+
stateSelected?.let { info.isSelected = it }
|
|
32
|
+
stateChecked?.let {
|
|
33
|
+
info.isCheckable = true
|
|
34
|
+
info.isChecked = it
|
|
35
|
+
}
|
|
36
|
+
role?.let { AccessibilityNodeInfoCompat.wrap(info).roleDescription = it }
|
|
37
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
38
|
+
val states = mutableListOf<String>()
|
|
39
|
+
if (stateBusy == true) states.add("busy")
|
|
40
|
+
when (stateExpanded) {
|
|
41
|
+
true -> states.add("expanded")
|
|
42
|
+
false -> states.add("collapsed")
|
|
43
|
+
null -> {}
|
|
44
|
+
}
|
|
45
|
+
if (states.isNotEmpty()) info.stateDescription = states.joinToString(", ")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
package com.pythonnative.runtime.views
|
|
2
|
+
|
|
3
|
+
import android.graphics.Canvas
|
|
4
|
+
import android.graphics.ColorFilter
|
|
5
|
+
import android.graphics.Paint
|
|
6
|
+
import android.graphics.PixelFormat
|
|
7
|
+
import android.graphics.RectF
|
|
8
|
+
import android.graphics.drawable.Drawable
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Background drawable that renders an optional rounded fill plus four
|
|
12
|
+
* independent border strips. Used for PythonNative's
|
|
13
|
+
* `border_<side>_width` / `border_<side>_color` style props, which
|
|
14
|
+
* `GradientDrawable`'s single uniform stroke cannot express.
|
|
15
|
+
*
|
|
16
|
+
* Widths are in pixels; sides are ordered left, top, right, bottom.
|
|
17
|
+
* The fill color is mutable so animated `background_color` frames can
|
|
18
|
+
* update it in place without allocating a new drawable.
|
|
19
|
+
*/
|
|
20
|
+
class PNBorderDrawable(
|
|
21
|
+
private var hasBackground: Boolean,
|
|
22
|
+
private var backgroundColor: Int,
|
|
23
|
+
private val cornerRadius: Float,
|
|
24
|
+
private val widths: FloatArray,
|
|
25
|
+
private val colors: IntArray,
|
|
26
|
+
) : Drawable() {
|
|
27
|
+
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
28
|
+
|
|
29
|
+
/** Replace the fill color (used by animated background frames). */
|
|
30
|
+
fun setFillColor(color: Int) {
|
|
31
|
+
hasBackground = true
|
|
32
|
+
backgroundColor = color
|
|
33
|
+
invalidateSelf()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun draw(canvas: Canvas) {
|
|
37
|
+
val b = RectF(bounds)
|
|
38
|
+
if (hasBackground) {
|
|
39
|
+
paint.style = Paint.Style.FILL
|
|
40
|
+
paint.color = backgroundColor
|
|
41
|
+
if (cornerRadius > 0f) {
|
|
42
|
+
canvas.drawRoundRect(b, cornerRadius, cornerRadius, paint)
|
|
43
|
+
} else {
|
|
44
|
+
canvas.drawRect(b, paint)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
paint.style = Paint.Style.FILL
|
|
48
|
+
if (widths[0] > 0f) {
|
|
49
|
+
paint.color = colors[0]
|
|
50
|
+
canvas.drawRect(b.left, b.top, b.left + widths[0], b.bottom, paint)
|
|
51
|
+
}
|
|
52
|
+
if (widths[1] > 0f) {
|
|
53
|
+
paint.color = colors[1]
|
|
54
|
+
canvas.drawRect(b.left, b.top, b.right, b.top + widths[1], paint)
|
|
55
|
+
}
|
|
56
|
+
if (widths[2] > 0f) {
|
|
57
|
+
paint.color = colors[2]
|
|
58
|
+
canvas.drawRect(b.right - widths[2], b.top, b.right, b.bottom, paint)
|
|
59
|
+
}
|
|
60
|
+
if (widths[3] > 0f) {
|
|
61
|
+
paint.color = colors[3]
|
|
62
|
+
canvas.drawRect(b.left, b.bottom - widths[3], b.right, b.bottom, paint)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override fun setAlpha(alpha: Int) {
|
|
67
|
+
paint.alpha = alpha
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override fun setColorFilter(colorFilter: ColorFilter?) {
|
|
71
|
+
paint.colorFilter = colorFilter
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@Deprecated("Deprecated in Java")
|
|
75
|
+
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
|
76
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package com.pythonnative.runtime.views
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import androidx.appcompat.widget.AppCompatEditText
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `EditText` that reports selection changes, which the platform only
|
|
8
|
+
* exposes through a protected override.
|
|
9
|
+
*/
|
|
10
|
+
class PNEditText(context: Context) : AppCompatEditText(context) {
|
|
11
|
+
/** Called with `(start, end)` whenever the selection or cursor moves. */
|
|
12
|
+
var onSelectionChangedListener: ((Int, Int) -> Unit)? = null
|
|
13
|
+
|
|
14
|
+
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
|
|
15
|
+
super.onSelectionChanged(selStart, selEnd)
|
|
16
|
+
onSelectionChangedListener?.invoke(selStart, selEnd)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package com.pythonnative.runtime.views
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.view.MotionEvent
|
|
5
|
+
import android.widget.FrameLayout
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Container `FrameLayout` with React Native-style `pointer_events`
|
|
9
|
+
* semantics. Component managers create these for flex containers and
|
|
10
|
+
* drive the mode via [setPointerEventsMode]:
|
|
11
|
+
*
|
|
12
|
+
* - `"auto"` (default): normal dispatch; the view and its children
|
|
13
|
+
* both receive touches.
|
|
14
|
+
* - `"none"`: neither the view nor its children receive touches; the
|
|
15
|
+
* event falls through to whatever sits underneath.
|
|
16
|
+
* - `"box_none"`: children receive touches, but the view itself never
|
|
17
|
+
* intercepts or consumes them (the styler also mutes the view's own
|
|
18
|
+
* touch listeners).
|
|
19
|
+
* - `"box_only"`: the view receives touches and its children don't;
|
|
20
|
+
* every event in the subtree is intercepted at this level.
|
|
21
|
+
*/
|
|
22
|
+
open class PNFrameLayout(context: Context) : FrameLayout(context) {
|
|
23
|
+
private var pointerEventsMode: String = "auto"
|
|
24
|
+
|
|
25
|
+
/** Set the pointer-events mode; `null` restores `"auto"`. */
|
|
26
|
+
fun setPointerEventsMode(mode: String?) {
|
|
27
|
+
pointerEventsMode = mode ?: "auto"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The current pointer-events mode. */
|
|
31
|
+
fun getPointerEventsMode(): String = pointerEventsMode
|
|
32
|
+
|
|
33
|
+
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
|
34
|
+
if (pointerEventsMode == "none") {
|
|
35
|
+
// Declining the whole dispatch lets the event pass through
|
|
36
|
+
// to views underneath, matching RN's "none".
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
return super.dispatchTouchEvent(ev)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
|
43
|
+
return when (pointerEventsMode) {
|
|
44
|
+
"box_only" -> true
|
|
45
|
+
"box_none" -> false
|
|
46
|
+
else -> super.onInterceptTouchEvent(ev)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
package com.pythonnative.runtime
|
|
2
|
+
|
|
3
|
+
import com.pythonnative.runtime.animation.AnimationSpecs
|
|
4
|
+
import org.json.JSONArray
|
|
5
|
+
import org.json.JSONObject
|
|
6
|
+
import org.junit.Assert.assertArrayEquals
|
|
7
|
+
import org.junit.Assert.assertEquals
|
|
8
|
+
import org.junit.Assert.assertTrue
|
|
9
|
+
import org.junit.Test
|
|
10
|
+
import kotlin.math.exp
|
|
11
|
+
import kotlin.math.sqrt
|
|
12
|
+
|
|
13
|
+
class AnimationSpecsTest {
|
|
14
|
+
@Test
|
|
15
|
+
fun springDampingRatio() {
|
|
16
|
+
// Critically damped when damping = 2 * sqrt(k * m).
|
|
17
|
+
val k = 100.0
|
|
18
|
+
val m = 2.0
|
|
19
|
+
val critical = 2 * sqrt(k * m)
|
|
20
|
+
assertEquals(1.0, AnimationSpecs.dampingRatio(k, critical, m), 1e-9)
|
|
21
|
+
val spec = JSONObject("""{"kind":"spring","from":0,"to":1,"stiffness":100,"damping":10,"mass":1}""")
|
|
22
|
+
val spring = AnimationSpecs.spring(spec)
|
|
23
|
+
assertEquals(100.0, spring.stiffness, 1e-9)
|
|
24
|
+
assertEquals(0.5, spring.dampingRatio, 1e-9)
|
|
25
|
+
// Mass scales the effective stiffness so the natural frequency matches.
|
|
26
|
+
val heavy = AnimationSpecs.spring(JSONObject("""{"kind":"spring","stiffness":100,"damping":10,"mass":4}"""))
|
|
27
|
+
assertEquals(25.0, heavy.stiffness, 1e-9)
|
|
28
|
+
assertEquals(10.0 / (2 * sqrt(400.0)), heavy.dampingRatio, 1e-9)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Test
|
|
32
|
+
fun decayFrictionReproducesPythonDecay() {
|
|
33
|
+
val k = 0.002
|
|
34
|
+
val friction = AnimationSpecs.decayFriction(k)
|
|
35
|
+
// FlingAnimation: v(t) = v0 * exp(-4.2 * friction * t); Python: v0 * exp(-k * 1000 * t).
|
|
36
|
+
val t = 0.25
|
|
37
|
+
assertEquals(exp(-k * 1000 * t), exp(-AnimationSpecs.FLING_FRICTION_SCALE * friction * t), 1e-9)
|
|
38
|
+
val decay = AnimationSpecs.decay(JSONObject("""{"kind":"decay","from":10,"velocity":2,"deceleration":0.002}"""))
|
|
39
|
+
assertEquals(2000.0, decay.startVelocity, 1e-9)
|
|
40
|
+
assertEquals(10.0 + 2.0 / (0.002 * 1000.0), decay.projectedFinal, 1e-9)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Test
|
|
44
|
+
fun timingDefaults() {
|
|
45
|
+
val timing = AnimationSpecs.timing(JSONObject("""{"kind":"timing","from":0,"to":1}"""))
|
|
46
|
+
assertEquals(300L, timing.durationMs)
|
|
47
|
+
assertEquals(1.0, timing.to, 0.0)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Test
|
|
51
|
+
fun easingNamesMatchPythonCurves() {
|
|
52
|
+
@Suppress("UNCHECKED_CAST")
|
|
53
|
+
val easeInOut = AnimationSpecs.resolveEasing("ease_in_out") as (Float) -> Float
|
|
54
|
+
assertEquals(0.5f, easeInOut(0.5f), 1e-6f)
|
|
55
|
+
assertEquals(0.15625f, easeInOut(0.25f), 1e-6f)
|
|
56
|
+
@Suppress("UNCHECKED_CAST")
|
|
57
|
+
val linear = AnimationSpecs.resolveEasing("linear") as (Float) -> Float
|
|
58
|
+
assertEquals(0.3f, linear(0.3f), 1e-6f)
|
|
59
|
+
@Suppress("UNCHECKED_CAST")
|
|
60
|
+
val fallback = AnimationSpecs.resolveEasing("does-not-exist") as (Float) -> Float
|
|
61
|
+
assertEquals(easeInOut(0.3f), fallback(0.3f), 1e-6f)
|
|
62
|
+
@Suppress("UNCHECKED_CAST")
|
|
63
|
+
val bounce = AnimationSpecs.resolveEasing("bounce") as (Float) -> Float
|
|
64
|
+
assertEquals(1f, bounce(1f), 1e-6f)
|
|
65
|
+
assertTrue(bounce(0.5f) in 0f..1f)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@Test
|
|
69
|
+
fun cubicBezierArraysAreControlPoints() {
|
|
70
|
+
val pts = AnimationSpecs.resolveEasing(JSONArray("[0.25, 0.1, 0.25, 1.0]")) as DoubleArray
|
|
71
|
+
assertArrayEquals(doubleArrayOf(0.25, 0.1, 0.25, 1.0), pts, 1e-9)
|
|
72
|
+
val css = AnimationSpecs.resolveEasing("cubic-bezier(0.42, 0, 1, 1)") as DoubleArray
|
|
73
|
+
assertArrayEquals(doubleArrayOf(0.42, 0.0, 1.0, 1.0), css, 1e-9)
|
|
74
|
+
}
|
|
75
|
+
}
|