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
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// `Modal`: a hidden on-tree placeholder whose children mount into a
|
|
4
|
+
/// presented `UIViewController` while `visible` is true.
|
|
5
|
+
public final class PNModalManager: PNComponentManager {
|
|
6
|
+
final class Presentation {
|
|
7
|
+
let controller: UIViewController
|
|
8
|
+
let content: UIView
|
|
9
|
+
init(controller: UIViewController, content: UIView) {
|
|
10
|
+
self.controller = controller
|
|
11
|
+
self.content = content
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
16
|
+
let placeholder = UIView(frame: .zero)
|
|
17
|
+
placeholder.isHidden = true
|
|
18
|
+
return placeholder
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
22
|
+
guard let state = PNViewState.existing(for: view) else { return }
|
|
23
|
+
let visible = PNProps.bool(PNProps.value(state.props, "visible")) ?? false
|
|
24
|
+
let presented = state.extras["modal"] is Presentation
|
|
25
|
+
if visible, !presented {
|
|
26
|
+
present(view, state)
|
|
27
|
+
} else if !visible, presented {
|
|
28
|
+
dismiss(view, state, emit: true)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public override func teardown(view: UIView) {
|
|
33
|
+
if let state = PNViewState.existing(for: view), state.extras["modal"] is Presentation {
|
|
34
|
+
dismiss(view, state, emit: false)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public override func childContainer(for view: UIView) -> UIView {
|
|
39
|
+
guard let state = PNViewState.existing(for: view), let modal = state.extras["modal"] as? Presentation else {
|
|
40
|
+
return view
|
|
41
|
+
}
|
|
42
|
+
return modal.content
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public override func insertChild(parent: UIView, child: UIView, index: Int) {
|
|
46
|
+
if let state = PNViewState.existing(for: parent), !(state.extras["modal"] is Presentation) {
|
|
47
|
+
var pending = (state.extras["pending_children"] as? [UIView]) ?? []
|
|
48
|
+
pending.removeAll { $0 === child }
|
|
49
|
+
pending.insert(child, at: max(0, min(index, pending.count)))
|
|
50
|
+
state.extras["pending_children"] = pending
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
super.insertChild(parent: parent, child: child, index: index)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public override func removeChild(parent: UIView, child: UIView) {
|
|
57
|
+
super.removeChild(parent: parent, child: child)
|
|
58
|
+
if let state = PNViewState.existing(for: parent), var pending = state.extras["pending_children"] as? [UIView] {
|
|
59
|
+
pending.removeAll { $0 === child }
|
|
60
|
+
state.extras["pending_children"] = pending
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
|
|
65
|
+
|
|
66
|
+
public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize { .zero }
|
|
67
|
+
|
|
68
|
+
private func present(_ placeholder: UIView, _ state: PNViewState) {
|
|
69
|
+
let props = state.props
|
|
70
|
+
let controller = PNModalViewController()
|
|
71
|
+
controller.onDismissed = { [weak placeholder] in
|
|
72
|
+
guard let placeholder = placeholder, let state = PNViewState.existing(for: placeholder),
|
|
73
|
+
state.extras["modal"] is Presentation
|
|
74
|
+
else { return }
|
|
75
|
+
state.extras.removeValue(forKey: "modal")
|
|
76
|
+
PNEvents.emit(placeholder, "on_dismiss")
|
|
77
|
+
PNEvents.emitIfWired(placeholder, "on_request_close")
|
|
78
|
+
}
|
|
79
|
+
let style = PNProps.string(PNProps.value(props, "presentation_style")) ?? "page_sheet"
|
|
80
|
+
let isOverlay = style == "overlay" || PNProps.bool(PNProps.value(props, "transparent")) == true
|
|
81
|
+
let content = UIView(frame: controller.view.bounds)
|
|
82
|
+
content.backgroundColor = isOverlay ? .clear : PNColor.parse(PNProps.value(props, "background_color")) ?? .systemBackground
|
|
83
|
+
content.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
84
|
+
controller.view.addSubview(content)
|
|
85
|
+
controller.view.backgroundColor = isOverlay ? UIColor.black.withAlphaComponent(0.4) : content.backgroundColor
|
|
86
|
+
switch isOverlay ? "overlay" : style {
|
|
87
|
+
case "full_screen": controller.modalPresentationStyle = .fullScreen
|
|
88
|
+
case "form_sheet": controller.modalPresentationStyle = .formSheet
|
|
89
|
+
case "overlay": controller.modalPresentationStyle = .overCurrentContext
|
|
90
|
+
default: controller.modalPresentationStyle = .pageSheet
|
|
91
|
+
}
|
|
92
|
+
switch PNProps.string(PNProps.value(props, "animation_type")) ?? PNProps.string(PNProps.value(props, "animation")) {
|
|
93
|
+
case "fade": controller.modalTransitionStyle = .crossDissolve
|
|
94
|
+
case "flip": controller.modalTransitionStyle = .flipHorizontal
|
|
95
|
+
default: controller.modalTransitionStyle = .coverVertical
|
|
96
|
+
}
|
|
97
|
+
if !isOverlay, PNProps.bool(PNProps.value(props, "dismiss_on_backdrop")) == false {
|
|
98
|
+
controller.isModalInPresentation = true
|
|
99
|
+
}
|
|
100
|
+
let presentation = Presentation(controller: controller, content: content)
|
|
101
|
+
state.extras["modal"] = presentation
|
|
102
|
+
for child in (state.extras.removeValue(forKey: "pending_children") as? [UIView]) ?? [] {
|
|
103
|
+
child.translatesAutoresizingMaskIntoConstraints = true
|
|
104
|
+
content.addSubview(child)
|
|
105
|
+
}
|
|
106
|
+
let animated = PNProps.string(PNProps.value(props, "animation_type")) != "none"
|
|
107
|
+
guard let top = PNWindow.topViewController() else {
|
|
108
|
+
state.extras.removeValue(forKey: "modal")
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
top.present(controller, animated: animated) { [weak placeholder] in
|
|
112
|
+
if let placeholder = placeholder { PNEvents.emit(placeholder, "on_show") }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private func dismiss(_ placeholder: UIView, _ state: PNViewState, emit: Bool) {
|
|
117
|
+
guard let modal = state.extras.removeValue(forKey: "modal") as? Presentation else { return }
|
|
118
|
+
(modal.controller as? PNModalViewController)?.onDismissed = nil
|
|
119
|
+
let animated = PNProps.string(PNProps.value(state.props, "animation_type")) != "none"
|
|
120
|
+
modal.controller.dismiss(animated: animated)
|
|
121
|
+
if emit { PNEvents.emit(placeholder, "on_dismiss") }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Reports interactive dismissal (sheet swipe) back to the manager.
|
|
126
|
+
final class PNModalViewController: UIViewController {
|
|
127
|
+
var onDismissed: (() -> Void)?
|
|
128
|
+
|
|
129
|
+
override func viewDidDisappear(_ animated: Bool) {
|
|
130
|
+
super.viewDidDisappear(animated)
|
|
131
|
+
if isBeingDismissed || presentingViewController == nil {
|
|
132
|
+
onDismissed?()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// Overlay view that only claims touches landing on one of its subviews.
|
|
138
|
+
final class PNPortalView: UIView {
|
|
139
|
+
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
|
140
|
+
for sub in subviews where !sub.isHidden && sub.alpha > 0.01 && sub.isUserInteractionEnabled {
|
|
141
|
+
if sub.frame.contains(point) { return true }
|
|
142
|
+
}
|
|
143
|
+
return false
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// `Portal`: floats children over the screen in a top-level overlay that
|
|
148
|
+
/// mirrors the screen host's root frame.
|
|
149
|
+
public final class PNPortalManager: PNComponentManager {
|
|
150
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
151
|
+
let overlay = PNPortalView(frame: .zero)
|
|
152
|
+
overlay.backgroundColor = .clear
|
|
153
|
+
return overlay
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
157
|
+
PNViewStyler.applyCommon(view, props)
|
|
158
|
+
if !initial { ensureAttached(view) }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public override func insertChild(parent: UIView, child: UIView, index: Int) {
|
|
162
|
+
ensureAttached(parent)
|
|
163
|
+
super.insertChild(parent: parent, child: child, index: index)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
|
|
167
|
+
|
|
168
|
+
public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize { .zero }
|
|
169
|
+
|
|
170
|
+
private func ensureAttached(_ overlay: UIView) {
|
|
171
|
+
guard let host = PNWindow.topViewController()?.view else { return }
|
|
172
|
+
if overlay.superview === host {
|
|
173
|
+
if host.subviews.last !== overlay {
|
|
174
|
+
host.bringSubviewToFront(overlay)
|
|
175
|
+
}
|
|
176
|
+
syncFrame(overlay, host: host)
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
overlay.removeFromSuperview()
|
|
180
|
+
host.addSubview(overlay)
|
|
181
|
+
syncFrame(overlay, host: host)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static func rootFrame(in host: UIView) -> CGRect {
|
|
185
|
+
let bounds = host.bounds
|
|
186
|
+
let insets = host.safeAreaInsets
|
|
187
|
+
let w = max(0, bounds.width - insets.left - insets.right)
|
|
188
|
+
let h = max(0, bounds.height - insets.top)
|
|
189
|
+
return CGRect(x: insets.left, y: insets.top, width: w, height: h)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private func syncFrame(_ overlay: UIView, host: UIView) {
|
|
193
|
+
overlay.frame = PNPortalManager.rootFrame(in: host)
|
|
194
|
+
overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Process-wide status bar state consulted by `PNViewController`.
|
|
199
|
+
public enum PNStatusBarState {
|
|
200
|
+
public static var hidden = false
|
|
201
|
+
public static var style: UIStatusBarStyle = .default
|
|
202
|
+
public static var animation: UIStatusBarAnimation = .fade
|
|
203
|
+
|
|
204
|
+
static func refresh() {
|
|
205
|
+
var controller = PNWindow.keyWindow()?.rootViewController
|
|
206
|
+
if let nav = controller as? UINavigationController { controller = nav.topViewController }
|
|
207
|
+
controller?.setNeedsStatusBarAppearanceUpdate()
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// `StatusBar`: a global side effect (hidden / style), no on-screen view.
|
|
212
|
+
public final class PNStatusBarManager: PNComponentManager {
|
|
213
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
214
|
+
let placeholder = UIView(frame: .zero)
|
|
215
|
+
placeholder.isHidden = true
|
|
216
|
+
return placeholder
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
220
|
+
if let hidden = PNProps.bool(PNProps.value(props, "hidden")) {
|
|
221
|
+
PNStatusBarState.hidden = hidden
|
|
222
|
+
}
|
|
223
|
+
if let style = PNProps.string(PNProps.value(props, "bar_style")) {
|
|
224
|
+
switch style {
|
|
225
|
+
case "light", "light_content": PNStatusBarState.style = .lightContent
|
|
226
|
+
case "dark", "dark_content": PNStatusBarState.style = .darkContent
|
|
227
|
+
default: PNStatusBarState.style = .default
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if let animation = PNProps.string(PNProps.value(props, "animation")) {
|
|
231
|
+
switch animation {
|
|
232
|
+
case "slide": PNStatusBarState.animation = .slide
|
|
233
|
+
case "none": PNStatusBarState.animation = .none
|
|
234
|
+
default: PNStatusBarState.animation = .fade
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
PNStatusBarState.refresh()
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
|
|
241
|
+
|
|
242
|
+
public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize { .zero }
|
|
243
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// `Pressable`: a touchable container with press feedback.
|
|
4
|
+
///
|
|
5
|
+
/// A zero-duration long-press recognizer tracks the raw touch for
|
|
6
|
+
/// `on_press_in` / `on_press_out` and the pressed-opacity feedback; a tap
|
|
7
|
+
/// recognizer fires `on_press` and a standard long press fires
|
|
8
|
+
/// `on_long_press`. Hit slop and pointer events come from
|
|
9
|
+
/// `PNContainerView`, so hit testing is entirely UIKit's.
|
|
10
|
+
public final class PNPressableManager: PNComponentManager {
|
|
11
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
12
|
+
let view = PNContainerView(frame: .zero)
|
|
13
|
+
view.isUserInteractionEnabled = true
|
|
14
|
+
return view
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public override func createView(tag: Int64, props: [String: Any]) -> UIView {
|
|
18
|
+
let view = super.createView(tag: tag, props: props)
|
|
19
|
+
let handler = PNPressHandler(view: view)
|
|
20
|
+
PNViewState.existing(for: view)?.retained.append(handler)
|
|
21
|
+
handler.install()
|
|
22
|
+
return view
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
26
|
+
PNViewStyler.applyCommon(view, props)
|
|
27
|
+
if PNProps.has(props, "disabled") {
|
|
28
|
+
view.isUserInteractionEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false)
|
|
29
|
+
}
|
|
30
|
+
if PNProps.has(props, "disabled") {
|
|
31
|
+
view.isUserInteractionEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false)
|
|
32
|
+
}
|
|
33
|
+
if let delay = PNProps.double(PNProps.value(props, "delay_long_press")),
|
|
34
|
+
let handler = PNViewState.existing(for: view)?.retained.compactMap({ $0 as? PNPressHandler }).first
|
|
35
|
+
{
|
|
36
|
+
handler.longPress.minimumPressDuration = max(0.05, delay / 1000)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Owns the three press recognizers of one Pressable.
|
|
42
|
+
final class PNPressHandler: NSObject, UIGestureRecognizerDelegate {
|
|
43
|
+
private weak var view: UIView?
|
|
44
|
+
let tap = UITapGestureRecognizer()
|
|
45
|
+
let longPress = UILongPressGestureRecognizer()
|
|
46
|
+
let touch = UILongPressGestureRecognizer()
|
|
47
|
+
|
|
48
|
+
init(view: UIView) {
|
|
49
|
+
self.view = view
|
|
50
|
+
super.init()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func install() {
|
|
54
|
+
guard let view = view else { return }
|
|
55
|
+
touch.minimumPressDuration = 0
|
|
56
|
+
tap.addTarget(self, action: #selector(onTap(_:)))
|
|
57
|
+
longPress.addTarget(self, action: #selector(onLongPress(_:)))
|
|
58
|
+
touch.addTarget(self, action: #selector(onTouch(_:)))
|
|
59
|
+
for recognizer in [tap, longPress, touch] {
|
|
60
|
+
recognizer.cancelsTouchesInView = false
|
|
61
|
+
recognizer.delegate = self
|
|
62
|
+
view.addGestureRecognizer(recognizer)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private var merged: [String: Any] {
|
|
67
|
+
view.flatMap { PNViewState.existing(for: $0)?.props } ?? [:]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@objc private func onTap(_ recognizer: UITapGestureRecognizer) {
|
|
71
|
+
guard let view = view, recognizer.state == .ended else { return }
|
|
72
|
+
PNEvents.emit(view, "on_press")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@objc private func onLongPress(_ recognizer: UILongPressGestureRecognizer) {
|
|
76
|
+
guard let view = view, recognizer.state == .began else { return }
|
|
77
|
+
PNEvents.emit(view, "on_long_press")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@objc private func onTouch(_ recognizer: UILongPressGestureRecognizer) {
|
|
81
|
+
guard let view = view else { return }
|
|
82
|
+
switch recognizer.state {
|
|
83
|
+
case .began:
|
|
84
|
+
feedback(pressed: true)
|
|
85
|
+
PNEvents.emit(view, "on_press_in")
|
|
86
|
+
case .ended, .cancelled, .failed:
|
|
87
|
+
feedback(pressed: false)
|
|
88
|
+
PNEvents.emit(view, "on_press_out")
|
|
89
|
+
default:
|
|
90
|
+
break
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private func feedback(pressed: Bool) {
|
|
95
|
+
guard let view = view else { return }
|
|
96
|
+
let props = merged
|
|
97
|
+
let target: CGFloat
|
|
98
|
+
let duration: TimeInterval
|
|
99
|
+
if pressed {
|
|
100
|
+
target = CGFloat(PNProps.double(PNProps.value(props, "pressed_opacity")) ?? 0.6)
|
|
101
|
+
duration = 0.05
|
|
102
|
+
} else {
|
|
103
|
+
target = CGFloat(PNProps.double(PNProps.value(props, "opacity")) ?? 1)
|
|
104
|
+
duration = 0.1
|
|
105
|
+
}
|
|
106
|
+
UIView.animate(withDuration: duration) { view.alpha = target }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Press recognizers recognize alongside everything, including the
|
|
110
|
+
// declarative `gestures` recognizers and a parent scroll view's pan.
|
|
111
|
+
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer) -> Bool {
|
|
112
|
+
true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
private final class PNLogicalScreen: UIView {
|
|
4
|
+
private var lastSize = CGSize.zero
|
|
5
|
+
override func layoutSubviews() {
|
|
6
|
+
super.layoutSubviews()
|
|
7
|
+
if bounds.size != lastSize {
|
|
8
|
+
lastSize = bounds.size
|
|
9
|
+
PNLayout.containerDidLayout()
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public final class PNScreenManager: PNComponentManager {
|
|
15
|
+
public override func makeView(props: [String: Any]) -> UIView { PNLogicalScreen(frame: .zero) }
|
|
16
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
17
|
+
if let controller = view.next as? UIViewController {
|
|
18
|
+
HostModule.applyOptions(PNViewState.existing(for: view)?.props ?? props, to: controller)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// UIKit owns the controller's content rectangle, including its navigation bar.
|
|
22
|
+
public override func setFrame(view: UIView, x: Double, y: Double, w: Double, h: Double) {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private final class PNLogicalStack: UIView, UINavigationControllerDelegate {
|
|
26
|
+
let navigation = UINavigationController()
|
|
27
|
+
var controllers: [Int64: UIViewController] = [:]
|
|
28
|
+
var order: [Int64] = []
|
|
29
|
+
var applying = false
|
|
30
|
+
var scheduled = false
|
|
31
|
+
override init(frame: CGRect) {
|
|
32
|
+
super.init(frame: frame)
|
|
33
|
+
navigation.delegate = self
|
|
34
|
+
addSubview(navigation.view)
|
|
35
|
+
}
|
|
36
|
+
required init?(coder: NSCoder) { fatalError("init(coder:) is unavailable") }
|
|
37
|
+
override func didMoveToWindow() {
|
|
38
|
+
super.didMoveToWindow()
|
|
39
|
+
guard window != nil, navigation.parent == nil else { return }
|
|
40
|
+
var responder: UIResponder? = superview
|
|
41
|
+
while let current = responder {
|
|
42
|
+
if let parent = current as? UIViewController {
|
|
43
|
+
parent.addChild(navigation)
|
|
44
|
+
navigation.didMove(toParent: parent)
|
|
45
|
+
parent.navigationController?.setNavigationBarHidden(true, animated: false)
|
|
46
|
+
break
|
|
47
|
+
}
|
|
48
|
+
responder = current.next
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
override func layoutSubviews() {
|
|
52
|
+
super.layoutSubviews()
|
|
53
|
+
navigation.view.frame = bounds
|
|
54
|
+
}
|
|
55
|
+
func schedule() {
|
|
56
|
+
guard !scheduled else { return }
|
|
57
|
+
scheduled = true
|
|
58
|
+
DispatchQueue.main.async { [weak self] in
|
|
59
|
+
guard let self = self else { return }
|
|
60
|
+
self.scheduled = false
|
|
61
|
+
self.applying = true
|
|
62
|
+
self.navigation.setViewControllers(self.order.compactMap { self.controllers[$0] }, animated: false)
|
|
63
|
+
if let tag = self.order.last, let state = PNViewRegistry.shared.view(for: tag).flatMap({ PNViewState.existing(for: $0) }),
|
|
64
|
+
let controller = self.controllers[tag] { HostModule.applyOptions(state.props, to: controller) }
|
|
65
|
+
self.applying = false
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
|
|
69
|
+
if !applying && navigation.viewControllers.count < order.count {
|
|
70
|
+
PNEvents.emit(self, "on_native_back", [order.count - navigation.viewControllers.count])
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Native screen presentation without importing or remounting App.
|
|
76
|
+
public final class PNScreenStackManager: PNComponentManager {
|
|
77
|
+
public override func makeView(props: [String: Any]) -> UIView { PNLogicalStack(frame: .zero) }
|
|
78
|
+
public override func insertChild(parent: UIView, child: UIView, index: Int) {
|
|
79
|
+
guard let stack = parent as? PNLogicalStack, let state = PNViewState.existing(for: child) else { return }
|
|
80
|
+
let controller = stack.controllers[state.tag] ?? UIViewController()
|
|
81
|
+
controller.edgesForExtendedLayout = []
|
|
82
|
+
controller.view = child
|
|
83
|
+
controller.title = state.props["title"] as? String
|
|
84
|
+
stack.controllers[state.tag] = controller
|
|
85
|
+
stack.order.removeAll { $0 == state.tag }
|
|
86
|
+
stack.order.insert(state.tag, at: min(index, stack.order.count))
|
|
87
|
+
stack.schedule()
|
|
88
|
+
}
|
|
89
|
+
public override func removeChild(parent: UIView, child: UIView) {
|
|
90
|
+
guard let stack = parent as? PNLogicalStack, let state = PNViewState.existing(for: child) else { return }
|
|
91
|
+
stack.order.removeAll { $0 == state.tag }
|
|
92
|
+
stack.controllers.removeValue(forKey: state.tag)
|
|
93
|
+
stack.schedule()
|
|
94
|
+
}
|
|
95
|
+
public override func command(view: UIView, name: String, args: [String: Any]) -> Any? {
|
|
96
|
+
if name == "restore_stack", let stack = view as? PNLogicalStack { stack.schedule() }
|
|
97
|
+
return nil
|
|
98
|
+
}
|
|
99
|
+
public override func teardown(view: UIView) {
|
|
100
|
+
guard let stack = view as? PNLogicalStack else { return }
|
|
101
|
+
stack.navigation.willMove(toParent: nil)
|
|
102
|
+
stack.navigation.view.removeFromSuperview()
|
|
103
|
+
stack.navigation.removeFromParent()
|
|
104
|
+
stack.controllers.removeAll()
|
|
105
|
+
stack.navigation.delegate = nil
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// `ScrollView`: a `UIScrollView` wrapping one layout-engine-sized child.
|
|
4
|
+
///
|
|
5
|
+
/// Scroll offsets are reported through `on_scroll` with
|
|
6
|
+
/// `{"x", "y", "extent", "range", "content_width", "content_height"}`.
|
|
7
|
+
/// Commands: `scroll_to_offset`, `scroll_to_end`, `get_scroll_offset`,
|
|
8
|
+
/// `flash_scroll_indicators`.
|
|
9
|
+
public final class PNScrollViewManager: PNComponentManager {
|
|
10
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
11
|
+
let scroll = UIScrollView(frame: .zero)
|
|
12
|
+
scroll.contentInsetAdjustmentBehavior = .never
|
|
13
|
+
return scroll
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public override func createView(tag: Int64, props: [String: Any]) -> UIView {
|
|
17
|
+
let view = super.createView(tag: tag, props: props)
|
|
18
|
+
if let scroll = view as? UIScrollView {
|
|
19
|
+
let delegate = PNScrollDelegate()
|
|
20
|
+
scroll.delegate = delegate
|
|
21
|
+
PNViewState.existing(for: scroll)?.retained.append(delegate)
|
|
22
|
+
}
|
|
23
|
+
return view
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
27
|
+
guard let scroll = view as? UIScrollView else { return }
|
|
28
|
+
PNViewStyler.applyCommon(scroll, props)
|
|
29
|
+
if PNProps.has(props, "refresh_control") {
|
|
30
|
+
applyRefresh(scroll, PNProps.value(props, "refresh_control"))
|
|
31
|
+
}
|
|
32
|
+
if PNProps.has(props, "shows_scroll_indicator") {
|
|
33
|
+
let visible = PNProps.bool(PNProps.value(props, "shows_scroll_indicator")) ?? true
|
|
34
|
+
scroll.showsVerticalScrollIndicator = visible
|
|
35
|
+
scroll.showsHorizontalScrollIndicator = visible
|
|
36
|
+
}
|
|
37
|
+
if PNProps.has(props, "paging_enabled") {
|
|
38
|
+
scroll.isPagingEnabled = PNProps.bool(PNProps.value(props, "paging_enabled")) ?? false
|
|
39
|
+
}
|
|
40
|
+
if PNProps.has(props, "bounces") {
|
|
41
|
+
scroll.bounces = PNProps.bool(PNProps.value(props, "bounces")) ?? true
|
|
42
|
+
}
|
|
43
|
+
if PNProps.has(props, "scroll_enabled") {
|
|
44
|
+
scroll.isScrollEnabled = PNProps.bool(PNProps.value(props, "scroll_enabled")) ?? true
|
|
45
|
+
}
|
|
46
|
+
if PNProps.has(props, "horizontal") {
|
|
47
|
+
let horizontal = PNProps.bool(PNProps.value(props, "horizontal")) ?? false
|
|
48
|
+
scroll.alwaysBounceHorizontal = horizontal
|
|
49
|
+
scroll.alwaysBounceVertical = !horizontal && scroll.refreshControl != nil
|
|
50
|
+
}
|
|
51
|
+
if let mode = PNProps.string(PNProps.value(props, "keyboard_dismiss_mode")) {
|
|
52
|
+
switch mode {
|
|
53
|
+
case "on_drag": scroll.keyboardDismissMode = .onDrag
|
|
54
|
+
case "interactive": scroll.keyboardDismissMode = .interactive
|
|
55
|
+
default: scroll.keyboardDismissMode = .none
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if PNProps.has(props, "content_inset") {
|
|
59
|
+
let inset = PNProps.dict(PNProps.value(props, "content_inset")) ?? [:]
|
|
60
|
+
scroll.contentInset = UIEdgeInsets(
|
|
61
|
+
top: CGFloat(PNProps.double(inset["top"]) ?? 0), left: CGFloat(PNProps.double(inset["left"]) ?? 0),
|
|
62
|
+
bottom: CGFloat(PNProps.double(inset["bottom"]) ?? 0), right: CGFloat(PNProps.double(inset["right"]) ?? 0)
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
if PNProps.has(props, "scroll_indicator_insets") {
|
|
66
|
+
let inset = PNProps.dict(PNProps.value(props, "scroll_indicator_insets")) ?? [:]
|
|
67
|
+
let insets = UIEdgeInsets(
|
|
68
|
+
top: CGFloat(PNProps.double(inset["top"]) ?? 0), left: CGFloat(PNProps.double(inset["left"]) ?? 0),
|
|
69
|
+
bottom: CGFloat(PNProps.double(inset["bottom"]) ?? 0), right: CGFloat(PNProps.double(inset["right"]) ?? 0)
|
|
70
|
+
)
|
|
71
|
+
scroll.verticalScrollIndicatorInsets = insets
|
|
72
|
+
scroll.horizontalScrollIndicatorInsets = insets
|
|
73
|
+
}
|
|
74
|
+
if PNProps.has(props, "scroll_event_throttle") {
|
|
75
|
+
PNViewState.existing(for: scroll)?.extras["throttle"] = PNProps.double(PNProps.value(props, "scroll_event_throttle")) ?? 0
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public override func command(view: UIView, name: String, args: [String: Any]) -> Any? {
|
|
80
|
+
guard let scroll = view as? UIScrollView else { return nil }
|
|
81
|
+
let animated = PNProps.bool(args["animated"]) ?? true
|
|
82
|
+
switch name {
|
|
83
|
+
case "scroll_to_offset":
|
|
84
|
+
let x = CGFloat(PNProps.finite(args["x"]))
|
|
85
|
+
let y = CGFloat(PNProps.finite(args["y"]))
|
|
86
|
+
scroll.setContentOffset(CGPoint(x: x, y: y), animated: animated)
|
|
87
|
+
case "scroll_to_end":
|
|
88
|
+
let content = scroll.contentSize
|
|
89
|
+
let bounds = scroll.bounds.size
|
|
90
|
+
let targetY = max(0, content.height - bounds.height)
|
|
91
|
+
let targetX = max(0, content.width - bounds.width)
|
|
92
|
+
let horizontal = content.width > bounds.width && content.height <= bounds.height
|
|
93
|
+
scroll.setContentOffset(horizontal ? CGPoint(x: targetX, y: 0) : CGPoint(x: 0, y: targetY), animated: animated)
|
|
94
|
+
case "get_scroll_offset":
|
|
95
|
+
return ["x": Double(scroll.contentOffset.x), "y": Double(scroll.contentOffset.y)]
|
|
96
|
+
case "flash_scroll_indicators":
|
|
97
|
+
scroll.flashScrollIndicators()
|
|
98
|
+
default:
|
|
99
|
+
break
|
|
100
|
+
}
|
|
101
|
+
return nil
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// MARK: - Refresh control
|
|
105
|
+
|
|
106
|
+
private func applyRefresh(_ scroll: UIScrollView, _ spec: Any?) {
|
|
107
|
+
guard let spec = spec else {
|
|
108
|
+
if let existing = scroll.refreshControl {
|
|
109
|
+
existing.endRefreshing()
|
|
110
|
+
scroll.refreshControl = nil
|
|
111
|
+
scroll.alwaysBounceVertical = false
|
|
112
|
+
}
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
let control: UIRefreshControl
|
|
116
|
+
if let existing = scroll.refreshControl {
|
|
117
|
+
control = existing
|
|
118
|
+
} else {
|
|
119
|
+
control = UIRefreshControl()
|
|
120
|
+
scroll.refreshControl = control
|
|
121
|
+
// Content that fits its bounds never engages the pan gesture
|
|
122
|
+
// without this, making the refresh control unreachable.
|
|
123
|
+
scroll.alwaysBounceVertical = true
|
|
124
|
+
let target = PNActionTarget { [weak scroll] in
|
|
125
|
+
guard let scroll = scroll else { return }
|
|
126
|
+
PNEvents.emit(scroll, "on_refresh")
|
|
127
|
+
}
|
|
128
|
+
control.addTarget(target, action: #selector(PNActionTarget.fire(_:forEvent:)), for: .valueChanged)
|
|
129
|
+
PNViewState.existing(for: scroll)?.retained.append(target)
|
|
130
|
+
}
|
|
131
|
+
let dict = spec as? [String: Any] ?? [:]
|
|
132
|
+
if let color = PNColor.parse(PNProps.value(dict, "tint_color") ?? PNProps.value(dict, "color")) {
|
|
133
|
+
control.tintColor = color
|
|
134
|
+
}
|
|
135
|
+
if let title = PNProps.string(PNProps.value(dict, "title")) {
|
|
136
|
+
control.attributedTitle = NSAttributedString(string: title)
|
|
137
|
+
}
|
|
138
|
+
if PNProps.bool(dict["refreshing"]) == true {
|
|
139
|
+
if !control.isRefreshing { control.beginRefreshing() }
|
|
140
|
+
} else if control.isRefreshing {
|
|
141
|
+
control.endRefreshing()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/// Shared scroll payload builder.
|
|
147
|
+
enum PNScrollPayload {
|
|
148
|
+
static func make(_ scroll: UIScrollView) -> [String: Any] {
|
|
149
|
+
let offset = scroll.contentOffset
|
|
150
|
+
let bounds = scroll.bounds.size
|
|
151
|
+
let content = scroll.contentSize
|
|
152
|
+
let horizontal = content.width > bounds.width && content.height <= bounds.height
|
|
153
|
+
return [
|
|
154
|
+
"x": Double(offset.x),
|
|
155
|
+
"y": Double(offset.y),
|
|
156
|
+
"extent": Double(horizontal ? bounds.width : bounds.height),
|
|
157
|
+
"range": Double(horizontal ? content.width : content.height),
|
|
158
|
+
"content_width": Double(content.width),
|
|
159
|
+
"content_height": Double(content.height),
|
|
160
|
+
"width": Double(bounds.width),
|
|
161
|
+
"height": Double(bounds.height),
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Forwards `UIScrollViewDelegate` callbacks to Python events.
|
|
167
|
+
final class PNScrollDelegate: NSObject, UIScrollViewDelegate {
|
|
168
|
+
private var lastEmit: TimeInterval = 0
|
|
169
|
+
|
|
170
|
+
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
171
|
+
guard let state = PNViewState.existing(for: scrollView), state.hasEvent("on_scroll") else { return }
|
|
172
|
+
let throttle = (state.extras["throttle"] as? Double ?? 0) / 1000
|
|
173
|
+
let now = CACurrentMediaTime()
|
|
174
|
+
if throttle > 0, now - lastEmit < throttle, scrollView.isDragging || scrollView.isDecelerating { return }
|
|
175
|
+
lastEmit = now
|
|
176
|
+
PNEvents.emit(scrollView, "on_scroll", [PNScrollPayload.make(scrollView)])
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
|
180
|
+
PNEvents.emitIfWired(scrollView, "on_scroll_begin_drag", [PNScrollPayload.make(scrollView)])
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
|
184
|
+
PNEvents.emitIfWired(scrollView, "on_scroll_end_drag", [PNScrollPayload.make(scrollView)])
|
|
185
|
+
if !decelerate {
|
|
186
|
+
PNEvents.emitIfWired(scrollView, "on_momentum_scroll_end", [PNScrollPayload.make(scrollView)])
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
|
191
|
+
PNEvents.emitIfWired(scrollView, "on_momentum_scroll_end", [PNScrollPayload.make(scrollView)])
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
|
195
|
+
PNEvents.emitIfWired(scrollView, "on_scroll", [PNScrollPayload.make(scrollView)])
|
|
196
|
+
}
|
|
197
|
+
}
|